All of lore.kernel.org
 help / color / mirror / Atom feed
From: Qu Wenruo <wqu@suse.com>
To: linux-btrfs@vger.kernel.org
Subject: [PATCH v2 2/2] btrfs-progs: cmds/filesystem: add --usage-ratio and --wasted-bytes for defrag
Date: Tue, 12 Mar 2024 14:27:31 +1030	[thread overview]
Message-ID: <90994d9b0f0453baf45256e2c2d3290041537fc7.1710214834.git.wqu@suse.com> (raw)
In-Reply-To: <cover.1710214834.git.wqu@suse.com>

This allows defrag subcommand to accept new "--usage-ratio" and
"--wasted-bytes" options.

These two options allows defrag to handle extents which have no adjacent
mergable extents but has low usage ratio or high wasted bytes against
its on-disk extent.

The default behavior is, defrag would go with 5% as the usage_ratio
and 16M as the wasted bytes on the first try.

If the kernel doesn't support it, then retry without the fine tunning
flags.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 Documentation/btrfs-filesystem.rst | 21 ++++++++++++
 cmds/filesystem.c                  | 53 ++++++++++++++++++++++++++++--
 2 files changed, 71 insertions(+), 3 deletions(-)

diff --git a/Documentation/btrfs-filesystem.rst b/Documentation/btrfs-filesystem.rst
index 83207a5a263e..213be6ff4a14 100644
--- a/Documentation/btrfs-filesystem.rst
+++ b/Documentation/btrfs-filesystem.rst
@@ -144,6 +144,27 @@ defragment [options] <file>|<dir> [<file>|<dir>...]
                 The range is default (the whole file) or given by *-s* and *-l*, split into
                 the steps or done in one go if the step is larger. Minimum range size is 256KiB.
 
+	--usage-ratio <ratio>
+		If a file extent which is not a defrag target (e.g. no mergeable
+		adjacent extent), but has a usage ratio lower than (ratio / 100)
+		of the on-disk extent size, it would also be defraged
+		for its potential to free up the on-disk extent.
+
+		Valid values are in the range [0, 100].
+
+	--wasted-bytes <bytes>[kKmMgGgtTpPeE]
+		If a file extent which is not a defrag target (e.g. no mergeable
+		adjacent extent), but has more "wasted" bytes (the difference
+		between the file extent and the on-disk extent size) than this
+		value, it would also be defragged for its potential to free up
+		on-disk extent.
+
+		Valid values are in the range [0, U32_MAX], but any value larger than 128K
+		would make no sense for compressed file extents, and any value larger than
+		128M would make no sense for regular file extents.
+		As the largest file extent supported is 128K for compressed extent and 128M
+		otherwise, thus it's impossible to free up more bytes than those limits.
+
         -v
                 (deprecated) alias for global *-v* option
 
diff --git a/cmds/filesystem.c b/cmds/filesystem.c
index c9930a02d879..9cc224454e4c 100644
--- a/cmds/filesystem.c
+++ b/cmds/filesystem.c
@@ -914,6 +914,8 @@ static const char * const cmd_filesystem_defrag_usage[] = {
 	OPTLINE("-l len", "defragment only up to len bytes"),
 	OPTLINE("-t size", "target extent size hint (default: 32M)"),
 	OPTLINE("--step SIZE", "process the range in given steps, flush after each one"),
+	OPTLINE("--usage-ratio RATIO", "defrag extents with utilization ratio lower than RATIO%"),
+	OPTLINE("--wasted-bytes SIZE", "defrag extents which can free up more bytes than SIZE"),
 	OPTLINE("-v", "deprecated, alias for global -v option"),
 	HELPINFO_INSERT_GLOBALS,
 	HELPINFO_INSERT_VERBOSE,
@@ -929,13 +931,32 @@ static struct btrfs_ioctl_defrag_range_args defrag_global_range;
 static int defrag_global_errors;
 static u64 defrag_global_step;
 
+static int defrag_ioctl(int fd, struct btrfs_ioctl_defrag_range_args *range)
+{
+	int ret = 0;
+
+	ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, range);
+	if (ret < 0 && ((errno == EOPNOTSUPP) | (errno == ENOTTY)) &&
+	    range->flags & (BTRFS_DEFRAG_RANGE_USAGE_RATIO |
+			    BTRFS_DEFRAG_RANGE_WASTED_BYTES)) {
+		/*
+		 * Older kernel, no ratio/wasted bytes fine-tunning support.
+		 * Retry with ratio/wasted bytes fine-tunning disabled.
+		 */
+		range->flags &= ~(BTRFS_DEFRAG_RANGE_USAGE_RATIO |
+				  BTRFS_DEFRAG_RANGE_WASTED_BYTES);
+		ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, range);
+	}
+	return ret;
+}
+
 static int defrag_range_in_steps(int fd, const struct stat *st) {
 	int ret = 0;
 	u64 end;
 	struct btrfs_ioctl_defrag_range_args range;
 
 	if (defrag_global_step == 0)
-		return ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &defrag_global_range);
+		return defrag_ioctl(fd, &defrag_global_range);
 
 	/*
 	 * If start is set but length is not within or beyond the u64 range,
@@ -946,13 +967,17 @@ static int defrag_range_in_steps(int fd, const struct stat *st) {
 
 	range = defrag_global_range;
 	range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
+	range.flags |= (BTRFS_DEFRAG_RANGE_USAGE_RATIO |
+			BTRFS_DEFRAG_RANGE_WASTED_BYTES);
+	range.usage_ratio = defrag_global_range.usage_ratio;
+	range.wasted_bytes = defrag_global_range.wasted_bytes;
 	while (range.start < end) {
 		u64 start;
 
 		range.len = defrag_global_step;
 		pr_verbose(LOG_VERBOSE, "defrag range step: start=%llu len=%llu step=%llu\n",
 			   range.start, range.len, defrag_global_step);
-		ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &range);
+		ret = defrag_ioctl(fd, &range);
 		if (ret < 0)
 			return ret;
 		if (check_add_overflow(range.start, defrag_global_step, &start))
@@ -1013,6 +1038,8 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
 	bool recursive = false;
 	int ret = 0;
 	int compress_type = BTRFS_COMPRESS_NONE;
+	u32 usage_ratio = 5;
+	u32 wasted_bytes = SZ_16M;
 
 	/*
 	 * Kernel 4.19+ supports defragmention of files open read-only,
@@ -1046,9 +1073,14 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
 	defrag_global_errors = 0;
 	optind = 0;
 	while(1) {
-		enum { GETOPT_VAL_STEP = GETOPT_VAL_FIRST };
+		enum { GETOPT_VAL_STEP = GETOPT_VAL_FIRST,
+		       GETOPT_VAL_USAGE_RATIO, GETOPT_VAL_WASTED_BYTES };
 		static const struct option long_options[] = {
 			{ "step", required_argument, NULL, GETOPT_VAL_STEP },
+			{ "usage-ratio", required_argument, NULL,
+				GETOPT_VAL_USAGE_RATIO },
+			{ "wasted-bytes", required_argument, NULL,
+				GETOPT_VAL_WASTED_BYTES },
 			{ NULL, 0, NULL, 0 }
 		};
 		int c;
@@ -1098,6 +1130,17 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
 				defrag_global_step = SZ_256K;
 			}
 			break;
+		case GETOPT_VAL_USAGE_RATIO:
+			usage_ratio = arg_strtou64(optarg);
+			if (usage_ratio > 100) {
+				error("invalid ratio, has %u expect [0, 100]",
+					usage_ratio);
+				exit(1);
+			}
+			break;
+		case GETOPT_VAL_WASTED_BYTES:
+			wasted_bytes = arg_strtou64_with_suffix(optarg);
+			break;
 		default:
 			usage_unknown_option(cmd, argv);
 		}
@@ -1116,6 +1159,10 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
 	}
 	if (flush)
 		defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
+	defrag_global_range.usage_ratio = usage_ratio;
+	defrag_global_range.wasted_bytes = wasted_bytes;
+	defrag_global_range.flags |= (BTRFS_DEFRAG_RANGE_USAGE_RATIO |
+				      BTRFS_DEFRAG_RANGE_WASTED_BYTES);
 
 	/*
 	 * Look for directory arguments and warn if the recursive mode is not
-- 
2.44.0


      parent reply	other threads:[~2024-03-12  3:57 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-12  3:57 [PATCH v2 0/2] btrfs-progs: cmds/filesystem: add --usage-ratio and --wasted-bytes options Qu Wenruo
2024-03-12  3:57 ` [PATCH v2 1/2] btrfs-progs: defrag: sync the usage ratio/wasted bytes fine-tunning from kernel Qu Wenruo
2024-03-12  3:57 ` Qu Wenruo [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=90994d9b0f0453baf45256e2c2d3290041537fc7.1710214834.git.wqu@suse.com \
    --to=wqu@suse.com \
    --cc=linux-btrfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.