@@ -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] <pool>"
385+ " ...\n" ));
385386 case HELP_RESILVER :
386387 return (gettext ("\tresilver <pool> ...\n" ));
387388 case HELP_TRIM :
@@ -6704,8 +6705,9 @@ scrub_callback(zpool_handle_t *zhp, void *data)
67046705}
67056706
67066707/*
6707- * zpool scrub [-s | -p] <pool> ...
6708+ * zpool scrub [-s | -p] [-e] <pool> ...
67086709 *
6710+ * -e Only scrub blocks in the error log.
67096711 * -s Stop. Stops any in-progress scrub.
67106712 * -p Pause. Pause in-progress scrub.
67116713 */
@@ -6718,14 +6720,21 @@ zpool_do_scrub(int argc, char **argv)
67186720 cb .cb_type = POOL_SCAN_SCRUB ;
67196721 cb .cb_scrub_cmd = POOL_SCRUB_NORMAL ;
67206722
6723+ boolean_t is_error_scrub = B_FALSE ;
6724+ boolean_t is_pause = B_FALSE ;
6725+ boolean_t is_stop = B_FALSE ;
6726+
67216727 /* check options */
6722- while ((c = getopt (argc , argv , "sp " )) != -1 ) {
6728+ while ((c = getopt (argc , argv , "eps " )) != -1 ) {
67236729 switch (c ) {
6730+ case 'e' :
6731+ is_error_scrub = B_TRUE ;
6732+ break ;
67246733 case 's' :
6725- cb . cb_type = POOL_SCAN_NONE ;
6734+ is_stop = B_TRUE ;
67266735 break ;
67276736 case 'p' :
6728- cb . cb_scrub_cmd = POOL_SCRUB_PAUSE ;
6737+ is_pause = B_TRUE ;
67296738 break ;
67306739 case '?' :
67316740 (void ) fprintf (stderr , gettext ("invalid option '%c'\n" ),
@@ -6734,11 +6743,27 @@ zpool_do_scrub(int argc, char **argv)
67346743 }
67356744 }
67366745
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" ));
6746+ if (is_pause && is_stop ) {
6747+ (void ) fprintf (stderr , gettext ("invalid option "
6748+ "combination :-s and -p are mutually exclusive\n" ));
67416749 usage (B_FALSE );
6750+ } else {
6751+ if (is_error_scrub ) {
6752+ cb .cb_type = POOL_ERRORSCRUB ;
6753+ if (is_pause ) {
6754+ cb .cb_scrub_cmd = POOL_SCRUB_PAUSE ;
6755+ } else if (is_stop ) {
6756+ cb .cb_scrub_cmd = POOL_ERRORSCRUB_STOP ;
6757+ } else {
6758+ cb .cb_scrub_cmd = POOL_SCRUB_NORMAL ;
6759+ }
6760+ } else {
6761+ if (is_pause ) {
6762+ cb .cb_scrub_cmd = POOL_SCRUB_PAUSE ;
6763+ } else if (is_stop ) {
6764+ cb .cb_type = POOL_SCAN_NONE ;
6765+ }
6766+ }
67426767 }
67436768
67446769 cb .cb_argc = argc ;
@@ -6912,6 +6937,70 @@ zpool_do_trim(int argc, char **argv)
69126937 return (error );
69136938}
69146939
6940+ /*
6941+ * Print out detailed error scrub status.
6942+ */
6943+ static void
6944+ print_err_scrub_status (pool_scan_stat_t * ps )
6945+ {
6946+ time_t start , end , pause ;
6947+ uint64_t total_secs_left ;
6948+ uint64_t secs_left , mins_left , hours_left , days_left ;
6949+ uint64_t examined , to_be_examined ;
6950+
6951+ if (ps == NULL || ps -> pss_error_scrub_func != POOL_ERRORSCRUB ) {
6952+ return ;
6953+ }
6954+
6955+ (void ) printf (gettext (" scrub: " ));
6956+
6957+ start = ps -> pss_error_scrub_start ;
6958+ end = ps -> pss_error_scrub_end ;
6959+ pause = ps -> pss_pass_error_scrub_pause ;
6960+ examined = ps -> pss_error_scrub_examined ;
6961+ to_be_examined = ps -> pss_error_scrub_to_be_examined ;
6962+
6963+ assert (ps -> pss_error_scrub_func == POOL_ERRORSCRUB );
6964+
6965+ if (ps -> pss_error_scrub_state == DSS_FINISHED ) {
6966+ total_secs_left = end - start ;
6967+ days_left = total_secs_left / 60 / 60 / 24 ;
6968+ hours_left = (total_secs_left / 60 / 60 ) % 24 ;
6969+ mins_left = (total_secs_left / 60 ) % 60 ;
6970+ secs_left = (total_secs_left % 60 );
6971+
6972+ (void ) printf (gettext ("scrubbed %llu error blocks in %llu days "
6973+ "%02llu:%02llu:%02llu on %s" ), (u_longlong_t )examined ,
6974+ (u_longlong_t )days_left , (u_longlong_t )hours_left ,
6975+ (u_longlong_t )mins_left , (u_longlong_t )secs_left ,
6976+ ctime (& end ));
6977+
6978+ return ;
6979+ } else if (ps -> pss_error_scrub_state == DSS_CANCELED ) {
6980+ (void ) printf (gettext ("error scrub canceled on %s" ),
6981+ ctime (& end ));
6982+ return ;
6983+ }
6984+ assert (ps -> pss_error_scrub_state == DSS_ERRORSCRUBING );
6985+
6986+ /* Error scrub is in progress. */
6987+ if (pause == 0 ) {
6988+ (void ) printf (gettext ("error scrub in progress since %s" ),
6989+ ctime (& start ));
6990+ } else {
6991+ (void ) printf (gettext ("error scrub paused since %s" ),
6992+ ctime (& pause ));
6993+ (void ) printf (gettext ("\terror scrub started on %s" ),
6994+ ctime (& start ));
6995+ }
6996+
6997+ double fraction_done = (double )examined / (to_be_examined + examined );
6998+ (void ) printf (gettext ("\t%.2f%% done, issued I/O for %llu error"
6999+ " blocks" ), 100 * fraction_done , (u_longlong_t )examined );
7000+
7001+ (void ) printf ("\n" );
7002+ }
7003+
69157004/*
69167005 * Print out detailed scrub status.
69177006 */
@@ -7687,6 +7776,7 @@ status_callback(zpool_handle_t *zhp, void *data)
76877776 ZPOOL_CONFIG_REMOVAL_STATS , (uint64_t * * )& prs , & c );
76887777
76897778 print_scan_status (ps );
7779+ print_err_scrub_status (ps );
76907780 print_checkpoint_scan_warning (ps , pcs );
76917781 print_removal_status (zhp , prs );
76927782 print_checkpoint_status (pcs );
0 commit comments