diff options
author | avg <avg@FreeBSD.org> | 2017-09-26 09:34:18 +0000 |
---|---|---|
committer | avg <avg@FreeBSD.org> | 2017-09-26 09:34:18 +0000 |
commit | b60520398f206195e21774c315afb59a0f6d7146 (patch) | |
tree | cd1f348c5d90819cdc0225e23d3466438421b2b4 /cddl/contrib/opensolaris/cmd | |
parent | 3b00a62a3635ddfd563366ae6b35d38adbf61dde (diff) | |
download | FreeBSD-src-b60520398f206195e21774c315afb59a0f6d7146.zip FreeBSD-src-b60520398f206195e21774c315afb59a0f6d7146.tar.gz |
MFC r323355: MFV r323107: 8414 Implemented zpool scrub pause/resume
illumos/illumos-gate@1702cce751c5cb7ead878d0205a6c90b027e3de8
https://github.com/illumos/illumos-gate/commit/1702cce751c5cb7ead878d0205a6c90b027e3de8
FreeBSD note: rather than merging the zpool.8 update I copied the zpool
scrub section from the illumos zpool.1m to FreeBSD zpool.8 almost
verbatim. Now that the illumos page uses the mdoc format, it was an
easier option. Perhaps the change is not in perfect compliance with the
FreeBSD style, but I think that it is acceptible.
https://www.illumos.org/issues/8414
This issue tracks the port of scrub pause from ZoL: https://github.com/zfsonlinux/zfs/pull/6167
Currently, there is no way to pause a scrub. Pausing may be useful when
the pool is busy with other I/O to preserve bandwidth.
Description
This patch adds the ability to pause and resume scrubbing. This is achieved
by maintaining a persistent on-disk scrub state. While the state is 'paused'
we do not scrub any more blocks. We do however perform regular scan
housekeeping such as freeing async destroyed and deadlist blocks while paused.
Motivation and Context
Scrub pausing can be an I/O intensive operation and people have been asking
for the ability to pause a scrub for a while. This allows one to preserve scrub
progress while freeing up bandwidth for other I/O.
Reviewed by: George Melikov <mail@gmelikov.ru>
Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed by: Brad Lewis <brad.lewis@delphix.com>
Reviewed by: Serapheim Dimitropoulos <serapheim@delphix.com>
Reviewed by: Matt Ahrens <mahrens@delphix.com>
Approved by: Dan McDonald <danmcd@joyent.com>
Author: Alek Pinchuk <apinchuk@datto.com>
Diffstat (limited to 'cddl/contrib/opensolaris/cmd')
-rw-r--r-- | cddl/contrib/opensolaris/cmd/zpool/zpool.8 | 76 | ||||
-rw-r--r-- | cddl/contrib/opensolaris/cmd/zpool/zpool_main.c | 61 |
2 files changed, 90 insertions, 47 deletions
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool.8 b/cddl/contrib/opensolaris/cmd/zpool/zpool.8 index c09448a..d021e25 100644 --- a/cddl/contrib/opensolaris/cmd/zpool/zpool.8 +++ b/cddl/contrib/opensolaris/cmd/zpool/zpool.8 @@ -19,14 +19,15 @@ .\" information: Portions Copyright [yyyy] [name of copyright owner] .\" .\" Copyright (c) 2010, Sun Microsystems, Inc. All Rights Reserved. -.\" Copyright 2011, Nexenta Systems, Inc. All Rights Reserved. .\" Copyright (c) 2011, Justin T. Gibbs <gibbs@FreeBSD.org> -.\" Copyright (c) 2013 by Delphix. All Rights Reserved. .\" Copyright (c) 2012, Glen Barber <gjb@FreeBSD.org> +.\" Copyright (c) 2013 by Delphix. All Rights Reserved. +.\" Copyright 2017 Nexenta Systems, Inc. +.\" Copyright (c) 2017 Datto Inc. .\" .\" $FreeBSD$ .\" -.Dd July 26, 2014 +.Dd September 08, 2017 .Dt ZPOOL 8 .Os .Sh NAME @@ -153,7 +154,7 @@ .Op Ar new_device .Nm .Cm scrub -.Op Fl s +.Op Fl s | Fl p .Ar pool ... .Nm .Cm set @@ -1543,43 +1544,54 @@ manner. .It Xo .Nm .Cm scrub -.Op Fl s +.Op Fl s | Fl p .Ar pool ... .Xc .Pp -Begins a scrub. The scrub examines all data in the specified pools to verify -that it checksums correctly. For replicated (mirror or -.No raidz ) -devices, -.Tn ZFS -automatically repairs any damage discovered during the scrub. The -.Qq Nm Cm status +Begins a scrub or resumes a paused scrub. +The scrub examines all data in the specified pools to verify that it checksums +correctly. +For replicated +.Pq mirror or raidz +devices, ZFS automatically repairs any damage discovered during the scrub. +The +.Nm zpool Cm status command reports the progress of the scrub and summarizes the results of the scrub upon completion. .Pp -Scrubbing and resilvering are very similar operations. The difference is that -resilvering only examines data that -.Tn ZFS -knows to be out of date (for example, when attaching a new device to a mirror -or replacing an existing device), whereas scrubbing examines all data to -discover silent errors due to hardware faults or disk failure. -.Pp -Because scrubbing and resilvering are -.Tn I/O Ns -intensive -operations, -.Tn ZFS -only allows one at a time. If a scrub is already in progress, the -.Qq Nm Cm scrub -command returns an error. To start a new scrub, you have to stop the old scrub -with the -.Qq Nm Cm scrub Fl s -command first. If a resilver is in progress, -.Tn ZFS -does not allow a scrub to be started until the resilver completes. -.Bl -tag -width indent +Scrubbing and resilvering are very similar operations. +The difference is that resilvering only examines data that ZFS knows to be out +of date +.Po +for example, when attaching a new device to a mirror or replacing an existing +device +.Pc , +whereas scrubbing examines all data to discover silent errors due to hardware +faults or disk failure. +.Pp +Because scrubbing and resilvering are I/O-intensive operations, ZFS only allows +one at a time. +If a scrub is paused, the +.Nm zpool Cm scrub +resumes it. +If a resilver is in progress, ZFS does not allow a scrub to be started until the +resilver completes. +.Bl -tag -width Ds .It Fl s Stop scrubbing. .El +.Bl -tag -width Ds +.It Fl p +Pause scrubbing. +Scrub pause state and progress are periodically synced to disk. +If the system is restarted or pool is exported during a paused scrub, +even after import, scrub will remain paused until it is resumed. +Once resumed the scrub will pick up from the place where it was last +checkpointed to disk. +To resume a paused scrub issue +.Nm zpool Cm scrub +again. +.El .It Xo .Nm .Cm set diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c index e2dc24c..572265f 100644 --- a/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c +++ b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c @@ -27,6 +27,7 @@ * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved. * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>. * Copyright 2016 Nexenta Systems, Inc. + * Copyright (c) 2017 Datto Inc. */ #include <solaris.h> @@ -252,7 +253,7 @@ get_usage(zpool_help_t idx) case HELP_REOPEN: return (gettext("\treopen <pool>\n")); case HELP_SCRUB: - return (gettext("\tscrub [-s] <pool> ...\n")); + return (gettext("\tscrub [-s | -p] <pool> ...\n")); case HELP_STATUS: return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " "[count]]\n")); @@ -3825,6 +3826,7 @@ typedef struct scrub_cbdata { int cb_type; int cb_argc; char **cb_argv; + pool_scrub_cmd_t cb_scrub_cmd; } scrub_cbdata_t; int @@ -3842,15 +3844,16 @@ scrub_callback(zpool_handle_t *zhp, void *data) return (1); } - err = zpool_scan(zhp, cb->cb_type); + err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd); return (err != 0); } /* - * zpool scrub [-s] <pool> ... + * zpool scrub [-s | -p] <pool> ... * * -s Stop. Stops any in-progress scrub. + * -p Pause. Pause in-progress scrub. */ int zpool_do_scrub(int argc, char **argv) @@ -3859,13 +3862,17 @@ zpool_do_scrub(int argc, char **argv) scrub_cbdata_t cb; cb.cb_type = POOL_SCAN_SCRUB; + cb.cb_scrub_cmd = POOL_SCRUB_NORMAL; /* check options */ - while ((c = getopt(argc, argv, "s")) != -1) { + while ((c = getopt(argc, argv, "sp")) != -1) { switch (c) { case 's': cb.cb_type = POOL_SCAN_NONE; break; + case 'p': + cb.cb_scrub_cmd = POOL_SCRUB_PAUSE; + break; case '?': (void) fprintf(stderr, gettext("invalid option '%c'\n"), optopt); @@ -3873,6 +3880,13 @@ zpool_do_scrub(int argc, char **argv) } } + if (cb.cb_type == POOL_SCAN_NONE && + cb.cb_scrub_cmd == POOL_SCRUB_PAUSE) { + (void) fprintf(stderr, gettext("invalid option combination: " + "-s and -p are mutually exclusive\n")); + usage(B_FALSE); + } + cb.cb_argc = argc; cb.cb_argv = argv; argc -= optind; @@ -3901,7 +3915,7 @@ typedef struct status_cbdata { void print_scan_status(pool_scan_stat_t *ps) { - time_t start, end; + time_t start, end, pause; uint64_t elapsed, mins_left, hours_left; uint64_t pass_exam, examined, total; uint_t rate; @@ -3919,6 +3933,7 @@ print_scan_status(pool_scan_stat_t *ps) start = ps->pss_start_time; end = ps->pss_end_time; + pause = ps->pss_pass_scrub_pause; zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); assert(ps->pss_func == POOL_SCAN_SCRUB || @@ -3961,8 +3976,17 @@ print_scan_status(pool_scan_stat_t *ps) * Scan is in progress. */ if (ps->pss_func == POOL_SCAN_SCRUB) { - (void) printf(gettext("scrub in progress since %s"), - ctime(&start)); + if (pause == 0) { + (void) printf(gettext("scrub in progress since %s"), + ctime(&start)); + } else { + char buf[32]; + struct tm *p = localtime(&pause); + (void) strftime(buf, sizeof (buf), "%a %b %e %T %Y", p); + (void) printf(gettext("scrub paused since %s\n"), buf); + (void) printf(gettext("\tscrub started on %s"), + ctime(&start)); + } } else if (ps->pss_func == POOL_SCAN_RESILVER) { (void) printf(gettext("resilver in progress since %s"), ctime(&start)); @@ -3974,6 +3998,7 @@ print_scan_status(pool_scan_stat_t *ps) /* elapsed time for this pass */ elapsed = time(NULL) - ps->pss_pass_start; + elapsed -= ps->pss_pass_scrub_spent_paused; elapsed = elapsed ? elapsed : 1; pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; rate = pass_exam / elapsed; @@ -3983,19 +4008,25 @@ print_scan_status(pool_scan_stat_t *ps) zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); zfs_nicenum(total, total_buf, sizeof (total_buf)); - zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); /* * do not print estimated time if hours_left is more than 30 days + * or we have a paused scrub */ - (void) printf(gettext(" %s scanned out of %s at %s/s"), - examined_buf, total_buf, rate_buf); - if (hours_left < (30 * 24)) { - (void) printf(gettext(", %lluh%um to go\n"), - (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); + if (pause == 0) { + zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); + (void) printf(gettext("\t%s scanned out of %s at %s/s"), + examined_buf, total_buf, rate_buf); + if (hours_left < (30 * 24)) { + (void) printf(gettext(", %lluh%um to go\n"), + (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); + } else { + (void) printf(gettext( + ", (scan is slow, no estimated time)\n")); + } } else { - (void) printf(gettext( - ", (scan is slow, no estimated time)\n")); + (void) printf(gettext("\t%s scanned out of %s\n"), + examined_buf, total_buf); } if (ps->pss_func == POOL_SCAN_RESILVER) { |