btrfs-progs: scrub limit: add option to apply the limit to all devices

Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
David Sterba 2023-12-09 01:24:47 +01:00
parent 30d1a2d390
commit eaa54973b6
3 changed files with 58 additions and 2 deletions

View File

@ -35,6 +35,8 @@ limit [options] <path>
-l|--limit SIZE
set the limit of the device to SIZE (size units with suffix),
or 0 to reset to *unlimited*
-a|--all
apply the limit to all devices
--raw
print all numbers raw values in bytes without the *B* suffix

View File

@ -1984,6 +1984,7 @@ static const char * const cmd_scrub_limit_usage[] = {
"btrfs scrub limit [options] <path>",
"Show or set scrub limits on devices of the given filesystem.",
"",
OPTLINE("-a|--all", "apply the limit to all devices"),
OPTLINE("-d|--devid DEVID", "select the device by DEVID to apply the limit"),
OPTLINE("-l|--limit SIZE", "set the limit of the device to SIZE (size units with suffix), or 0 to reset to unlimited"),
HELPINFO_UNITS_LONG,
@ -2003,6 +2004,7 @@ static int cmd_scrub_limit(const struct cmd_struct *cmd, int argc, char **argv)
bool devid_set = false;
u64 opt_limit = 0;
bool limit_set = false;
bool all_set = false;
unit_mode = get_unit_mode_from_arg(&argc, argv, 0);
@ -2010,16 +2012,20 @@ static int cmd_scrub_limit(const struct cmd_struct *cmd, int argc, char **argv)
while (1) {
int c;
static const struct option long_options[] = {
{ "all", no_argument, NULL, 'a' },
{ "devid", required_argument, NULL, 'd' },
{ "limit", required_argument, NULL, 'l' },
{ NULL, 0, NULL, 0 }
};
c = getopt_long(argc, argv, "d:l:", long_options, NULL);
c = getopt_long(argc, argv, "ad:l:", long_options, NULL);
if (c < 0)
break;
switch (c) {
case 'a':
all_set = true;
break;
case 'd':
opt_devid = arg_strtou64(optarg);
devid_set = true;
@ -2035,10 +2041,23 @@ static int cmd_scrub_limit(const struct cmd_struct *cmd, int argc, char **argv)
if (check_argc_exact(argc - optind, 1))
return 1;
if ((devid_set && !limit_set) || (!devid_set && limit_set)) {
if (devid_set && all_set) {
error("--all and --devid cannot be used at the same time");
return 1;
}
if (devid_set && !limit_set) {
error("--devid and --limit must be set together");
return 1;
}
if (all_set && !limit_set) {
error("--all and --limit must be set together");
return 1;
}
if (!all_set && !devid_set && limit_set) {
error("--limit must be used with either --all or --deivd");
return 1;
}
fd = open_file_or_dir(argv[optind], &dirstream);
if (fd < 0)
@ -2086,6 +2105,37 @@ static int cmd_scrub_limit(const struct cmd_struct *cmd, int argc, char **argv)
goto out;
}
if (all_set && limit_set) {
/* Set on all devices. */
for (u64 devid = 1; devid <= fi_args.max_id; devid++) {
u64 limit;
struct btrfs_ioctl_dev_info_args di_args = { 0 };
ret = device_get_info(fd, devid, &di_args);
if (ret == -ENODEV) {
continue;
} else if (ret < 0) {
errno = -ret;
error("cannot read devid %llu info: %m", devid);
goto out;
}
limit = read_scrub_device_limit(fd, di_args.devid);
pr_verbose(LOG_DEFAULT, "Set scrub limit of devid %llu from %s%s to %s%s\n",
devid,
limit > 0 ? pretty_size_mode(limit, unit_mode) : "unlimited",
limit > 0 ? "/s" : "",
opt_limit > 0 ? pretty_size_mode(opt_limit, unit_mode) : "unlimited",
opt_limit > 0 ? "/s" : "");
ret = write_scrub_device_limit(fd, devid, opt_limit);
if (ret < 0) {
error("cannot write to the sysfs file of devid %llu: %m", devid);
goto out;
}
}
ret = 0;
goto out;
}
cols = 3;
table = table_create(cols, 2 + fi_args.num_devices);
if (!table) {

View File

@ -43,6 +43,10 @@ done
cd "$here"
run_check "$TOP/btrfs" scrub limit "$TEST_MNT"
# Set limits for all devices
run_check $SUDO_HELPER "$TOP/btrfs" scrub limit -a -l 30m "$TEST_MNT"
run_check "$TOP/btrfs" scrub limit "$TEST_MNT"
run_check_umount_test_dev
cleanup_loopdevs