summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs/zfs/dsl_dataset.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/fs/zfs/dsl_dataset.c')
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_dataset.c85
1 files changed, 79 insertions, 6 deletions
diff --git a/usr/src/uts/common/fs/zfs/dsl_dataset.c b/usr/src/uts/common/fs/zfs/dsl_dataset.c
index 7db7745270..d660cca0ca 100644
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c
+++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c
@@ -36,6 +36,9 @@
#include <sys/unique.h>
#include <sys/zfs_context.h>
+static int dsl_dataset_destroy_begin_sync(dsl_dir_t *dd,
+ void *arg, dmu_tx_t *tx);
+
#define DOS_REF_MAX (1ULL << 62)
#define DSL_DEADLIST_BLOCKSIZE SPA_MAXBLOCKSIZE
@@ -370,7 +373,7 @@ dsl_dataset_open_obj(dsl_pool_t *dp, uint64_t dsobj, const char *snapname,
mutex_enter(&ds->ds_lock);
if ((DS_MODE_LEVEL(mode) == DS_MODE_PRIMARY &&
- ds->ds_phys->ds_restoring && !DS_MODE_IS_RESTORE(mode)) ||
+ ds->ds_phys->ds_inconsistent && !DS_MODE_IS_INCONSISTENT(mode)) ||
(ds->ds_open_refcount + weight > DOS_REF_MAX)) {
mutex_exit(&ds->ds_lock);
dsl_dataset_close(ds, DS_MODE_NONE, tag);
@@ -612,7 +615,6 @@ dsl_dataset_create_sync(dsl_dir_t *pds, const char *fullname,
return (0);
}
-
int
dsl_dataset_destroy(const char *name)
{
@@ -642,16 +644,65 @@ dsl_dataset_destroy(const char *name)
} else {
char buf[MAXNAMELEN];
char *cp;
-
+ objset_t *os;
+ uint64_t obj;
dsl_dir_t *pds;
+
if (dd->dd_phys->dd_parent_obj == 0) {
dsl_dir_close(dd, FTAG);
return (EINVAL);
}
+
+ err = dmu_objset_open(name, DMU_OST_ANY,
+ DS_MODE_PRIMARY | DS_MODE_INCONSISTENT, &os);
+ if (err) {
+ dsl_dir_close(dd, FTAG);
+ return (err);
+ }
+
+ /*
+ * Check for errors and mark this ds as inconsistent, in
+ * case we crash while freeing the objects.
+ */
+ err = dsl_dir_sync_task(os->os->os_dsl_dataset->ds_dir,
+ dsl_dataset_destroy_begin_sync, os->os->os_dsl_dataset, 0);
+ if (err) {
+ dmu_objset_close(os);
+ dsl_dir_close(dd, FTAG);
+ return (err);
+ }
+
/*
- * Make sure it's not dirty before we destroy it.
+ * remove the objects in open context, so that we won't
+ * have too much to do in syncing context.
*/
+ for (obj = 0; err == 0;
+ err = dmu_object_next(os, &obj, FALSE)) {
+ dmu_tx_t *tx = dmu_tx_create(os);
+ dmu_tx_hold_free(tx, obj, 0, DMU_OBJECT_END);
+ dmu_tx_hold_bonus(tx, obj);
+ err = dmu_tx_assign(tx, TXG_WAIT);
+ if (err) {
+ /*
+ * Perhaps there is not enough disk
+ * space. Just deal with it from
+ * dsl_dataset_destroy_sync().
+ */
+ dmu_tx_abort(tx);
+ continue;
+ }
+ VERIFY(0 == dmu_object_free(os, obj, tx));
+ dmu_tx_commit(tx);
+ }
+ dmu_objset_close(os);
+ if (err != ESRCH) {
+ dsl_dir_close(dd, FTAG);
+ return (err);
+ }
+
+ /* Make sure it's not dirty before we finish destroying it. */
txg_wait_synced(dd->dd_pool, 0);
+
/*
* Blow away the dsl_dir + head dataset.
* dsl_dir_destroy_sync() will call
@@ -888,7 +939,7 @@ dsl_dataset_rollback_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx)
ds->ds_prev->ds_phys->ds_compressed_bytes;
ds->ds_phys->ds_uncompressed_bytes =
ds->ds_prev->ds_phys->ds_uncompressed_bytes;
- ds->ds_phys->ds_restoring = ds->ds_prev->ds_phys->ds_restoring;
+ ds->ds_phys->ds_inconsistent = ds->ds_prev->ds_phys->ds_inconsistent;
ds->ds_phys->ds_unique_bytes = 0;
dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
@@ -901,6 +952,28 @@ dsl_dataset_rollback_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx)
return (0);
}
+/* ARGSUSED */
+static int
+dsl_dataset_destroy_begin_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx)
+{
+ dsl_dataset_t *ds = arg;
+
+ /*
+ * Can't delete a head dataset if there are snapshots of it.
+ * (Except if the only snapshots are from the branch we cloned
+ * from.)
+ */
+ if (ds->ds_prev != NULL &&
+ ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object)
+ return (EINVAL);
+
+ /* Mark it as inconsistent on-disk, in case we crash */
+ dmu_buf_will_dirty(ds->ds_dbuf, tx);
+ ds->ds_phys->ds_inconsistent = TRUE;
+
+ return (0);
+}
+
int
dsl_dataset_destroy_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx)
{
@@ -1274,7 +1347,7 @@ dsl_dataset_snapshot_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx)
dsphys->ds_used_bytes = ds->ds_phys->ds_used_bytes;
dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes;
dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes;
- dsphys->ds_restoring = ds->ds_phys->ds_restoring;
+ dsphys->ds_inconsistent = ds->ds_phys->ds_inconsistent;
dsphys->ds_bp = ds->ds_phys->ds_bp;
dmu_buf_rele(dbuf, FTAG);