changeset 10204:83c3a84aecef

6760420 zfs unmount -f causes recv to fail 6759975 zplprops unavailable to examiner of in-progress receive
author Matthew Ahrens <Matthew.Ahrens@Sun.COM>
date Wed, 29 Jul 2009 14:12:34 -0700
parents 9e2435db6932
children 4c854da9e3ee
files usr/src/lib/libzfs/common/libzfs_dataset.c usr/src/uts/common/fs/zfs/dmu_send.c usr/src/uts/common/fs/zfs/dsl_dataset.c usr/src/uts/common/fs/zfs/sys/dmu.h usr/src/uts/common/fs/zfs/sys/dsl_dataset.h usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h usr/src/uts/common/fs/zfs/zfs_ioctl.c usr/src/uts/common/fs/zfs/zfs_vfsops.c
diffstat 8 files changed, 59 insertions(+), 123 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c	Wed Jul 29 11:53:29 2009 -0700
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c	Wed Jul 29 14:12:34 2009 -0700
@@ -1675,21 +1675,13 @@
 		(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
 		if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) {
 			zcmd_free_nvlists(&zc);
-			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
-			    "unable to get %s property"),
-			    zfs_prop_to_name(prop));
-			return (zfs_error(zhp->zfs_hdl, EZFS_BADVERSION,
-			    dgettext(TEXT_DOMAIN, "internal error")));
+			return (-1);
 		}
 		if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 ||
 		    nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop),
 		    val) != 0) {
 			zcmd_free_nvlists(&zc);
-			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
-			    "unable to get %s property"),
-			    zfs_prop_to_name(prop));
-			return (zfs_error(zhp->zfs_hdl, EZFS_NOMEM,
-			    dgettext(TEXT_DOMAIN, "internal error")));
+			return (-1);
 		}
 		if (zplprops)
 			nvlist_free(zplprops);
--- a/usr/src/uts/common/fs/zfs/dmu_send.c	Wed Jul 29 11:53:29 2009 -0700
+++ b/usr/src/uts/common/fs/zfs/dmu_send.c	Wed Jul 29 14:12:34 2009 -0700
@@ -483,7 +483,7 @@
 
 /* ARGSUSED */
 static void
-recv_online_incremental_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
+recv_incremental_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
 {
 	dsl_dataset_t *ohds = arg1;
 	struct recvbeginsyncarg *rbsa = arg2;
@@ -513,27 +513,13 @@
 	    dp->dp_spa, tx, cr, "dataset = %lld", dsobj);
 }
 
-/* ARGSUSED */
-static void
-recv_offline_incremental_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
-{
-	dsl_dataset_t *ds = arg1;
-
-	dmu_buf_will_dirty(ds->ds_dbuf, tx);
-	ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT;
-
-	spa_history_internal_log(LOG_DS_REPLAY_INC_SYNC,
-	    ds->ds_dir->dd_pool->dp_spa, tx, cr, "dataset = %lld",
-	    ds->ds_object);
-}
-
 /*
  * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin()
  * succeeds; otherwise we will leak the holds on the datasets.
  */
 int
 dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb,
-    boolean_t force, objset_t *origin, boolean_t online, dmu_recv_cookie_t *drc)
+    boolean_t force, objset_t *origin, dmu_recv_cookie_t *drc)
 {
 	int err = 0;
 	boolean_t byteswap;
@@ -582,36 +568,8 @@
 	/*
 	 * Process the begin in syncing context.
 	 */
-	if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE) && !online) {
-		/* offline incremental receive */
-		err = dsl_dataset_own(tofs, 0, dmu_recv_tag, &ds);
-		if (err)
-			return (err);
-
-		/*
-		 * Only do the rollback if the most recent snapshot
-		 * matches the incremental source
-		 */
-		if (force) {
-			if (ds->ds_prev == NULL ||
-			    ds->ds_prev->ds_phys->ds_guid !=
-			    rbsa.fromguid) {
-				dsl_dataset_disown(ds, dmu_recv_tag);
-				return (ENODEV);
-			}
-			(void) dsl_dataset_rollback(ds, DMU_OST_NONE);
-		}
-		rbsa.force = B_FALSE;
-		err = dsl_sync_task_do(ds->ds_dir->dd_pool,
-		    recv_incremental_check,
-		    recv_offline_incremental_sync, ds, &rbsa, 1);
-		if (err) {
-			dsl_dataset_disown(ds, dmu_recv_tag);
-			return (err);
-		}
-		drc->drc_logical_ds = drc->drc_real_ds = ds;
-	} else if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE)) {
-		/* online incremental receive */
+	if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE)) {
+		/* incremental receive */
 
 		/* tmp clone name is: tofs/%tosnap" */
 		(void) snprintf(rbsa.clonelastname, sizeof (rbsa.clonelastname),
@@ -622,11 +580,18 @@
 		if (err)
 			return (err);
 
+		/* must not have an incremental recv already in progress */
+		if (!mutex_tryenter(&ds->ds_recvlock)) {
+			dsl_dataset_rele(ds, dmu_recv_tag);
+			return (EBUSY);
+		}
+
 		rbsa.force = force;
 		err = dsl_sync_task_do(ds->ds_dir->dd_pool,
 		    recv_incremental_check,
-		    recv_online_incremental_sync, ds, &rbsa, 5);
+		    recv_incremental_sync, ds, &rbsa, 5);
 		if (err) {
+			mutex_exit(&ds->ds_recvlock);
 			dsl_dataset_rele(ds, dmu_recv_tag);
 			return (err);
 		}
@@ -931,26 +896,6 @@
 	return (err);
 }
 
-void
-dmu_recv_abort_cleanup(dmu_recv_cookie_t *drc)
-{
-	if (drc->drc_newfs || drc->drc_real_ds != drc->drc_logical_ds) {
-		/*
-		 * online incremental or new fs: destroy the fs (which
-		 * may be a clone) that we created
-		 */
-		(void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag);
-		if (drc->drc_real_ds != drc->drc_logical_ds)
-			dsl_dataset_rele(drc->drc_logical_ds, dmu_recv_tag);
-	} else {
-		/*
-		 * offline incremental: rollback to most recent snapshot.
-		 */
-		(void) dsl_dataset_rollback(drc->drc_real_ds, DMU_OST_NONE);
-		dsl_dataset_disown(drc->drc_real_ds, dmu_recv_tag);
-	}
-}
-
 /*
  * NB: callers *must* call dmu_recv_end() if this succeeds.
  */
@@ -1078,11 +1023,16 @@
 
 	if (ra.err != 0) {
 		/*
-		 * rollback or destroy what we created, so we don't
-		 * leave it in the restoring state.
+		 * destroy what we created, so we don't leave it in the
+		 * inconsistent restoring state.
 		 */
 		txg_wait_synced(drc->drc_real_ds->ds_dir->dd_pool, 0);
-		dmu_recv_abort_cleanup(drc);
+
+		(void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag);
+		if (drc->drc_real_ds != drc->drc_logical_ds) {
+			mutex_exit(&drc->drc_logical_ds->ds_recvlock);
+			dsl_dataset_rele(drc->drc_logical_ds, dmu_recv_tag);
+		}
 	}
 
 	kmem_free(ra.buf, ra.bufsize);
@@ -1150,6 +1100,7 @@
 		}
 		/* dsl_dataset_destroy() will disown the ds */
 		(void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag);
+		mutex_exit(&drc->drc_logical_ds->ds_recvlock);
 		if (err)
 			return (err);
 	}
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c	Wed Jul 29 11:53:29 2009 -0700
+++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c	Wed Jul 29 14:12:34 2009 -0700
@@ -262,6 +262,7 @@
 	ASSERT(!list_link_active(&ds->ds_synced_link));
 
 	mutex_destroy(&ds->ds_lock);
+	mutex_destroy(&ds->ds_recvlock);
 	mutex_destroy(&ds->ds_opening_lock);
 	mutex_destroy(&ds->ds_deadlist.bpl_lock);
 	rw_destroy(&ds->ds_rwlock);
@@ -359,6 +360,7 @@
 		ds->ds_phys = dbuf->db_data;
 
 		mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL);
+		mutex_init(&ds->ds_recvlock, NULL, MUTEX_DEFAULT, NULL);
 		mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL);
 		mutex_init(&ds->ds_deadlist.bpl_lock, NULL, MUTEX_DEFAULT,
 		    NULL);
@@ -377,6 +379,7 @@
 			 * just opened it.
 			 */
 			mutex_destroy(&ds->ds_lock);
+			mutex_destroy(&ds->ds_recvlock);
 			mutex_destroy(&ds->ds_opening_lock);
 			mutex_destroy(&ds->ds_deadlist.bpl_lock);
 			rw_destroy(&ds->ds_rwlock);
@@ -448,6 +451,7 @@
 				dsl_dataset_drop_ref(ds->ds_prev, ds);
 			dsl_dir_close(ds->ds_dir, ds);
 			mutex_destroy(&ds->ds_lock);
+			mutex_destroy(&ds->ds_recvlock);
 			mutex_destroy(&ds->ds_opening_lock);
 			mutex_destroy(&ds->ds_deadlist.bpl_lock);
 			rw_destroy(&ds->ds_rwlock);
--- a/usr/src/uts/common/fs/zfs/sys/dmu.h	Wed Jul 29 11:53:29 2009 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/dmu.h	Wed Jul 29 14:12:34 2009 -0700
@@ -646,10 +646,9 @@
 } dmu_recv_cookie_t;
 
 int dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *,
-    boolean_t force, objset_t *origin, boolean_t online, dmu_recv_cookie_t *);
+    boolean_t force, objset_t *origin, dmu_recv_cookie_t *);
 int dmu_recv_stream(dmu_recv_cookie_t *drc, struct vnode *vp, offset_t *voffp);
 int dmu_recv_end(dmu_recv_cookie_t *drc);
-void dmu_recv_abort_cleanup(dmu_recv_cookie_t *drc);
 
 /* CRC64 table */
 #define	ZFS_CRC64_POLY	0xC96C5795D7870F42ULL	/* ECMA-182, reflected form */
--- a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h	Wed Jul 29 11:53:29 2009 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h	Wed Jul 29 14:12:34 2009 -0700
@@ -111,6 +111,9 @@
 	/* has internal locking: */
 	bplist_t ds_deadlist;
 
+	/* to protect against multiple concurrent incremental recv */
+	kmutex_t ds_recvlock;
+
 	/* protected by lock on pool's dp_dirty_datasets list */
 	txg_node_t ds_dirty_link;
 	list_node_t ds_synced_link;
--- a/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h	Wed Jul 29 11:53:29 2009 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h	Wed Jul 29 14:12:34 2009 -0700
@@ -73,7 +73,6 @@
 	boolean_t	z_vscan;	/* virus scan on/off */
 	boolean_t	z_use_fuids;	/* version allows fuids */
 	boolean_t	z_replay;	/* set during ZIL replay */
-	kmutex_t	z_online_recv_lock; /* held while recv in progress */
 	uint64_t	z_version;	/* ZPL version */
 	uint64_t	z_shares_dir;	/* hidden shares dir */
 	kmutex_t	z_lock;
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c	Wed Jul 29 11:53:29 2009 -0700
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c	Wed Jul 29 14:12:34 2009 -0700
@@ -2708,7 +2708,6 @@
 	file_t *fp;
 	objset_t *os;
 	dmu_recv_cookie_t drc;
-	zfsvfs_t *zfsvfs = NULL;
 	boolean_t force = (boolean_t)zc->zc_guid;
 	int error, fd;
 	offset_t off;
@@ -2740,25 +2739,12 @@
 		return (EBADF);
 	}
 
-	if (getzfsvfs(tofs, &zfsvfs) == 0) {
-		if (!mutex_tryenter(&zfsvfs->z_online_recv_lock)) {
-			VFS_RELE(zfsvfs->z_vfs);
-			zfsvfs = NULL;
-			error = EBUSY;
-			goto out;
-		}
+	if (props && dmu_objset_open(tofs, DMU_OST_ANY,
+	    DS_MODE_USER | DS_MODE_READONLY, &os) == 0) {
 		/*
 		 * If new properties are supplied, they are to completely
 		 * replace the existing ones, so stash away the existing ones.
 		 */
-		if (props)
-			(void) dsl_prop_get_all(zfsvfs->z_os, &origprops, TRUE);
-	} else if (props && dmu_objset_open(tofs, DMU_OST_ANY,
-	    DS_MODE_USER | DS_MODE_READONLY, &os) == 0) {
-		/*
-		 * Get the props even if there was no zfsvfs (zvol or
-		 * unmounted zpl).
-		 */
 		(void) dsl_prop_get_all(os, &origprops, TRUE);
 
 		dmu_objset_close(os);
@@ -2772,7 +2758,7 @@
 	}
 
 	error = dmu_recv_begin(tofs, tosnap, &zc->zc_begin_record,
-	    force, origin, zfsvfs != NULL, &drc);
+	    force, origin, &drc);
 	if (origin)
 		dmu_objset_close(origin);
 	if (error)
@@ -2793,25 +2779,33 @@
 	off = fp->f_offset;
 	error = dmu_recv_stream(&drc, fp->f_vnode, &off);
 
-	if (error == 0 && zfsvfs) {
-		char *osname;
-		int mode;
-
-		/* online recv */
-		osname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
-		error = zfs_suspend_fs(zfsvfs, osname, &mode);
-		if (error == 0) {
-			int resume_err;
-
+	if (error == 0) {
+		zfsvfs_t *zfsvfs = NULL;
+
+		if (getzfsvfs(tofs, &zfsvfs) == 0) {
+			/* online recv */
+			int end_err;
+			char *osname;
+			int mode;
+
+			osname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+			error = zfs_suspend_fs(zfsvfs, osname, &mode);
+			/*
+			 * If the suspend fails, then the recv_end will
+			 * likely also fail, and clean up after itself.
+			 */
+			end_err = dmu_recv_end(&drc);
+			if (error == 0) {
+				int resume_err =
+				    zfs_resume_fs(zfsvfs, osname, mode);
+				error = error ? error : resume_err;
+			}
+			error = error ? error : end_err;
+			VFS_RELE(zfsvfs->z_vfs);
+			kmem_free(osname, MAXNAMELEN);
+		} else {
 			error = dmu_recv_end(&drc);
-			resume_err = zfs_resume_fs(zfsvfs, osname, mode);
-			error = error ? error : resume_err;
-		} else {
-			dmu_recv_abort_cleanup(&drc);
 		}
-		kmem_free(osname, MAXNAMELEN);
-	} else if (error == 0) {
-		error = dmu_recv_end(&drc);
 	}
 
 	zc->zc_cookie = off - fp->f_offset;
@@ -2826,10 +2820,6 @@
 		(void) zfs_set_prop_nvlist(tofs, origprops);
 	}
 out:
-	if (zfsvfs) {
-		mutex_exit(&zfsvfs->z_online_recv_lock);
-		VFS_RELE(zfsvfs->z_vfs);
-	}
 	nvlist_free(props);
 	nvlist_free(origprops);
 	releasef(fd);
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c	Wed Jul 29 11:53:29 2009 -0700
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c	Wed Jul 29 14:12:34 2009 -0700
@@ -935,7 +935,6 @@
 		goto out;
 
 	mutex_init(&zfsvfs->z_znodes_lock, NULL, MUTEX_DEFAULT, NULL);
-	mutex_init(&zfsvfs->z_online_recv_lock, NULL, MUTEX_DEFAULT, NULL);
 	mutex_init(&zfsvfs->z_lock, NULL, MUTEX_DEFAULT, NULL);
 	list_create(&zfsvfs->z_all_znodes, sizeof (znode_t),
 	    offsetof(znode_t, z_link_node));
@@ -1051,7 +1050,6 @@
 	zfs_fuid_destroy(zfsvfs);
 
 	mutex_destroy(&zfsvfs->z_znodes_lock);
-	mutex_destroy(&zfsvfs->z_online_recv_lock);
 	mutex_destroy(&zfsvfs->z_lock);
 	list_destroy(&zfsvfs->z_all_znodes);
 	rrw_destroy(&zfsvfs->z_teardown_lock);