xref: /titanic_50/usr/src/cmd/ndmpd/ndmp/ndmpd_chkpnt.c (revision 356f72340a69936724c69f2f87fffa6f5887f885)
1 /*
2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3  * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
4  * Copyright (c) 2013 Steven Hartland. All rights reserved.
5  */
6 
7 /*
8  * BSD 3 Clause License
9  *
10  * Copyright (c) 2007, The Storage Networking Industry Association.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 	- Redistributions of source code must retain the above copyright
16  *	  notice, this list of conditions and the following disclaimer.
17  *
18  * 	- Redistributions in binary form must reproduce the above copyright
19  *	  notice, this list of conditions and the following disclaimer in
20  *	  the documentation and/or other materials provided with the
21  *	  distribution.
22  *
23  *	- Neither the name of The Storage Networking Industry Association (SNIA)
24  *	  nor the names of its contributors may be used to endorse or promote
25  *	  products derived from this software without specific prior written
26  *	  permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
32  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  */
40 
41 #include <stdio.h>
42 #include <string.h>
43 #include "ndmpd.h"
44 #include <libzfs.h>
45 
46 typedef struct snap_param {
47 	char *snp_name;
48 	boolean_t snp_found;
49 } snap_param_t;
50 
51 static int cleanup_fd = -1;
52 
53 /*
54  * ndmp_has_backup
55  *
56  * Call backup function which looks for backup snapshot.
57  * This is a callback function used with zfs_iter_snapshots.
58  *
59  * Parameters:
60  *   zhp (input) - ZFS handle pointer
61  *   data (output) - 0 - no backup snapshot
62  *		     1 - has backup snapshot
63  *
64  * Returns:
65  *   0: on success
66  *  -1: otherwise
67  */
68 static int
69 ndmp_has_backup(zfs_handle_t *zhp, void *data)
70 {
71 	const char *name;
72 	snap_param_t *chp = (snap_param_t *)data;
73 
74 	name = zfs_get_name(zhp);
75 	if (name == NULL ||
76 	    strstr(name, chp->snp_name) == NULL) {
77 		zfs_close(zhp);
78 		return (-1);
79 	}
80 
81 	chp->snp_found = 1;
82 	zfs_close(zhp);
83 
84 	return (0);
85 }
86 
87 /*
88  * ndmp_has_backup_snapshot
89  *
90  * Returns TRUE if the volume has an active backup snapshot, otherwise,
91  * returns FALSE.
92  *
93  * Parameters:
94  *   volname (input) - name of the volume
95  *
96  * Returns:
97  *   0: on success
98  *  -1: otherwise
99  */
100 static int
101 ndmp_has_backup_snapshot(char *volname, char *jobname)
102 {
103 	zfs_handle_t *zhp;
104 	snap_param_t snp;
105 	char chname[ZFS_MAX_DATASET_NAME_LEN];
106 
107 	(void) mutex_lock(&zlib_mtx);
108 	if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) {
109 		NDMP_LOG(LOG_ERR, "Cannot open snapshot %s.", volname);
110 		(void) mutex_unlock(&zlib_mtx);
111 		return (-1);
112 	}
113 
114 	snp.snp_found = 0;
115 	(void) snprintf(chname, ZFS_MAX_DATASET_NAME_LEN, "@%s", jobname);
116 	snp.snp_name = chname;
117 
118 	(void) zfs_iter_snapshots(zhp, ndmp_has_backup, &snp);
119 	zfs_close(zhp);
120 	(void) mutex_unlock(&zlib_mtx);
121 
122 	return (snp.snp_found);
123 }
124 
125 /*
126  * ndmp_create_snapshot
127  *
128  * This function will parse the path to get the real volume name.
129  * It will then create a snapshot based on volume and job name.
130  * This function should be called before the NDMP backup is started.
131  *
132  * Parameters:
133  *   vol_name (input) - name of the volume
134  *
135  * Returns:
136  *   0: on success
137  *   -1: otherwise
138  */
139 int
140 ndmp_create_snapshot(char *vol_name, char *jname)
141 {
142 	char vol[ZFS_MAX_DATASET_NAME_LEN];
143 
144 	if (vol_name == 0 ||
145 	    get_zfsvolname(vol, sizeof (vol), vol_name) == -1)
146 		return (0);
147 
148 	/*
149 	 * If there is an old snapshot left from the previous
150 	 * backup it could be stale one and it must be
151 	 * removed before using it.
152 	 */
153 	if (ndmp_has_backup_snapshot(vol, jname))
154 		(void) snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL);
155 
156 	return (snapshot_create(vol, jname, B_FALSE, B_TRUE));
157 }
158 
159 /*
160  * ndmp_remove_snapshot
161  *
162  * This function will parse the path to get the real volume name.
163  * It will then remove the snapshot for that volume and job name.
164  * This function should be called after NDMP backup is finished.
165  *
166  * Parameters:
167  *   vol_name (input) - name of the volume
168  *
169  * Returns:
170  *   0: on success
171  *   -1: otherwise
172  */
173 int
174 ndmp_remove_snapshot(char *vol_name, char *jname)
175 {
176 	char vol[ZFS_MAX_DATASET_NAME_LEN];
177 
178 	if (vol_name == 0 ||
179 	    get_zfsvolname(vol, sizeof (vol), vol_name) == -1)
180 		return (0);
181 
182 	return (snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL));
183 }
184 
185 /*
186  * Put a hold on snapshot
187  */
188 int
189 snapshot_hold(char *volname, char *snapname, char *jname, boolean_t recursive)
190 {
191 	zfs_handle_t *zhp;
192 	char *p;
193 
194 	if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) {
195 		NDMP_LOG(LOG_ERR, "Cannot open volume %s.", volname);
196 		return (-1);
197 	}
198 
199 	if (cleanup_fd == -1 && (cleanup_fd = open(ZFS_DEV,
200 	    O_RDWR|O_EXCL)) < 0) {
201 		NDMP_LOG(LOG_ERR, "Cannot open dev %d", errno);
202 		zfs_close(zhp);
203 		return (-1);
204 	}
205 
206 	p = strchr(snapname, '@') + 1;
207 	if (zfs_hold(zhp, p, jname, recursive, cleanup_fd) != 0) {
208 		NDMP_LOG(LOG_ERR, "Cannot hold snapshot %s", p);
209 		zfs_close(zhp);
210 		return (-1);
211 	}
212 	zfs_close(zhp);
213 	return (0);
214 }
215 
216 int
217 snapshot_release(char *volname, char *snapname, char *jname,
218     boolean_t recursive)
219 {
220 	zfs_handle_t *zhp;
221 	char *p;
222 	int rv = 0;
223 
224 	if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) {
225 		NDMP_LOG(LOG_ERR, "Cannot open volume %s", volname);
226 		return (-1);
227 	}
228 
229 	p = strchr(snapname, '@') + 1;
230 	if (zfs_release(zhp, p, jname, recursive) != 0) {
231 		NDMP_LOG(LOG_DEBUG, "Cannot release snapshot %s", p);
232 		rv = -1;
233 	}
234 	if (cleanup_fd != -1) {
235 		(void) close(cleanup_fd);
236 		cleanup_fd = -1;
237 	}
238 	zfs_close(zhp);
239 	return (rv);
240 }
241 
242 /*
243  * Create a snapshot on the volume
244  */
245 int
246 snapshot_create(char *volname, char *jname, boolean_t recursive,
247     boolean_t hold)
248 {
249 	char snapname[ZFS_MAX_DATASET_NAME_LEN];
250 	int rv;
251 
252 	if (!volname || !*volname)
253 		return (-1);
254 
255 	(void) snprintf(snapname, ZFS_MAX_DATASET_NAME_LEN,
256 	    "%s@%s", volname, jname);
257 
258 	(void) mutex_lock(&zlib_mtx);
259 	if ((rv = zfs_snapshot(zlibh, snapname, recursive, NULL))
260 	    == -1) {
261 		if (errno == EEXIST) {
262 			(void) mutex_unlock(&zlib_mtx);
263 			return (0);
264 		}
265 		NDMP_LOG(LOG_DEBUG,
266 		    "snapshot_create: %s failed (err=%d): %s",
267 		    snapname, errno, libzfs_error_description(zlibh));
268 		(void) mutex_unlock(&zlib_mtx);
269 		return (rv);
270 	}
271 	if (hold && snapshot_hold(volname, snapname, jname, recursive) != 0) {
272 		NDMP_LOG(LOG_DEBUG,
273 		    "snapshot_create: %s hold failed (err=%d): %s",
274 		    snapname, errno, libzfs_error_description(zlibh));
275 		(void) mutex_unlock(&zlib_mtx);
276 		return (-1);
277 	}
278 
279 	(void) mutex_unlock(&zlib_mtx);
280 	return (0);
281 }
282 
283 /*
284  * Remove and release the backup snapshot
285  */
286 int
287 snapshot_destroy(char *volname, char *jname, boolean_t recursive,
288     boolean_t hold, int *zfs_err)
289 {
290 	char snapname[ZFS_MAX_DATASET_NAME_LEN];
291 	zfs_handle_t *zhp;
292 	zfs_type_t ztype;
293 	char *namep;
294 	int err;
295 
296 	if (zfs_err)
297 		*zfs_err = 0;
298 
299 	if (!volname || !*volname)
300 		return (-1);
301 
302 	if (recursive) {
303 		ztype = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM;
304 		namep = volname;
305 	} else {
306 		(void) snprintf(snapname, ZFS_MAX_DATASET_NAME_LEN,
307 		    "%s@%s", volname, jname);
308 		namep = snapname;
309 		ztype = ZFS_TYPE_SNAPSHOT;
310 	}
311 
312 	(void) mutex_lock(&zlib_mtx);
313 	if (hold &&
314 	    snapshot_release(volname, namep, jname, recursive) != 0) {
315 		NDMP_LOG(LOG_DEBUG,
316 		    "snapshot_destroy: %s release failed (err=%d): %s",
317 		    namep, errno, libzfs_error_description(zlibh));
318 		(void) mutex_unlock(&zlib_mtx);
319 		return (-1);
320 	}
321 
322 	if ((zhp = zfs_open(zlibh, namep, ztype)) == NULL) {
323 		NDMP_LOG(LOG_DEBUG, "snapshot_destroy: open %s failed",
324 		    namep);
325 		(void) mutex_unlock(&zlib_mtx);
326 		return (-1);
327 	}
328 
329 	if (recursive) {
330 		err = zfs_destroy_snaps(zhp, jname, B_TRUE);
331 	} else {
332 		err = zfs_destroy(zhp, B_TRUE);
333 	}
334 
335 	if (err) {
336 		NDMP_LOG(LOG_ERR, "%s (recursive destroy: %d): %d; %s; %s",
337 		    namep,
338 		    recursive,
339 		    libzfs_errno(zlibh),
340 		    libzfs_error_action(zlibh),
341 		    libzfs_error_description(zlibh));
342 
343 		if (zfs_err)
344 			*zfs_err = err;
345 	}
346 
347 	zfs_close(zhp);
348 	(void) mutex_unlock(&zlib_mtx);
349 
350 	return (0);
351 }
352