@@ -381,7 +381,8 @@ get_usage(zpool_help_t idx)
381381 return (gettext ("\tinitialize [-c | -s] <pool> "
382382 "[<device> ...]\n" ));
383383 case HELP_SCRUB :
384- return (gettext ("\tscrub [-s | -p] <pool> ...\n" ));
384+ return (gettext ("\tscrub [-s | -p | -e | -e -s | -e -p] <pool>"
385+ " ...\n" ));
385386 case HELP_RESILVER :
386387 return (gettext ("\tresilver <pool> ...\n" ));
387388 case HELP_TRIM :
@@ -6691,7 +6692,11 @@ scrub_callback(zpool_handle_t *zhp, void *data)
66916692 return (1 );
66926693 }
66936694
6694- err = zpool_scan (zhp , cb -> cb_type , cb -> cb_scrub_cmd );
6695+ if (cb -> cb_type == POOL_RESCRUB ) {
6696+ err = zpool_rescrub (zhp , cb -> cb_type , cb -> cb_scrub_cmd );
6697+ } else {
6698+ err = zpool_scan (zhp , cb -> cb_type , cb -> cb_scrub_cmd );
6699+ }
66956700
66966701 if (err == 0 && zpool_has_checkpoint (zhp ) &&
66976702 cb -> cb_type == POOL_SCAN_SCRUB ) {
@@ -6706,6 +6711,7 @@ scrub_callback(zpool_handle_t *zhp, void *data)
67066711/*
67076712 * zpool scrub [-s | -p] <pool> ...
67086713 *
6714+ * -e For error blocks. Starts/Resumes error blocks scrubbing.
67096715 * -s Stop. Stops any in-progress scrub.
67106716 * -p Pause. Pause in-progress scrub.
67116717 */
@@ -6718,27 +6724,52 @@ zpool_do_scrub(int argc, char **argv)
67186724 cb .cb_type = POOL_SCAN_SCRUB ;
67196725 cb .cb_scrub_cmd = POOL_SCRUB_NORMAL ;
67206726
6727+ boolean_t is_error_scrub = B_FALSE ;
6728+ boolean_t is_pause = B_FALSE ;
6729+ boolean_t is_stop = B_FALSE ;
67216730 /* check options */
6722- while ((c = getopt (argc , argv , "sp " )) != -1 ) {
6731+ while ((c = getopt (argc , argv , "eps " )) != -1 ) {
67236732 switch (c ) {
6724- case 's' :
6725- cb . cb_type = POOL_SCAN_NONE ;
6733+ case 'e' : {
6734+ is_error_scrub = B_TRUE ;
67266735 break ;
6727- case 'p' :
6728- cb .cb_scrub_cmd = POOL_SCRUB_PAUSE ;
6736+ }
6737+ case 's' : {
6738+ is_stop = B_TRUE ;
6739+ break ;
6740+ }
6741+ case 'p' : {
6742+ is_pause = B_TRUE ;
67296743 break ;
6744+ }
67306745 case '?' :
67316746 (void ) fprintf (stderr , gettext ("invalid option '%c'\n" ),
67326747 optopt );
67336748 usage (B_FALSE );
67346749 }
67356750 }
67366751
6737- if (cb .cb_type == POOL_SCAN_NONE &&
6738- cb .cb_scrub_cmd == POOL_SCRUB_PAUSE ) {
6739- (void ) fprintf (stderr , gettext ("invalid option combination: "
6740- "-s and -p are mutually exclusive\n" ));
6752+ if (is_pause && is_stop ) {
6753+ (void ) fprintf (stderr , gettext ("invalid option "
6754+ "combination :-s and -p are mutually exclusive\n" ));
67416755 usage (B_FALSE );
6756+ } else {
6757+ if (is_error_scrub ) {
6758+ cb .cb_type = POOL_RESCRUB ;
6759+ if (is_pause ) {
6760+ cb .cb_scrub_cmd = POOL_RESCRUB_PAUSE ;
6761+ } else if (is_stop ) {
6762+ cb .cb_scrub_cmd = POOL_RESCRUB_STOP ;
6763+ } else {
6764+ cb .cb_scrub_cmd = POOL_RESCRUB_NORMAL ;
6765+ }
6766+ } else {
6767+ if (is_pause ) {
6768+ cb .cb_scrub_cmd = POOL_SCRUB_PAUSE ;
6769+ } else if (is_stop ) {
6770+ cb .cb_type = POOL_SCAN_NONE ;
6771+ }
6772+ }
67426773 }
67436774
67446775 cb .cb_argc = argc ;
@@ -6912,6 +6943,69 @@ zpool_do_trim(int argc, char **argv)
69126943 return (error );
69136944}
69146945
6946+ static void
6947+ print_err_scrub_status (pool_scan_stat_t * ps )
6948+ {
6949+ time_t start , end , pause ;
6950+ uint64_t total_secs_left ;
6951+ uint64_t secs_left , mins_left , hours_left , days_left ;
6952+ uint64_t examined , to_be_examined ;
6953+
6954+ (void ) printf (gettext (" error scrub: " ));
6955+
6956+ if (ps == NULL || ps -> pss_error_scrub_func == POOL_SCAN_NONE ||
6957+ ps -> pss_error_scrub_func >= POOL_SCAN_FUNCS ) {
6958+ (void ) printf (gettext ("no error scrubbing requested\n" ));
6959+ return ;
6960+ }
6961+
6962+ start = ps -> pss_error_scrub_start ;
6963+ end = ps -> pss_error_scrub_end ;
6964+ pause = ps -> pss_pass_error_scrub_pause ;
6965+ examined = ps -> pss_error_scrub_examined ;
6966+ to_be_examined = ps -> pss_error_scrub_to_be_examined ;
6967+
6968+ assert (ps -> pss_error_scrub_func == POOL_RESCRUB );
6969+
6970+ if (ps -> pss_error_scrub_state == DSS_FINISHED ) {
6971+ total_secs_left = end - start ;
6972+ days_left = total_secs_left / 60 / 60 / 24 ;
6973+ hours_left = (total_secs_left / 60 / 60 ) % 24 ;
6974+ mins_left = (total_secs_left / 60 ) % 60 ;
6975+ secs_left = (total_secs_left % 60 );
6976+
6977+ (void ) printf (gettext ("scrubbed %llu error blocks in %llu days "
6978+ "%02llu:%02llu:%02llu on %s" ), (u_longlong_t )examined ,
6979+ (u_longlong_t )days_left , (u_longlong_t )hours_left ,
6980+ (u_longlong_t )mins_left , (u_longlong_t )secs_left ,
6981+ ctime (& end ));
6982+
6983+ return ;
6984+ } else if (ps -> pss_error_scrub_state == DSS_CANCELED ) {
6985+ (void ) printf (gettext ("error scrub canceled on %s" ),
6986+ ctime (& end ));
6987+ return ;
6988+ }
6989+ assert (ps -> pss_error_scrub_state == DSS_RESCRUBING );
6990+
6991+ /* Error scrub is in progress. */
6992+ if (pause == 0 ) {
6993+ (void ) printf (gettext ("error scrub in progress since %s" ),
6994+ ctime (& start ));
6995+ } else {
6996+ (void ) printf (gettext ("error scrub paused since %s" ),
6997+ ctime (& pause ));
6998+ (void ) printf (gettext ("\terror scrub started on %s" ),
6999+ ctime (& start ));
7000+ }
7001+
7002+ double fraction_done = (double )examined / (to_be_examined + examined );
7003+ (void ) printf (gettext ("\t%.2f%% done, issused i/o for %llu error"
7004+ " blocks" ), 100 * fraction_done , (u_longlong_t )examined );
7005+
7006+ (void ) printf (gettext ("\n" ));
7007+ }
7008+
69157009/*
69167010 * Print out detailed scrub status.
69177011 */
@@ -7687,6 +7781,7 @@ status_callback(zpool_handle_t *zhp, void *data)
76877781 ZPOOL_CONFIG_REMOVAL_STATS , (uint64_t * * )& prs , & c );
76887782
76897783 print_scan_status (ps );
7784+ print_err_scrub_status (ps );
76907785 print_checkpoint_scan_warning (ps , pcs );
76917786 print_removal_status (zhp , prs );
76927787 print_checkpoint_status (pcs );
0 commit comments