Date: Tue, 30 Jul 2013 21:20:13 +0000 (UTC) From: Xin LI <delphij@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r253820 - in head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs: . sys Message-ID: <201307302120.r6ULKD8q073634@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201307302120.r6ULKD8q073634>