# HG changeset patch # User Keith M Wesolowski # Date 1374947510 25200 # Node ID 520f3adc5d460e4a79921e4df16fb8f9699b97fe # Parent 3ca4e9e72fe7b4a01f2fc99a2b1b76fee80473cf 3894 zfs should not allow snapshot of inconsistent dataset Reviewed by: Matthew Ahrens Approved by: Gordon Ross diff -r 3ca4e9e72fe7 -r 520f3adc5d46 usr/src/cmd/zfs/zfs_main.c --- a/usr/src/cmd/zfs/zfs_main.c Sat Jul 27 10:50:07 2013 -0700 +++ b/usr/src/cmd/zfs/zfs_main.c Sat Jul 27 10:51:50 2013 -0700 @@ -3461,6 +3461,12 @@ int rv = 0; int error; + if (sd->sd_recursive && + zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) != 0) { + zfs_close(zhp); + return (0); + } + error = asprintf(&name, "%s@%s", zfs_get_name(zhp), sd->sd_snapname); if (error == -1) nomem(); diff -r 3ca4e9e72fe7 -r 520f3adc5d46 usr/src/common/zfs/zfs_prop.c --- a/usr/src/common/zfs/zfs_prop.c Sat Jul 27 10:50:07 2013 -0700 +++ b/usr/src/common/zfs/zfs_prop.c Sat Jul 27 10:51:50 2013 -0700 @@ -395,6 +395,8 @@ PROP_READONLY, ZFS_TYPE_DATASET, "UNIQUE"); zprop_register_hidden(ZFS_PROP_OBJSETID, "objsetid", PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_DATASET, "OBJSETID"); + zprop_register_hidden(ZFS_PROP_INCONSISTENT, "inconsistent", + PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_DATASET, "INCONSISTENT"); /* oddball properties */ zprop_register_impl(ZFS_PROP_CREATION, "creation", PROP_TYPE_NUMBER, 0, diff -r 3ca4e9e72fe7 -r 520f3adc5d46 usr/src/lib/libzfs/common/libzfs_dataset.c --- a/usr/src/lib/libzfs/common/libzfs_dataset.c Sat Jul 27 10:50:07 2013 -0700 +++ b/usr/src/lib/libzfs/common/libzfs_dataset.c Sat Jul 27 10:51:50 2013 -0700 @@ -1843,6 +1843,10 @@ zcmd_free_nvlists(&zc); break; + case ZFS_PROP_INCONSISTENT: + *val = zhp->zfs_dmustats.dds_inconsistent; + break; + default: switch (zfs_prop_get_type(prop)) { case PROP_TYPE_NUMBER: @@ -3325,13 +3329,16 @@ char name[ZFS_MAXNAMELEN]; int rv = 0; - (void) snprintf(name, sizeof (name), - "%s@%s", zfs_get_name(zhp), sd->sd_snapname); - - fnvlist_add_boolean(sd->sd_nvl, name); - - rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd); + if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) { + (void) snprintf(name, sizeof (name), + "%s@%s", zfs_get_name(zhp), sd->sd_snapname); + + fnvlist_add_boolean(sd->sd_nvl, name); + + rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd); + } zfs_close(zhp); + return (rv); } diff -r 3ca4e9e72fe7 -r 520f3adc5d46 usr/src/uts/common/fs/zfs/dmu_send.c --- a/usr/src/uts/common/fs/zfs/dmu_send.c Sat Jul 27 10:50:07 2013 -0700 +++ b/usr/src/uts/common/fs/zfs/dmu_send.c Sat Jul 27 10:51:50 2013 -0700 @@ -1553,7 +1553,7 @@ return (error); } error = dsl_dataset_snapshot_check_impl(origin_head, - drc->drc_tosnap, tx); + drc->drc_tosnap, tx, B_TRUE); dsl_dataset_rele(origin_head, FTAG); if (error != 0) return (error); @@ -1561,7 +1561,7 @@ error = dsl_destroy_head_check_impl(drc->drc_ds, 1); } else { error = dsl_dataset_snapshot_check_impl(drc->drc_ds, - drc->drc_tosnap, tx); + drc->drc_tosnap, tx, B_TRUE); } return (error); } diff -r 3ca4e9e72fe7 -r 520f3adc5d46 usr/src/uts/common/fs/zfs/dsl_dataset.c --- a/usr/src/uts/common/fs/zfs/dsl_dataset.c Sat Jul 27 10:50:07 2013 -0700 +++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c Sat Jul 27 10:51:50 2013 -0700 @@ -947,7 +947,7 @@ int dsl_dataset_snapshot_check_impl(dsl_dataset_t *ds, const char *snapname, - dmu_tx_t *tx) + dmu_tx_t *tx, boolean_t recv) { int error; uint64_t value; @@ -973,6 +973,18 @@ if (error != ENOENT) return (error); + /* + * We don't allow taking snapshots of inconsistent datasets, such as + * those into which we are currently receiving. However, if we are + * creating this snapshot as part of a receive, this check will be + * executed atomically with respect to the completion of the receive + * itself but prior to the clearing of DS_FLAG_INCONSISTENT; in this + * case we ignore this, knowing it will be fixed up for us shortly in + * dmu_recv_end_sync(). + */ + if (!recv && DS_IS_INCONSISTENT(ds)) + return (SET_ERROR(EBUSY)); + error = dsl_dataset_snapshot_reserve_space(ds, tx); if (error != 0) return (error); @@ -1009,7 +1021,7 @@ error = dsl_dataset_hold(dp, dsname, FTAG, &ds); if (error == 0) { error = dsl_dataset_snapshot_check_impl(ds, - atp + 1, tx); + atp + 1, tx, B_FALSE); dsl_dataset_rele(ds, FTAG); } @@ -1262,7 +1274,8 @@ if (error != 0) return (error); - error = dsl_dataset_snapshot_check_impl(ds, ddsta->ddsta_snapname, tx); + error = dsl_dataset_snapshot_check_impl(ds, ddsta->ddsta_snapname, + tx, B_FALSE); if (error != 0) { dsl_dataset_rele(ds, FTAG); return (error); diff -r 3ca4e9e72fe7 -r 520f3adc5d46 usr/src/uts/common/fs/zfs/sys/dsl_dataset.h --- a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h Sat Jul 27 10:50:07 2013 -0700 +++ b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h Sat Jul 27 10:51:50 2013 -0700 @@ -251,7 +251,7 @@ void dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone, dsl_dataset_t *origin_head, dmu_tx_t *tx); int dsl_dataset_snapshot_check_impl(dsl_dataset_t *ds, const char *snapname, - dmu_tx_t *tx); + dmu_tx_t *tx, boolean_t recv); void dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname, dmu_tx_t *tx); diff -r 3ca4e9e72fe7 -r 520f3adc5d46 usr/src/uts/common/sys/fs/zfs.h --- a/usr/src/uts/common/sys/fs/zfs.h Sat Jul 27 10:50:07 2013 -0700 +++ b/usr/src/uts/common/sys/fs/zfs.h Sat Jul 27 10:51:50 2013 -0700 @@ -140,6 +140,7 @@ ZFS_PROP_CLONES, ZFS_PROP_LOGICALUSED, ZFS_PROP_LOGICALREFERENCED, + ZFS_PROP_INCONSISTENT, /* not exposed to the user */ ZFS_NUM_PROPS } zfs_prop_t;