svn commit: r253820 - in head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs: . sys

Xin LI delphij at FreeBSD.org
Tue Jul 30 21:20:14 UTC 2013


Author: delphij
Date: Tue Jul 30 21:20:12 2013
New Revision: 253820
URL: http://svnweb.freebsd.org/changeset/base/253820

Log:
  MFV r253782:
  
  To quote Illumos issue #3888:
  
  When 'zfs recv -F' is used with an incremental recv it rolls
  back any changes made since the last snapshot in case new
  changes were made to the file system while the recv is in
  progress (without -F the recv would fail when it does it's
  final check to commit the recv-ed data as the recv-ed data
  conflicts with the newly written data).
  
  However, if there is a snapshot taken after the recv began
  rolling back to the 'latest' snapshot will not help and the
  recv will still fail. 'zfs recv -F' should be extended to
  destroy any snapshots created since the source snapshot when
  finishing the recv (effectively rolling back through all
  snapshots, instead of just to the latest snapshot).
  
  Illumos ZFS issues:
    3888 zfs recv -F should destroy any snapshots created since the
         incremental source
  
  MFC after:	2 weeks

Modified:
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_destroy.h
Directory Properties:
  head/sys/cddl/contrib/opensolaris/   (props changed)

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c	Tue Jul 30 21:02:09 2013	(r253819)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c	Tue Jul 30 21:20:12 2013	(r253820)
@@ -683,6 +683,7 @@ typedef struct dmu_recv_begin_arg {
 	const char *drba_origin;
 	dmu_recv_cookie_t *drba_cookie;
 	cred_t *drba_cred;
+	uint64_t drba_snapobj;
 } dmu_recv_begin_arg_t;
 
 static int
@@ -693,11 +694,6 @@ recv_begin_check_existing_impl(dmu_recv_
 	int error;
 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
 
-	/* must not have any changes since most recent snapshot */
-	if (!drba->drba_cookie->drc_force &&
-	    dsl_dataset_modified_since_lastsnap(ds))
-		return (SET_ERROR(ETXTBSY));
-
 	/* temporary clone name must not exist */
 	error = zap_lookup(dp->dp_meta_objset,
 	    ds->ds_dir->dd_phys->dd_child_dir_zapobj, recv_clone_name,
@@ -713,41 +709,47 @@ recv_begin_check_existing_impl(dmu_recv_
 		return (error == 0 ? EEXIST : error);
 
 	if (fromguid != 0) {
-		/* if incremental, most recent snapshot must match fromguid */
-		if (ds->ds_prev == NULL)
+		dsl_dataset_t *snap;
+		uint64_t obj = ds->ds_phys->ds_prev_snap_obj;
+
+		/* Find snapshot in this dir that matches fromguid. */
+		while (obj != 0) {
+			error = dsl_dataset_hold_obj(dp, obj, FTAG,
+			    &snap);
+			if (error != 0)
+				return (SET_ERROR(ENODEV));
+			if (snap->ds_dir != ds->ds_dir) {
+				dsl_dataset_rele(snap, FTAG);
+				return (SET_ERROR(ENODEV));
+			}
+			if (snap->ds_phys->ds_guid == fromguid)
+				break;
+			obj = snap->ds_phys->ds_prev_snap_obj;
+			dsl_dataset_rele(snap, FTAG);
+		}
+		if (obj == 0)
 			return (SET_ERROR(ENODEV));
 
-		/*
-		 * most recent snapshot must match fromguid, or there are no
-		 * changes since the fromguid one
-		 */
-		if (ds->ds_prev->ds_phys->ds_guid != fromguid) {
-			uint64_t birth = ds->ds_prev->ds_phys->ds_bp.blk_birth;
-			uint64_t obj = ds->ds_prev->ds_phys->ds_prev_snap_obj;
-			while (obj != 0) {
-				dsl_dataset_t *snap;
-				error = dsl_dataset_hold_obj(dp, obj, FTAG,
-				    &snap);
-				if (error != 0)
-					return (SET_ERROR(ENODEV));
-				if (snap->ds_phys->ds_creation_txg < birth) {
-					dsl_dataset_rele(snap, FTAG);
-					return (SET_ERROR(ENODEV));
-				}
-				if (snap->ds_phys->ds_guid == fromguid) {
-					dsl_dataset_rele(snap, FTAG);
-					break; /* it's ok */
-				}
-				obj = snap->ds_phys->ds_prev_snap_obj;
+		if (drba->drba_cookie->drc_force) {
+			drba->drba_snapobj = obj;
+		} else {
+			/*
+			 * If we are not forcing, there must be no
+			 * changes since fromsnap.
+			 */
+			if (dsl_dataset_modified_since_snap(ds, snap)) {
 				dsl_dataset_rele(snap, FTAG);
+				return (SET_ERROR(ETXTBSY));
 			}
-			if (obj == 0)
-				return (SET_ERROR(ENODEV));
+			drba->drba_snapobj = ds->ds_prev->ds_object;
 		}
+
+		dsl_dataset_rele(snap, FTAG);
 	} else {
 		/* if full, most recent snapshot must be $ORIGIN */
 		if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL)
 			return (SET_ERROR(ENODEV));
+		drba->drba_snapobj = ds->ds_phys->ds_prev_snap_obj;
 	}
 
 	return (0);
@@ -856,8 +858,14 @@ dmu_recv_begin_sync(void *arg, dmu_tx_t 
 	error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
 	if (error == 0) {
 		/* create temporary clone */
+		dsl_dataset_t *snap = NULL;
+		if (drba->drba_snapobj != 0) {
+			VERIFY0(dsl_dataset_hold_obj(dp,
+			    drba->drba_snapobj, FTAG, &snap));
+		}
 		dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name,
-		    ds->ds_prev, crflags, drba->drba_cred, tx);
+		    snap, crflags, drba->drba_cred, tx);
+		dsl_dataset_rele(snap, FTAG);
 		dsl_dataset_rele(ds, FTAG);
 	} else {
 		dsl_dir_t *dd;
@@ -1601,6 +1609,32 @@ dmu_recv_end_check(void *arg, dmu_tx_t *
 		error = dsl_dataset_hold(dp, drc->drc_tofs, FTAG, &origin_head);
 		if (error != 0)
 			return (error);
+		if (drc->drc_force) {
+			/*
+			 * We will destroy any snapshots in tofs (i.e. before
+			 * origin_head) that are after the origin (which is
+			 * the snap before drc_ds, because drc_ds can not
+			 * have any snaps of its own).
+			 */
+			uint64_t obj = origin_head->ds_phys->ds_prev_snap_obj;
+			while (obj != drc->drc_ds->ds_phys->ds_prev_snap_obj) {
+				dsl_dataset_t *snap;
+				error = dsl_dataset_hold_obj(dp, obj, FTAG,
+				    &snap);
+				if (error != 0)
+					return (error);
+				if (snap->ds_dir != origin_head->ds_dir)
+					error = SET_ERROR(EINVAL);
+				if (error == 0)  {
+					error = dsl_destroy_snapshot_check_impl(
+					    snap, B_FALSE);
+				}
+				obj = snap->ds_phys->ds_prev_snap_obj;
+				dsl_dataset_rele(snap, FTAG);
+				if (error != 0)
+					return (error);
+			}
+		}
 		error = dsl_dataset_clone_swap_check_impl(drc->drc_ds,
 		    origin_head, drc->drc_force, drc->drc_owner, tx);
 		if (error != 0) {
@@ -1635,6 +1669,27 @@ dmu_recv_end_sync(void *arg, dmu_tx_t *t
 
 		VERIFY0(dsl_dataset_hold(dp, drc->drc_tofs, FTAG,
 		    &origin_head));
+
+		if (drc->drc_force) {
+			/*
+			 * Destroy any snapshots of drc_tofs (origin_head)
+			 * after the origin (the snap before drc_ds).
+			 */
+			uint64_t obj = origin_head->ds_phys->ds_prev_snap_obj;
+			while (obj != drc->drc_ds->ds_phys->ds_prev_snap_obj) {
+				dsl_dataset_t *snap;
+				VERIFY0(dsl_dataset_hold_obj(dp, obj, FTAG,
+				    &snap));
+				ASSERT3P(snap->ds_dir, ==, origin_head->ds_dir);
+				obj = snap->ds_phys->ds_prev_snap_obj;
+				dsl_destroy_snapshot_sync_impl(snap,
+				    B_FALSE, tx);
+				dsl_dataset_rele(snap, FTAG);
+			}
+		}
+		VERIFY3P(drc->drc_ds->ds_prev, ==,
+		    origin_head->ds_prev);
+
 		dsl_dataset_clone_swap_sync_impl(drc->drc_ds,
 		    origin_head, tx);
 		dsl_dataset_snapshot_sync_impl(origin_head,

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c	Tue Jul 30 21:02:09 2013	(r253819)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c	Tue Jul 30 21:20:12 2013	(r253820)
@@ -1593,16 +1593,16 @@ dsl_dataset_space(dsl_dataset_t *ds,
 }
 
 boolean_t
-dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds)
+dsl_dataset_modified_since_snap(dsl_dataset_t *ds, dsl_dataset_t *snap)
 {
 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
 
 	ASSERT(dsl_pool_config_held(dp));
-	if (ds->ds_prev == NULL)
+	if (snap == NULL)
 		return (B_FALSE);
 	if (ds->ds_phys->ds_bp.blk_birth >
-	    ds->ds_prev->ds_phys->ds_creation_txg) {
-		objset_t *os, *os_prev;
+	    snap->ds_phys->ds_creation_txg) {
+		objset_t *os, *os_snap;
 		/*
 		 * It may be that only the ZIL differs, because it was
 		 * reset in the head.  Don't count that as being
@@ -1610,10 +1610,10 @@ dsl_dataset_modified_since_lastsnap(dsl_
 		 */
 		if (dmu_objset_from_ds(ds, &os) != 0)
 			return (B_TRUE);
-		if (dmu_objset_from_ds(ds->ds_prev, &os_prev) != 0)
+		if (dmu_objset_from_ds(snap, &os_snap) != 0)
 			return (B_TRUE);
 		return (bcmp(&os->os_phys->os_meta_dnode,
-		    &os_prev->os_phys->os_meta_dnode,
+		    &os_snap->os_phys->os_meta_dnode,
 		    sizeof (os->os_phys->os_meta_dnode)) != 0);
 	}
 	return (B_FALSE);
@@ -2436,15 +2436,14 @@ dsl_dataset_clone_swap_check_impl(dsl_da
 	    dsl_dataset_is_snapshot(origin_head))
 		return (SET_ERROR(EINVAL));
 
-	/* the branch point should be just before them */
-	if (clone->ds_prev != origin_head->ds_prev)
+	/* if we are not forcing, the branch point should be just before them */
+	if (!force && clone->ds_prev != origin_head->ds_prev)
 		return (SET_ERROR(EINVAL));
 
 	/* clone should be the clone (unless they are unrelated) */
 	if (clone->ds_prev != NULL &&
 	    clone->ds_prev != clone->ds_dir->dd_pool->dp_origin_snap &&
-	    origin_head->ds_object !=
-	    clone->ds_prev->ds_phys->ds_next_snap_obj)
+	    origin_head->ds_dir != clone->ds_prev->ds_dir)
 		return (SET_ERROR(EINVAL));
 
 	/* the clone should be a child of the origin */
@@ -2452,7 +2451,8 @@ dsl_dataset_clone_swap_check_impl(dsl_da
 		return (SET_ERROR(EINVAL));
 
 	/* origin_head shouldn't be modified unless 'force' */
-	if (!force && dsl_dataset_modified_since_lastsnap(origin_head))
+	if (!force &&
+	    dsl_dataset_modified_since_snap(origin_head, origin_head->ds_prev))
 		return (SET_ERROR(ETXTBSY));
 
 	/* origin_head should have no long holds (e.g. is not mounted) */
@@ -2489,6 +2489,7 @@ dsl_dataset_clone_swap_sync_impl(dsl_dat
 	ASSERT(clone->ds_reserved == 0);
 	ASSERT(origin_head->ds_quota == 0 ||
 	    clone->ds_phys->ds_unique_bytes <= origin_head->ds_quota);
+	ASSERT3P(clone->ds_prev, ==, origin_head->ds_prev);
 
 	dmu_buf_will_dirty(clone->ds_dbuf, tx);
 	dmu_buf_will_dirty(origin_head->ds_dbuf, tx);

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c	Tue Jul 30 21:02:09 2013	(r253819)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c	Tue Jul 30 21:20:12 2013	(r253820)
@@ -46,10 +46,7 @@ typedef struct dmu_snapshots_destroy_arg
 	nvlist_t *dsda_errlist;
 } dmu_snapshots_destroy_arg_t;
 
-/*
- * ds must be owned.
- */
-static int
+int
 dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boolean_t defer)
 {
 	if (!dsl_dataset_is_snapshot(ds))

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h	Tue Jul 30 21:02:09 2013	(r253819)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h	Tue Jul 30 21:20:12 2013	(r253820)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  */
@@ -206,7 +206,8 @@ void dsl_dataset_set_blkptr(dsl_dataset_
 
 spa_t *dsl_dataset_get_spa(dsl_dataset_t *ds);
 
-boolean_t dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds);
+boolean_t dsl_dataset_modified_since_snap(dsl_dataset_t *ds,
+    dsl_dataset_t *snap);
 
 void dsl_dataset_sync(dsl_dataset_t *os, zio_t *zio, dmu_tx_t *tx);
 

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_destroy.h
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_destroy.h	Tue Jul 30 21:02:09 2013	(r253819)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_destroy.h	Tue Jul 30 21:20:12 2013	(r253820)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  */
 
@@ -35,15 +35,16 @@ struct nvlist;
 struct dsl_dataset;
 struct dmu_tx;
 
-int dsl_destroy_snapshots_nvl(struct nvlist *snaps, boolean_t defer,
-    struct nvlist *errlist);
-int dsl_destroy_snapshot(const char *name, boolean_t defer);
-int dsl_destroy_head(const char *name);
-int dsl_destroy_head_check_impl(struct dsl_dataset *ds, int expected_holds);
-void dsl_destroy_head_sync_impl(struct dsl_dataset *ds, struct dmu_tx *tx);
-int dsl_destroy_inconsistent(const char *dsname, void *arg);
-void dsl_destroy_snapshot_sync_impl(struct dsl_dataset *ds,
-    boolean_t defer, struct dmu_tx *tx);
+int dsl_destroy_snapshots_nvl(struct nvlist *, boolean_t,
+    struct nvlist *);
+int dsl_destroy_snapshot(const char *, boolean_t);
+int dsl_destroy_head(const char *);
+int dsl_destroy_head_check_impl(struct dsl_dataset *, int);
+void dsl_destroy_head_sync_impl(struct dsl_dataset *, struct dmu_tx *);
+int dsl_destroy_inconsistent(const char *, void *);
+int dsl_destroy_snapshot_check_impl(struct dsl_dataset *, boolean_t);
+void dsl_destroy_snapshot_sync_impl(struct dsl_dataset *,
+    boolean_t, struct dmu_tx *);
 
 #ifdef	__cplusplus
 }


More information about the svn-src-all mailing list