diff --git a/Documentation/btrfs-scrub.rst b/Documentation/btrfs-scrub.rst index be106a551..de097bf79 100644 --- a/Documentation/btrfs-scrub.rst +++ b/Documentation/btrfs-scrub.rst @@ -69,7 +69,7 @@ resume [-BdqrR] | .. _man-scrub-start: -start [-BdrRf] | +start [-BdrRft] | Start a scrub on all devices of the mounted filesystem identified by *path* or on a single *device*. If a scrub is already running, the new one will not start. A device of an unmounted filesystem cannot be @@ -96,6 +96,13 @@ start [-BdrRf] | can avoid writes from scrub. -R raw print mode, print full data instead of summary + -t + set the scrub throughput limit for each device, acts the same as + ``btrfs scrub limit -a -l ``. + + The value is bytes per second, and accept the usual KMGT prefixes. + After the scrub is finished, the throughput limit will be reset to + zero (aka, no limit). -f force starting new scrub even if a scrub is already running, this can useful when scrub status file is damaged and reports a diff --git a/cmds/scrub.c b/cmds/scrub.c index b2cdc924d..bcdbac5fa 100644 --- a/cmds/scrub.c +++ b/cmds/scrub.c @@ -1265,11 +1265,12 @@ static int scrub_start(const struct cmd_struct *cmd, int argc, char **argv, struct scrub_progress_cycle spc; pthread_mutex_t spc_write_mutex = PTHREAD_MUTEX_INITIALIZER; void *terr; + u64 throughput = 0; u64 devid; bool force = false; bool nothing_to_resume = false; - while ((c = getopt(argc, argv, "BdqrRc:n:f")) != -1) { + while ((c = getopt(argc, argv, "BdqrRc:n:ft")) != -1) { switch (c) { case 'B': do_background = false; @@ -1291,6 +1292,9 @@ static int scrub_start(const struct cmd_struct *cmd, int argc, char **argv, case 'c': ioprio_class = (int)strtol(optarg, NULL, 10); break; + case 't': + throughput = arg_strtou64_with_suffix(optarg); + break; case 'n': ioprio_classdata = (int)strtol(optarg, NULL, 10); break; @@ -1389,6 +1393,12 @@ static int scrub_start(const struct cmd_struct *cmd, int argc, char **argv, for (i = 0; i < fi_args.num_devices; ++i) { devid = di_args[i].devid; + ret = write_scrub_device_limit(fdmnt, devid, throughput); + if (ret < 0) { + errno = -ret; + warning("failed to set scrub throughput limit on devid %llu: %m", + devid); + } ret = pthread_mutex_init(&sp[i].progress_mutex, NULL); if (ret) { errno = ret; @@ -1568,6 +1578,16 @@ static int scrub_start(const struct cmd_struct *cmd, int argc, char **argv, err = 0; for (i = 0; i < fi_args.num_devices; ++i) { + /* We have set the limit, now reset it to 0. */ + if (throughput) { + ret = write_scrub_device_limit(fdmnt, di_args[i].devid, 0); + if (ret < 0) { + errno = -ret; + warning("failed to reset scrub throughput limit on devid %llu: %m", + di_args[i].devid); + } + } + if (sp[i].skip) continue; devid = di_args[i].devid; @@ -1713,6 +1733,7 @@ static const char * const cmd_scrub_start_usage[] = { OPTLINE("-c", "set ioprio class (see ionice(1) manpage)"), OPTLINE("-n", "set ioprio classdata (see ionice(1) manpage)"), OPTLINE("-f", "force starting new scrub even if a scrub is already running this is useful when scrub stats record file is damaged"), + OPTLINE("-t", "set the throughput limit for each device"), OPTLINE("-q", "deprecated, alias for global -q option"), HELPINFO_INSERT_GLOBALS, HELPINFO_INSERT_QUIET,