xref: /titanic_41/usr/src/cmd/ndmpd/ndmp/ndmpd_chkpnt.c (revision 675fc291908baceb17f92b0b6d961439aaddafc9)
12654012fSReza Sabdar /*
28c4f9701SJanice Chang  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3*675fc291SMatthew Ahrens  * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
4a7a845e4SSteven Hartland  * Copyright (c) 2013 Steven Hartland. All rights reserved.
52654012fSReza Sabdar  */
62654012fSReza Sabdar 
72654012fSReza Sabdar /*
82654012fSReza Sabdar  * BSD 3 Clause License
92654012fSReza Sabdar  *
102654012fSReza Sabdar  * Copyright (c) 2007, The Storage Networking Industry Association.
112654012fSReza Sabdar  *
122654012fSReza Sabdar  * Redistribution and use in source and binary forms, with or without
132654012fSReza Sabdar  * modification, are permitted provided that the following conditions
142654012fSReza Sabdar  * are met:
152654012fSReza Sabdar  * 	- Redistributions of source code must retain the above copyright
162654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer.
172654012fSReza Sabdar  *
182654012fSReza Sabdar  * 	- Redistributions in binary form must reproduce the above copyright
192654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer in
202654012fSReza Sabdar  *	  the documentation and/or other materials provided with the
212654012fSReza Sabdar  *	  distribution.
222654012fSReza Sabdar  *
232654012fSReza Sabdar  *	- Neither the name of The Storage Networking Industry Association (SNIA)
242654012fSReza Sabdar  *	  nor the names of its contributors may be used to endorse or promote
252654012fSReza Sabdar  *	  products derived from this software without specific prior written
262654012fSReza Sabdar  *	  permission.
272654012fSReza Sabdar  *
282654012fSReza Sabdar  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
292654012fSReza Sabdar  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
302654012fSReza Sabdar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
312654012fSReza Sabdar  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
322654012fSReza Sabdar  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
332654012fSReza Sabdar  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
342654012fSReza Sabdar  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
352654012fSReza Sabdar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
362654012fSReza Sabdar  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
372654012fSReza Sabdar  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
382654012fSReza Sabdar  * POSSIBILITY OF SUCH DAMAGE.
392654012fSReza Sabdar  */
402654012fSReza Sabdar 
412654012fSReza Sabdar #include <stdio.h>
422654012fSReza Sabdar #include <string.h>
432654012fSReza Sabdar #include "ndmpd.h"
442654012fSReza Sabdar #include <libzfs.h>
452654012fSReza Sabdar 
46876b86efSReza Sabdar typedef struct snap_param {
47876b86efSReza Sabdar 	char *snp_name;
48876b86efSReza Sabdar 	boolean_t snp_found;
49876b86efSReza Sabdar } snap_param_t;
502654012fSReza Sabdar 
51876b86efSReza Sabdar static int cleanup_fd = -1;
522654012fSReza Sabdar 
532654012fSReza Sabdar /*
542654012fSReza Sabdar  * ndmp_has_backup
552654012fSReza Sabdar  *
562654012fSReza Sabdar  * Call backup function which looks for backup snapshot.
572654012fSReza Sabdar  * This is a callback function used with zfs_iter_snapshots.
582654012fSReza Sabdar  *
592654012fSReza Sabdar  * Parameters:
602654012fSReza Sabdar  *   zhp (input) - ZFS handle pointer
612654012fSReza Sabdar  *   data (output) - 0 - no backup snapshot
622654012fSReza Sabdar  *		     1 - has backup snapshot
632654012fSReza Sabdar  *
642654012fSReza Sabdar  * Returns:
652654012fSReza Sabdar  *   0: on success
662654012fSReza Sabdar  *  -1: otherwise
672654012fSReza Sabdar  */
682654012fSReza Sabdar static int
ndmp_has_backup(zfs_handle_t * zhp,void * data)692654012fSReza Sabdar ndmp_has_backup(zfs_handle_t *zhp, void *data)
702654012fSReza Sabdar {
712654012fSReza Sabdar 	const char *name;
72876b86efSReza Sabdar 	snap_param_t *chp = (snap_param_t *)data;
732654012fSReza Sabdar 
742654012fSReza Sabdar 	name = zfs_get_name(zhp);
752654012fSReza Sabdar 	if (name == NULL ||
76876b86efSReza Sabdar 	    strstr(name, chp->snp_name) == NULL) {
772654012fSReza Sabdar 		zfs_close(zhp);
782654012fSReza Sabdar 		return (-1);
792654012fSReza Sabdar 	}
802654012fSReza Sabdar 
81876b86efSReza Sabdar 	chp->snp_found = 1;
822654012fSReza Sabdar 	zfs_close(zhp);
832654012fSReza Sabdar 
842654012fSReza Sabdar 	return (0);
852654012fSReza Sabdar }
862654012fSReza Sabdar 
872654012fSReza Sabdar /*
88876b86efSReza Sabdar  * ndmp_has_backup_snapshot
892654012fSReza Sabdar  *
902654012fSReza Sabdar  * Returns TRUE if the volume has an active backup snapshot, otherwise,
912654012fSReza Sabdar  * returns FALSE.
922654012fSReza Sabdar  *
932654012fSReza Sabdar  * Parameters:
942654012fSReza Sabdar  *   volname (input) - name of the volume
952654012fSReza Sabdar  *
962654012fSReza Sabdar  * Returns:
972654012fSReza Sabdar  *   0: on success
982654012fSReza Sabdar  *  -1: otherwise
992654012fSReza Sabdar  */
1002654012fSReza Sabdar static int
ndmp_has_backup_snapshot(char * volname,char * jobname)101876b86efSReza Sabdar ndmp_has_backup_snapshot(char *volname, char *jobname)
1022654012fSReza Sabdar {
1032654012fSReza Sabdar 	zfs_handle_t *zhp;
104876b86efSReza Sabdar 	snap_param_t snp;
105*675fc291SMatthew Ahrens 	char chname[ZFS_MAX_DATASET_NAME_LEN];
1062654012fSReza Sabdar 
1072654012fSReza Sabdar 	(void) mutex_lock(&zlib_mtx);
1082654012fSReza Sabdar 	if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) {
109876b86efSReza Sabdar 		NDMP_LOG(LOG_ERR, "Cannot open snapshot %s.", volname);
1102654012fSReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
1112654012fSReza Sabdar 		return (-1);
1122654012fSReza Sabdar 	}
1132654012fSReza Sabdar 
114876b86efSReza Sabdar 	snp.snp_found = 0;
115*675fc291SMatthew Ahrens 	(void) snprintf(chname, ZFS_MAX_DATASET_NAME_LEN, "@%s", jobname);
116876b86efSReza Sabdar 	snp.snp_name = chname;
1172654012fSReza Sabdar 
118876b86efSReza Sabdar 	(void) zfs_iter_snapshots(zhp, ndmp_has_backup, &snp);
1192654012fSReza Sabdar 	zfs_close(zhp);
1202654012fSReza Sabdar 	(void) mutex_unlock(&zlib_mtx);
1212654012fSReza Sabdar 
122876b86efSReza Sabdar 	return (snp.snp_found);
1232654012fSReza Sabdar }
1242654012fSReza Sabdar 
1252654012fSReza Sabdar /*
126876b86efSReza Sabdar  * ndmp_create_snapshot
1272654012fSReza Sabdar  *
128876b86efSReza Sabdar  * This function will parse the path to get the real volume name.
129876b86efSReza Sabdar  * It will then create a snapshot based on volume and job name.
1302654012fSReza Sabdar  * This function should be called before the NDMP backup is started.
1312654012fSReza Sabdar  *
1322654012fSReza Sabdar  * Parameters:
1332654012fSReza Sabdar  *   vol_name (input) - name of the volume
1342654012fSReza Sabdar  *
1352654012fSReza Sabdar  * Returns:
1362654012fSReza Sabdar  *   0: on success
1372654012fSReza Sabdar  *   -1: otherwise
1382654012fSReza Sabdar  */
1392654012fSReza Sabdar int
ndmp_create_snapshot(char * vol_name,char * jname)140876b86efSReza Sabdar ndmp_create_snapshot(char *vol_name, char *jname)
1412654012fSReza Sabdar {
142*675fc291SMatthew Ahrens 	char vol[ZFS_MAX_DATASET_NAME_LEN];
1432654012fSReza Sabdar 
1442654012fSReza Sabdar 	if (vol_name == 0 ||
1452654012fSReza Sabdar 	    get_zfsvolname(vol, sizeof (vol), vol_name) == -1)
1462654012fSReza Sabdar 		return (0);
1472654012fSReza Sabdar 
1482654012fSReza Sabdar 	/*
149876b86efSReza Sabdar 	 * If there is an old snapshot left from the previous
150876b86efSReza Sabdar 	 * backup it could be stale one and it must be
1512654012fSReza Sabdar 	 * removed before using it.
1522654012fSReza Sabdar 	 */
153876b86efSReza Sabdar 	if (ndmp_has_backup_snapshot(vol, jname))
154876b86efSReza Sabdar 		(void) snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL);
1552654012fSReza Sabdar 
156876b86efSReza Sabdar 	return (snapshot_create(vol, jname, B_FALSE, B_TRUE));
1572654012fSReza Sabdar }
1582654012fSReza Sabdar 
1592654012fSReza Sabdar /*
160876b86efSReza Sabdar  * ndmp_remove_snapshot
1612654012fSReza Sabdar  *
162876b86efSReza Sabdar  * This function will parse the path to get the real volume name.
163876b86efSReza Sabdar  * It will then remove the snapshot for that volume and job name.
1642654012fSReza Sabdar  * This function should be called after NDMP backup is finished.
1652654012fSReza Sabdar  *
1662654012fSReza Sabdar  * Parameters:
1672654012fSReza Sabdar  *   vol_name (input) - name of the volume
1682654012fSReza Sabdar  *
1692654012fSReza Sabdar  * Returns:
1702654012fSReza Sabdar  *   0: on success
1712654012fSReza Sabdar  *   -1: otherwise
1722654012fSReza Sabdar  */
1732654012fSReza Sabdar int
ndmp_remove_snapshot(char * vol_name,char * jname)174876b86efSReza Sabdar ndmp_remove_snapshot(char *vol_name, char *jname)
1752654012fSReza Sabdar {
176*675fc291SMatthew Ahrens 	char vol[ZFS_MAX_DATASET_NAME_LEN];
1772654012fSReza Sabdar 
1782654012fSReza Sabdar 	if (vol_name == 0 ||
179876b86efSReza Sabdar 	    get_zfsvolname(vol, sizeof (vol), vol_name) == -1)
1802654012fSReza Sabdar 		return (0);
1812654012fSReza Sabdar 
182876b86efSReza Sabdar 	return (snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL));
183876b86efSReza Sabdar }
1842654012fSReza Sabdar 
185876b86efSReza Sabdar /*
186876b86efSReza Sabdar  * Put a hold on snapshot
187876b86efSReza Sabdar  */
188876b86efSReza Sabdar int
snapshot_hold(char * volname,char * snapname,char * jname,boolean_t recursive)189876b86efSReza Sabdar snapshot_hold(char *volname, char *snapname, char *jname, boolean_t recursive)
190876b86efSReza Sabdar {
191876b86efSReza Sabdar 	zfs_handle_t *zhp;
192876b86efSReza Sabdar 	char *p;
193876b86efSReza Sabdar 
194876b86efSReza Sabdar 	if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) {
195876b86efSReza Sabdar 		NDMP_LOG(LOG_ERR, "Cannot open volume %s.", volname);
196876b86efSReza Sabdar 		return (-1);
197876b86efSReza Sabdar 	}
198876b86efSReza Sabdar 
199876b86efSReza Sabdar 	if (cleanup_fd == -1 && (cleanup_fd = open(ZFS_DEV,
200876b86efSReza Sabdar 	    O_RDWR|O_EXCL)) < 0) {
201876b86efSReza Sabdar 		NDMP_LOG(LOG_ERR, "Cannot open dev %d", errno);
202876b86efSReza Sabdar 		zfs_close(zhp);
203876b86efSReza Sabdar 		return (-1);
204876b86efSReza Sabdar 	}
205876b86efSReza Sabdar 
206876b86efSReza Sabdar 	p = strchr(snapname, '@') + 1;
207a7a845e4SSteven Hartland 	if (zfs_hold(zhp, p, jname, recursive, cleanup_fd) != 0) {
208876b86efSReza Sabdar 		NDMP_LOG(LOG_ERR, "Cannot hold snapshot %s", p);
209876b86efSReza Sabdar 		zfs_close(zhp);
210876b86efSReza Sabdar 		return (-1);
211876b86efSReza Sabdar 	}
212876b86efSReza Sabdar 	zfs_close(zhp);
213876b86efSReza Sabdar 	return (0);
214876b86efSReza Sabdar }
215876b86efSReza Sabdar 
216876b86efSReza Sabdar int
snapshot_release(char * volname,char * snapname,char * jname,boolean_t recursive)217876b86efSReza Sabdar snapshot_release(char *volname, char *snapname, char *jname,
218876b86efSReza Sabdar     boolean_t recursive)
219876b86efSReza Sabdar {
220876b86efSReza Sabdar 	zfs_handle_t *zhp;
221876b86efSReza Sabdar 	char *p;
222876b86efSReza Sabdar 	int rv = 0;
223876b86efSReza Sabdar 
224876b86efSReza Sabdar 	if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) {
225876b86efSReza Sabdar 		NDMP_LOG(LOG_ERR, "Cannot open volume %s", volname);
226876b86efSReza Sabdar 		return (-1);
227876b86efSReza Sabdar 	}
228876b86efSReza Sabdar 
229876b86efSReza Sabdar 	p = strchr(snapname, '@') + 1;
230876b86efSReza Sabdar 	if (zfs_release(zhp, p, jname, recursive) != 0) {
231876b86efSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Cannot release snapshot %s", p);
232876b86efSReza Sabdar 		rv = -1;
233876b86efSReza Sabdar 	}
234876b86efSReza Sabdar 	if (cleanup_fd != -1) {
235876b86efSReza Sabdar 		(void) close(cleanup_fd);
236876b86efSReza Sabdar 		cleanup_fd = -1;
237876b86efSReza Sabdar 	}
238876b86efSReza Sabdar 	zfs_close(zhp);
239876b86efSReza Sabdar 	return (rv);
240876b86efSReza Sabdar }
241876b86efSReza Sabdar 
242876b86efSReza Sabdar /*
243876b86efSReza Sabdar  * Create a snapshot on the volume
244876b86efSReza Sabdar  */
245876b86efSReza Sabdar int
snapshot_create(char * volname,char * jname,boolean_t recursive,boolean_t hold)246876b86efSReza Sabdar snapshot_create(char *volname, char *jname, boolean_t recursive,
247876b86efSReza Sabdar     boolean_t hold)
248876b86efSReza Sabdar {
249*675fc291SMatthew Ahrens 	char snapname[ZFS_MAX_DATASET_NAME_LEN];
250876b86efSReza Sabdar 	int rv;
251876b86efSReza Sabdar 
252876b86efSReza Sabdar 	if (!volname || !*volname)
253876b86efSReza Sabdar 		return (-1);
254876b86efSReza Sabdar 
255*675fc291SMatthew Ahrens 	(void) snprintf(snapname, ZFS_MAX_DATASET_NAME_LEN,
256*675fc291SMatthew Ahrens 	    "%s@%s", volname, jname);
257876b86efSReza Sabdar 
258876b86efSReza Sabdar 	(void) mutex_lock(&zlib_mtx);
259876b86efSReza Sabdar 	if ((rv = zfs_snapshot(zlibh, snapname, recursive, NULL))
260876b86efSReza Sabdar 	    == -1) {
261876b86efSReza Sabdar 		if (errno == EEXIST) {
262876b86efSReza Sabdar 			(void) mutex_unlock(&zlib_mtx);
263876b86efSReza Sabdar 			return (0);
264876b86efSReza Sabdar 		}
265876b86efSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
266876b86efSReza Sabdar 		    "snapshot_create: %s failed (err=%d): %s",
267876b86efSReza Sabdar 		    snapname, errno, libzfs_error_description(zlibh));
268876b86efSReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
269876b86efSReza Sabdar 		return (rv);
270876b86efSReza Sabdar 	}
271876b86efSReza Sabdar 	if (hold && snapshot_hold(volname, snapname, jname, recursive) != 0) {
272876b86efSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
273876b86efSReza Sabdar 		    "snapshot_create: %s hold failed (err=%d): %s",
274876b86efSReza Sabdar 		    snapname, errno, libzfs_error_description(zlibh));
275876b86efSReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
276876b86efSReza Sabdar 		return (-1);
277876b86efSReza Sabdar 	}
278876b86efSReza Sabdar 
279876b86efSReza Sabdar 	(void) mutex_unlock(&zlib_mtx);
280876b86efSReza Sabdar 	return (0);
281876b86efSReza Sabdar }
282876b86efSReza Sabdar 
283876b86efSReza Sabdar /*
284876b86efSReza Sabdar  * Remove and release the backup snapshot
285876b86efSReza Sabdar  */
286876b86efSReza Sabdar int
snapshot_destroy(char * volname,char * jname,boolean_t recursive,boolean_t hold,int * zfs_err)287876b86efSReza Sabdar snapshot_destroy(char *volname, char *jname, boolean_t recursive,
288876b86efSReza Sabdar     boolean_t hold, int *zfs_err)
289876b86efSReza Sabdar {
290*675fc291SMatthew Ahrens 	char snapname[ZFS_MAX_DATASET_NAME_LEN];
291876b86efSReza Sabdar 	zfs_handle_t *zhp;
292876b86efSReza Sabdar 	zfs_type_t ztype;
293588541fbSReza Sabdar 	char *namep;
294876b86efSReza Sabdar 	int err;
295876b86efSReza Sabdar 
296876b86efSReza Sabdar 	if (zfs_err)
297876b86efSReza Sabdar 		*zfs_err = 0;
298876b86efSReza Sabdar 
299876b86efSReza Sabdar 	if (!volname || !*volname)
300876b86efSReza Sabdar 		return (-1);
301876b86efSReza Sabdar 
302876b86efSReza Sabdar 	if (recursive) {
303876b86efSReza Sabdar 		ztype = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM;
304588541fbSReza Sabdar 		namep = volname;
305876b86efSReza Sabdar 	} else {
306*675fc291SMatthew Ahrens 		(void) snprintf(snapname, ZFS_MAX_DATASET_NAME_LEN,
307*675fc291SMatthew Ahrens 		    "%s@%s", volname, jname);
308588541fbSReza Sabdar 		namep = snapname;
309876b86efSReza Sabdar 		ztype = ZFS_TYPE_SNAPSHOT;
310876b86efSReza Sabdar 	}
311876b86efSReza Sabdar 
312876b86efSReza Sabdar 	(void) mutex_lock(&zlib_mtx);
313876b86efSReza Sabdar 	if (hold &&
314588541fbSReza Sabdar 	    snapshot_release(volname, namep, jname, recursive) != 0) {
315876b86efSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
316876b86efSReza Sabdar 		    "snapshot_destroy: %s release failed (err=%d): %s",
317588541fbSReza Sabdar 		    namep, errno, libzfs_error_description(zlibh));
318876b86efSReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
319876b86efSReza Sabdar 		return (-1);
320876b86efSReza Sabdar 	}
321876b86efSReza Sabdar 
322588541fbSReza Sabdar 	if ((zhp = zfs_open(zlibh, namep, ztype)) == NULL) {
323876b86efSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "snapshot_destroy: open %s failed",
324588541fbSReza Sabdar 		    namep);
325876b86efSReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
326876b86efSReza Sabdar 		return (-1);
327876b86efSReza Sabdar 	}
328876b86efSReza Sabdar 
329876b86efSReza Sabdar 	if (recursive) {
330876b86efSReza Sabdar 		err = zfs_destroy_snaps(zhp, jname, B_TRUE);
331876b86efSReza Sabdar 	} else {
332876b86efSReza Sabdar 		err = zfs_destroy(zhp, B_TRUE);
333876b86efSReza Sabdar 	}
334876b86efSReza Sabdar 
335876b86efSReza Sabdar 	if (err) {
336876b86efSReza Sabdar 		NDMP_LOG(LOG_ERR, "%s (recursive destroy: %d): %d; %s; %s",
337588541fbSReza Sabdar 		    namep,
338876b86efSReza Sabdar 		    recursive,
339876b86efSReza Sabdar 		    libzfs_errno(zlibh),
340876b86efSReza Sabdar 		    libzfs_error_action(zlibh),
341876b86efSReza Sabdar 		    libzfs_error_description(zlibh));
342876b86efSReza Sabdar 
343876b86efSReza Sabdar 		if (zfs_err)
344876b86efSReza Sabdar 			*zfs_err = err;
345876b86efSReza Sabdar 	}
346876b86efSReza Sabdar 
347876b86efSReza Sabdar 	zfs_close(zhp);
348876b86efSReza Sabdar 	(void) mutex_unlock(&zlib_mtx);
349876b86efSReza Sabdar 
350876b86efSReza Sabdar 	return (0);
3512654012fSReza Sabdar }
352