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