5959#include <sys/wait.h>
6060#include <zfs_prop.h>
6161#include <sys/fs/zfs.h>
62+ #include <sys/dsl_scan.h>
6263#include <sys/stat.h>
6364#include <sys/systeminfo.h>
6465#include <sys/fm/fs/zfs.h>
@@ -512,8 +513,8 @@ get_usage(zpool_help_t idx)
512513 return (gettext ("\tinitialize [-c | -s | -u] [-w] <-a | <pool> "
513514 "[<device> ...]>\n" ));
514515 case HELP_SCRUB :
515- return (gettext ("\tscrub [-e | -s | -p | -C | -E | -S] [-w ] "
516- "<-a | <pool> [<pool> ...]>\n" ));
516+ return (gettext ("\tscrub [-e | -s | -p | -C | -E | -S | -t ] "
517+ "[-w] <-a | <pool> [<pool> ...]>\n" ));
517518 case HELP_RESILVER :
518519 return (gettext ("\tresilver <pool> ...\n" ));
519520 case HELP_TRIM :
@@ -8518,7 +8519,7 @@ date_string_to_sec(const char *timestr, boolean_t rounding)
85188519}
85198520
85208521/*
8521- * zpool scrub [-e | -s | -p | -C | -E | -S] [-w] [-a | <pool> ...]
8522+ * zpool scrub [-e | -s | -p | -C | -E | -S | -t ] [-w] [-a | <pool> ...]
85228523 *
85238524 * -a Scrub all pools.
85248525 * -e Only scrub blocks in the error log.
@@ -8527,6 +8528,7 @@ date_string_to_sec(const char *timestr, boolean_t rounding)
85278528 * -s Stop. Stops any in-progress scrub.
85288529 * -p Pause. Pause in-progress scrub.
85298530 * -w Wait. Blocks until scrub has completed.
8531+ * -t Decompress and decrypt (if key is loaded) scrubbed blocks.
85308532 * -C Scrub from last saved txg.
85318533 */
85328534int
@@ -8538,24 +8540,26 @@ zpool_do_scrub(int argc, char **argv)
85388540 int error ;
85398541
85408542 cb .cb_type = POOL_SCAN_SCRUB ;
8541- cb .cb_scrub_cmd = POOL_SCRUB_NORMAL ;
8543+ cb .cb_scrub_cmd = 0 ;
85428544 cb .cb_date_start = cb .cb_date_end = 0 ;
85438545
85448546 boolean_t is_error_scrub = B_FALSE ;
85458547 boolean_t is_pause = B_FALSE ;
85468548 boolean_t is_stop = B_FALSE ;
8547- boolean_t is_txg_continue = B_FALSE ;
85488549 boolean_t scrub_all = B_FALSE ;
85498550
85508551 /* check options */
8551- while ((c = getopt (argc , argv , "aspweCE:S:" )) != -1 ) {
8552+ while ((c = getopt (argc , argv , "aspweCE:S:t " )) != -1 ) {
85528553 switch (c ) {
85538554 case 'a' :
85548555 scrub_all = B_TRUE ;
85558556 break ;
85568557 case 'e' :
85578558 is_error_scrub = B_TRUE ;
85588559 break ;
8560+ case 't' :
8561+ cb .cb_scrub_cmd |= POOL_SCRUB_THOROUGH ;
8562+ break ;
85598563 case 'E' :
85608564 /*
85618565 * Round the date. It's better to scrub more data than
@@ -8576,7 +8580,7 @@ zpool_do_scrub(int argc, char **argv)
85768580 wait = B_TRUE ;
85778581 break ;
85788582 case 'C' :
8579- is_txg_continue = B_TRUE ;
8583+ cb . cb_scrub_cmd |= POOL_SCRUB_FROM_LAST_TXG ;
85808584 break ;
85818585 case '?' :
85828586 (void ) fprintf (stderr , gettext ("invalid option '%c'\n" ),
@@ -8589,17 +8593,38 @@ zpool_do_scrub(int argc, char **argv)
85898593 (void ) fprintf (stderr , gettext ("invalid option "
85908594 "combination: -s and -p are mutually exclusive\n" ));
85918595 usage (B_FALSE );
8592- } else if (is_pause && is_txg_continue ) {
8596+ } else if (is_error_scrub && is_pause ) {
8597+ (void ) fprintf (stderr , gettext ("invalid option "
8598+ "combination: -e and -p are mutually exclusive\n" ));
8599+ usage (B_FALSE );
8600+ } else if (is_error_scrub && is_stop ) {
8601+ (void ) fprintf (stderr , gettext ("invalid option "
8602+ "combination: -e and -s are mutually exclusive\n" ));
8603+ usage (B_FALSE );
8604+ } else if (is_error_scrub &&
8605+ (cb .cb_scrub_cmd & POOL_SCRUB_FROM_LAST_TXG )) {
8606+ (void ) fprintf (stderr , gettext ("invalid option "
8607+ "combination: -e and -C are mutually exclusive\n" ));
8608+ usage (B_FALSE );
8609+ } else if (is_error_scrub && (cb .cb_scrub_cmd & POOL_SCRUB_THOROUGH )) {
8610+ (void ) fprintf (stderr , gettext ("invalid option "
8611+ "combination: -e and -t are mutually exclusive\n" ));
8612+ usage (B_FALSE );
8613+ } else if (is_pause && (cb .cb_scrub_cmd & POOL_SCRUB_FROM_LAST_TXG )) {
85938614 (void ) fprintf (stderr , gettext ("invalid option "
85948615 "combination: -p and -C are mutually exclusive\n" ));
85958616 usage (B_FALSE );
8596- } else if (is_stop && is_txg_continue ) {
8617+ } else if (is_pause && (cb .cb_scrub_cmd & POOL_SCRUB_THOROUGH )) {
8618+ (void ) fprintf (stderr , gettext ("invalid option "
8619+ "combination: -p and -t are mutually exclusive\n" ));
8620+ usage (B_FALSE );
8621+ } else if (is_stop && (cb .cb_scrub_cmd & POOL_SCRUB_FROM_LAST_TXG )) {
85978622 (void ) fprintf (stderr , gettext ("invalid option "
85988623 "combination: -s and -C are mutually exclusive\n" ));
85998624 usage (B_FALSE );
8600- } else if (is_error_scrub && is_txg_continue ) {
8625+ } else if (is_stop && ( cb . cb_scrub_cmd & POOL_SCRUB_THOROUGH ) ) {
86018626 (void ) fprintf (stderr , gettext ("invalid option "
8602- "combination: -e and -C are mutually exclusive\n" ));
8627+ "combination: -s and -t are mutually exclusive\n" ));
86038628 usage (B_FALSE );
86048629 } else {
86058630 if (is_error_scrub )
@@ -8609,19 +8634,31 @@ zpool_do_scrub(int argc, char **argv)
86098634 cb .cb_scrub_cmd = POOL_SCRUB_PAUSE ;
86108635 } else if (is_stop ) {
86118636 cb .cb_type = POOL_SCAN_NONE ;
8612- } else if (is_txg_continue ) {
8613- cb .cb_scrub_cmd = POOL_SCRUB_FROM_LAST_TXG ;
86148637 } else {
8615- cb .cb_scrub_cmd = POOL_SCRUB_NORMAL ;
8638+ if ((cb .cb_scrub_cmd & (POOL_SCRUB_NORMAL |
8639+ POOL_SCRUB_THOROUGH )) == 0 )
8640+ cb .cb_scrub_cmd |= POOL_SCRUB_NORMAL ;
86168641 }
86178642 }
86188643
8644+ uint64_t scrub_kind = cb .cb_scrub_cmd & (POOL_SCRUB_NORMAL |
8645+ POOL_SCRUB_THOROUGH );
86198646 if ((cb .cb_date_start != 0 || cb .cb_date_end != 0 ) &&
8620- cb .cb_scrub_cmd != POOL_SCRUB_NORMAL ) {
8621- (void ) fprintf (stderr , gettext ("invalid option combination: "
8622- "start/end date is available only with normal scrub\n" ));
8647+ (cb .cb_scrub_cmd & POOL_SCRUB_FROM_LAST_TXG )) {
8648+ (void ) fprintf (stderr , gettext ("invalid option "
8649+ "combination: -C and -S/-E date are mutually "
8650+ "exclusive\n" ));
8651+ usage (B_FALSE );
8652+ } else if ((cb .cb_date_start != 0 || cb .cb_date_end != 0 ) &&
8653+ (is_error_scrub ||
8654+ (scrub_kind != POOL_SCRUB_NORMAL &&
8655+ scrub_kind != POOL_SCRUB_THOROUGH ))) {
8656+ (void ) fprintf (stderr , gettext ("invalid option "
8657+ "combination: start/end date is available only "
8658+ "with normal or thorough scrub\n" ));
86238659 usage (B_FALSE );
86248660 }
8661+
86258662 if (cb .cb_date_start != 0 && cb .cb_date_end != 0 &&
86268663 cb .cb_date_start > cb .cb_date_end ) {
86278664 (void ) fprintf (stderr , gettext ("invalid arguments: "
@@ -8941,7 +8978,7 @@ print_err_scrub_status(pool_scan_stat_t *ps)
89418978 * Print out detailed scrub status.
89428979 */
89438980static void
8944- print_scan_scrub_resilver_status (pool_scan_stat_t * ps )
8981+ print_scan_scrub_resilver_status (pool_scan_stat_t * ps , uint_t c )
89458982{
89468983 time_t start , end , pause ;
89478984 uint64_t pass_scanned , scanned , pass_issued , issued , total_s , total_i ;
@@ -8976,10 +9013,22 @@ print_scan_scrub_resilver_status(pool_scan_stat_t *ps)
89769013 secs_to_dhms (end - start , time_buf );
89779014
89789015 if (is_scrub ) {
8979- (void ) printf (gettext ("scrub repaired %s "
8980- "in %s with %llu errors on %s" ), processed_buf ,
8981- time_buf , (u_longlong_t )ps -> pss_errors ,
8982- ctime (& end ));
9016+ boolean_t is_thorough =
9017+ (c > offsetof(pool_scan_stat_t ,
9018+ pss_pass_scrub_flags ) / 8 ) &&
9019+ (ps -> pss_pass_scrub_flags & DSF_SCRUB_THOROUGH ) !=
9020+ 0 ;
9021+ if (is_thorough ) {
9022+ (void ) printf (gettext ("thorough scrub repaired"
9023+ " %s in %s with %llu errors on %s" ),
9024+ processed_buf , time_buf ,
9025+ (u_longlong_t )ps -> pss_errors , ctime (& end ));
9026+ } else {
9027+ (void ) printf (gettext ("scrub repaired %s "
9028+ "in %s with %llu errors on %s" ),
9029+ processed_buf , time_buf ,
9030+ (u_longlong_t )ps -> pss_errors , ctime (& end ));
9031+ }
89839032 } else if (is_resilver ) {
89849033 (void ) printf (gettext ("resilvered %s "
89859034 "in %s with %llu errors on %s" ), processed_buf ,
@@ -8989,8 +9038,18 @@ print_scan_scrub_resilver_status(pool_scan_stat_t *ps)
89899038 return ;
89909039 } else if (ps -> pss_state == DSS_CANCELED ) {
89919040 if (is_scrub ) {
8992- (void ) printf (gettext ("scrub canceled on %s" ),
8993- ctime (& end ));
9041+ boolean_t is_thorough =
9042+ (c > offsetof(pool_scan_stat_t ,
9043+ pss_pass_scrub_flags ) / 8 ) &&
9044+ (ps -> pss_pass_scrub_flags & DSF_SCRUB_THOROUGH ) !=
9045+ 0 ;
9046+ if (is_thorough ) {
9047+ (void ) printf (gettext ("thorough scrub canceled"
9048+ " on %s" ), ctime (& end ));
9049+ } else {
9050+ (void ) printf (gettext ("scrub canceled on %s" ),
9051+ ctime (& end ));
9052+ }
89949053 } else if (is_resilver ) {
89959054 (void ) printf (gettext ("resilver canceled on %s" ),
89969055 ctime (& end ));
@@ -9002,14 +9061,30 @@ print_scan_scrub_resilver_status(pool_scan_stat_t *ps)
90029061
90039062 /* Scan is in progress. Resilvers can't be paused. */
90049063 if (is_scrub ) {
9064+ boolean_t is_thorough =
9065+ (c > offsetof(pool_scan_stat_t ,
9066+ pss_pass_scrub_flags ) / 8 ) &&
9067+ (ps -> pss_pass_scrub_flags & DSF_SCRUB_THOROUGH ) != 0 ;
90059068 if (pause == 0 ) {
9006- (void ) printf (gettext ("scrub in progress since %s" ),
9007- ctime (& start ));
9069+ if (is_thorough ) {
9070+ (void ) printf (gettext ("thorough scrub in "
9071+ "progress since %s" ), ctime (& start ));
9072+ } else {
9073+ (void ) printf (gettext ("scrub in progress "
9074+ "since %s" ), ctime (& start ));
9075+ }
90089076 } else {
9009- (void ) printf (gettext ("scrub paused since %s" ),
9010- ctime (& pause ));
9011- (void ) printf (gettext ("\tscrub started on %s" ),
9012- ctime (& start ));
9077+ if (is_thorough ) {
9078+ (void ) printf (gettext ("thorough scrub "
9079+ "paused since %s" ), ctime (& pause ));
9080+ (void ) printf (gettext ("\tthorough scrub "
9081+ "started on %s" ), ctime (& start ));
9082+ } else {
9083+ (void ) printf (gettext ("scrub paused since %s" ),
9084+ ctime (& pause ));
9085+ (void ) printf (gettext ("\tscrub started on %s" ),
9086+ ctime (& start ));
9087+ }
90139088 }
90149089 } else if (is_resilver ) {
90159090 (void ) printf (gettext ("resilver in progress since %s" ),
@@ -10124,7 +10199,7 @@ print_scan_status(zpool_handle_t *zhp, nvlist_t *nvroot)
1012410199
1012510200 /* Always print the scrub status when available. */
1012610201 if (have_scrub && scrub_start > errorscrub_start )
10127- print_scan_scrub_resilver_status (ps );
10202+ print_scan_scrub_resilver_status (ps , c );
1012810203 else if (have_errorscrub && errorscrub_start >= scrub_start )
1012910204 print_err_scrub_status (ps );
1013010205
@@ -10134,7 +10209,7 @@ print_scan_status(zpool_handle_t *zhp, nvlist_t *nvroot)
1013410209 */
1013510210 if (active_resilver || (!active_rebuild && have_resilver &&
1013610211 resilver_end_time && resilver_end_time > rebuild_end_time )) {
10137- print_scan_scrub_resilver_status (ps );
10212+ print_scan_scrub_resilver_status (ps , c );
1013810213 } else if (active_rebuild || (!active_resilver && have_rebuild &&
1013910214 rebuild_end_time && rebuild_end_time > resilver_end_time )) {
1014010215 print_rebuild_status (zhp , nvroot );
0 commit comments