Author: mav Date: Wed Feb 26 15:45:04 2020 New Revision: 358336 URL: https://svnweb.freebsd.org/changeset/base/358336
Log: 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 <tcap...@datto.com> Reviewed by: George Melikov <m...@gmelikov.ru> Signed-off-by: Brian Behlendorf <behlendo...@llnl.gov> Closes #7098 zfsonlinux/zfs@f90a30ad1b32a971f62a540f8944e42f99b254ce MFC after: 1 week Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c ============================================================================== --- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c Wed Feb 26 15:15:55 2020 (r358335) +++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c Wed Feb 26 15:45:04 2020 (r358336) @@ -125,6 +125,7 @@ static boolean_t scan_ds_queue_contains(dsl_scan_t *sc 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 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. */ @@ -3652,6 +3661,8 @@ dsl_scan_scrub_done(zio_t *zio) dsl_scan_io_queue_t *queue = zio->io_private; abd_free(zio->io_abd); + + ASSERT3U(scn->scn_maxinflight_bytes, >, 0); if (queue == NULL) { mutex_enter(&spa->spa_scrub_lock); _______________________________________________ svn-src-all@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"