xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_chkpnt.c (revision 6e2462f93bf3de7b08885a4677464e11be3c807b)
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  * 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_MAX_DATASET_NAME_LEN];
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_MAX_DATASET_NAME_LEN, "@%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_MAX_DATASET_NAME_LEN];
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_MAX_DATASET_NAME_LEN];
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_MAX_DATASET_NAME_LEN];
251 	int rv;
252 
253 	if (!volname || !*volname)
254 		return (-1);
255 
256 	(void) snprintf(snapname, ZFS_MAX_DATASET_NAME_LEN,
257 	    "%s@%s", volname, jname);
258 
259 	(void) mutex_lock(&zlib_mtx);
260 	if ((rv = zfs_snapshot(zlibh, snapname, recursive, NULL))
261 	    == -1) {
262 		if (errno == EEXIST) {
263 			(void) mutex_unlock(&zlib_mtx);
264 			return (0);
265 		}
266 		NDMP_LOG(LOG_DEBUG,
267 		    "snapshot_create: %s failed (err=%d): %s",
268 		    snapname, errno, libzfs_error_description(zlibh));
269 		(void) mutex_unlock(&zlib_mtx);
270 		return (rv);
271 	}
272 	if (hold && snapshot_hold(volname, snapname, jname, recursive) != 0) {
273 		NDMP_LOG(LOG_DEBUG,
274 		    "snapshot_create: %s hold failed (err=%d): %s",
275 		    snapname, errno, libzfs_error_description(zlibh));
276 		(void) mutex_unlock(&zlib_mtx);
277 		return (-1);
278 	}
279 
280 	(void) mutex_unlock(&zlib_mtx);
281 	return (0);
282 }
283 
284 /*
285  * Remove and release the backup snapshot
286  */
287 int
288 snapshot_destroy(char *volname, char *jname, boolean_t recursive,
289     boolean_t hold, int *zfs_err)
290 {
291 	char snapname[ZFS_MAX_DATASET_NAME_LEN];
292 	zfs_handle_t *zhp;
293 	zfs_type_t ztype;
294 	char *namep;
295 	int err;
296 
297 	if (zfs_err)
298 		*zfs_err = 0;
299 
300 	if (!volname || !*volname)
301 		return (-1);
302 
303 	if (recursive) {
304 		ztype = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM;
305 		namep = volname;
306 	} else {
307 		(void) snprintf(snapname, ZFS_MAX_DATASET_NAME_LEN,
308 		    "%s@%s", volname, jname);
309 		namep = snapname;
310 		ztype = ZFS_TYPE_SNAPSHOT;
311 	}
312 
313 	(void) mutex_lock(&zlib_mtx);
314 	if (hold &&
315 	    snapshot_release(volname, namep, jname, recursive) != 0) {
316 		NDMP_LOG(LOG_DEBUG,
317 		    "snapshot_destroy: %s release failed (err=%d): %s",
318 		    namep, errno, libzfs_error_description(zlibh));
319 		(void) mutex_unlock(&zlib_mtx);
320 		return (-1);
321 	}
322 
323 	if ((zhp = zfs_open(zlibh, namep, ztype)) == NULL) {
324 		NDMP_LOG(LOG_DEBUG, "snapshot_destroy: open %s failed",
325 		    namep);
326 		(void) mutex_unlock(&zlib_mtx);
327 		return (-1);
328 	}
329 
330 	if (recursive) {
331 		err = zfs_destroy_snaps(zhp, jname, B_TRUE);
332 	} else {
333 		err = zfs_destroy(zhp, B_TRUE);
334 	}
335 
336 	if (err) {
337 		NDMP_LOG(LOG_ERR, "%s (recursive destroy: %d): %d; %s; %s",
338 		    namep,
339 		    recursive,
340 		    libzfs_errno(zlibh),
341 		    libzfs_error_action(zlibh),
342 		    libzfs_error_description(zlibh));
343 
344 		if (zfs_err)
345 			*zfs_err = err;
346 	}
347 
348 	zfs_close(zhp);
349 	(void) mutex_unlock(&zlib_mtx);
350 
351 	return (0);
352 }
353