@@ -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 :
@@ -6702,10 +6703,10 @@ scrub_callback(zpool_handle_t *zhp, void *data)
67026703
67036704 return (err != 0 );
67046705}
6705-
67066706/*
6707- * zpool scrub [-s | -p] <pool> ...
6707+ * zpool scrub [-s | -p] [-e] <pool> ...
67086708 *
6709+ * -e Only scrub blocks in the error log.
67096710 * -s Stop. Stops any in-progress scrub.
67106711 * -p Pause. Pause in-progress scrub.
67116712 */
@@ -6718,14 +6719,21 @@ zpool_do_scrub(int argc, char **argv)
67186719 cb .cb_type = POOL_SCAN_SCRUB ;
67196720 cb .cb_scrub_cmd = POOL_SCRUB_NORMAL ;
67206721
6722+ boolean_t is_error_scrub = B_FALSE ;
6723+ boolean_t is_pause = B_FALSE ;
6724+ boolean_t is_stop = B_FALSE ;
6725+
67216726 /* check options */
6722- while ((c = getopt (argc , argv , "sp " )) != -1 ) {
6727+ while ((c = getopt (argc , argv , "pse " )) != -1 ) {
67236728 switch (c ) {
6729+ case 'e' :
6730+ is_error_scrub = B_TRUE ;
6731+ break ;
67246732 case 's' :
6725- cb . cb_type = POOL_SCAN_NONE ;
6733+ is_stop = B_TRUE ;
67266734 break ;
67276735 case 'p' :
6728- cb . cb_scrub_cmd = POOL_SCRUB_PAUSE ;
6736+ is_pause = B_TRUE ;
67296737 break ;
67306738 case '?' :
67316739 (void ) fprintf (stderr , gettext ("invalid option '%c'\n" ),
@@ -6734,11 +6742,27 @@ zpool_do_scrub(int argc, char **argv)
67346742 }
67356743 }
67366744
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" ));
6745+ if (is_pause && is_stop ) {
6746+ (void ) fprintf (stderr , gettext ("invalid option "
6747+ "combination :-s and -p are mutually exclusive\n" ));
67416748 usage (B_FALSE );
6749+ } else {
6750+ if (is_error_scrub ) {
6751+ cb .cb_type = POOL_ERRORSCRUB ;
6752+ if (is_pause ) {
6753+ cb .cb_scrub_cmd = POOL_SCRUB_PAUSE ;
6754+ } else if (is_stop ) {
6755+ cb .cb_scrub_cmd = POOL_ERRORSCRUB_STOP ;
6756+ } else {
6757+ cb .cb_scrub_cmd = POOL_SCRUB_NORMAL ;
6758+ }
6759+ } else {
6760+ if (is_pause ) {
6761+ cb .cb_scrub_cmd = POOL_SCRUB_PAUSE ;
6762+ } else if (is_stop ) {
6763+ cb .cb_type = POOL_SCAN_NONE ;
6764+ }
6765+ }
67426766 }
67436767
67446768 cb .cb_argc = argc ;
@@ -6912,6 +6936,71 @@ zpool_do_trim(int argc, char **argv)
69126936 return (error );
69136937}
69146938
6939+ /*
6940+ * Print out detailed error scrub status.
6941+ */
6942+ static void
6943+ print_err_scrub_status (pool_scan_stat_t * ps )
6944+ {
6945+ time_t start , end , pause ;
6946+ uint64_t total_secs_left ;
6947+ uint64_t secs_left , mins_left , hours_left , days_left ;
6948+ uint64_t examined , to_be_examined ;
6949+
6950+ (void ) printf (gettext (" error scrub: " ));
6951+
6952+ if (ps == NULL || ps -> pss_error_scrub_func != POOL_ERRORSCRUB ) {
6953+ (void ) printf (gettext ("no error scrubbing requested\n" ));
6954+ return ;
6955+ }
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, issused i/o for %llu error"
6999+ " blocks" ), 100 * fraction_done , (u_longlong_t )examined );
7000+
7001+ (void ) printf (gettext ("\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