6678308 zfs receive dumps core when -n is used, fails on replication stream
authorTim Haley <Tim.Haley@Sun.COM>
Mon, 18 Aug 2008 21:10:03 -0600
changeset 7366 33de5956afbb
parent 7365 121c0d90fc62
child 7367 57a71b725a3b
6678308 zfs receive dumps core when -n is used, fails on replication stream
usr/src/lib/libzfs/common/libzfs_changelist.c
usr/src/lib/libzfs/common/libzfs_dataset.c
usr/src/lib/libzfs/common/libzfs_impl.h
usr/src/lib/libzfs/common/libzfs_mount.c
usr/src/lib/libzfs/common/libzfs_sendrecv.c
--- a/usr/src/lib/libzfs/common/libzfs_changelist.c	Mon Aug 18 20:25:59 2008 -0600
+++ b/usr/src/lib/libzfs/common/libzfs_changelist.c	Mon Aug 18 21:10:03 2008 -0600
@@ -26,8 +26,6 @@
  * Portions Copyright 2007 Ramprakash Jelari
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <libintl.h>
 #include <libuutil.h>
 #include <stddef.h>
@@ -80,7 +78,8 @@
 	boolean_t		cl_waslegacy;
 	boolean_t		cl_allchildren;
 	boolean_t		cl_alldependents;
-	int			cl_flags;
+	int			cl_mflags;	/* Mount flags */
+	int			cl_gflags;	/* Gather request flags */
 	boolean_t		cl_haszonedchild;
 	boolean_t		cl_sorted;
 };
@@ -149,7 +148,7 @@
 			switch (clp->cl_prop) {
 			case ZFS_PROP_MOUNTPOINT:
 				if (zfs_unmount(cn->cn_handle, NULL,
-				    clp->cl_flags) != 0) {
+				    clp->cl_mflags) != 0) {
 					ret = -1;
 					cn->cn_needpost = B_FALSE;
 				}
@@ -480,7 +479,8 @@
 		}
 
 		cn->cn_handle = zhp;
-		cn->cn_mounted = zfs_is_mounted(zhp, NULL);
+		cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) ||
+		    zfs_is_mounted(zhp, NULL);
 		cn->cn_shared = zfs_is_shared(zhp);
 		cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
 		cn->cn_needpost = B_TRUE;
@@ -556,7 +556,8 @@
  * mark whether it was shared beforehand.
  */
 prop_changelist_t *
-changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
+changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
+    int mnt_flags)
 {
 	prop_changelist_t *clp;
 	prop_changenode_t *cn;
@@ -592,7 +593,8 @@
 
 	clp->cl_list = uu_list_create(clp->cl_pool, NULL,
 	    clp->cl_sorted ? UU_LIST_SORTED : 0);
-	clp->cl_flags = flags;
+	clp->cl_gflags = gather_flags;
+	clp->cl_mflags = mnt_flags;
 
 	if (clp->cl_list == NULL) {
 		assert(uu_error() == UU_ERROR_NO_MEMORY);
@@ -673,7 +675,8 @@
 	}
 
 	cn->cn_handle = temp;
-	cn->cn_mounted = zfs_is_mounted(temp, NULL);
+	cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) ||
+	    zfs_is_mounted(temp, NULL);
 	cn->cn_shared = zfs_is_shared(temp);
 	cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
 	cn->cn_needpost = B_TRUE;
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c	Mon Aug 18 20:25:59 2008 -0600
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c	Mon Aug 18 21:10:03 2008 -0600
@@ -1789,7 +1789,7 @@
 
 	prop = zfs_name_to_prop(propname);
 
-	if ((cl = changelist_gather(zhp, prop, 0)) == NULL)
+	if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
 		goto error;
 
 	if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
@@ -1979,7 +1979,7 @@
 	/*
 	 * Determine datasets which will be affected by this change, if any.
 	 */
-	if ((cl = changelist_gather(zhp, prop, 0)) == NULL)
+	if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
 		return (-1);
 
 	if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
@@ -3575,7 +3575,7 @@
 		/* We must destroy this clone; first unmount it */
 		prop_changelist_t *clp;
 
-		clp = changelist_gather(zhp, ZFS_PROP_NAME,
+		clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
 		    cbp->cb_force ? MS_FORCE: 0);
 		if (clp == NULL || changelist_prefix(clp) != 0) {
 			cbp->cb_error = B_TRUE;
@@ -3851,7 +3851,7 @@
 			goto error;
 		}
 	} else {
-		if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL)
+		if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0)) == NULL)
 			return (-1);
 
 		if (changelist_haszonedchild(cl)) {
--- a/usr/src/lib/libzfs/common/libzfs_impl.h	Mon Aug 18 20:25:59 2008 -0600
+++ b/usr/src/lib/libzfs/common/libzfs_impl.h	Mon Aug 18 21:10:03 2008 -0600
@@ -27,8 +27,6 @@
 #ifndef	_LIBFS_IMPL_H
 #define	_LIBFS_IMPL_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/dmu.h>
 #include <sys/fs/zfs.h>
 #include <sys/zfs_ioctl.h>
@@ -138,6 +136,13 @@
 int zprop_expand_list(libzfs_handle_t *hdl, zprop_list_t **plp,
     zfs_type_t type);
 
+/*
+ * Use this changelist_gather() flag to force attempting mounts
+ * on each change node regardless of whether or not it is currently
+ * mounted.
+ */
+#define	CL_GATHER_MOUNT_ALWAYS	1
+
 typedef struct prop_changelist prop_changelist_t;
 
 int zcmd_alloc_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *, size_t);
@@ -152,7 +157,7 @@
 void changelist_rename(prop_changelist_t *, const char *, const char *);
 void changelist_remove(prop_changelist_t *, const char *);
 void changelist_free(prop_changelist_t *);
-prop_changelist_t *changelist_gather(zfs_handle_t *, zfs_prop_t, int);
+prop_changelist_t *changelist_gather(zfs_handle_t *, zfs_prop_t, int, int);
 int changelist_unshare(prop_changelist_t *, zfs_share_proto_t *);
 int changelist_haszonedchild(prop_changelist_t *);
 
--- a/usr/src/lib/libzfs/common/libzfs_mount.c	Mon Aug 18 20:25:59 2008 -0600
+++ b/usr/src/lib/libzfs/common/libzfs_mount.c	Mon Aug 18 21:10:03 2008 -0600
@@ -24,8 +24,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Routines to manage ZFS mounts.  We separate all the nasty routines that have
  * to deal with the OS.  The following functions are the main entry points --
@@ -440,7 +438,7 @@
 	prop_changelist_t *clp;
 	int ret;
 
-	clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags);
+	clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, 0, flags);
 	if (clp == NULL)
 		return (-1);
 
@@ -945,7 +943,7 @@
 	prop_changelist_t *clp;
 	int ret;
 
-	clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0);
+	clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0, 0);
 	if (clp == NULL)
 		return (-1);
 
--- a/usr/src/lib/libzfs/common/libzfs_sendrecv.c	Mon Aug 18 20:25:59 2008 -0600
+++ b/usr/src/lib/libzfs/common/libzfs_sendrecv.c	Mon Aug 18 21:10:03 2008 -0600
@@ -24,8 +24,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
@@ -51,6 +49,9 @@
 
 #include <fletcher.c> /* XXX */
 
+static int zfs_receive_impl(libzfs_handle_t *, const char *, recvflags_t,
+    int, avl_tree_t *, char **);
+
 /*
  * Routines for dealing with the AVL tree of fs-nvlists
  */
@@ -882,7 +883,8 @@
 	zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
 	if (zhp == NULL)
 		return (-1);
-	clp = changelist_gather(zhp, ZFS_PROP_NAME, flags.force ? MS_FORCE : 0);
+	clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
+	    flags.force ? MS_FORCE : 0);
 	zfs_close(zhp);
 	if (clp == NULL)
 		return (-1);
@@ -953,7 +955,8 @@
 	zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
 	if (zhp == NULL)
 		return (-1);
-	clp = changelist_gather(zhp, ZFS_PROP_NAME, flags.force ? MS_FORCE : 0);
+	clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
+	    flags.force ? MS_FORCE : 0);
 	zfs_close(zhp);
 	if (clp == NULL)
 		return (-1);
@@ -1345,7 +1348,8 @@
 
 static int
 zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
-    recvflags_t flags, dmu_replay_record_t *drr, zio_cksum_t *zc)
+    recvflags_t flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
+    char **top_zfs)
 {
 	nvlist_t *stream_nv = NULL;
 	avl_tree_t *stream_avl = NULL;
@@ -1457,7 +1461,8 @@
 		 * zfs_receive_one() will take care of it (ie,
 		 * recv_skip() and return 0).
 		 */
-		error = zfs_receive(hdl, destname, flags, fd, stream_avl);
+		error = zfs_receive_impl(hdl, destname, flags, fd,
+		    stream_avl, top_zfs);
 		if (error == ENODATA) {
 			error = 0;
 			break;
@@ -1523,7 +1528,7 @@
 		case DRR_WRITE:
 			if (byteswap) {
 				drr->drr_u.drr_write.drr_length =
-				    BSWAP_32(drr->drr_u.drr_write.drr_length);
+				    BSWAP_64(drr->drr_u.drr_write.drr_length);
 			}
 			(void) recv_read(hdl, fd, buf,
 			    drr->drr_u.drr_write.drr_length, B_FALSE, NULL);
@@ -1548,7 +1553,8 @@
 static int
 zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
     recvflags_t flags, dmu_replay_record_t *drr,
-    dmu_replay_record_t *drr_noswap, avl_tree_t *stream_avl)
+    dmu_replay_record_t *drr_noswap, avl_tree_t *stream_avl,
+    char **top_zfs)
 {
 	zfs_cmd_t zc = { 0 };
 	time_t begin_time;
@@ -1759,7 +1765,7 @@
 		if (!flags.dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM &&
 		    stream_wantsnewfs) {
 			/* We can't do online recv in this case */
-			clp = changelist_gather(zhp, ZFS_PROP_NAME, 0);
+			clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0);
 			if (clp == NULL) {
 				zcmd_free_nvlists(&zc);
 				return (-1);
@@ -1931,18 +1937,24 @@
 		*cp = '\0';
 		h = zfs_open(hdl, zc.zc_value,
 		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
-		*cp = '@';
 		if (h != NULL) {
 			if (h->zfs_type == ZFS_TYPE_VOLUME) {
+				*cp = '@';
 				err = zvol_create_link(hdl, h->zfs_name);
 				if (err == 0 && ioctl_err == 0)
 					err = zvol_create_link(hdl,
 					    zc.zc_value);
 			} else if (newfs) {
-				err = zfs_mount(h, NULL, 0);
+				/*
+				 * Track the first/top of hierarchy fs,
+				 * for mounting and sharing later.
+				 */
+				if (top_zfs && *top_zfs == NULL)
+					*top_zfs = zfs_strdup(hdl, zc.zc_value);
 			}
 			zfs_close(h);
 		}
+		*cp = '@';
 	}
 
 	if (clp) {
@@ -1970,15 +1982,9 @@
 	return (0);
 }
 
-/*
- * Restores a backup of tosnap from the file descriptor specified by infd.
- * Return 0 on total success, -2 if some things couldn't be
- * destroyed/renamed/promoted, -1 if some things couldn't be received.
- * (-1 will override -2).
- */
-int
-zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
-    int infd, avl_tree_t *stream_avl)
+static int
+zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
+    int infd, avl_tree_t *stream_avl, char **top_zfs)
 {
 	int err;
 	dmu_replay_record_t drr, drr_noswap;
@@ -2044,10 +2050,10 @@
 
 	if (drrb->drr_version == DMU_BACKUP_STREAM_VERSION) {
 		return (zfs_receive_one(hdl, infd, tosnap, flags,
-		    &drr, &drr_noswap, stream_avl));
+		    &drr, &drr_noswap, stream_avl, top_zfs));
 	} else if (drrb->drr_version == DMU_BACKUP_HEADER_VERSION) {
 		return (zfs_receive_package(hdl, infd, tosnap, flags,
-		    &drr, &zcksum));
+		    &drr, &zcksum, top_zfs));
 	} else {
 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 		    "stream is unsupported version %llu"),
@@ -2055,3 +2061,42 @@
 		return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
 	}
 }
+
+/*
+ * Restores a backup of tosnap from the file descriptor specified by infd.
+ * Return 0 on total success, -2 if some things couldn't be
+ * destroyed/renamed/promoted, -1 if some things couldn't be received.
+ * (-1 will override -2).
+ */
+int
+zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
+    int infd, avl_tree_t *stream_avl)
+{
+	char *top_zfs = NULL;
+	int err;
+
+	err = zfs_receive_impl(hdl, tosnap, flags, infd, stream_avl, &top_zfs);
+
+	if (err == 0 && top_zfs) {
+		zfs_handle_t *zhp;
+		prop_changelist_t *clp;
+
+		zhp = zfs_open(hdl, top_zfs, ZFS_TYPE_FILESYSTEM);
+		if (zhp != NULL) {
+			clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,
+			    CL_GATHER_MOUNT_ALWAYS, 0);
+			zfs_close(zhp);
+			if (clp != NULL) {
+				/* mount and share received datasets */
+				err = changelist_postfix(clp);
+				changelist_free(clp);
+			}
+		}
+		if (zhp == NULL || clp == NULL || err)
+			err = -1;
+	}
+	if (top_zfs)
+		free(top_zfs);
+
+	return (err);
+}