summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorbonwick <none@none>2006-04-01 21:50:51 -0800
committerbonwick <none@none>2006-04-01 21:50:51 -0800
commite19302335c33c8c6e0b0b5e426fc1f6352c84b5d (patch)
tree23df7a5300fb3815187c6738c4245cec975f234b /usr/src
parentd64e89e7a834c2c403a48d72dea4ba04f3c2c0ba (diff)
downloadillumos-gate-e19302335c33c8c6e0b0b5e426fc1f6352c84b5d.tar.gz
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
6395670 Performance degradation while reading sequentially with large block size
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/zdb/zdb.c4
-rw-r--r--usr/src/cmd/ztest/ztest.c9
-rw-r--r--usr/src/uts/common/fs/zfs/dmu.c17
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_dataset.c85
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dmu.h4
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dsl_dataset.h2
6 files changed, 99 insertions, 22 deletions
diff --git a/usr/src/cmd/zdb/zdb.c b/usr/src/cmd/zdb/zdb.c
index 3247184dfe..9f1b3bec16 100644
--- a/usr/src/cmd/zdb/zdb.c
+++ b/usr/src/cmd/zdb/zdb.c
@@ -727,8 +727,8 @@ dump_dsl_dataset(objset_t *os, uint64_t object, void *data, size_t size)
(u_longlong_t)ds->ds_fsid_guid);
(void) printf("\t\tguid = %llu\n",
(u_longlong_t)ds->ds_guid);
- (void) printf("\t\trestoring = %llu\n",
- (u_longlong_t)ds->ds_restoring);
+ (void) printf("\t\tinconsistent = %llu\n",
+ (u_longlong_t)ds->ds_inconsistent);
(void) printf("\t\tbp = %s\n", blkbuf);
}
diff --git a/usr/src/cmd/ztest/ztest.c b/usr/src/cmd/ztest/ztest.c
index 790f2cf24b..b98bc5e8bb 100644
--- a/usr/src/cmd/ztest/ztest.c
+++ b/usr/src/cmd/ztest/ztest.c
@@ -1055,9 +1055,12 @@ ztest_destroy_cb(char *name, void *arg)
DS_MODE_STANDARD | DS_MODE_READONLY, &os);
ASSERT3U(error, ==, 0);
error = dmu_object_info(os, ZTEST_DIROBJ, &doi);
- ASSERT3U(error, ==, 0);
- ASSERT3U(doi.doi_type, ==, DMU_OT_UINT64_OTHER);
- ASSERT3S(doi.doi_physical_blks, >=, 0);
+ if (error != ENOENT) {
+ /* We could have crashed in the middle of destroying it */
+ ASSERT3U(error, ==, 0);
+ ASSERT3U(doi.doi_type, ==, DMU_OT_UINT64_OTHER);
+ ASSERT3S(doi.doi_physical_blks, >=, 0);
+ }
dmu_objset_close(os);
/*
diff --git a/usr/src/uts/common/fs/zfs/dmu.c b/usr/src/uts/common/fs/zfs/dmu.c
index a2a3d1f3dd..2f6abbadae 100644
--- a/usr/src/uts/common/fs/zfs/dmu.c
+++ b/usr/src/uts/common/fs/zfs/dmu.c
@@ -169,7 +169,7 @@ dmu_buf_hold_array(objset_t *os, uint64_t object, uint64_t offset,
}
flags = DB_RF_CANFAIL | DB_RF_NEVERWAIT;
- if (length >= zfetch_array_rd_sz)
+ if (length > zfetch_array_rd_sz)
flags |= DB_RF_NOPREFETCH;
err = dnode_hold(os->os, object, FTAG, &dn);
@@ -791,7 +791,7 @@ replay_incremental_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx)
/* The point of no (unsuccessful) return. */
dmu_buf_will_dirty(ds->ds_dbuf, tx);
- ds->ds_phys->ds_restoring = TRUE;
+ ds->ds_phys->ds_inconsistent = TRUE;
dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG);
return (0);
@@ -843,7 +843,7 @@ replay_full_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx)
ds, drrb->drr_type, tx);
dmu_buf_will_dirty(ds->ds_dbuf, tx);
- ds->ds_phys->ds_restoring = TRUE;
+ ds->ds_phys->ds_inconsistent = TRUE;
dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG);
return (0);
@@ -871,20 +871,21 @@ replay_end_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx)
/* set snapshot's creation time and guid */
VERIFY(0 == dsl_dataset_open_spa(dd->dd_pool->dp_spa, drrb->drr_toname,
- DS_MODE_PRIMARY | DS_MODE_READONLY | DS_MODE_RESTORE, FTAG, &ds));
+ DS_MODE_PRIMARY | DS_MODE_READONLY | DS_MODE_INCONSISTENT,
+ FTAG, &ds));
dmu_buf_will_dirty(ds->ds_dbuf, tx);
ds->ds_phys->ds_creation_time = drrb->drr_creation_time;
ds->ds_phys->ds_guid = drrb->drr_toguid;
- ds->ds_phys->ds_restoring = FALSE;
+ ds->ds_phys->ds_inconsistent = FALSE;
dsl_dataset_close(ds, DS_MODE_PRIMARY, FTAG);
VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool,
dd->dd_phys->dd_head_dataset_obj,
- NULL, DS_MODE_STANDARD | DS_MODE_RESTORE, FTAG, &ds));
+ NULL, DS_MODE_STANDARD | DS_MODE_INCONSISTENT, FTAG, &ds));
dmu_buf_will_dirty(ds->ds_dbuf, tx);
- ds->ds_phys->ds_restoring = FALSE;
+ ds->ds_phys->ds_inconsistent = FALSE;
dsl_dataset_close(ds, DS_MODE_STANDARD, FTAG);
return (0);
@@ -1267,7 +1268,7 @@ dmu_recvbackup(char *tosnap, struct drr_begin *drrb, uint64_t *sizep,
cp = strchr(tosnap, '@');
*cp = '\0';
ra.err = dmu_objset_open(tosnap, DMU_OST_ANY,
- DS_MODE_PRIMARY | DS_MODE_RESTORE, &os);
+ DS_MODE_PRIMARY | DS_MODE_INCONSISTENT, &os);
*cp = '@';
ASSERT3U(ra.err, ==, 0);
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);
diff --git a/usr/src/uts/common/fs/zfs/sys/dmu.h b/usr/src/uts/common/fs/zfs/sys/dmu.h
index 315b0ddee9..1bfd3890d8 100644
--- a/usr/src/uts/common/fs/zfs/sys/dmu.h
+++ b/usr/src/uts/common/fs/zfs/sys/dmu.h
@@ -130,8 +130,8 @@ void zfs_znode_byteswap(void *buf, size_t size);
#define DS_MODE_LEVEL(x) ((x) & (DS_MODE_LEVELS - 1))
#define DS_MODE_READONLY 0x8
#define DS_MODE_IS_READONLY(x) ((x) & DS_MODE_READONLY)
-#define DS_MODE_RESTORE 0x10
-#define DS_MODE_IS_RESTORE(x) ((x) & DS_MODE_RESTORE)
+#define DS_MODE_INCONSISTENT 0x10
+#define DS_MODE_IS_INCONSISTENT(x) ((x) & DS_MODE_INCONSISTENT)
#define DS_FIND_SNAPSHOTS 0x01
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 3411eba68b..2a4ce242dc 100644
--- a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h
+++ b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h
@@ -65,7 +65,7 @@ typedef struct dsl_dataset_phys {
*/
uint64_t ds_fsid_guid;
uint64_t ds_guid;
- uint64_t ds_restoring; /* boolean */
+ uint64_t ds_inconsistent; /* boolean */
blkptr_t ds_bp;
uint64_t ds_pad[8]; /* pad out to 256 bytes for good measure */
} dsl_dataset_phys_t;