MFV r254749:
Don't hold dd_lock for long by breaking it when not doing dsl_dir accounting. It is not necessary to hold the lock while manipulating the parent's accounting, because there is no interface for userland to see a consistent picture of both parent and child at the same time anyway. Illumos ZFS issues: 4046 dsl_dataset_t ds_dir->dd_lock is highly contended
This commit is contained in:
parent
b1dbe0883f
commit
a6fe3ad03c
@ -101,9 +101,8 @@ dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx)
|
||||
used, compressed, uncompressed);
|
||||
return;
|
||||
}
|
||||
dmu_buf_will_dirty(ds->ds_dbuf, tx);
|
||||
|
||||
mutex_enter(&ds->ds_dir->dd_lock);
|
||||
dmu_buf_will_dirty(ds->ds_dbuf, tx);
|
||||
mutex_enter(&ds->ds_lock);
|
||||
delta = parent_delta(ds, used);
|
||||
ds->ds_phys->ds_referenced_bytes += used;
|
||||
@ -115,7 +114,6 @@ dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx)
|
||||
compressed, uncompressed, tx);
|
||||
dsl_dir_transfer_space(ds->ds_dir, used - delta,
|
||||
DD_USED_REFRSRV, DD_USED_HEAD, tx);
|
||||
mutex_exit(&ds->ds_dir->dd_lock);
|
||||
}
|
||||
|
||||
int
|
||||
@ -150,7 +148,6 @@ dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx,
|
||||
dprintf_bp(bp, "freeing ds=%llu", ds->ds_object);
|
||||
dsl_free(tx->tx_pool, tx->tx_txg, bp);
|
||||
|
||||
mutex_enter(&ds->ds_dir->dd_lock);
|
||||
mutex_enter(&ds->ds_lock);
|
||||
ASSERT(ds->ds_phys->ds_unique_bytes >= used ||
|
||||
!DS_UNIQUE_IS_ACCURATE(ds));
|
||||
@ -161,7 +158,6 @@ dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx,
|
||||
delta, -compressed, -uncompressed, tx);
|
||||
dsl_dir_transfer_space(ds->ds_dir, -used - delta,
|
||||
DD_USED_REFRSRV, DD_USED_HEAD, tx);
|
||||
mutex_exit(&ds->ds_dir->dd_lock);
|
||||
} else {
|
||||
dprintf_bp(bp, "putting on dead list: %s", "");
|
||||
if (async) {
|
||||
@ -596,31 +592,6 @@ dsl_dataset_name(dsl_dataset_t *ds, char *name)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
dsl_dataset_namelen(dsl_dataset_t *ds)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (ds == NULL) {
|
||||
result = 3; /* "mos" */
|
||||
} else {
|
||||
result = dsl_dir_namelen(ds->ds_dir);
|
||||
VERIFY0(dsl_dataset_get_snapname(ds));
|
||||
if (ds->ds_snapname[0]) {
|
||||
++result; /* adding one for the @-sign */
|
||||
if (!MUTEX_HELD(&ds->ds_lock)) {
|
||||
mutex_enter(&ds->ds_lock);
|
||||
result += strlen(ds->ds_snapname);
|
||||
mutex_exit(&ds->ds_lock);
|
||||
} else {
|
||||
result += strlen(ds->ds_snapname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
dsl_dataset_rele(dsl_dataset_t *ds, void *tag)
|
||||
{
|
||||
|
@ -845,11 +845,21 @@ dsl_dir_diduse_space(dsl_dir_t *dd, dd_used_t type,
|
||||
int64_t used, int64_t compressed, int64_t uncompressed, dmu_tx_t *tx)
|
||||
{
|
||||
int64_t accounted_delta;
|
||||
|
||||
/*
|
||||
* dsl_dataset_set_refreservation_sync_impl() calls this with
|
||||
* dd_lock held, so that it can atomically update
|
||||
* ds->ds_reserved and the dsl_dir accounting, so that
|
||||
* dsl_dataset_check_quota() can see dataset and dir accounting
|
||||
* consistently.
|
||||
*/
|
||||
boolean_t needlock = !MUTEX_HELD(&dd->dd_lock);
|
||||
|
||||
ASSERT(dmu_tx_is_syncing(tx));
|
||||
ASSERT(type < DD_USED_NUM);
|
||||
|
||||
dmu_buf_will_dirty(dd->dd_dbuf, tx);
|
||||
|
||||
if (needlock)
|
||||
mutex_enter(&dd->dd_lock);
|
||||
accounted_delta = parent_delta(dd, dd->dd_phys->dd_used_bytes, used);
|
||||
@ -858,7 +868,6 @@ dsl_dir_diduse_space(dsl_dir_t *dd, dd_used_t type,
|
||||
dd->dd_phys->dd_compressed_bytes >= -compressed);
|
||||
ASSERT(uncompressed >= 0 ||
|
||||
dd->dd_phys->dd_uncompressed_bytes >= -uncompressed);
|
||||
dmu_buf_will_dirty(dd->dd_dbuf, tx);
|
||||
dd->dd_phys->dd_used_bytes += used;
|
||||
dd->dd_phys->dd_uncompressed_bytes += uncompressed;
|
||||
dd->dd_phys->dd_compressed_bytes += compressed;
|
||||
@ -891,8 +900,6 @@ void
|
||||
dsl_dir_transfer_space(dsl_dir_t *dd, int64_t delta,
|
||||
dd_used_t oldtype, dd_used_t newtype, dmu_tx_t *tx)
|
||||
{
|
||||
boolean_t needlock = !MUTEX_HELD(&dd->dd_lock);
|
||||
|
||||
ASSERT(dmu_tx_is_syncing(tx));
|
||||
ASSERT(oldtype < DD_USED_NUM);
|
||||
ASSERT(newtype < DD_USED_NUM);
|
||||
@ -900,17 +907,15 @@ dsl_dir_transfer_space(dsl_dir_t *dd, int64_t delta,
|
||||
if (delta == 0 || !(dd->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN))
|
||||
return;
|
||||
|
||||
if (needlock)
|
||||
mutex_enter(&dd->dd_lock);
|
||||
dmu_buf_will_dirty(dd->dd_dbuf, tx);
|
||||
mutex_enter(&dd->dd_lock);
|
||||
ASSERT(delta > 0 ?
|
||||
dd->dd_phys->dd_used_breakdown[oldtype] >= delta :
|
||||
dd->dd_phys->dd_used_breakdown[newtype] >= -delta);
|
||||
ASSERT(dd->dd_phys->dd_used_bytes >= ABS(delta));
|
||||
dmu_buf_will_dirty(dd->dd_dbuf, tx);
|
||||
dd->dd_phys->dd_used_breakdown[oldtype] -= delta;
|
||||
dd->dd_phys->dd_used_breakdown[newtype] += delta;
|
||||
if (needlock)
|
||||
mutex_exit(&dd->dd_lock);
|
||||
mutex_exit(&dd->dd_lock);
|
||||
}
|
||||
|
||||
typedef struct dsl_dir_set_qr_arg {
|
||||
|
Loading…
x
Reference in New Issue
Block a user