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