summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith M Wesolowski <wesolows@foobazco.org>2013-07-03 18:30:55 +0000
committerKeith M Wesolowski <wesolows@foobazco.org>2013-07-05 16:02:07 +0000
commit0fe60623dc0a8afa2fd9432c8bfc14b2fc9d1514 (patch)
tree0caee270f0c8dfbb56fe60493f6871d018abef51
parent5f9af889e6d7ace4d369bd2cc4dade5ea3744639 (diff)
downloadillumos-joyent-0fe60623dc0a8afa2fd9432c8bfc14b2fc9d1514.tar.gz
OS-2358 zfs should not allow snapshot of inconsistent dataset
Reviewed by: Bill Pijewski <wdp@joyent.com>
-rw-r--r--usr/src/uts/common/fs/zfs/dmu_send.c4
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_dataset.c25
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dsl_dataset.h2
3 files changed, 25 insertions, 6 deletions
diff --git a/usr/src/uts/common/fs/zfs/dmu_send.c b/usr/src/uts/common/fs/zfs/dmu_send.c
index cbbde2071b..843516325e 100644
--- a/usr/src/uts/common/fs/zfs/dmu_send.c
+++ b/usr/src/uts/common/fs/zfs/dmu_send.c
@@ -1553,7 +1553,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);
@@ -1561,7 +1561,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/usr/src/uts/common/fs/zfs/dsl_dataset.c b/usr/src/uts/common/fs/zfs/dsl_dataset.c
index d59b6fa052..cb62fd7c7e 100644
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c
+++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c
@@ -947,7 +947,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;
@@ -973,6 +973,24 @@ 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) {
+ mutex_enter(&ds->ds_lock);
+ if (DS_IS_INCONSISTENT(ds)) {
+ mutex_exit(&ds->ds_lock);
+ return (SET_ERROR(EBUSY));
+ }
+ mutex_exit(&ds->ds_lock);
+ }
+
error = dsl_dataset_snapshot_reserve_space(ds, tx);
if (error != 0)
return (error);
@@ -1009,7 +1027,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 + 2, tx, B_FALSE);
dsl_dataset_rele(ds, FTAG);
}
@@ -1262,7 +1280,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);
diff --git a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h
index cbb6f86539..58e4c58286 100644
--- a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h
+++ b/usr/src/uts/common/fs/zfs/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);