Skip to content

Commit

Permalink
3894 zfs should not allow snapshot of inconsistent dataset
Browse files Browse the repository at this point in the history
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Approved by: Gordon Ross <gwr@nexenta.com>
  • Loading branch information
Keith M Wesolowski authored and rmustacc committed Jul 28, 2013
1 parent 91948b5 commit ca48f36
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 10 deletions.
6 changes: 6 additions & 0 deletions usr/src/cmd/zfs/zfs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3461,6 +3461,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();
Expand Down
2 changes: 2 additions & 0 deletions usr/src/common/zfs/zfs_prop.c
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,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");

/* oddball properties */
zprop_register_impl(ZFS_PROP_CREATION, "creation", PROP_TYPE_NUMBER, 0,
Expand Down
15 changes: 11 additions & 4 deletions usr/src/lib/libzfs/common/libzfs_dataset.c
Original file line number Diff line number Diff line change
Expand Up @@ -1843,6 +1843,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:
Expand Down Expand Up @@ -3325,13 +3329,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);
}

Expand Down
4 changes: 2 additions & 2 deletions usr/src/uts/common/fs/zfs/dmu_send.c
Original file line number Diff line number Diff line change
Expand Up @@ -1553,15 +1553,15 @@ 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);

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);
}
Expand Down
19 changes: 16 additions & 3 deletions usr/src/uts/common/fs/zfs/dsl_dataset.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -973,6 +973,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);
Expand Down Expand Up @@ -1009,7 +1021,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);
}

Expand Down Expand Up @@ -1262,7 +1274,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);
Expand Down
2 changes: 1 addition & 1 deletion usr/src/uts/common/fs/zfs/sys/dsl_dataset.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions usr/src/uts/common/sys/fs/zfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ typedef enum {
ZFS_PROP_CLONES,
ZFS_PROP_LOGICALUSED,
ZFS_PROP_LOGICALREFERENCED,
ZFS_PROP_INCONSISTENT, /* not exposed to the user */
ZFS_NUM_PROPS
} zfs_prop_t;

Expand Down

0 comments on commit ca48f36

Please sign in to comment.