summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/zfs/zfs_main.c6
-rw-r--r--include/sys/dsl_dataset.h2
-rw-r--r--include/sys/fs/zfs.h1
-rw-r--r--lib/libzfs/libzfs_dataset.c15
-rw-r--r--module/zcommon/zfs_prop.c2
-rw-r--r--module/zfs/dmu_send.c4
-rw-r--r--module/zfs/dsl_dataset.c19
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);