diff options
author | bonwick <none@none> | 2006-04-01 21:50:51 -0800 |
---|---|---|
committer | bonwick <none@none> | 2006-04-01 21:50:51 -0800 |
commit | e19302335c33c8c6e0b0b5e426fc1f6352c84b5d (patch) | |
tree | 23df7a5300fb3815187c6738c4245cec975f234b /usr/src | |
parent | d64e89e7a834c2c403a48d72dea4ba04f3c2c0ba (diff) | |
download | illumos-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.c | 4 | ||||
-rw-r--r-- | usr/src/cmd/ztest/ztest.c | 9 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/dmu.c | 17 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/dsl_dataset.c | 85 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/dmu.h | 4 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/dsl_dataset.h | 2 |
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; |