From cc7219701571d162fdfa1ee6a1196e932cf12689 Mon Sep 17 00:00:00 2001 From: Mariusz Zaborski Date: Thu, 29 Aug 2024 09:59:07 +0000 Subject: [PATCH] scrub: add option to scrub only recent data Sponsored-By: Wasabi Technology, Inc. Sponsored-By: Klara Inc. Signed-off-by: Mariusz Zaborski --- cmd/zpool/zpool_main.c | 28 ++++++++++++++++++++++++---- include/sys/dsl_scan.h | 1 + include/sys/fs/zfs.h | 1 + man/man4/zfs.4 | 3 +++ man/man8/zpool-scrub.8 | 5 +++++ module/zfs/dsl_scan.c | 6 ++++++ module/zfs/zfs_ioctl.c | 10 ++++++++++ 7 files changed, 50 insertions(+), 4 deletions(-) diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index 3de140856742..7859b041914a 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -506,7 +506,7 @@ get_usage(zpool_help_t idx) return (gettext("\tinitialize [-c | -s | -u] [-w] " "[ ...]\n")); case HELP_SCRUB: - return (gettext("\tscrub [-s | -p] [-w] [-e] [-C] " + return (gettext("\tscrub [-s | -p] [-w] [-e] [-C] [-R] " " ...\n")); case HELP_RESILVER: return (gettext("\tresilver ...\n")); @@ -8398,6 +8398,7 @@ wait_callback(zpool_handle_t *zhp, void *data) * -e Only scrub blocks in the error log. * -s Stop. Stops any in-progress scrub. * -p Pause. Pause in-progress scrub. + * -R Scrub only recent data. * -w Wait. Blocks until scrub has completed. */ int @@ -8415,9 +8416,10 @@ zpool_do_scrub(int argc, char **argv) boolean_t is_pause = B_FALSE; boolean_t is_stop = B_FALSE; boolean_t is_txg_continue = B_FALSE; + boolean_t is_recent_scrub = B_FALSE; /* check options */ - while ((c = getopt(argc, argv, "spweC")) != -1) { + while ((c = getopt(argc, argv, "spweCR")) != -1) { switch (c) { case 'C': is_txg_continue = B_TRUE; @@ -8431,6 +8433,9 @@ zpool_do_scrub(int argc, char **argv) case 'p': is_pause = B_TRUE; break; + case 'R': + is_recent_scrub = B_TRUE; + break; case 'w': wait = B_TRUE; break; @@ -8457,11 +8462,26 @@ zpool_do_scrub(int argc, char **argv) (void) fprintf(stderr, gettext("invalid option " "combination :-e and -C are mutually exclusive\n")); usage(B_FALSE); + } else if (is_pause && is_recent_scrub) { + (void) fprintf(stderr, gettext("invalid option " + "combination :-p and -R are mutually exclusive\n")); + usage(B_FALSE); + } else if (is_stop && is_recent_scrub) { + (void) fprintf(stderr, gettext("invalid option " + "combination :-s and -R are mutually exclusive\n")); + usage(B_FALSE); + } else if (is_error_scrub && is_recent_scrub) { + (void) fprintf(stderr, gettext("invalid option " + "combination :-e and -R are mutually exclusive\n")); + usage(B_FALSE); } else { - if (is_error_scrub) + if (is_error_scrub) { cb.cb_type = POOL_SCAN_ERRORSCRUB; + } - if (is_pause) { + if (is_recent_scrub) { + cb.cb_scrub_cmd = POOL_SCRUB_RECENT_TXGS; + } else if (is_pause) { cb.cb_scrub_cmd = POOL_SCRUB_PAUSE; } else if (is_stop) { cb.cb_type = POOL_SCAN_NONE; diff --git a/include/sys/dsl_scan.h b/include/sys/dsl_scan.h index d9f2c1be8bc1..5cc99ad9d159 100644 --- a/include/sys/dsl_scan.h +++ b/include/sys/dsl_scan.h @@ -44,6 +44,7 @@ struct dsl_pool; struct dmu_tx; extern int zfs_scan_suspend_progress; +extern uint_t zfs_scrub_recent_txgs; /* * All members of this structure must be uint64_t, for byteswap diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index 69441066e626..78133d01a012 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -1077,6 +1077,7 @@ typedef enum pool_scrub_cmd { POOL_SCRUB_NORMAL = 0, POOL_SCRUB_PAUSE, POOL_SCRUB_FROM_LAST_TXG, + POOL_SCRUB_RECENT_TXGS, POOL_SCRUB_FLAGS_END } pool_scrub_cmd_t; diff --git a/man/man4/zfs.4 b/man/man4/zfs.4 index 20bb95c1aeea..f09b90665dab 100644 --- a/man/man4/zfs.4 +++ b/man/man4/zfs.4 @@ -1986,6 +1986,9 @@ working on a scrub between TXG flushes. .It Sy zfs_scrub_error_blocks_per_txg Ns = Ns Sy 4096 Pq uint Error blocks to be scrubbed in one txg. . +.It Sy zfs_scrub_recent_txgs Ns = Ns Sy 256 Pq uint +Number of txgs to be considered as recent when performing a recent data scrub. +. .It Sy zfs_scan_checkpoint_intval Ns = Ns Sy 7200 Ns s Po 2 hour Pc Pq uint To preserve progress across reboots, the sequential scan algorithm periodically needs to stop metadata scanning and issue all the verification I/O to disk. diff --git a/man/man8/zpool-scrub.8 b/man/man8/zpool-scrub.8 index 023ec33fb374..39d14eecbc66 100644 --- a/man/man8/zpool-scrub.8 +++ b/man/man8/zpool-scrub.8 @@ -40,6 +40,7 @@ .Op Fl w .Op Fl e .Op Fl C +.Op Fl R .Ar pool Ns … . .Sh DESCRIPTION @@ -119,6 +120,10 @@ resilvering, nor can it be run when a regular scrub is paused. Continue scrub from last saved txg (see zpool .Sy last_scrubbed_txg property). +.It Fl R +Scrub only recent data (this can be controlled by the +.Sy zfs_scrub_recent_txgs +parameter). .El .Sh EXAMPLES .Ss Example 1 diff --git a/module/zfs/dsl_scan.c b/module/zfs/dsl_scan.c index 76db3b55c64b..6f900118936d 100644 --- a/module/zfs/dsl_scan.c +++ b/module/zfs/dsl_scan.c @@ -239,6 +239,9 @@ static int zfs_free_bpobj_enabled = 1; /* Error blocks to be scrubbed in one txg. */ static uint_t zfs_scrub_error_blocks_per_txg = 1 << 12; +/* The number of TXGs should be scrubbed while scrubbing recent data. */ +uint_t zfs_scrub_recent_txgs = 256; + /* the order has to match pool_scan_type */ static scan_cb_t *scan_funcs[POOL_SCAN_FUNCS] = { NULL, @@ -5323,4 +5326,7 @@ ZFS_MODULE_PARAM(zfs, zfs_, resilver_disable_defer, INT, ZMOD_RW, ZFS_MODULE_PARAM(zfs, zfs_, scrub_error_blocks_per_txg, UINT, ZMOD_RW, "Error blocks to be scrubbed in one txg"); + +ZFS_MODULE_PARAM(zfs, zfs_, scrub_recent_txgs, UINT, ZMOD_RW, + "The number of TXGs should be scrubbed while scrubbing recent data"); /* END CSTYLED */ diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 0b6683ffb987..6eddf2d7420e 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -1722,6 +1722,16 @@ zfs_ioc_pool_scrub(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) } else if (scan_cmd == POOL_SCRUB_FROM_LAST_TXG) { error = spa_scan_range(spa, scan_type, spa_get_last_scrubbed_txg(spa), 0); + } else if (scan_cmd == POOL_SCRUB_RECENT_TXGS) { + uint64_t start; + + start = 0; + if (spa_last_synced_txg(spa) > zfs_scrub_recent_txgs) { + start = spa_last_synced_txg(spa) - + zfs_scrub_recent_txgs; + } + + error = spa_scan_range(spa, scan_type, start, 0); } else { error = spa_scan(spa, scan_type); }