scrub: add option to scrub only recent data

Sponsored-By: Wasabi Technology, Inc.
Sponsored-By: Klara Inc.
Signed-off-by: Mariusz Zaborski <mariusz.zaborski@klarasystems.com>
This commit is contained in:
Mariusz Zaborski 2024-08-29 09:59:07 +00:00 committed by Mariusz Zaborski
parent 4dde5c3f35
commit 4823cc2492
8 changed files with 86 additions and 17 deletions

View File

@ -506,7 +506,7 @@ get_usage(zpool_help_t idx)
return (gettext("\tinitialize [-c | -s | -u] [-w] <pool> " return (gettext("\tinitialize [-c | -s | -u] [-w] <pool> "
"[<device> ...]\n")); "[<device> ...]\n"));
case HELP_SCRUB: case HELP_SCRUB:
return (gettext("\tscrub [-s | -p] [-w] [-e] [-C] " return (gettext("\tscrub [-s | -p] [-w] [-e] [-C] [-R] "
"<pool> ...\n")); "<pool> ...\n"));
case HELP_RESILVER: case HELP_RESILVER:
return (gettext("\tresilver <pool> ...\n")); return (gettext("\tresilver <pool> ...\n"));
@ -8398,6 +8398,7 @@ wait_callback(zpool_handle_t *zhp, void *data)
* -e Only scrub blocks in the error log. * -e Only scrub blocks in the error log.
* -s Stop. Stops any in-progress scrub. * -s Stop. Stops any in-progress scrub.
* -p Pause. Pause in-progress scrub. * -p Pause. Pause in-progress scrub.
* -R Scrub only recent data.
* -w Wait. Blocks until scrub has completed. * -w Wait. Blocks until scrub has completed.
*/ */
int int
@ -8415,9 +8416,10 @@ zpool_do_scrub(int argc, char **argv)
boolean_t is_pause = B_FALSE; boolean_t is_pause = B_FALSE;
boolean_t is_stop = B_FALSE; boolean_t is_stop = B_FALSE;
boolean_t is_txg_continue = B_FALSE; boolean_t is_txg_continue = B_FALSE;
boolean_t is_recent_scrub = B_FALSE;
/* check options */ /* check options */
while ((c = getopt(argc, argv, "spweC")) != -1) { while ((c = getopt(argc, argv, "spweCR")) != -1) {
switch (c) { switch (c) {
case 'C': case 'C':
is_txg_continue = B_TRUE; is_txg_continue = B_TRUE;
@ -8431,6 +8433,9 @@ zpool_do_scrub(int argc, char **argv)
case 'p': case 'p':
is_pause = B_TRUE; is_pause = B_TRUE;
break; break;
case 'R':
is_recent_scrub = B_TRUE;
break;
case 'w': case 'w':
wait = B_TRUE; wait = B_TRUE;
break; break;
@ -8457,11 +8462,26 @@ zpool_do_scrub(int argc, char **argv)
(void) fprintf(stderr, gettext("invalid option " (void) fprintf(stderr, gettext("invalid option "
"combination :-e and -C are mutually exclusive\n")); "combination :-e and -C are mutually exclusive\n"));
usage(B_FALSE); 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 { } else {
if (is_error_scrub) if (is_error_scrub) {
cb.cb_type = POOL_SCAN_ERRORSCRUB; 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; cb.cb_scrub_cmd = POOL_SCRUB_PAUSE;
} else if (is_stop) { } else if (is_stop) {
cb.cb_type = POOL_SCAN_NONE; cb.cb_type = POOL_SCAN_NONE;

View File

@ -44,6 +44,7 @@ struct dsl_pool;
struct dmu_tx; struct dmu_tx;
extern int zfs_scan_suspend_progress; extern int zfs_scan_suspend_progress;
extern uint_t zfs_scrub_recent_txgs;
/* /*
* All members of this structure must be uint64_t, for byteswap * All members of this structure must be uint64_t, for byteswap

View File

@ -1077,6 +1077,7 @@ typedef enum pool_scrub_cmd {
POOL_SCRUB_NORMAL = 0, POOL_SCRUB_NORMAL = 0,
POOL_SCRUB_PAUSE, POOL_SCRUB_PAUSE,
POOL_SCRUB_FROM_LAST_TXG, POOL_SCRUB_FROM_LAST_TXG,
POOL_SCRUB_RECENT_TXGS,
POOL_SCRUB_FLAGS_END POOL_SCRUB_FLAGS_END
} pool_scrub_cmd_t; } pool_scrub_cmd_t;

View File

@ -183,8 +183,8 @@
<elf-symbol name='fsleep' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='fsleep' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='get_dataset_depth' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='get_dataset_depth' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='get_system_hostid' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='get_system_hostid' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getexecname' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='get_timestamp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='get_timestamp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getexecname' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getextmntent' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='getextmntent' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getmntany' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='getmntany' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getprop_uint64' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='getprop_uint64' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@ -466,6 +466,7 @@
<elf-symbol name='zpool_clear' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_clear' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_clear_label' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_clear_label' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_close' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_close' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_collect_unsup_feat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_create' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_create' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_default_search_paths' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_default_search_paths' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_destroy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_destroy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@ -485,8 +486,8 @@
<elf-symbol name='zpool_export_force' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_export_force' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_feature_init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_feature_init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_find_config' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_find_config' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_find_vdev' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_find_parent_vdev' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_find_parent_vdev' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_find_vdev' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_find_vdev_by_physpath' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_find_vdev_by_physpath' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_free_handles' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_free_handles' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_get_all_vdev_props' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_get_all_vdev_props' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@ -529,7 +530,6 @@
<elf-symbol name='zpool_prefetch' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_prefetch' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_prepare_and_label_disk' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_prepare_and_label_disk' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_prepare_disk' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_prepare_disk' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_collect_unsup_feat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_prop_align_right' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_prop_align_right' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_prop_column_name' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_prop_column_name' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_prop_default_numeric' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_prop_default_numeric' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@ -5809,7 +5809,8 @@
<enumerator name='POOL_SCRUB_NORMAL' value='0'/> <enumerator name='POOL_SCRUB_NORMAL' value='0'/>
<enumerator name='POOL_SCRUB_PAUSE' value='1'/> <enumerator name='POOL_SCRUB_PAUSE' value='1'/>
<enumerator name='POOL_SCRUB_FROM_LAST_TXG' value='2'/> <enumerator name='POOL_SCRUB_FROM_LAST_TXG' value='2'/>
<enumerator name='POOL_SCRUB_FLAGS_END' value='3'/> <enumerator name='POOL_SCRUB_RECENT_TXGS' value='3'/>
<enumerator name='POOL_SCRUB_FLAGS_END' value='4'/>
</enum-decl> </enum-decl>
<typedef-decl name='pool_scrub_cmd_t' type-id='a1474cbd' id='b51cf3c2'/> <typedef-decl name='pool_scrub_cmd_t' type-id='a1474cbd' id='b51cf3c2'/>
<enum-decl name='zpool_errata' id='d9abbf54'> <enum-decl name='zpool_errata' id='d9abbf54'>
@ -7839,7 +7840,7 @@
</data-member> </data-member>
</class-decl> </class-decl>
<typedef-decl name='vdev_cbdata_t' type-id='b8006be8' id='a9679c94'/> <typedef-decl name='vdev_cbdata_t' type-id='b8006be8' id='a9679c94'/>
<class-decl name='zprop_get_cbdata' size-in-bits='832' is-struct='yes' visibility='default' id='f3d3c319'> <class-decl name='zprop_get_cbdata' size-in-bits='960' is-struct='yes' visibility='default' id='f3d3c319'>
<data-member access='public' layout-offset-in-bits='0'> <data-member access='public' layout-offset-in-bits='0'>
<var-decl name='cb_sources' type-id='95e97e5e' visibility='default'/> <var-decl name='cb_sources' type-id='95e97e5e' visibility='default'/>
</data-member> </data-member>
@ -7858,6 +7859,9 @@
<data-member access='public' layout-offset-in-bits='448'> <data-member access='public' layout-offset-in-bits='448'>
<var-decl name='cb_first' type-id='c19b74c3' visibility='default'/> <var-decl name='cb_first' type-id='c19b74c3' visibility='default'/>
</data-member> </data-member>
<data-member access='public' layout-offset-in-bits='480'>
<var-decl name='cb_json' type-id='c19b74c3' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='512'> <data-member access='public' layout-offset-in-bits='512'>
<var-decl name='cb_proplist' type-id='3a9b2288' visibility='default'/> <var-decl name='cb_proplist' type-id='3a9b2288' visibility='default'/>
</data-member> </data-member>
@ -7867,6 +7871,15 @@
<data-member access='public' layout-offset-in-bits='640'> <data-member access='public' layout-offset-in-bits='640'>
<var-decl name='cb_vdevs' type-id='a9679c94' visibility='default'/> <var-decl name='cb_vdevs' type-id='a9679c94' visibility='default'/>
</data-member> </data-member>
<data-member access='public' layout-offset-in-bits='832'>
<var-decl name='cb_jsobj' type-id='5ce45b60' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='896'>
<var-decl name='cb_json_as_int' type-id='c19b74c3' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='928'>
<var-decl name='cb_json_pool_key_guid' type-id='c19b74c3' visibility='default'/>
</data-member>
</class-decl> </class-decl>
<typedef-decl name='zprop_get_cbdata_t' type-id='f3d3c319' id='f3d87113'/> <typedef-decl name='zprop_get_cbdata_t' type-id='f3d3c319' id='f3d87113'/>
<typedef-decl name='zprop_func' type-id='2e711a2a' id='1ec3747a'/> <typedef-decl name='zprop_func' type-id='2e711a2a' id='1ec3747a'/>
@ -7970,6 +7983,11 @@
<qualified-type-def type-id='d33f11cb' restrict='yes' id='5c53ba29'/> <qualified-type-def type-id='d33f11cb' restrict='yes' id='5c53ba29'/>
<pointer-type-def type-id='ffa52b96' size-in-bits='64' id='76c8174b'/> <pointer-type-def type-id='ffa52b96' size-in-bits='64' id='76c8174b'/>
<pointer-type-def type-id='f3d87113' size-in-bits='64' id='0d2a0670'/> <pointer-type-def type-id='f3d87113' size-in-bits='64' id='0d2a0670'/>
<function-decl name='nvlist_print_json' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='822cd80b'/>
<parameter type-id='5ce45b60'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='zpool_label_disk' mangled-name='zpool_label_disk' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_label_disk'> <function-decl name='zpool_label_disk' mangled-name='zpool_label_disk' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_label_disk'>
<parameter type-id='b0382bb3'/> <parameter type-id='b0382bb3'/>
<parameter type-id='4c81de99'/> <parameter type-id='4c81de99'/>
@ -8077,6 +8095,11 @@
<parameter type-id='d33f11cb'/> <parameter type-id='d33f11cb'/>
<return type-id='48b5725f'/> <return type-id='48b5725f'/>
</function-decl> </function-decl>
<function-decl name='putc' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='95e97e5e'/>
<parameter type-id='822cd80b'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='puts' visibility='default' binding='global' size-in-bits='64'> <function-decl name='puts' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/> <parameter type-id='80f4b756'/>
<return type-id='95e97e5e'/> <return type-id='95e97e5e'/>
@ -8095,6 +8118,11 @@
<parameter type-id='95e97e5e'/> <parameter type-id='95e97e5e'/>
<return type-id='48b5725f'/> <return type-id='48b5725f'/>
</function-decl> </function-decl>
<function-decl name='strspn' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<return type-id='b59d7dce'/>
</function-decl>
<function-decl name='strnlen' visibility='default' binding='global' size-in-bits='64'> <function-decl name='strnlen' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/> <parameter type-id='80f4b756'/>
<parameter type-id='b59d7dce'/> <parameter type-id='b59d7dce'/>
@ -8294,12 +8322,12 @@
<function-decl name='zfs_version_print' mangled-name='zfs_version_print' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_version_print'> <function-decl name='zfs_version_print' mangled-name='zfs_version_print' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_version_print'>
<return type-id='95e97e5e'/> <return type-id='95e97e5e'/>
</function-decl> </function-decl>
<function-decl name='use_color' mangled-name='use_color' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='use_color'>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='zfs_version_nvlist' mangled-name='zfs_version_nvlist' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_version_nvlist'> <function-decl name='zfs_version_nvlist' mangled-name='zfs_version_nvlist' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_version_nvlist'>
<return type-id='5ce45b60'/> <return type-id='5ce45b60'/>
</function-decl> </function-decl>
<function-decl name='use_color' mangled-name='use_color' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='use_color'>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='printf_color' mangled-name='printf_color' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='printf_color'> <function-decl name='printf_color' mangled-name='printf_color' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='printf_color'>
<parameter type-id='80f4b756' name='color'/> <parameter type-id='80f4b756' name='color'/>
<parameter type-id='80f4b756' name='format'/> <parameter type-id='80f4b756' name='format'/>
@ -8804,11 +8832,6 @@
<parameter type-id='78c01427'/> <parameter type-id='78c01427'/>
<return type-id='13956559'/> <return type-id='13956559'/>
</function-decl> </function-decl>
<function-decl name='strspn' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<return type-id='b59d7dce'/>
</function-decl>
<function-decl name='zfs_dirnamelen' mangled-name='zfs_dirnamelen' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_dirnamelen'> <function-decl name='zfs_dirnamelen' mangled-name='zfs_dirnamelen' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_dirnamelen'>
<parameter type-id='80f4b756' name='path'/> <parameter type-id='80f4b756' name='path'/>
<return type-id='79a0948f'/> <return type-id='79a0948f'/>

View File

@ -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 .It Sy zfs_scrub_error_blocks_per_txg Ns = Ns Sy 4096 Pq uint
Error blocks to be scrubbed in one txg. 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 .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 To preserve progress across reboots, the sequential scan algorithm periodically
needs to stop metadata scanning and issue all the verification I/O to disk. needs to stop metadata scanning and issue all the verification I/O to disk.

View File

@ -40,6 +40,7 @@
.Op Fl w .Op Fl w
.Op Fl e .Op Fl e
.Op Fl C .Op Fl C
.Op Fl R
.Ar pool Ns .Ar pool Ns
. .
.Sh DESCRIPTION .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 Continue scrub from last saved txg (see zpool
.Sy last_scrubbed_txg .Sy last_scrubbed_txg
property). property).
.It Fl R
Scrub only recent data (this can be controlled by the
.Sy zfs_scrub_recent_txgs
parameter).
.El .El
.Sh EXAMPLES .Sh EXAMPLES
.Ss Example 1 .Ss Example 1

View File

@ -239,6 +239,9 @@ static int zfs_free_bpobj_enabled = 1;
/* Error blocks to be scrubbed in one txg. */ /* Error blocks to be scrubbed in one txg. */
static uint_t zfs_scrub_error_blocks_per_txg = 1 << 12; 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 */ /* the order has to match pool_scan_type */
static scan_cb_t *scan_funcs[POOL_SCAN_FUNCS] = { static scan_cb_t *scan_funcs[POOL_SCAN_FUNCS] = {
NULL, 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, ZFS_MODULE_PARAM(zfs, zfs_, scrub_error_blocks_per_txg, UINT, ZMOD_RW,
"Error blocks to be scrubbed in one txg"); "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 */ /* END CSTYLED */

View File

@ -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) { } else if (scan_cmd == POOL_SCRUB_FROM_LAST_TXG) {
error = spa_scan_range(spa, scan_type, error = spa_scan_range(spa, scan_type,
spa_get_last_scrubbed_txg(spa), 0); 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 { } else {
error = spa_scan(spa, scan_type); error = spa_scan(spa, scan_type);
} }