summaryrefslogtreecommitdiffstats
path: root/sys/cddl
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cddl')
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c119
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c23
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c5
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h5
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_destroy.h21
5 files changed, 114 insertions, 59 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
index 5c15009..a86814a 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
@@ -683,6 +683,7 @@ typedef struct dmu_recv_begin_arg {
const char *drba_origin;
dmu_recv_cookie_t *drba_cookie;
cred_t *drba_cred;
+ uint64_t drba_snapobj;
} dmu_recv_begin_arg_t;
static int
@@ -693,11 +694,6 @@ recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds,
int error;
dsl_pool_t *dp = ds->ds_dir->dd_pool;
- /* must not have any changes since most recent snapshot */
- if (!drba->drba_cookie->drc_force &&
- dsl_dataset_modified_since_lastsnap(ds))
- return (SET_ERROR(ETXTBSY));
-
/* temporary clone name must not exist */
error = zap_lookup(dp->dp_meta_objset,
ds->ds_dir->dd_phys->dd_child_dir_zapobj, recv_clone_name,
@@ -713,41 +709,47 @@ recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds,
return (error == 0 ? EEXIST : error);
if (fromguid != 0) {
- /* if incremental, most recent snapshot must match fromguid */
- if (ds->ds_prev == NULL)
+ dsl_dataset_t *snap;
+ uint64_t obj = ds->ds_phys->ds_prev_snap_obj;
+
+ /* Find snapshot in this dir that matches fromguid. */
+ while (obj != 0) {
+ error = dsl_dataset_hold_obj(dp, obj, FTAG,
+ &snap);
+ if (error != 0)
+ return (SET_ERROR(ENODEV));
+ if (snap->ds_dir != ds->ds_dir) {
+ dsl_dataset_rele(snap, FTAG);
+ return (SET_ERROR(ENODEV));
+ }
+ if (snap->ds_phys->ds_guid == fromguid)
+ break;
+ obj = snap->ds_phys->ds_prev_snap_obj;
+ dsl_dataset_rele(snap, FTAG);
+ }
+ if (obj == 0)
return (SET_ERROR(ENODEV));
- /*
- * most recent snapshot must match fromguid, or there are no
- * changes since the fromguid one
- */
- if (ds->ds_prev->ds_phys->ds_guid != fromguid) {
- uint64_t birth = ds->ds_prev->ds_phys->ds_bp.blk_birth;
- uint64_t obj = ds->ds_prev->ds_phys->ds_prev_snap_obj;
- while (obj != 0) {
- dsl_dataset_t *snap;
- error = dsl_dataset_hold_obj(dp, obj, FTAG,
- &snap);
- if (error != 0)
- return (SET_ERROR(ENODEV));
- if (snap->ds_phys->ds_creation_txg < birth) {
- dsl_dataset_rele(snap, FTAG);
- return (SET_ERROR(ENODEV));
- }
- if (snap->ds_phys->ds_guid == fromguid) {
- dsl_dataset_rele(snap, FTAG);
- break; /* it's ok */
- }
- obj = snap->ds_phys->ds_prev_snap_obj;
+ if (drba->drba_cookie->drc_force) {
+ drba->drba_snapobj = obj;
+ } else {
+ /*
+ * If we are not forcing, there must be no
+ * changes since fromsnap.
+ */
+ if (dsl_dataset_modified_since_snap(ds, snap)) {
dsl_dataset_rele(snap, FTAG);
+ return (SET_ERROR(ETXTBSY));
}
- if (obj == 0)
- return (SET_ERROR(ENODEV));
+ drba->drba_snapobj = ds->ds_prev->ds_object;
}
+
+ dsl_dataset_rele(snap, FTAG);
} else {
/* if full, most recent snapshot must be $ORIGIN */
if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL)
return (SET_ERROR(ENODEV));
+ drba->drba_snapobj = ds->ds_phys->ds_prev_snap_obj;
}
return (0);
@@ -856,8 +858,14 @@ dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
if (error == 0) {
/* create temporary clone */
+ dsl_dataset_t *snap = NULL;
+ if (drba->drba_snapobj != 0) {
+ VERIFY0(dsl_dataset_hold_obj(dp,
+ drba->drba_snapobj, FTAG, &snap));
+ }
dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name,
- ds->ds_prev, crflags, drba->drba_cred, tx);
+ snap, crflags, drba->drba_cred, tx);
+ dsl_dataset_rele(snap, FTAG);
dsl_dataset_rele(ds, FTAG);
} else {
dsl_dir_t *dd;
@@ -1601,6 +1609,32 @@ dmu_recv_end_check(void *arg, dmu_tx_t *tx)
error = dsl_dataset_hold(dp, drc->drc_tofs, FTAG, &origin_head);
if (error != 0)
return (error);
+ if (drc->drc_force) {
+ /*
+ * We will destroy any snapshots in tofs (i.e. before
+ * origin_head) that are after the origin (which is
+ * the snap before drc_ds, because drc_ds can not
+ * have any snaps of its own).
+ */
+ uint64_t obj = origin_head->ds_phys->ds_prev_snap_obj;
+ while (obj != drc->drc_ds->ds_phys->ds_prev_snap_obj) {
+ dsl_dataset_t *snap;
+ error = dsl_dataset_hold_obj(dp, obj, FTAG,
+ &snap);
+ if (error != 0)
+ return (error);
+ if (snap->ds_dir != origin_head->ds_dir)
+ error = SET_ERROR(EINVAL);
+ if (error == 0) {
+ error = dsl_destroy_snapshot_check_impl(
+ snap, B_FALSE);
+ }
+ obj = snap->ds_phys->ds_prev_snap_obj;
+ dsl_dataset_rele(snap, FTAG);
+ if (error != 0)
+ return (error);
+ }
+ }
error = dsl_dataset_clone_swap_check_impl(drc->drc_ds,
origin_head, drc->drc_force, drc->drc_owner, tx);
if (error != 0) {
@@ -1635,6 +1669,27 @@ dmu_recv_end_sync(void *arg, dmu_tx_t *tx)
VERIFY0(dsl_dataset_hold(dp, drc->drc_tofs, FTAG,
&origin_head));
+
+ if (drc->drc_force) {
+ /*
+ * Destroy any snapshots of drc_tofs (origin_head)
+ * after the origin (the snap before drc_ds).
+ */
+ uint64_t obj = origin_head->ds_phys->ds_prev_snap_obj;
+ while (obj != drc->drc_ds->ds_phys->ds_prev_snap_obj) {
+ dsl_dataset_t *snap;
+ VERIFY0(dsl_dataset_hold_obj(dp, obj, FTAG,
+ &snap));
+ ASSERT3P(snap->ds_dir, ==, origin_head->ds_dir);
+ obj = snap->ds_phys->ds_prev_snap_obj;
+ dsl_destroy_snapshot_sync_impl(snap,
+ B_FALSE, tx);
+ dsl_dataset_rele(snap, FTAG);
+ }
+ }
+ VERIFY3P(drc->drc_ds->ds_prev, ==,
+ origin_head->ds_prev);
+
dsl_dataset_clone_swap_sync_impl(drc->drc_ds,
origin_head, tx);
dsl_dataset_snapshot_sync_impl(origin_head,
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
index 774f354..1faebc1 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
@@ -1593,16 +1593,16 @@ dsl_dataset_space(dsl_dataset_t *ds,
}
boolean_t
-dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds)
+dsl_dataset_modified_since_snap(dsl_dataset_t *ds, dsl_dataset_t *snap)
{
dsl_pool_t *dp = ds->ds_dir->dd_pool;
ASSERT(dsl_pool_config_held(dp));
- if (ds->ds_prev == NULL)
+ if (snap == NULL)
return (B_FALSE);
if (ds->ds_phys->ds_bp.blk_birth >
- ds->ds_prev->ds_phys->ds_creation_txg) {
- objset_t *os, *os_prev;
+ snap->ds_phys->ds_creation_txg) {
+ objset_t *os, *os_snap;
/*
* It may be that only the ZIL differs, because it was
* reset in the head. Don't count that as being
@@ -1610,10 +1610,10 @@ dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds)
*/
if (dmu_objset_from_ds(ds, &os) != 0)
return (B_TRUE);
- if (dmu_objset_from_ds(ds->ds_prev, &os_prev) != 0)
+ if (dmu_objset_from_ds(snap, &os_snap) != 0)
return (B_TRUE);
return (bcmp(&os->os_phys->os_meta_dnode,
- &os_prev->os_phys->os_meta_dnode,
+ &os_snap->os_phys->os_meta_dnode,
sizeof (os->os_phys->os_meta_dnode)) != 0);
}
return (B_FALSE);
@@ -2436,15 +2436,14 @@ dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone,
dsl_dataset_is_snapshot(origin_head))
return (SET_ERROR(EINVAL));
- /* the branch point should be just before them */
- if (clone->ds_prev != origin_head->ds_prev)
+ /* if we are not forcing, the branch point should be just before them */
+ if (!force && clone->ds_prev != origin_head->ds_prev)
return (SET_ERROR(EINVAL));
/* clone should be the clone (unless they are unrelated) */
if (clone->ds_prev != NULL &&
clone->ds_prev != clone->ds_dir->dd_pool->dp_origin_snap &&
- origin_head->ds_object !=
- clone->ds_prev->ds_phys->ds_next_snap_obj)
+ origin_head->ds_dir != clone->ds_prev->ds_dir)
return (SET_ERROR(EINVAL));
/* the clone should be a child of the origin */
@@ -2452,7 +2451,8 @@ dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone,
return (SET_ERROR(EINVAL));
/* origin_head shouldn't be modified unless 'force' */
- if (!force && dsl_dataset_modified_since_lastsnap(origin_head))
+ if (!force &&
+ dsl_dataset_modified_since_snap(origin_head, origin_head->ds_prev))
return (SET_ERROR(ETXTBSY));
/* origin_head should have no long holds (e.g. is not mounted) */
@@ -2489,6 +2489,7 @@ dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
ASSERT(clone->ds_reserved == 0);
ASSERT(origin_head->ds_quota == 0 ||
clone->ds_phys->ds_unique_bytes <= origin_head->ds_quota);
+ ASSERT3P(clone->ds_prev, ==, origin_head->ds_prev);
dmu_buf_will_dirty(clone->ds_dbuf, tx);
dmu_buf_will_dirty(origin_head->ds_dbuf, tx);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c
index f968215..ef46df8 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c
@@ -46,10 +46,7 @@ typedef struct dmu_snapshots_destroy_arg {
nvlist_t *dsda_errlist;
} dmu_snapshots_destroy_arg_t;
-/*
- * ds must be owned.
- */
-static int
+int
dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boolean_t defer)
{
if (!dsl_dataset_is_snapshot(ds))
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h
index 2a6e0b8..fa7cad7 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
*/
@@ -206,7 +206,8 @@ void dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx);
spa_t *dsl_dataset_get_spa(dsl_dataset_t *ds);
-boolean_t dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds);
+boolean_t dsl_dataset_modified_since_snap(dsl_dataset_t *ds,
+ dsl_dataset_t *snap);
void dsl_dataset_sync(dsl_dataset_t *os, zio_t *zio, dmu_tx_t *tx);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_destroy.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_destroy.h
index c5a70bb..3f63864 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_destroy.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_destroy.h
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
*/
@@ -35,15 +35,16 @@ struct nvlist;
struct dsl_dataset;
struct dmu_tx;
-int dsl_destroy_snapshots_nvl(struct nvlist *snaps, boolean_t defer,
- struct nvlist *errlist);
-int dsl_destroy_snapshot(const char *name, boolean_t defer);
-int dsl_destroy_head(const char *name);
-int dsl_destroy_head_check_impl(struct dsl_dataset *ds, int expected_holds);
-void dsl_destroy_head_sync_impl(struct dsl_dataset *ds, struct dmu_tx *tx);
-int dsl_destroy_inconsistent(const char *dsname, void *arg);
-void dsl_destroy_snapshot_sync_impl(struct dsl_dataset *ds,
- boolean_t defer, struct dmu_tx *tx);
+int dsl_destroy_snapshots_nvl(struct nvlist *, boolean_t,
+ struct nvlist *);
+int dsl_destroy_snapshot(const char *, boolean_t);
+int dsl_destroy_head(const char *);
+int dsl_destroy_head_check_impl(struct dsl_dataset *, int);
+void dsl_destroy_head_sync_impl(struct dsl_dataset *, struct dmu_tx *);
+int dsl_destroy_inconsistent(const char *, void *);
+int dsl_destroy_snapshot_check_impl(struct dsl_dataset *, boolean_t);
+void dsl_destroy_snapshot_sync_impl(struct dsl_dataset *,
+ boolean_t, struct dmu_tx *);
#ifdef __cplusplus
}
OpenPOWER on IntegriCloud