Skip to content

Commit

Permalink
btrfs-progs: scrub: add the new --limit option to set the throughput …
Browse files Browse the repository at this point in the history
…limit at runtime

Add a new option `--limit <throughput_limit>` to `btrfs scrub start`.

This has some extra behavior differences compared to `btrfs scrub limit`:

- Only set the value for the involved scrub device(s)
  If it's a full fs scrub, it will be the same as
  `btrfs scrub limit -a -l <value>`.
  If it's a single device, it will bt the same as
  `btrfs scrub limit -d <devid> -l <value>`.

- Automatically revert to the old limit after scrub is finished

- It only needs one single command line to set the limit

Issue: #943
Signed-off-by: Qu Wenruo <[email protected]>
  • Loading branch information
adam900710 committed Feb 11, 2025
1 parent e162294 commit 1b28dd7
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 3 deletions.
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

0 comments on commit 1b28dd7

Please sign in to comment.