Print this page
5269 zfs: zpool import slow
While importing a pool all objsets are enumerated twice, once to check
the zil log chains and once to claim them. On pools with many datasets
this process might take a substantial amount of time.
Speed up the process by parallelizing it utilizing a taskq. The number
of parallel tasks is limited to 4 times the number of leaf vdevs.

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/zfs/zil.c
          +++ new/usr/src/uts/common/fs/zfs/zil.c
↓ open down ↓ 616 lines elided ↑ open up ↑
 617  617  
 618  618  void
 619  619  zil_destroy_sync(zilog_t *zilog, dmu_tx_t *tx)
 620  620  {
 621  621          ASSERT(list_is_empty(&zilog->zl_lwb_list));
 622  622          (void) zil_parse(zilog, zil_free_log_block,
 623  623              zil_free_log_record, tx, zilog->zl_header->zh_claim_txg);
 624  624  }
 625  625  
 626  626  int
 627      -zil_claim(const char *osname, void *txarg)
      627 +zil_claim(dsl_pool_t *dp, dsl_dataset_t *ds, void *txarg)
 628  628  {
 629  629          dmu_tx_t *tx = txarg;
 630  630          uint64_t first_txg = dmu_tx_get_txg(tx);
 631  631          zilog_t *zilog;
 632  632          zil_header_t *zh;
 633  633          objset_t *os;
 634  634          int error;
 635  635  
 636      -        error = dmu_objset_own(osname, DMU_OST_ANY, B_FALSE, FTAG, &os);
      636 +        error = dmu_objset_own_obj(dp, ds->ds_object,
      637 +            DMU_OST_ANY, B_FALSE, FTAG, &os);
 637  638          if (error != 0) {
 638      -                cmn_err(CE_WARN, "can't open objset for %s", osname);
      639 +                cmn_err(CE_WARN, "can't open objset %llu, error %d",
      640 +                    (unsigned long long)ds->ds_object, error);
 639  641                  return (0);
 640  642          }
 641  643  
 642  644          zilog = dmu_objset_zil(os);
 643  645          zh = zil_header_in_syncing_context(zilog);
 644  646  
 645  647          if (spa_get_log_state(zilog->zl_spa) == SPA_LOG_CLEAR) {
 646  648                  if (!BP_IS_HOLE(&zh->zh_log))
 647  649                          zio_free_zil(zilog->zl_spa, first_txg, &zh->zh_log);
 648  650                  BP_ZERO(&zh->zh_log);
↓ open down ↓ 26 lines elided ↑ open up ↑
 675  677          dmu_objset_disown(os, FTAG);
 676  678          return (0);
 677  679  }
 678  680  
 679  681  /*
 680  682   * Check the log by walking the log chain.
 681  683   * Checksum errors are ok as they indicate the end of the chain.
 682  684   * Any other error (no device or read failure) returns an error.
 683  685   */
 684  686  int
 685      -zil_check_log_chain(const char *osname, void *tx)
      687 +zil_check_log_chain(dsl_pool_t *dp, dsl_dataset_t *ds, void *tx)
 686  688  {
 687  689          zilog_t *zilog;
 688  690          objset_t *os;
 689  691          blkptr_t *bp;
 690  692          int error;
 691  693  
 692  694          ASSERT(tx == NULL);
 693  695  
 694      -        error = dmu_objset_hold(osname, FTAG, &os);
      696 +        error = dmu_objset_from_ds(ds, &os);
 695  697          if (error != 0) {
 696      -                cmn_err(CE_WARN, "can't open objset for %s", osname);
      698 +                cmn_err(CE_WARN, "can't open objset %llu, error %d",
      699 +                    (unsigned long long)ds->ds_object, error);
 697  700                  return (0);
 698  701          }
 699  702  
 700  703          zilog = dmu_objset_zil(os);
 701  704          bp = (blkptr_t *)&zilog->zl_header->zh_log;
 702  705  
 703  706          /*
 704  707           * Check the first block and determine if it's on a log device
 705  708           * which may have been removed or faulted prior to loading this
 706  709           * pool.  If so, there's no point in checking the rest of the log
↓ open down ↓ 2 lines elided ↑ open up ↑
 709  712          if (!BP_IS_HOLE(bp)) {
 710  713                  vdev_t *vd;
 711  714                  boolean_t valid = B_TRUE;
 712  715  
 713  716                  spa_config_enter(os->os_spa, SCL_STATE, FTAG, RW_READER);
 714  717                  vd = vdev_lookup_top(os->os_spa, DVA_GET_VDEV(&bp->blk_dva[0]));
 715  718                  if (vd->vdev_islog && vdev_is_dead(vd))
 716  719                          valid = vdev_log_state_valid(vd);
 717  720                  spa_config_exit(os->os_spa, SCL_STATE, FTAG);
 718  721  
 719      -                if (!valid) {
 720      -                        dmu_objset_rele(os, FTAG);
      722 +                if (!valid)
 721  723                          return (0);
 722      -                }
 723  724          }
 724  725  
 725  726          /*
 726  727           * Because tx == NULL, zil_claim_log_block() will not actually claim
 727  728           * any blocks, but just determine whether it is possible to do so.
 728  729           * In addition to checking the log chain, zil_claim_log_block()
 729  730           * will invoke zio_claim() with a done func of spa_claim_notify(),
 730  731           * which will update spa_max_claim_txg.  See spa_load() for details.
 731  732           */
 732  733          error = zil_parse(zilog, zil_claim_log_block, zil_claim_log_record, tx,
 733  734              zilog->zl_header->zh_claim_txg ? -1ULL : spa_first_txg(os->os_spa));
 734  735  
 735      -        dmu_objset_rele(os, FTAG);
 736      -
 737  736          return ((error == ECKSUM || error == ENOENT) ? 0 : error);
 738  737  }
 739  738  
 740  739  static int
 741  740  zil_vdev_compare(const void *x1, const void *x2)
 742  741  {
 743  742          const uint64_t v1 = ((zil_vdev_node_t *)x1)->zv_vdev;
 744  743          const uint64_t v2 = ((zil_vdev_node_t *)x2)->zv_vdev;
 745  744  
 746  745          if (v1 < v2)
↓ open down ↓ 1377 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX