diff mbox series

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

Message ID af7ddf3a70eac6363fa09bd8f26a44afdf34010d.1738657422.git.wqu@suse.com (mailing list archive)
State New
Headers show
Series btrfs-progs: scrub: add the new -t option to set the limit at runtime | expand

Commit Message

Qu Wenruo Feb. 4, 2025, 8:23 a.m. UTC
I know there is already `btrfs scrub limit` command to set the limit,
but a lot of users are not aware of that command.

Thus adding a new option `-t <throughput_limit>` to `btrfs scrub start`.

This has some extra behavior 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 reset the limit after scrub is finished

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

Issue: #943
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
RFC:
I'm not sure if this is really needed since we already have `btrfs scrub
limit`.
Involved tools like btrfs-maintenance scripts should have such support,
but to my surprise, David introduced the `btrfs scrub limit` but not
adding any support to btrfs-maintenance.
---
 Documentation/btrfs-scrub.rst |  9 ++++++++-
 cmds/scrub.c                  | 23 ++++++++++++++++++++++-
 2 files changed, 30 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/Documentation/btrfs-scrub.rst b/Documentation/btrfs-scrub.rst
index be106a551ade..de097bf79177 100644
--- a/Documentation/btrfs-scrub.rst
+++ b/Documentation/btrfs-scrub.rst
@@ -69,7 +69,7 @@  resume [-BdqrR] <path>|<device>
 
 .. _man-scrub-start:
 
-start [-BdrRf] <path>|<device>
+start [-BdrRft] <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
@@ -96,6 +96,13 @@  start [-BdrRf] <path>|<device>
                 can avoid writes from scrub.
         -R
                 raw print mode, print full data instead of summary
+	-t <throughput_limit>
+		set the scrub throughput limit for each device, acts the same as
+		``btrfs scrub limit -a -l <throughput_limit>``.
+
+		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 b2cdc924df97..bcdbac5fa40d 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,