diff options
author | Keith M Wesolowski <[email protected]> | 2013-07-27 10:51:50 -0700 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2013-11-04 11:18:14 -0800 |
commit | 96c2e961938d4018ddb393fa60e004d8a91a58e9 (patch) | |
tree | 6f831e836b96ef81a5daac0ef712df6ac394c492 | |
parent | 1a077756e8ba946a55f999fa1cb5f0e7dcb9aa81 (diff) |
Illumos #3894
3894 zfs should not allow snapshot of inconsistent dataset
Reviewed by: Matthew Ahrens <[email protected]>
Approved by: Gordon Ross <[email protected]>
References:
https://www.illumos.org/issues/3894
illumos/illumos-gate@ca48f36f20f6098ceb19d5b084b6b3d4b8eca9fa
Ported-by: Richard Yao <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Issue #1775
-rw-r--r-- | cmd/zfs/zfs_main.c | 6 | ||||
-rw-r--r-- | include/sys/dsl_dataset.h | 2 | ||||
-rw-r--r-- | include/sys/fs/zfs.h | 1 | ||||
-rw-r--r-- | lib/libzfs/libzfs_dataset.c | 15 | ||||
-rw-r--r-- | module/zcommon/zfs_prop.c | 2 | ||||
-rw-r--r-- | module/zfs/dmu_send.c | 4 | ||||
-rw-r--r-- | module/zfs/dsl_dataset.c | 19 |
7 files changed, 39 insertions, 10 deletions
diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 08d16aa1f..fba3e255c 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -3480,6 +3480,12 @@ zfs_snapshot_cb(zfs_handle_t *zhp, void *arg) 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 --git a/include/sys/dsl_dataset.h b/include/sys/dsl_dataset.h index 725f0d233..e8e26b9f9 100644 --- a/include/sys/dsl_dataset.h +++ b/include/sys/dsl_dataset.h @@ -251,7 +251,7 @@ int dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone, 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 --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index 89ac90ba7..6b2d0f508 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -140,6 +140,7 @@ typedef enum { ZFS_PROP_CLONES, ZFS_PROP_LOGICALUSED, ZFS_PROP_LOGICALREFERENCED, + ZFS_PROP_INCONSISTENT, /* not exposed to the user */ ZFS_PROP_SNAPDEV, ZFS_PROP_ACLTYPE, ZFS_NUM_PROPS diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 3bbd653c6..3b5fc4549 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -1872,6 +1872,10 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, 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: @@ -3514,13 +3518,16 @@ zfs_snapshot_cb(zfs_handle_t *zhp, void *arg) char name[ZFS_MAXNAMELEN]; int rv = 0; - (void) snprintf(name, sizeof (name), - "%s@%s", zfs_get_name(zhp), sd->sd_snapname); + 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); + fnvlist_add_boolean(sd->sd_nvl, name); - rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd); + rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd); + } zfs_close(zhp); + return (rv); } diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c index 93ccfef6b..abd547f10 100644 --- a/module/zcommon/zfs_prop.c +++ b/module/zcommon/zfs_prop.c @@ -410,6 +410,8 @@ zfs_prop_init(void) 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"); /* * Property to be removed once libbe is integrated diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index 87744cb72..e80631b48 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -1584,7 +1584,7 @@ dmu_recv_end_check(void *arg, dmu_tx_t *tx) 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); @@ -1592,7 +1592,7 @@ dmu_recv_end_check(void *arg, dmu_tx_t *tx) 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 --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index 5ed3e8e87..16d5dad49 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -929,7 +929,7 @@ typedef struct dsl_dataset_snapshot_arg { 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; @@ -955,6 +955,18 @@ dsl_dataset_snapshot_check_impl(dsl_dataset_t *ds, const char *snapname, 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); @@ -991,7 +1003,7 @@ dsl_dataset_snapshot_check(void *arg, dmu_tx_t *tx) 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); } @@ -1243,7 +1255,8 @@ dsl_dataset_snapshot_tmp_check(void *arg, dmu_tx_t *tx) 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); |