From f2aca4b8b30d9ec789eaa2af8525d4431f8ff422 Mon Sep 17 00:00:00 2001 From: Mariusz Zaborski Date: Mon, 21 Aug 2023 16:35:24 +0200 Subject: [PATCH] Redesign scan/scrub interfact to allow scrubing range of TXGs Sponsored-By: Wasabi Technology, Inc. Sponsored-By: Klara Inc. Signed-off-by: Mariusz Zaborski --- include/sys/dsl_scan.h | 3 ++- include/sys/spa.h | 2 ++ module/zfs/dsl_scan.c | 51 ++++++++++++++++++++++++++++++------------ module/zfs/spa.c | 13 ++++++++++- 4 files changed, 53 insertions(+), 16 deletions(-) diff --git a/include/sys/dsl_scan.h b/include/sys/dsl_scan.h index 63734dbc176f..d9f2c1be8bc1 100644 --- a/include/sys/dsl_scan.h +++ b/include/sys/dsl_scan.h @@ -189,7 +189,8 @@ void dsl_scan_setup_sync(void *, dmu_tx_t *); void dsl_scan_fini(struct dsl_pool *dp); void dsl_scan_sync(struct dsl_pool *, dmu_tx_t *); int dsl_scan_cancel(struct dsl_pool *); -int dsl_scan(struct dsl_pool *, pool_scan_func_t); +int dsl_scan(struct dsl_pool *, pool_scan_func_t, uint64_t starttxg, + uint64_t txgend); void dsl_scan_assess_vdev(struct dsl_pool *dp, vdev_t *vd); boolean_t dsl_scan_scrubbing(const struct dsl_pool *dp); boolean_t dsl_errorscrubbing(const struct dsl_pool *dp); diff --git a/include/sys/spa.h b/include/sys/spa.h index ca30b60c0af7..01070c09e6e3 100644 --- a/include/sys/spa.h +++ b/include/sys/spa.h @@ -821,6 +821,8 @@ extern void spa_l2cache_drop(spa_t *spa); /* scanning */ extern int spa_scan(spa_t *spa, pool_scan_func_t func); +extern int spa_scan_range(spa_t *spa, pool_scan_func_t func, uint64_t txgstart, + uint64_t txgend); extern int spa_scan_stop(spa_t *spa); extern int spa_scrub_pause_resume(spa_t *spa, pool_scrub_cmd_t flag); diff --git a/module/zfs/dsl_scan.c b/module/zfs/dsl_scan.c index 6cd0dbdea195..2c4a1a535515 100644 --- a/module/zfs/dsl_scan.c +++ b/module/zfs/dsl_scan.c @@ -852,18 +852,24 @@ dsl_scan_setup_check(void *arg, dmu_tx_t *tx) return (0); } +typedef struct { + pool_scan_func_t func; + uint64_t txgstart; + uint64_t txgend; +} setup_sync_arg_t; + void dsl_scan_setup_sync(void *arg, dmu_tx_t *tx) { - (void) arg; + setup_sync_arg_t *setup_sync_arg = (setup_sync_arg_t *)arg; dsl_scan_t *scn = dmu_tx_pool(tx)->dp_scan; - pool_scan_func_t *funcp = arg; dmu_object_type_t ot = 0; dsl_pool_t *dp = scn->scn_dp; spa_t *spa = dp->dp_spa; ASSERT(!dsl_scan_is_running(scn)); - ASSERT(*funcp > POOL_SCAN_NONE && *funcp < POOL_SCAN_FUNCS); + ASSERT3U(setup_sync_arg->func, >, POOL_SCAN_NONE); + ASSERT3U(setup_sync_arg->func, <, POOL_SCAN_FUNCS); memset(&scn->scn_phys, 0, sizeof (scn->scn_phys)); /* @@ -873,10 +879,14 @@ dsl_scan_setup_sync(void *arg, dmu_tx_t *tx) memset(&scn->errorscrub_phys, 0, sizeof (scn->errorscrub_phys)); dsl_errorscrub_sync_state(scn, tx); - scn->scn_phys.scn_func = *funcp; + scn->scn_phys.scn_func = setup_sync_arg->func; scn->scn_phys.scn_state = DSS_SCANNING; - scn->scn_phys.scn_min_txg = 0; - scn->scn_phys.scn_max_txg = tx->tx_txg; + scn->scn_phys.scn_min_txg = setup_sync_arg->txgstart; + if (setup_sync_arg->txgend == 0) { + scn->scn_phys.scn_max_txg = tx->tx_txg; + } else { + scn->scn_phys.scn_max_txg = setup_sync_arg->txgend; + } scn->scn_phys.scn_ddt_class_max = DDT_CLASSES - 1; /* the entire DDT */ scn->scn_phys.scn_start_time = gethrestime_sec(); scn->scn_phys.scn_errors = 0; @@ -963,7 +973,7 @@ dsl_scan_setup_sync(void *arg, dmu_tx_t *tx) spa_history_log_internal(spa, "scan setup", tx, "func=%u mintxg=%llu maxtxg=%llu", - *funcp, (u_longlong_t)scn->scn_phys.scn_min_txg, + setup_sync_arg->func, (u_longlong_t)scn->scn_phys.scn_min_txg, (u_longlong_t)scn->scn_phys.scn_max_txg); } @@ -973,10 +983,16 @@ dsl_scan_setup_sync(void *arg, dmu_tx_t *tx) * error scrub. */ int -dsl_scan(dsl_pool_t *dp, pool_scan_func_t func) +dsl_scan(dsl_pool_t *dp, pool_scan_func_t func, uint64_t txgstart, + uint64_t txgend) { spa_t *spa = dp->dp_spa; dsl_scan_t *scn = dp->dp_scan; + setup_sync_arg_t setup_sync_arg; + + if (func != POOL_SCAN_SCRUB && (txgstart != 0 || txgend != 0)) { + return (EINVAL); + } /* * Purge all vdev caches and probe all devices. We do this here @@ -1027,8 +1043,13 @@ dsl_scan(dsl_pool_t *dp, pool_scan_func_t func) return (SET_ERROR(err)); } + setup_sync_arg.func = func; + setup_sync_arg.txgstart = txgstart; + setup_sync_arg.txgend = txgend; + return (dsl_sync_task(spa_name(spa), dsl_scan_setup_check, - dsl_scan_setup_sync, &func, 0, ZFS_SPACE_CHECK_EXTRA_RESERVED)); + dsl_scan_setup_sync, &setup_sync_arg, 0, + ZFS_SPACE_CHECK_EXTRA_RESERVED)); } static void @@ -4330,14 +4351,16 @@ dsl_scan_sync(dsl_pool_t *dp, dmu_tx_t *tx) * current scan progress is below zfs_resilver_defer_percent. */ if (dsl_scan_restarting(scn, tx) || restart_early) { - pool_scan_func_t func = POOL_SCAN_SCRUB; + setup_sync_arg_t setup_sync_arg = { + .func = POOL_SCAN_SCRUB, + }; dsl_scan_done(scn, B_FALSE, tx); if (vdev_resilver_needed(spa->spa_root_vdev, NULL, NULL)) - func = POOL_SCAN_RESILVER; + setup_sync_arg.func = POOL_SCAN_RESILVER; zfs_dbgmsg("restarting scan func=%u on %s txg=%llu early=%d", - func, dp->dp_spa->spa_name, (longlong_t)tx->tx_txg, - restart_early); - dsl_scan_setup_sync(&func, tx); + setup_sync_arg.func, dp->dp_spa->spa_name, + (longlong_t)tx->tx_txg, restart_early); + dsl_scan_setup_sync(&setup_sync_arg, tx); } /* diff --git a/module/zfs/spa.c b/module/zfs/spa.c index 6b8c7ee93daa..ff32e678a03e 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -8867,6 +8867,13 @@ spa_scan_stop(spa_t *spa) int spa_scan(spa_t *spa, pool_scan_func_t func) +{ + return (spa_scan_range(spa, func, 0, 0)); +} + +int +spa_scan_range(spa_t *spa, pool_scan_func_t func, uint64_t txgstart, + uint64_t txgend) { ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == 0); @@ -8877,6 +8884,9 @@ spa_scan(spa_t *spa, pool_scan_func_t func) !spa_feature_is_enabled(spa, SPA_FEATURE_RESILVER_DEFER)) return (SET_ERROR(ENOTSUP)); + if (func != POOL_SCAN_SCRUB && (txgstart != 0 || txgend != 0)) + return (SET_ERROR(ENOTSUP)); + /* * If a resilver was requested, but there is no DTL on a * writeable leaf device, we have nothing to do. @@ -8891,7 +8901,7 @@ spa_scan(spa_t *spa, pool_scan_func_t func) !spa_feature_is_enabled(spa, SPA_FEATURE_HEAD_ERRLOG)) return (SET_ERROR(ENOTSUP)); - return (dsl_scan(spa->spa_dsl_pool, func)); + return (dsl_scan(spa->spa_dsl_pool, func, txgstart, txgend)); } /* @@ -10974,6 +10984,7 @@ EXPORT_SYMBOL(spa_l2cache_drop); /* scanning */ EXPORT_SYMBOL(spa_scan); +EXPORT_SYMBOL(spa_scan_range); EXPORT_SYMBOL(spa_scan_stop); /* spa syncing */