Print this page
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>


  83 dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx)
  84 {
  85         int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp);
  86         int compressed = BP_GET_PSIZE(bp);
  87         int uncompressed = BP_GET_UCSIZE(bp);
  88         int64_t delta;
  89 
  90         dprintf_bp(bp, "ds=%p", ds);
  91 
  92         ASSERT(dmu_tx_is_syncing(tx));
  93         /* It could have been compressed away to nothing */
  94         if (BP_IS_HOLE(bp))
  95                 return;
  96         ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE);
  97         ASSERT(DMU_OT_IS_VALID(BP_GET_TYPE(bp)));
  98         if (ds == NULL) {
  99                 dsl_pool_mos_diduse_space(tx->tx_pool,
 100                     used, compressed, uncompressed);
 101                 return;
 102         }
 103         dmu_buf_will_dirty(ds->ds_dbuf, tx);
 104 
 105         mutex_enter(&ds->ds_dir->dd_lock);
 106         mutex_enter(&ds->ds_lock);
 107         delta = parent_delta(ds, used);
 108         ds->ds_phys->ds_referenced_bytes += used;
 109         ds->ds_phys->ds_compressed_bytes += compressed;
 110         ds->ds_phys->ds_uncompressed_bytes += uncompressed;
 111         ds->ds_phys->ds_unique_bytes += used;
 112         mutex_exit(&ds->ds_lock);
 113         dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta,
 114             compressed, uncompressed, tx);
 115         dsl_dir_transfer_space(ds->ds_dir, used - delta,
 116             DD_USED_REFRSRV, DD_USED_HEAD, tx);
 117         mutex_exit(&ds->ds_dir->dd_lock);
 118 }
 119 
 120 int
 121 dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx,
 122     boolean_t async)
 123 {
 124         if (BP_IS_HOLE(bp))
 125                 return (0);
 126 
 127         ASSERT(dmu_tx_is_syncing(tx));
 128         ASSERT(bp->blk_birth <= tx->tx_txg);
 129 
 130         int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp);
 131         int compressed = BP_GET_PSIZE(bp);
 132         int uncompressed = BP_GET_UCSIZE(bp);
 133 
 134         ASSERT(used > 0);
 135         if (ds == NULL) {
 136                 dsl_free(tx->tx_pool, tx->tx_txg, bp);
 137                 dsl_pool_mos_diduse_space(tx->tx_pool,
 138                     -used, -compressed, -uncompressed);
 139                 return (used);
 140         }
 141         ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool);
 142 
 143         ASSERT(!dsl_dataset_is_snapshot(ds));
 144         dmu_buf_will_dirty(ds->ds_dbuf, tx);
 145 
 146         if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) {
 147                 int64_t delta;
 148 
 149                 dprintf_bp(bp, "freeing ds=%llu", ds->ds_object);
 150                 dsl_free(tx->tx_pool, tx->tx_txg, bp);
 151 
 152                 mutex_enter(&ds->ds_dir->dd_lock);
 153                 mutex_enter(&ds->ds_lock);
 154                 ASSERT(ds->ds_phys->ds_unique_bytes >= used ||
 155                     !DS_UNIQUE_IS_ACCURATE(ds));
 156                 delta = parent_delta(ds, -used);
 157                 ds->ds_phys->ds_unique_bytes -= used;
 158                 mutex_exit(&ds->ds_lock);
 159                 dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD,
 160                     delta, -compressed, -uncompressed, tx);
 161                 dsl_dir_transfer_space(ds->ds_dir, -used - delta,
 162                     DD_USED_REFRSRV, DD_USED_HEAD, tx);
 163                 mutex_exit(&ds->ds_dir->dd_lock);
 164         } else {
 165                 dprintf_bp(bp, "putting on dead list: %s", "");
 166                 if (async) {
 167                         /*
 168                          * We are here as part of zio's write done callback,
 169                          * which means we're a zio interrupt thread.  We can't
 170                          * call dsl_deadlist_insert() now because it may block
 171                          * waiting for I/O.  Instead, put bp on the deferred
 172                          * queue and let dsl_pool_sync() finish the job.
 173                          */
 174                         bplist_append(&ds->ds_pending_deadlist, bp);
 175                 } else {
 176                         dsl_deadlist_insert(&ds->ds_deadlist, bp, tx);
 177                 }
 178                 ASSERT3U(ds->ds_prev->ds_object, ==,
 179                     ds->ds_phys->ds_prev_snap_obj);
 180                 ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0);
 181                 /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */
 182                 if (ds->ds_prev->ds_phys->ds_next_snap_obj ==
 183                     ds->ds_object && bp->blk_birth >


 574         } else {
 575                 dsl_dir_name(ds->ds_dir, name);
 576                 VERIFY0(dsl_dataset_get_snapname(ds));
 577                 if (ds->ds_snapname[0]) {
 578                         (void) strcat(name, "@");
 579                         /*
 580                          * We use a "recursive" mutex so that we
 581                          * can call dprintf_ds() with ds_lock held.
 582                          */
 583                         if (!MUTEX_HELD(&ds->ds_lock)) {
 584                                 mutex_enter(&ds->ds_lock);
 585                                 (void) strcat(name, ds->ds_snapname);
 586                                 mutex_exit(&ds->ds_lock);
 587                         } else {
 588                                 (void) strcat(name, ds->ds_snapname);
 589                         }
 590                 }
 591         }
 592 }
 593 
 594 static int
 595 dsl_dataset_namelen(dsl_dataset_t *ds)
 596 {
 597         int result;
 598 
 599         if (ds == NULL) {
 600                 result = 3;     /* "mos" */
 601         } else {
 602                 result = dsl_dir_namelen(ds->ds_dir);
 603                 VERIFY0(dsl_dataset_get_snapname(ds));
 604                 if (ds->ds_snapname[0]) {
 605                         ++result;       /* adding one for the @-sign */
 606                         if (!MUTEX_HELD(&ds->ds_lock)) {
 607                                 mutex_enter(&ds->ds_lock);
 608                                 result += strlen(ds->ds_snapname);
 609                                 mutex_exit(&ds->ds_lock);
 610                         } else {
 611                                 result += strlen(ds->ds_snapname);
 612                         }
 613                 }
 614         }
 615 
 616         return (result);
 617 }
 618 
 619 void
 620 dsl_dataset_rele(dsl_dataset_t *ds, void *tag)
 621 {
 622         dmu_buf_rele(ds->ds_dbuf, tag);
 623 }
 624 
 625 void
 626 dsl_dataset_disown(dsl_dataset_t *ds, void *tag)
 627 {
 628         ASSERT(ds->ds_owner == tag && ds->ds_dbuf != NULL);
 629 
 630         mutex_enter(&ds->ds_lock);
 631         ds->ds_owner = NULL;
 632         mutex_exit(&ds->ds_lock);
 633         dsl_dataset_long_rele(ds, tag);
 634         if (ds->ds_dbuf != NULL)
 635                 dsl_dataset_rele(ds, tag);
 636         else
 637                 dsl_dataset_evict(NULL, ds);
 638 }




  83 dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx)
  84 {
  85         int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp);
  86         int compressed = BP_GET_PSIZE(bp);
  87         int uncompressed = BP_GET_UCSIZE(bp);
  88         int64_t delta;
  89 
  90         dprintf_bp(bp, "ds=%p", ds);
  91 
  92         ASSERT(dmu_tx_is_syncing(tx));
  93         /* It could have been compressed away to nothing */
  94         if (BP_IS_HOLE(bp))
  95                 return;
  96         ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE);
  97         ASSERT(DMU_OT_IS_VALID(BP_GET_TYPE(bp)));
  98         if (ds == NULL) {
  99                 dsl_pool_mos_diduse_space(tx->tx_pool,
 100                     used, compressed, uncompressed);
 101                 return;
 102         }

 103 
 104         dmu_buf_will_dirty(ds->ds_dbuf, tx);
 105         mutex_enter(&ds->ds_lock);
 106         delta = parent_delta(ds, used);
 107         ds->ds_phys->ds_referenced_bytes += used;
 108         ds->ds_phys->ds_compressed_bytes += compressed;
 109         ds->ds_phys->ds_uncompressed_bytes += uncompressed;
 110         ds->ds_phys->ds_unique_bytes += used;
 111         mutex_exit(&ds->ds_lock);
 112         dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta,
 113             compressed, uncompressed, tx);
 114         dsl_dir_transfer_space(ds->ds_dir, used - delta,
 115             DD_USED_REFRSRV, DD_USED_HEAD, tx);

 116 }
 117 
 118 int
 119 dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx,
 120     boolean_t async)
 121 {
 122         if (BP_IS_HOLE(bp))
 123                 return (0);
 124 
 125         ASSERT(dmu_tx_is_syncing(tx));
 126         ASSERT(bp->blk_birth <= tx->tx_txg);
 127 
 128         int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp);
 129         int compressed = BP_GET_PSIZE(bp);
 130         int uncompressed = BP_GET_UCSIZE(bp);
 131 
 132         ASSERT(used > 0);
 133         if (ds == NULL) {
 134                 dsl_free(tx->tx_pool, tx->tx_txg, bp);
 135                 dsl_pool_mos_diduse_space(tx->tx_pool,
 136                     -used, -compressed, -uncompressed);
 137                 return (used);
 138         }
 139         ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool);
 140 
 141         ASSERT(!dsl_dataset_is_snapshot(ds));
 142         dmu_buf_will_dirty(ds->ds_dbuf, tx);
 143 
 144         if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) {
 145                 int64_t delta;
 146 
 147                 dprintf_bp(bp, "freeing ds=%llu", ds->ds_object);
 148                 dsl_free(tx->tx_pool, tx->tx_txg, bp);
 149 

 150                 mutex_enter(&ds->ds_lock);
 151                 ASSERT(ds->ds_phys->ds_unique_bytes >= used ||
 152                     !DS_UNIQUE_IS_ACCURATE(ds));
 153                 delta = parent_delta(ds, -used);
 154                 ds->ds_phys->ds_unique_bytes -= used;
 155                 mutex_exit(&ds->ds_lock);
 156                 dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD,
 157                     delta, -compressed, -uncompressed, tx);
 158                 dsl_dir_transfer_space(ds->ds_dir, -used - delta,
 159                     DD_USED_REFRSRV, DD_USED_HEAD, tx);

 160         } else {
 161                 dprintf_bp(bp, "putting on dead list: %s", "");
 162                 if (async) {
 163                         /*
 164                          * We are here as part of zio's write done callback,
 165                          * which means we're a zio interrupt thread.  We can't
 166                          * call dsl_deadlist_insert() now because it may block
 167                          * waiting for I/O.  Instead, put bp on the deferred
 168                          * queue and let dsl_pool_sync() finish the job.
 169                          */
 170                         bplist_append(&ds->ds_pending_deadlist, bp);
 171                 } else {
 172                         dsl_deadlist_insert(&ds->ds_deadlist, bp, tx);
 173                 }
 174                 ASSERT3U(ds->ds_prev->ds_object, ==,
 175                     ds->ds_phys->ds_prev_snap_obj);
 176                 ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0);
 177                 /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */
 178                 if (ds->ds_prev->ds_phys->ds_next_snap_obj ==
 179                     ds->ds_object && bp->blk_birth >


 570         } else {
 571                 dsl_dir_name(ds->ds_dir, name);
 572                 VERIFY0(dsl_dataset_get_snapname(ds));
 573                 if (ds->ds_snapname[0]) {
 574                         (void) strcat(name, "@");
 575                         /*
 576                          * We use a "recursive" mutex so that we
 577                          * can call dprintf_ds() with ds_lock held.
 578                          */
 579                         if (!MUTEX_HELD(&ds->ds_lock)) {
 580                                 mutex_enter(&ds->ds_lock);
 581                                 (void) strcat(name, ds->ds_snapname);
 582                                 mutex_exit(&ds->ds_lock);
 583                         } else {
 584                                 (void) strcat(name, ds->ds_snapname);
 585                         }
 586                 }
 587         }
 588 }
 589 

























 590 void
 591 dsl_dataset_rele(dsl_dataset_t *ds, void *tag)
 592 {
 593         dmu_buf_rele(ds->ds_dbuf, tag);
 594 }
 595 
 596 void
 597 dsl_dataset_disown(dsl_dataset_t *ds, void *tag)
 598 {
 599         ASSERT(ds->ds_owner == tag && ds->ds_dbuf != NULL);
 600 
 601         mutex_enter(&ds->ds_lock);
 602         ds->ds_owner = NULL;
 603         mutex_exit(&ds->ds_lock);
 604         dsl_dataset_long_rele(ds, tag);
 605         if (ds->ds_dbuf != NULL)
 606                 dsl_dataset_rele(ds, tag);
 607         else
 608                 dsl_dataset_evict(NULL, ds);
 609 }