Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

btrfs-progs: scrub: add the new -t option to set the limit at runtime #947

Open
wants to merge 1 commit into
base: devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion Documentation/btrfs-scrub.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ resume [-BdqrR] <path>|<device>

.. _man-scrub-start:

start [-BdrRf] <path>|<device>
start [options] <path>|<device>
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
Expand All @@ -96,6 +96,17 @@ start [-BdrRf] <path>|<device>
can avoid writes from scrub.
-R
raw print mode, print full data instead of summary
--limit <limit>
set the scrub throughput limit for each device.

If the scrub is for the whole fs, it's the same as
:command:`btrfs scrub limit -a -l <value>`.
If the scrub is for a single device, it's the same as
:command:`btrfs scrub limit -d <devid> -l <value>`.

The value is bytes per second, and accepts the usual KMGT prefixes.
After the scrub is finished, the throughput limit will be reset to
the old value of each device.
-f
force starting new scrub even if a scrub is already running,
this can useful when scrub status file is damaged and reports a
Expand Down
34 changes: 32 additions & 2 deletions cmds/scrub.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ struct scrub_progress {
pthread_mutex_t progress_mutex;
int ioprio_class;
int ioprio_classdata;
u64 old_limit;
u64 limit;
};

Expand Down Expand Up @@ -1230,7 +1231,6 @@ static int scrub_start(const struct cmd_struct *cmd, int argc, char **argv,
int fdres = -1;
int ret;
pid_t pid;
int c;
int i;
int err = 0;
int e_uncorrectable = 0;
Expand Down Expand Up @@ -1265,11 +1265,22 @@ 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_limit = 0;
u64 devid;
bool force = false;
bool nothing_to_resume = false;

while ((c = getopt(argc, argv, "BdqrRc:n:f")) != -1) {
while (1) {
int c;
enum { GETOPT_VAL_LIMIT = GETOPT_VAL_FIRST };
static const struct option long_options[] = {
{"limit", required_argument, NULL, GETOPT_VAL_LIMIT},
{ NULL, 0, NULL, 0 }
};

c = getopt_long(argc, argv, "BdqrRc:n:f", long_options, NULL);
if (c < 0)
break;
switch (c) {
case 'B':
do_background = false;
Expand Down Expand Up @@ -1297,6 +1308,9 @@ static int scrub_start(const struct cmd_struct *cmd, int argc, char **argv,
case 'f':
force = true;
break;
case GETOPT_VAL_LIMIT:
throughput_limit = arg_strtou64_with_suffix(optarg);
break;
default:
usage_unknown_option(cmd, argv);
}
Expand Down Expand Up @@ -1389,6 +1403,13 @@ 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;
sp[i].old_limit = read_scrub_device_limit(fdmnt, devid);
ret = write_scrub_device_limit(fdmnt, devid, throughput_limit);
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;
Expand Down Expand Up @@ -1568,6 +1589,14 @@ static int scrub_start(const struct cmd_struct *cmd, int argc, char **argv,

err = 0;
for (i = 0; i < fi_args.num_devices; ++i) {
/* Revert to the older scrub limit. */
ret = write_scrub_device_limit(fdmnt, di_args[i].devid, sp[i].old_limit);
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;
Expand Down Expand Up @@ -1713,6 +1742,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("--limit", "set the throughput limit for each device"),
OPTLINE("-q", "deprecated, alias for global -q option"),
HELPINFO_INSERT_GLOBALS,
HELPINFO_INSERT_QUIET,
Expand Down