Merge 4823cc2492
into 17dd66deda
This commit is contained in:
commit
50292ff580
|
@ -512,7 +512,8 @@ 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] <pool> ...\n"));
|
return (gettext("\tscrub [-s | -p] [-w] [-e] [-C] [-R] "
|
||||||
|
"<pool> ...\n"));
|
||||||
case HELP_RESILVER:
|
case HELP_RESILVER:
|
||||||
return (gettext("\tresilver <pool> ...\n"));
|
return (gettext("\tresilver <pool> ...\n"));
|
||||||
case HELP_TRIM:
|
case HELP_TRIM:
|
||||||
|
@ -8399,11 +8400,13 @@ wait_callback(zpool_handle_t *zhp, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* zpool scrub [-s | -p] [-w] [-e] <pool> ...
|
* zpool scrub [-s | -p] [-w] [-e] [-C] <pool> ...
|
||||||
*
|
*
|
||||||
|
* -C Scrub from last saved txg.
|
||||||
* -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
|
||||||
|
@ -8420,10 +8423,15 @@ zpool_do_scrub(int argc, char **argv)
|
||||||
boolean_t is_error_scrub = B_FALSE;
|
boolean_t is_error_scrub = B_FALSE;
|
||||||
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_recent_scrub = B_FALSE;
|
||||||
|
|
||||||
/* check options */
|
/* check options */
|
||||||
while ((c = getopt(argc, argv, "spwe")) != -1) {
|
while ((c = getopt(argc, argv, "spweCR")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
case 'C':
|
||||||
|
is_txg_continue = B_TRUE;
|
||||||
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
is_error_scrub = B_TRUE;
|
is_error_scrub = B_TRUE;
|
||||||
break;
|
break;
|
||||||
|
@ -8433,6 +8441,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;
|
||||||
|
@ -8447,14 +8458,43 @@ zpool_do_scrub(int argc, char **argv)
|
||||||
(void) fprintf(stderr, gettext("invalid option "
|
(void) fprintf(stderr, gettext("invalid option "
|
||||||
"combination :-s and -p are mutually exclusive\n"));
|
"combination :-s and -p are mutually exclusive\n"));
|
||||||
usage(B_FALSE);
|
usage(B_FALSE);
|
||||||
|
} else if (is_pause && is_txg_continue) {
|
||||||
|
(void) fprintf(stderr, gettext("invalid option "
|
||||||
|
"combination :-p and -C are mutually exclusive\n"));
|
||||||
|
usage(B_FALSE);
|
||||||
|
} else if (is_stop && is_txg_continue) {
|
||||||
|
(void) fprintf(stderr, gettext("invalid option "
|
||||||
|
"combination :-s and -C are mutually exclusive\n"));
|
||||||
|
usage(B_FALSE);
|
||||||
|
} else if (is_error_scrub && is_txg_continue) {
|
||||||
|
(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 {
|
} 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;
|
||||||
|
} else if (is_txg_continue) {
|
||||||
|
cb.cb_scrub_cmd = POOL_SCRUB_FROM_LAST_TXG;
|
||||||
} else {
|
} else {
|
||||||
cb.cb_scrub_cmd = POOL_SCRUB_NORMAL;
|
cb.cb_scrub_cmd = POOL_SCRUB_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,6 +381,7 @@ typedef struct dmu_buf {
|
||||||
#define DMU_POOL_CREATION_VERSION "creation_version"
|
#define DMU_POOL_CREATION_VERSION "creation_version"
|
||||||
#define DMU_POOL_SCAN "scan"
|
#define DMU_POOL_SCAN "scan"
|
||||||
#define DMU_POOL_ERRORSCRUB "error_scrub"
|
#define DMU_POOL_ERRORSCRUB "error_scrub"
|
||||||
|
#define DMU_POOL_LAST_SCRUBBED_TXG "last_scrubbed_txg"
|
||||||
#define DMU_POOL_FREE_BPOBJ "free_bpobj"
|
#define DMU_POOL_FREE_BPOBJ "free_bpobj"
|
||||||
#define DMU_POOL_BPTREE_OBJ "bptree_obj"
|
#define DMU_POOL_BPTREE_OBJ "bptree_obj"
|
||||||
#define DMU_POOL_EMPTY_BPOBJ "empty_bpobj"
|
#define DMU_POOL_EMPTY_BPOBJ "empty_bpobj"
|
||||||
|
|
|
@ -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
|
||||||
|
@ -189,7 +190,8 @@ void dsl_scan_setup_sync(void *, dmu_tx_t *);
|
||||||
void dsl_scan_fini(struct dsl_pool *dp);
|
void dsl_scan_fini(struct dsl_pool *dp);
|
||||||
void dsl_scan_sync(struct dsl_pool *, dmu_tx_t *);
|
void dsl_scan_sync(struct dsl_pool *, dmu_tx_t *);
|
||||||
int dsl_scan_cancel(struct dsl_pool *);
|
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);
|
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_scan_scrubbing(const struct dsl_pool *dp);
|
||||||
boolean_t dsl_errorscrubbing(const struct dsl_pool *dp);
|
boolean_t dsl_errorscrubbing(const struct dsl_pool *dp);
|
||||||
|
|
|
@ -261,6 +261,7 @@ typedef enum {
|
||||||
ZPOOL_PROP_DEDUP_TABLE_SIZE,
|
ZPOOL_PROP_DEDUP_TABLE_SIZE,
|
||||||
ZPOOL_PROP_DEDUP_TABLE_QUOTA,
|
ZPOOL_PROP_DEDUP_TABLE_QUOTA,
|
||||||
ZPOOL_PROP_DEDUPCACHED,
|
ZPOOL_PROP_DEDUPCACHED,
|
||||||
|
ZPOOL_PROP_LAST_SCRUBBED_TXG,
|
||||||
ZPOOL_NUM_PROPS
|
ZPOOL_NUM_PROPS
|
||||||
} zpool_prop_t;
|
} zpool_prop_t;
|
||||||
|
|
||||||
|
@ -1075,6 +1076,8 @@ typedef enum pool_scan_func {
|
||||||
typedef enum pool_scrub_cmd {
|
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_RECENT_TXGS,
|
||||||
POOL_SCRUB_FLAGS_END
|
POOL_SCRUB_FLAGS_END
|
||||||
} pool_scrub_cmd_t;
|
} pool_scrub_cmd_t;
|
||||||
|
|
||||||
|
|
|
@ -821,6 +821,8 @@ extern void spa_l2cache_drop(spa_t *spa);
|
||||||
|
|
||||||
/* scanning */
|
/* scanning */
|
||||||
extern int spa_scan(spa_t *spa, pool_scan_func_t func);
|
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_scan_stop(spa_t *spa);
|
||||||
extern int spa_scrub_pause_resume(spa_t *spa, pool_scrub_cmd_t flag);
|
extern int spa_scrub_pause_resume(spa_t *spa, pool_scrub_cmd_t flag);
|
||||||
|
|
||||||
|
@ -1067,6 +1069,7 @@ extern uint64_t spa_get_deadman_failmode(spa_t *spa);
|
||||||
extern void spa_set_deadman_failmode(spa_t *spa, const char *failmode);
|
extern void spa_set_deadman_failmode(spa_t *spa, const char *failmode);
|
||||||
extern boolean_t spa_suspended(spa_t *spa);
|
extern boolean_t spa_suspended(spa_t *spa);
|
||||||
extern uint64_t spa_bootfs(spa_t *spa);
|
extern uint64_t spa_bootfs(spa_t *spa);
|
||||||
|
extern uint64_t spa_get_last_scrubbed_txg(spa_t *spa);
|
||||||
extern uint64_t spa_delegation(spa_t *spa);
|
extern uint64_t spa_delegation(spa_t *spa);
|
||||||
extern objset_t *spa_meta_objset(spa_t *spa);
|
extern objset_t *spa_meta_objset(spa_t *spa);
|
||||||
extern space_map_t *spa_syncing_log_sm(spa_t *spa);
|
extern space_map_t *spa_syncing_log_sm(spa_t *spa);
|
||||||
|
|
|
@ -318,6 +318,7 @@ struct spa {
|
||||||
uint64_t spa_scan_pass_scrub_spent_paused; /* total paused */
|
uint64_t spa_scan_pass_scrub_spent_paused; /* total paused */
|
||||||
uint64_t spa_scan_pass_exam; /* examined bytes per pass */
|
uint64_t spa_scan_pass_exam; /* examined bytes per pass */
|
||||||
uint64_t spa_scan_pass_issued; /* issued bytes per pass */
|
uint64_t spa_scan_pass_issued; /* issued bytes per pass */
|
||||||
|
uint64_t spa_scrubbed_last_txg; /* last txg scrubbed */
|
||||||
|
|
||||||
/* error scrub pause time in milliseconds */
|
/* error scrub pause time in milliseconds */
|
||||||
uint64_t spa_scan_pass_errorscrub_pause;
|
uint64_t spa_scan_pass_errorscrub_pause;
|
||||||
|
|
|
@ -2963,7 +2963,8 @@
|
||||||
<enumerator name='ZPOOL_PROP_DEDUP_TABLE_SIZE' value='36'/>
|
<enumerator name='ZPOOL_PROP_DEDUP_TABLE_SIZE' value='36'/>
|
||||||
<enumerator name='ZPOOL_PROP_DEDUP_TABLE_QUOTA' value='37'/>
|
<enumerator name='ZPOOL_PROP_DEDUP_TABLE_QUOTA' value='37'/>
|
||||||
<enumerator name='ZPOOL_PROP_DEDUPCACHED' value='38'/>
|
<enumerator name='ZPOOL_PROP_DEDUPCACHED' value='38'/>
|
||||||
<enumerator name='ZPOOL_NUM_PROPS' value='39'/>
|
<enumerator name='ZPOOL_PROP_LAST_SCRUBBED_TXG' value='39'/>
|
||||||
|
<enumerator name='ZPOOL_NUM_PROPS' value='40'/>
|
||||||
</enum-decl>
|
</enum-decl>
|
||||||
<typedef-decl name='zpool_prop_t' type-id='af1ba157' id='5d0c23fb'/>
|
<typedef-decl name='zpool_prop_t' type-id='af1ba157' id='5d0c23fb'/>
|
||||||
<typedef-decl name='regoff_t' type-id='95e97e5e' id='54a2a2a8'/>
|
<typedef-decl name='regoff_t' type-id='95e97e5e' id='54a2a2a8'/>
|
||||||
|
@ -5815,7 +5816,9 @@
|
||||||
<underlying-type type-id='9cac1fee'/>
|
<underlying-type type-id='9cac1fee'/>
|
||||||
<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_FLAGS_END' value='2'/>
|
<enumerator name='POOL_SCRUB_FROM_LAST_TXG' value='2'/>
|
||||||
|
<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'>
|
||||||
|
|
|
@ -378,6 +378,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf,
|
||||||
case ZPOOL_PROP_BCLONEUSED:
|
case ZPOOL_PROP_BCLONEUSED:
|
||||||
case ZPOOL_PROP_DEDUP_TABLE_SIZE:
|
case ZPOOL_PROP_DEDUP_TABLE_SIZE:
|
||||||
case ZPOOL_PROP_DEDUPCACHED:
|
case ZPOOL_PROP_DEDUPCACHED:
|
||||||
|
case ZPOOL_PROP_LAST_SCRUBBED_TXG:
|
||||||
if (literal)
|
if (literal)
|
||||||
(void) snprintf(buf, len, "%llu",
|
(void) snprintf(buf, len, "%llu",
|
||||||
(u_longlong_t)intval);
|
(u_longlong_t)intval);
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -135,6 +135,14 @@ A unique identifier for the pool.
|
||||||
The current health of the pool.
|
The current health of the pool.
|
||||||
Health can be one of
|
Health can be one of
|
||||||
.Sy ONLINE , DEGRADED , FAULTED , OFFLINE, REMOVED , UNAVAIL .
|
.Sy ONLINE , DEGRADED , FAULTED , OFFLINE, REMOVED , UNAVAIL .
|
||||||
|
.It Sy last_scrubbed_txg
|
||||||
|
Indicates the transaction group (TXG) up to which the most recent scrub
|
||||||
|
operation has checked and repaired the dataset.
|
||||||
|
This provides insight into the data integrity status of their pool at
|
||||||
|
a specific point in time.
|
||||||
|
The
|
||||||
|
.Xr zpool-scrub 8
|
||||||
|
might be used to utilize this property.
|
||||||
.It Sy leaked
|
.It Sy leaked
|
||||||
Space not released while
|
Space not released while
|
||||||
.Sy freeing
|
.Sy freeing
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
.Op Fl s Ns | Ns Fl p
|
.Op Fl s Ns | Ns Fl p
|
||||||
.Op Fl w
|
.Op Fl w
|
||||||
.Op Fl e
|
.Op Fl e
|
||||||
|
.Op Fl C
|
||||||
|
.Op Fl R
|
||||||
.Ar pool Ns …
|
.Ar pool Ns …
|
||||||
.
|
.
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
|
@ -114,6 +116,14 @@ The pool must have been scrubbed at least once with the
|
||||||
feature enabled to use this option.
|
feature enabled to use this option.
|
||||||
Error scrubbing cannot be run simultaneously with regular scrubbing or
|
Error scrubbing cannot be run simultaneously with regular scrubbing or
|
||||||
resilvering, nor can it be run when a regular scrub is paused.
|
resilvering, nor can it be run when a regular scrub is paused.
|
||||||
|
.It Fl C
|
||||||
|
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
|
.El
|
||||||
.Sh EXAMPLES
|
.Sh EXAMPLES
|
||||||
.Ss Example 1
|
.Ss Example 1
|
||||||
|
|
|
@ -129,6 +129,10 @@ zpool_prop_init(void)
|
||||||
0, PROP_READONLY, ZFS_TYPE_POOL, "<size>", "DDTSIZE", B_FALSE,
|
0, PROP_READONLY, ZFS_TYPE_POOL, "<size>", "DDTSIZE", B_FALSE,
|
||||||
sfeatures);
|
sfeatures);
|
||||||
|
|
||||||
|
zprop_register_number(ZPOOL_PROP_LAST_SCRUBBED_TXG,
|
||||||
|
"last_scrubbed_txg", 0, PROP_READONLY, ZFS_TYPE_POOL, "<txg>",
|
||||||
|
"LAST_SCRUBBED_TXG", B_FALSE, sfeatures);
|
||||||
|
|
||||||
/* default number properties */
|
/* default number properties */
|
||||||
zprop_register_number(ZPOOL_PROP_VERSION, "version", SPA_VERSION,
|
zprop_register_number(ZPOOL_PROP_VERSION, "version", SPA_VERSION,
|
||||||
PROP_DEFAULT, ZFS_TYPE_POOL, "<version>", "VERSION", B_FALSE,
|
PROP_DEFAULT, ZFS_TYPE_POOL, "<version>", "VERSION", B_FALSE,
|
||||||
|
|
|
@ -228,6 +228,9 @@ static int zfs_resilver_disable_defer = B_FALSE;
|
||||||
((scn)->scn_phys.scn_func == POOL_SCAN_SCRUB || \
|
((scn)->scn_phys.scn_func == POOL_SCAN_SCRUB || \
|
||||||
(scn)->scn_phys.scn_func == POOL_SCAN_RESILVER)
|
(scn)->scn_phys.scn_func == POOL_SCAN_RESILVER)
|
||||||
|
|
||||||
|
#define DSL_SCAN_IS_SCRUB(scn) \
|
||||||
|
((scn)->scn_phys.scn_func == POOL_SCAN_SCRUB)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable/disable the processing of the free_bpobj object.
|
* Enable/disable the processing of the free_bpobj object.
|
||||||
*/
|
*/
|
||||||
|
@ -236,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,
|
||||||
|
@ -848,18 +854,24 @@ dsl_scan_setup_check(void *arg, dmu_tx_t *tx)
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
pool_scan_func_t func;
|
||||||
|
uint64_t txgstart;
|
||||||
|
uint64_t txgend;
|
||||||
|
} setup_sync_arg_t;
|
||||||
|
|
||||||
void
|
void
|
||||||
dsl_scan_setup_sync(void *arg, dmu_tx_t *tx)
|
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;
|
dsl_scan_t *scn = dmu_tx_pool(tx)->dp_scan;
|
||||||
pool_scan_func_t *funcp = arg;
|
|
||||||
dmu_object_type_t ot = 0;
|
dmu_object_type_t ot = 0;
|
||||||
dsl_pool_t *dp = scn->scn_dp;
|
dsl_pool_t *dp = scn->scn_dp;
|
||||||
spa_t *spa = dp->dp_spa;
|
spa_t *spa = dp->dp_spa;
|
||||||
|
|
||||||
ASSERT(!dsl_scan_is_running(scn));
|
ASSERT(!dsl_scan_is_running(scn));
|
||||||
ASSERT(*funcp > POOL_SCAN_NONE && *funcp < POOL_SCAN_FUNCS);
|
ASSERT(setup_sync_arg->func > POOL_SCAN_NONE &&
|
||||||
|
setup_sync_arg->func < POOL_SCAN_FUNCS);
|
||||||
memset(&scn->scn_phys, 0, sizeof (scn->scn_phys));
|
memset(&scn->scn_phys, 0, sizeof (scn->scn_phys));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -869,10 +881,14 @@ dsl_scan_setup_sync(void *arg, dmu_tx_t *tx)
|
||||||
memset(&scn->errorscrub_phys, 0, sizeof (scn->errorscrub_phys));
|
memset(&scn->errorscrub_phys, 0, sizeof (scn->errorscrub_phys));
|
||||||
dsl_errorscrub_sync_state(scn, tx);
|
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_state = DSS_SCANNING;
|
||||||
scn->scn_phys.scn_min_txg = 0;
|
scn->scn_phys.scn_min_txg = setup_sync_arg->txgstart;
|
||||||
scn->scn_phys.scn_max_txg = tx->tx_txg;
|
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_ddt_class_max = DDT_CLASSES - 1; /* the entire DDT */
|
||||||
scn->scn_phys.scn_start_time = gethrestime_sec();
|
scn->scn_phys.scn_start_time = gethrestime_sec();
|
||||||
scn->scn_phys.scn_errors = 0;
|
scn->scn_phys.scn_errors = 0;
|
||||||
|
@ -959,7 +975,7 @@ dsl_scan_setup_sync(void *arg, dmu_tx_t *tx)
|
||||||
|
|
||||||
spa_history_log_internal(spa, "scan setup", tx,
|
spa_history_log_internal(spa, "scan setup", tx,
|
||||||
"func=%u mintxg=%llu maxtxg=%llu",
|
"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);
|
(u_longlong_t)scn->scn_phys.scn_max_txg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -969,10 +985,16 @@ dsl_scan_setup_sync(void *arg, dmu_tx_t *tx)
|
||||||
* error scrub.
|
* error scrub.
|
||||||
*/
|
*/
|
||||||
int
|
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;
|
spa_t *spa = dp->dp_spa;
|
||||||
dsl_scan_t *scn = dp->dp_scan;
|
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
|
* Purge all vdev caches and probe all devices. We do this here
|
||||||
|
@ -1023,8 +1045,13 @@ dsl_scan(dsl_pool_t *dp, pool_scan_func_t func)
|
||||||
return (SET_ERROR(err));
|
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,
|
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
|
static void
|
||||||
|
@ -1112,15 +1139,24 @@ dsl_scan_done(dsl_scan_t *scn, boolean_t complete, dmu_tx_t *tx)
|
||||||
|
|
||||||
spa_notify_waiters(spa);
|
spa_notify_waiters(spa);
|
||||||
|
|
||||||
if (dsl_scan_restarting(scn, tx))
|
if (dsl_scan_restarting(scn, tx)) {
|
||||||
spa_history_log_internal(spa, "scan aborted, restarting", tx,
|
spa_history_log_internal(spa, "scan aborted, restarting", tx,
|
||||||
"errors=%llu", (u_longlong_t)spa_approx_errlog_size(spa));
|
"errors=%llu", (u_longlong_t)spa_approx_errlog_size(spa));
|
||||||
else if (!complete)
|
} else if (!complete) {
|
||||||
spa_history_log_internal(spa, "scan cancelled", tx,
|
spa_history_log_internal(spa, "scan cancelled", tx,
|
||||||
"errors=%llu", (u_longlong_t)spa_approx_errlog_size(spa));
|
"errors=%llu", (u_longlong_t)spa_approx_errlog_size(spa));
|
||||||
else
|
} else {
|
||||||
spa_history_log_internal(spa, "scan done", tx,
|
spa_history_log_internal(spa, "scan done", tx,
|
||||||
"errors=%llu", (u_longlong_t)spa_approx_errlog_size(spa));
|
"errors=%llu", (u_longlong_t)spa_approx_errlog_size(spa));
|
||||||
|
if (DSL_SCAN_IS_SCRUB(scn)) {
|
||||||
|
VERIFY0(zap_update(dp->dp_meta_objset,
|
||||||
|
DMU_POOL_DIRECTORY_OBJECT,
|
||||||
|
DMU_POOL_LAST_SCRUBBED_TXG,
|
||||||
|
sizeof (uint64_t), 1,
|
||||||
|
&scn->scn_phys.scn_max_txg, tx));
|
||||||
|
spa->spa_scrubbed_last_txg = scn->scn_phys.scn_max_txg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (DSL_SCAN_IS_SCRUB_RESILVER(scn)) {
|
if (DSL_SCAN_IS_SCRUB_RESILVER(scn)) {
|
||||||
spa->spa_scrub_active = B_FALSE;
|
spa->spa_scrub_active = B_FALSE;
|
||||||
|
@ -4301,13 +4337,16 @@ dsl_scan_sync(dsl_pool_t *dp, dmu_tx_t *tx)
|
||||||
*/
|
*/
|
||||||
if (dsl_scan_restarting(scn, tx) ||
|
if (dsl_scan_restarting(scn, tx) ||
|
||||||
(spa->spa_resilver_deferred && zfs_resilver_disable_defer)) {
|
(spa->spa_resilver_deferred && zfs_resilver_disable_defer)) {
|
||||||
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);
|
dsl_scan_done(scn, B_FALSE, tx);
|
||||||
if (vdev_resilver_needed(spa->spa_root_vdev, NULL, NULL))
|
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",
|
zfs_dbgmsg("restarting scan func=%u on %s txg=%llu",
|
||||||
func, dp->dp_spa->spa_name, (longlong_t)tx->tx_txg);
|
setup_sync_arg.func, dp->dp_spa->spa_name,
|
||||||
dsl_scan_setup_sync(&func, tx);
|
(longlong_t)tx->tx_txg);
|
||||||
|
dsl_scan_setup_sync(&setup_sync_arg, tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5287,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 */
|
||||||
|
|
|
@ -458,6 +458,9 @@ spa_prop_get_config(spa_t *spa, nvlist_t **nvp)
|
||||||
spa_prop_add_list(*nvp, ZPOOL_PROP_DEDUP_TABLE_SIZE, NULL,
|
spa_prop_add_list(*nvp, ZPOOL_PROP_DEDUP_TABLE_SIZE, NULL,
|
||||||
ddt_get_ddt_dsize(spa), src);
|
ddt_get_ddt_dsize(spa), src);
|
||||||
|
|
||||||
|
spa_prop_add_list(*nvp, ZPOOL_PROP_LAST_SCRUBBED_TXG, NULL,
|
||||||
|
spa_get_last_scrubbed_txg(spa), src);
|
||||||
|
|
||||||
spa_prop_add_list(*nvp, ZPOOL_PROP_HEALTH, NULL,
|
spa_prop_add_list(*nvp, ZPOOL_PROP_HEALTH, NULL,
|
||||||
rvd->vdev_state, src);
|
rvd->vdev_state, src);
|
||||||
|
|
||||||
|
@ -4737,6 +4740,12 @@ spa_ld_get_props(spa_t *spa)
|
||||||
if (error != 0 && error != ENOENT)
|
if (error != 0 && error != ENOENT)
|
||||||
return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
|
return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
|
||||||
|
|
||||||
|
/* Load the last scrubbed txg. */
|
||||||
|
error = spa_dir_prop(spa, DMU_POOL_LAST_SCRUBBED_TXG,
|
||||||
|
&spa->spa_scrubbed_last_txg, B_FALSE);
|
||||||
|
if (error != 0 && error != ENOENT)
|
||||||
|
return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load the livelist deletion field. If a livelist is queued for
|
* Load the livelist deletion field. If a livelist is queued for
|
||||||
* deletion, indicate that in the spa
|
* deletion, indicate that in the spa
|
||||||
|
@ -8877,6 +8886,13 @@ spa_scan_stop(spa_t *spa)
|
||||||
|
|
||||||
int
|
int
|
||||||
spa_scan(spa_t *spa, pool_scan_func_t func)
|
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);
|
ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == 0);
|
||||||
|
|
||||||
|
@ -8887,6 +8903,9 @@ spa_scan(spa_t *spa, pool_scan_func_t func)
|
||||||
!spa_feature_is_enabled(spa, SPA_FEATURE_RESILVER_DEFER))
|
!spa_feature_is_enabled(spa, SPA_FEATURE_RESILVER_DEFER))
|
||||||
return (SET_ERROR(ENOTSUP));
|
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
|
* If a resilver was requested, but there is no DTL on a
|
||||||
* writeable leaf device, we have nothing to do.
|
* writeable leaf device, we have nothing to do.
|
||||||
|
@ -8901,7 +8920,7 @@ spa_scan(spa_t *spa, pool_scan_func_t func)
|
||||||
!spa_feature_is_enabled(spa, SPA_FEATURE_HEAD_ERRLOG))
|
!spa_feature_is_enabled(spa, SPA_FEATURE_HEAD_ERRLOG))
|
||||||
return (SET_ERROR(ENOTSUP));
|
return (SET_ERROR(ENOTSUP));
|
||||||
|
|
||||||
return (dsl_scan(spa->spa_dsl_pool, func));
|
return (dsl_scan(spa->spa_dsl_pool, func, txgstart, txgend));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -10982,6 +11001,7 @@ EXPORT_SYMBOL(spa_l2cache_drop);
|
||||||
|
|
||||||
/* scanning */
|
/* scanning */
|
||||||
EXPORT_SYMBOL(spa_scan);
|
EXPORT_SYMBOL(spa_scan);
|
||||||
|
EXPORT_SYMBOL(spa_scan_range);
|
||||||
EXPORT_SYMBOL(spa_scan_stop);
|
EXPORT_SYMBOL(spa_scan_stop);
|
||||||
|
|
||||||
/* spa syncing */
|
/* spa syncing */
|
||||||
|
|
|
@ -2679,6 +2679,12 @@ spa_mode(spa_t *spa)
|
||||||
return (spa->spa_mode);
|
return (spa->spa_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
spa_get_last_scrubbed_txg(spa_t *spa)
|
||||||
|
{
|
||||||
|
return (spa->spa_scrubbed_last_txg);
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t
|
uint64_t
|
||||||
spa_bootfs(spa_t *spa)
|
spa_bootfs(spa_t *spa)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1719,6 +1719,19 @@ zfs_ioc_pool_scrub(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
|
||||||
error = spa_scrub_pause_resume(spa, POOL_SCRUB_PAUSE);
|
error = spa_scrub_pause_resume(spa, POOL_SCRUB_PAUSE);
|
||||||
} else if (scan_type == POOL_SCAN_NONE) {
|
} else if (scan_type == POOL_SCAN_NONE) {
|
||||||
error = spa_scan_stop(spa);
|
error = spa_scan_stop(spa);
|
||||||
|
} 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 {
|
} else {
|
||||||
error = spa_scan(spa, scan_type);
|
error = spa_scan(spa, scan_type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1218,6 +1218,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||||
functional/cli_root/zpool_scrub/zpool_scrub_multiple_copies.ksh \
|
functional/cli_root/zpool_scrub/zpool_scrub_multiple_copies.ksh \
|
||||||
functional/cli_root/zpool_scrub/zpool_scrub_offline_device.ksh \
|
functional/cli_root/zpool_scrub/zpool_scrub_offline_device.ksh \
|
||||||
functional/cli_root/zpool_scrub/zpool_scrub_print_repairing.ksh \
|
functional/cli_root/zpool_scrub/zpool_scrub_print_repairing.ksh \
|
||||||
|
functional/cli_root/zpool_scrub/zpool_scrub_txg_continue_from_last.ksh \
|
||||||
functional/cli_root/zpool_scrub/zpool_error_scrub_001_pos.ksh \
|
functional/cli_root/zpool_scrub/zpool_error_scrub_001_pos.ksh \
|
||||||
functional/cli_root/zpool_scrub/zpool_error_scrub_002_pos.ksh \
|
functional/cli_root/zpool_scrub/zpool_error_scrub_002_pos.ksh \
|
||||||
functional/cli_root/zpool_scrub/zpool_error_scrub_003_pos.ksh \
|
functional/cli_root/zpool_scrub/zpool_error_scrub_003_pos.ksh \
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
#!/bin/ksh -p
|
||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License (the "License").
|
||||||
|
# You may not use this file except in compliance with the License.
|
||||||
|
#
|
||||||
|
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
# or https://opensource.org/licenses/CDDL-1.0.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
|
||||||
|
# Copyright (c) 2023, Klara Inc.
|
||||||
|
#
|
||||||
|
# This software was developed by
|
||||||
|
# Mariusz Zaborski <mariusz.zaborski@klarasystems.com>
|
||||||
|
# under sponsorship from Wasabi Technology, Inc. and Klara Inc.
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
. $STF_SUITE/tests/functional/cli_root/zpool_scrub/zpool_scrub.cfg
|
||||||
|
. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.kshlib
|
||||||
|
|
||||||
|
#
|
||||||
|
# DESCRIPTION:
|
||||||
|
# Verify scrub -C
|
||||||
|
#
|
||||||
|
# STRATEGY:
|
||||||
|
# 1. Create a pool and create one file.
|
||||||
|
# 2. Verify that the last_txg_scrub is 0.
|
||||||
|
# 3. Run scrub.
|
||||||
|
# 4. Verify that the last_txg_scrub is set.
|
||||||
|
# 5. Create second file.
|
||||||
|
# 6. Invalidate both files.
|
||||||
|
# 7. Run scrub only from last point.
|
||||||
|
# 8. Verify that only one file, that was created with newer txg,
|
||||||
|
# was detected.
|
||||||
|
#
|
||||||
|
|
||||||
|
verify_runnable "global"
|
||||||
|
|
||||||
|
function cleanup
|
||||||
|
{
|
||||||
|
log_must zinject -c all
|
||||||
|
log_must rm -f $mntpnt/f1
|
||||||
|
log_must rm -f $mntpnt/f2
|
||||||
|
}
|
||||||
|
|
||||||
|
log_onexit cleanup
|
||||||
|
|
||||||
|
log_assert "Verify scrub -C."
|
||||||
|
|
||||||
|
# Create one file.
|
||||||
|
mntpnt=$(get_prop mountpoint $TESTPOOL/$TESTFS)
|
||||||
|
|
||||||
|
log_must file_write -b 1048576 -c 10 -o create -d 0 -f $mntpnt/f1
|
||||||
|
log_must sync_pool $TESTPOOL true
|
||||||
|
f1txg=$(get_last_txg_synced $TESTPOOL)
|
||||||
|
|
||||||
|
# Verify that last_scrubbed_txg isn't set.
|
||||||
|
zpoollasttxg=$(zpool get -H -o value last_scrubbed_txg $TESTPOOL)
|
||||||
|
log_must [ $zpoollasttxg -eq 0 ]
|
||||||
|
|
||||||
|
# Run scrub.
|
||||||
|
log_must zpool scrub -w $TESTPOOL
|
||||||
|
|
||||||
|
# Verify that last_scrubbed_txg is set.
|
||||||
|
zpoollasttxg=$(zpool get -H -o value last_scrubbed_txg $TESTPOOL)
|
||||||
|
log_must [ $zpoollasttxg -ne 0 ]
|
||||||
|
|
||||||
|
# Create second file.
|
||||||
|
log_must file_write -b 1048576 -c 10 -o create -d 0 -f $mntpnt/f2
|
||||||
|
log_must sync_pool $TESTPOOL true
|
||||||
|
f2txg=$(get_last_txg_synced $TESTPOOL)
|
||||||
|
|
||||||
|
# Make sure that the sync txg are different.
|
||||||
|
log_must [ $f1txg -ne $f2txg ]
|
||||||
|
|
||||||
|
# Insert faults.
|
||||||
|
log_must zinject -a -t data -e io -T read $mntpnt/f1
|
||||||
|
log_must zinject -a -t data -e io -T read $mntpnt/f2
|
||||||
|
|
||||||
|
# Run scrub from last saved point.
|
||||||
|
log_must zpool scrub -w -C $TESTPOOL
|
||||||
|
|
||||||
|
# Verify that only newer file was detected.
|
||||||
|
log_mustnot eval "zpool status -v $TESTPOOL | grep '$mntpnt/f1'"
|
||||||
|
log_must eval "zpool status -v $TESTPOOL | grep '$mntpnt/f2'"
|
||||||
|
|
||||||
|
# Verify that both files are corrupted.
|
||||||
|
log_must zpool scrub -w $TESTPOOL
|
||||||
|
log_must eval "zpool status -v $TESTPOOL | grep '$mntpnt/f1'"
|
||||||
|
log_must eval "zpool status -v $TESTPOOL | grep '$mntpnt/f2'"
|
||||||
|
|
||||||
|
log_pass "Verified scrub -C show expected status."
|
Loading…
Reference in New Issue