btrfs-progs: scrub limit: allow to set the limit
Add new options to set the per-device limit (requires root privileges as it writes to the sysfs files). Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
87dba20daf
commit
30d1a2d390
|
@ -26,10 +26,16 @@ cancel <path>|<device>
|
|||
.. _man-scrub-limit:
|
||||
|
||||
limit [options] <path>
|
||||
Show scrub limits set on devices of the given filesystem.
|
||||
Show or set scrub limits on devices of the given filesystem.
|
||||
|
||||
``Options``
|
||||
|
||||
-d|--devid DEVID
|
||||
select the device by DEVID to apply the limit
|
||||
-l|--limit SIZE
|
||||
set the limit of the device to SIZE (size units with suffix),
|
||||
or 0 to reset to *unlimited*
|
||||
|
||||
--raw
|
||||
print all numbers raw values in bytes without the *B* suffix
|
||||
--human-readable
|
||||
|
|
65
cmds/scrub.c
65
cmds/scrub.c
|
@ -50,6 +50,7 @@
|
|||
#include "common/open-utils.h"
|
||||
#include "common/units.h"
|
||||
#include "common/device-utils.h"
|
||||
#include "common/parse-utils.h"
|
||||
#include "common/sysfs-utils.h"
|
||||
#include "common/string-table.h"
|
||||
#include "common/string-utils.h"
|
||||
|
@ -1212,6 +1213,17 @@ static u64 read_scrub_device_limit(int fd, u64 devid)
|
|||
return limit;
|
||||
}
|
||||
|
||||
static u64 write_scrub_device_limit(int fd, u64 devid, u64 limit)
|
||||
{
|
||||
char path[PATH_MAX] = { 0 };
|
||||
int ret;
|
||||
|
||||
/* /sys/fs/btrfs/FSID/devinfo/1/scrub_speed_max */
|
||||
snprintf(path, sizeof(path), "devinfo/%llu/scrub_speed_max", devid);
|
||||
ret = sysfs_write_fsid_file_u64(fd, path, limit);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scrub_start(const struct cmd_struct *cmd, int argc, char **argv,
|
||||
bool resume)
|
||||
{
|
||||
|
@ -1970,8 +1982,10 @@ static DEFINE_SIMPLE_COMMAND(scrub_status, "status");
|
|||
|
||||
static const char * const cmd_scrub_limit_usage[] = {
|
||||
"btrfs scrub limit [options] <path>",
|
||||
"Show scrub limits set on devices of the given filesystem.",
|
||||
"Show or set scrub limits on devices of the given filesystem.",
|
||||
"",
|
||||
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,
|
||||
NULL
|
||||
};
|
||||
|
@ -1985,6 +1999,10 @@ static int cmd_scrub_limit(const struct cmd_struct *cmd, int argc, char **argv)
|
|||
int fd = -1;
|
||||
DIR *dirstream = NULL;
|
||||
int cols, idx;
|
||||
u64 opt_devid = 0;
|
||||
bool devid_set = false;
|
||||
u64 opt_limit = 0;
|
||||
bool limit_set = false;
|
||||
|
||||
unit_mode = get_unit_mode_from_arg(&argc, argv, 0);
|
||||
|
||||
|
@ -1992,14 +2010,24 @@ static int cmd_scrub_limit(const struct cmd_struct *cmd, int argc, char **argv)
|
|||
while (1) {
|
||||
int c;
|
||||
static const struct option long_options[] = {
|
||||
{ "devid", required_argument, NULL, 'd' },
|
||||
{ "limit", required_argument, NULL, 'l' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, "", long_options, NULL);
|
||||
c = getopt_long(argc, argv, "d:l:", long_options, NULL);
|
||||
if (c < 0)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'd':
|
||||
opt_devid = arg_strtou64(optarg);
|
||||
devid_set = true;
|
||||
break;
|
||||
case 'l':
|
||||
opt_limit = parse_size_from_string(optarg);
|
||||
limit_set = true;
|
||||
break;
|
||||
default:
|
||||
usage_unknown_option(cmd, argv);
|
||||
}
|
||||
|
@ -2007,6 +2035,11 @@ 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)) {
|
||||
error("--devid and --limit must be set together");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fd = open_file_or_dir(argv[optind], &dirstream);
|
||||
if (fd < 0)
|
||||
return 1;
|
||||
|
@ -2025,6 +2058,34 @@ static int cmd_scrub_limit(const struct cmd_struct *cmd, int argc, char **argv)
|
|||
uuid_unparse(fi_args.fsid, fsid);
|
||||
pr_verbose(LOG_DEFAULT, "UUID: %s\n", fsid);
|
||||
|
||||
if (devid_set) {
|
||||
/* Set one device only. */
|
||||
struct btrfs_ioctl_dev_info_args di_args = { 0 };
|
||||
u64 limit;
|
||||
|
||||
ret = device_get_info(fd, opt_devid, &di_args);
|
||||
if (ret == -ENODEV) {
|
||||
error("device with devid %llu not found", opt_devid);
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
limit = read_scrub_device_limit(fd, opt_devid);
|
||||
pr_verbose(LOG_DEFAULT, "Set scrub limit of devid %llu from %s%s to %s%s\n",
|
||||
opt_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, opt_devid, opt_limit);
|
||||
if (ret < 0) {
|
||||
errno = -ret;
|
||||
error("cannot write to the sysfs file: %m");
|
||||
ret = 1;
|
||||
}
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cols = 3;
|
||||
table = table_create(cols, 2 + fi_args.num_devices);
|
||||
if (!table) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/bash
|
||||
# Read scrub limits on a filesystem
|
||||
# Read and set scrub limits on a filesystem
|
||||
|
||||
source "$TEST_TOP/common" || exit
|
||||
|
||||
|
@ -7,15 +7,19 @@ setup_root_helper
|
|||
setup_loopdevs 4
|
||||
prepare_loopdevs
|
||||
TEST_DEV=${loopdevs[1]}
|
||||
support=true
|
||||
|
||||
fsid="13411a59-ccea-4296-a6f8-1446ccf8c9be"
|
||||
sysfs="/sys/fs/btrfs/13411a59-ccea-4296-a6f8-1446ccf8c9be"
|
||||
|
||||
run_check $SUDO_HELPER "$TOP/mkfs.btrfs" -f --uuid "$fsid" -d raid1 -m raid1 "${loopdevs[@]}"
|
||||
run_check_mount_test_dev
|
||||
|
||||
# Set the limits directly
|
||||
for i in "$sysfs"/devinfo/*/scrub_speed_max; do
|
||||
if ! [ -f "$i" ]; then
|
||||
_log "sysfs file scrub_speed_max not available, skip setting limits"
|
||||
support=false
|
||||
break;
|
||||
fi
|
||||
run_check cat "$i"
|
||||
|
@ -23,6 +27,22 @@ for i in "$sysfs"/devinfo/*/scrub_speed_max; do
|
|||
done
|
||||
# This works even if scrub_speed_max files don't exist, this is equivalent to unlimited
|
||||
run_check "$TOP/btrfs" scrub limit "$TEST_MNT"
|
||||
|
||||
# The rest of the test would fail
|
||||
if ! $support; then
|
||||
run_check_umount_test_dev
|
||||
cleanup_loopdevs
|
||||
fi
|
||||
|
||||
# Set the limits by command
|
||||
here=`pwd`
|
||||
cd "$sysfs/devinfo"
|
||||
for i in *; do
|
||||
run_check $SUDO_HELPER "$TOP/btrfs" scrub limit -d "$i" -l 20m "$TEST_MNT"
|
||||
done
|
||||
cd "$here"
|
||||
run_check "$TOP/btrfs" scrub limit "$TEST_MNT"
|
||||
|
||||
run_check_umount_test_dev
|
||||
|
||||
cleanup_loopdevs
|
||||
|
|
Loading…
Reference in New Issue