diff options
author | Alexander Motin <mav@FreeBSD.org> | 2020-02-26 15:45:04 +0000 |
---|---|---|
committer | Alexander Motin <mav@FreeBSD.org> | 2020-02-26 15:45:04 +0000 |
commit | 4b7f090f8d3d2f0eccef89c14f641319a19cf65c (patch) | |
tree | 370d3460ab9a5c69eda0cc9a414ffa54f0e92c32 /sys/cddl | |
parent | 06bd9afc5fcf4ac29557aa1a6aef819f2e0f1e7d (diff) | |
download | src-4b7f090f8d3d2f0eccef89c14f641319a19cf65c.tar.gz src-4b7f090f8d3d2f0eccef89c14f641319a19cf65c.zip |
MFZoL: Fix txg_sync_thread hang in scan_exec_io()
When scn->scn_maxinflight_bytes has not been initialized it's
possible to hang on the condition variable in scan_exec_io().
This issue was uncovered by ztest and is only possible when
deduplication is enabled through the following call path.
txg_sync_thread()
spa_sync()
ddt_sync_table()
ddt_sync_entry()
dsl_scan_ddt_entry()
dsl_scan_scrub_cb()
dsl_scan_enqueuei()
scan_exec_io()
cv_wait()
Resolve the issue by always initializing scn_maxinflight_bytes
to a reasonable minimum value. This value will be recalculated
in dsl_scan_sync() to pick up changes to zfs_scan_vdev_limit
and the addition/removal of vdevs.
Reviewed-by: Tom Caputi <tcaputi@datto.com>
Reviewed by: George Melikov <mail@gmelikov.ru>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #7098
zfsonlinux/zfs@f90a30ad1b32a971f62a540f8944e42f99b254ce
MFC after: 1 week
Notes
Notes:
svn path=/head/; revision=358336
Diffstat (limited to 'sys/cddl')
-rw-r--r-- | sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c index 316b09ad5db9..a3f3c51c5dca 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c @@ -125,6 +125,7 @@ static boolean_t scan_ds_queue_contains(dsl_scan_t *scn, uint64_t dsobj, static void scan_ds_queue_insert(dsl_scan_t *scn, uint64_t dsobj, uint64_t txg); static void scan_ds_queue_remove(dsl_scan_t *scn, uint64_t dsobj); static void scan_ds_queue_sync(dsl_scan_t *scn, dmu_tx_t *tx); +static uint64_t dsl_scan_count_leaves(vdev_t *vd); extern int zfs_vdev_async_write_active_min_dirty_percent; @@ -439,6 +440,14 @@ dsl_scan_init(dsl_pool_t *dp, uint64_t txg) scn->scn_async_destroying = spa_feature_is_active(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY); + /* + * Calculate the max number of in-flight bytes for pool-wide + * scanning operations (minimum 1MB). Limits for the issuing + * phase are done per top-level vdev and are handled separately. + */ + scn->scn_maxinflight_bytes = MAX(zfs_scan_vdev_limit * + dsl_scan_count_leaves(spa->spa_root_vdev), 1ULL << 20); + bcopy(&scn->scn_phys, &scn->scn_phys_cached, sizeof (scn->scn_phys)); avl_create(&scn->scn_queue, scan_ds_queue_compare, sizeof (scan_ds_t), offsetof(scan_ds_t, sds_node)); @@ -2350,7 +2359,7 @@ dsl_scan_ddt_entry(dsl_scan_t *scn, enum zio_checksum checksum, zbookmark_phys_t zb = { 0 }; int p; - if (scn->scn_phys.scn_state != DSS_SCANNING) + if (!dsl_scan_is_running(scn)) return; for (p = 0; p < DDT_PHYS_TYPES; p++, ddp++) { @@ -3333,7 +3342,7 @@ dsl_scan_sync(dsl_pool_t *dp, dmu_tx_t *tx) uint64_t nr_leaves = dsl_scan_count_leaves(spa->spa_root_vdev); /* - * Calculate the max number of in-flight bytes for pool-wide + * Recalculate the max number of in-flight bytes for pool-wide * scanning operations (minimum 1MB). Limits for the issuing * phase are done per top-level vdev and are handled separately. */ @@ -3653,6 +3662,8 @@ dsl_scan_scrub_done(zio_t *zio) abd_free(zio->io_abd); + ASSERT3U(scn->scn_maxinflight_bytes, >, 0); + if (queue == NULL) { mutex_enter(&spa->spa_scrub_lock); ASSERT3U(spa->spa_scrub_inflight, >=, BP_GET_PSIZE(bp)); |