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-head
mailing list