Skip to content
Permalink
Browse files

4046 dsl_dataset_t ds_dir->dd_lock is highly contended

Reviewed by: Eric Schrock <eric.schrock@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Approved by: Garrett D'Amore <garrett@damore.org>
  • Loading branch information...
ahrens authored and Christopher Siden committed Aug 22, 2013
1 parent 60c49c6 commit b62969f868a827f0823a084bc0af9c7d8b76c659
Showing with 14 additions and 38 deletions.
  1. +1 −30 usr/src/uts/common/fs/zfs/dsl_dataset.c
  2. +13 −8 usr/src/uts/common/fs/zfs/dsl_dir.c
@@ -100,9 +100,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;
@@ -114,7 +113,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
@@ -149,7 +147,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));
@@ -160,7 +157,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) {
@@ -591,31 +587,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)
{
@@ -841,11 +841,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);
@@ -854,7 +864,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;
@@ -887,26 +896,22 @@ 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);

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 {

0 comments on commit b62969f

Please sign in to comment.
You can’t perform that action at this time.