@@ -395,7 +395,7 @@ get_usage(zpool_help_t idx)
395395 return (gettext ("\tinitialize [-c | -s] [-w] <pool> "
396396 "[<device> ...]\n" ));
397397 case HELP_SCRUB :
398- return (gettext ("\tscrub [-s | -p] [-w] <pool> ...\n" ));
398+ return (gettext ("\tscrub [-s | -p] [-w] [-e] <pool> ...\n" ));
399399 case HELP_RESILVER :
400400 return (gettext ("\tresilver <pool> ...\n" ));
401401 case HELP_TRIM :
@@ -7145,8 +7145,9 @@ wait_callback(zpool_handle_t *zhp, void *data)
71457145}
71467146
71477147/*
7148- * zpool scrub [-s | -p] [-w] <pool> ...
7148+ * zpool scrub [-s | -p] [-w] [-e] <pool> ...
71497149 *
7150+ * -e Only scrub blocks in the error log.
71507151 * -s Stop. Stops any in-progress scrub.
71517152 * -p Pause. Pause in-progress scrub.
71527153 * -w Wait. Blocks until scrub has completed.
@@ -7162,14 +7163,21 @@ zpool_do_scrub(int argc, char **argv)
71627163 cb .cb_type = POOL_SCAN_SCRUB ;
71637164 cb .cb_scrub_cmd = POOL_SCRUB_NORMAL ;
71647165
7166+ boolean_t is_error_scrub = B_FALSE ;
7167+ boolean_t is_pause = B_FALSE ;
7168+ boolean_t is_stop = B_FALSE ;
7169+
71657170 /* check options */
7166- while ((c = getopt (argc , argv , "spw " )) != -1 ) {
7171+ while ((c = getopt (argc , argv , "spwe " )) != -1 ) {
71677172 switch (c ) {
7173+ case 'e' :
7174+ is_error_scrub = B_TRUE ;
7175+ break ;
71687176 case 's' :
7169- cb . cb_type = POOL_SCAN_NONE ;
7177+ is_stop = B_TRUE ;
71707178 break ;
71717179 case 'p' :
7172- cb . cb_scrub_cmd = POOL_SCRUB_PAUSE ;
7180+ is_pause = B_TRUE ;
71737181 break ;
71747182 case 'w' :
71757183 wait = B_TRUE ;
@@ -7181,11 +7189,27 @@ zpool_do_scrub(int argc, char **argv)
71817189 }
71827190 }
71837191
7184- if (cb .cb_type == POOL_SCAN_NONE &&
7185- cb .cb_scrub_cmd == POOL_SCRUB_PAUSE ) {
7186- (void ) fprintf (stderr , gettext ("invalid option combination: "
7187- "-s and -p are mutually exclusive\n" ));
7192+ if (is_pause && is_stop ) {
7193+ (void ) fprintf (stderr , gettext ("invalid option "
7194+ "combination :-s and -p are mutually exclusive\n" ));
71887195 usage (B_FALSE );
7196+ } else {
7197+ if (is_error_scrub ) {
7198+ cb .cb_type = POOL_ERRORSCRUB ;
7199+ if (is_pause ) {
7200+ cb .cb_scrub_cmd = POOL_SCRUB_PAUSE ;
7201+ } else if (is_stop ) {
7202+ cb .cb_scrub_cmd = POOL_ERRORSCRUB_STOP ;
7203+ } else {
7204+ cb .cb_scrub_cmd = POOL_SCRUB_NORMAL ;
7205+ }
7206+ } else {
7207+ if (is_pause ) {
7208+ cb .cb_scrub_cmd = POOL_SCRUB_PAUSE ;
7209+ } else if (is_stop ) {
7210+ cb .cb_type = POOL_SCAN_NONE ;
7211+ }
7212+ }
71897213 }
71907214
71917215 if (wait && (cb .cb_type == POOL_SCAN_NONE ||
@@ -7408,6 +7432,70 @@ secs_to_dhms(uint64_t total, char *buf)
74087432 }
74097433}
74107434
7435+ /*
7436+ * Print out detailed error scrub status.
7437+ */
7438+ static void
7439+ print_err_scrub_status (pool_scan_stat_t * ps )
7440+ {
7441+ time_t start , end , pause ;
7442+ uint64_t total_secs_left ;
7443+ uint64_t secs_left , mins_left , hours_left , days_left ;
7444+ uint64_t examined , to_be_examined ;
7445+
7446+ if (ps == NULL || ps -> pss_error_scrub_func != POOL_ERRORSCRUB ) {
7447+ return ;
7448+ }
7449+
7450+ (void ) printf (gettext (" scrub: " ));
7451+
7452+ start = ps -> pss_error_scrub_start ;
7453+ end = ps -> pss_error_scrub_end ;
7454+ pause = ps -> pss_pass_error_scrub_pause ;
7455+ examined = ps -> pss_error_scrub_examined ;
7456+ to_be_examined = ps -> pss_error_scrub_to_be_examined ;
7457+
7458+ assert (ps -> pss_error_scrub_func == POOL_ERRORSCRUB );
7459+
7460+ if (ps -> pss_error_scrub_state == DSS_FINISHED ) {
7461+ total_secs_left = end - start ;
7462+ days_left = total_secs_left / 60 / 60 / 24 ;
7463+ hours_left = (total_secs_left / 60 / 60 ) % 24 ;
7464+ mins_left = (total_secs_left / 60 ) % 60 ;
7465+ secs_left = (total_secs_left % 60 );
7466+
7467+ (void ) printf (gettext ("scrubbed %llu error blocks in %llu days "
7468+ "%02llu:%02llu:%02llu on %s" ), (u_longlong_t )examined ,
7469+ (u_longlong_t )days_left , (u_longlong_t )hours_left ,
7470+ (u_longlong_t )mins_left , (u_longlong_t )secs_left ,
7471+ ctime (& end ));
7472+
7473+ return ;
7474+ } else if (ps -> pss_error_scrub_state == DSS_CANCELED ) {
7475+ (void ) printf (gettext ("error scrub canceled on %s" ),
7476+ ctime (& end ));
7477+ return ;
7478+ }
7479+ assert (ps -> pss_error_scrub_state == DSS_ERRORSCRUBBING );
7480+
7481+ /* Error scrub is in progress. */
7482+ if (pause == 0 ) {
7483+ (void ) printf (gettext ("error scrub in progress since %s" ),
7484+ ctime (& start ));
7485+ } else {
7486+ (void ) printf (gettext ("error scrub paused since %s" ),
7487+ ctime (& pause ));
7488+ (void ) printf (gettext ("\terror scrub started on %s" ),
7489+ ctime (& start ));
7490+ }
7491+
7492+ double fraction_done = (double )examined / (to_be_examined + examined );
7493+ (void ) printf (gettext ("\t%.2f%% done, issued I/O for %llu error"
7494+ " blocks" ), 100 * fraction_done , (u_longlong_t )examined );
7495+
7496+ (void ) printf ("\n" );
7497+ }
7498+
74117499/*
74127500 * Print out detailed scrub status.
74137501 */
@@ -7733,6 +7821,7 @@ print_scan_status(zpool_handle_t *zhp, nvlist_t *nvroot)
77337821{
77347822 uint64_t rebuild_end_time = 0 , resilver_end_time = 0 ;
77357823 boolean_t have_resilver = B_FALSE , have_scrub = B_FALSE ;
7824+ boolean_t have_errorscrub = B_FALSE ;
77367825 boolean_t active_resilver = B_FALSE ;
77377826 pool_checkpoint_stat_t * pcs = NULL ;
77387827 pool_scan_stat_t * ps = NULL ;
@@ -7747,6 +7836,7 @@ print_scan_status(zpool_handle_t *zhp, nvlist_t *nvroot)
77477836
77487837 have_resilver = (ps -> pss_func == POOL_SCAN_RESILVER );
77497838 have_scrub = (ps -> pss_func == POOL_SCAN_SCRUB );
7839+ have_errorscrub = (ps -> pss_error_scrub_func == POOL_ERRORSCRUB );
77507840 }
77517841
77527842 boolean_t active_rebuild = check_rebuilding (nvroot , & rebuild_end_time );
@@ -7755,6 +7845,8 @@ print_scan_status(zpool_handle_t *zhp, nvlist_t *nvroot)
77557845 /* Always print the scrub status when available. */
77567846 if (have_scrub )
77577847 print_scan_scrub_resilver_status (ps );
7848+ if (have_errorscrub )
7849+ print_err_scrub_status (ps );
77587850
77597851 /*
77607852 * When there is an active resilver or rebuild print its status.
@@ -8463,6 +8555,7 @@ status_callback(zpool_handle_t *zhp, void *data)
84638555
84648556 (void ) nvlist_lookup_uint64_array (nvroot ,
84658557 ZPOOL_CONFIG_REMOVAL_STATS , (uint64_t * * )& prs , & c );
8558+
84668559 print_removal_status (zhp , prs );
84678560
84688561 (void ) nvlist_lookup_uint64_array (nvroot ,
0 commit comments