Skip to contentSkip to conversation

Btrfs-progs, balance filters: stripes, limits

PATCH Superseded David Sterba 1 participant 8 messages Oct 13, 2015

Subsystems (2)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore

David Sterba

author maintainer
#0 lore raw

cover Btrfs-progs, balance filters: stripes, limits

Here's the userspace part that enables the use of stripes and enhanced limit filters.

David Sterba (6):
btrfs-progs: cleanup and comment parse_range
btrfs-progs: extend parse_range API to accept a relaxed range
btrfs-progs: add helpers for parsing 32bit ranges
btrfs-progs: add helpers to print ranges
btrfs-progs: extend balance args to take min/max limit filter
btrfs-progs: balance: enhance the limit fiter with range

Gabríel Arthúr Pétursson (1):
btrfs-progs: balance: add stripes filter

 Documentation/btrfs-balance.asciidoc |   8 ++
 cmds-balance.c                       | 172 +++++++++++++++++++++++++++++------
 ioctl.h                              |  17 +++-
 volumes.h                            |   2 +
 4 files changed, 168 insertions(+), 31 deletions(-)
Signature · 1 line
2.6.1
author maintainer
#1 lore raw

PATCH 1/7 btrfs-progs: cleanup and comment parse_range

Simplify a check and unindent some code.

---
 cmds-balance.c | 63 ++++++++++++++++++++++++++++++++++------------------------
 1 file changed, 37 insertions(+), 26 deletions(-)
cmds-balance.c +37 -26
index 9af218bbfa51..798b533aa7d6 100644
@@ -88,43 +88,54 @@ static int parse_u64(const char *str, u64 *result)
 	return 0;
 }
 
+/*
+ * Parse range that's missing some part that can be implicit:
+ * a..b	- exact range, a can be equal to b
+ * a..	- implicitly unbounded maximum (end == (u64)-1)
+ * ..b	- implicitly starting at 0
+ * a	- invalid; unclear semantics, use parse_u64 instead
+ *
+ * Returned values are u64, value validation and interpretation should be done
+ * by the caller.
+ */
 static int parse_range(const char *range, u64 *start, u64 *end)
 {
 	char *dots;
+	const char *rest;
+	int skipped = 0;
 
 	dots = strstr(range, "..");
-	if (dots) {
-		const char *rest = dots + 2;
-		int skipped = 0;
-
-		*dots = 0;
+	if (!dots)
+		return 1;
 
-		if (!*rest) {
-			*end = (u64)-1;
-			skipped++;
-		} else {
-			if (parse_u64(rest, end))
-				return 1;
-		}
-		if (dots == range) {
-			*start = 0;
-			skipped++;
-		} else {
-			if (parse_u64(range, start))
-				return 1;
-		}
+	rest = dots + 2;
+	*dots = 0;
 
-		if (*start >= *end) {
-			fprintf(stderr, "Range %llu..%llu doesn't make "
-				"sense\n", (unsigned long long)*start,
-				(unsigned long long)*end);
+	if (!*rest) {
+		*end = (u64)-1;
+		skipped++;
+	} else {
+		if (parse_u64(rest, end))
 			return 1;
-		}
+	}
+	if (dots == range) {
+		*start = 0;
+		skipped++;
+	} else {
+		if (parse_u64(range, start))
+			return 1;
+	}
 
-		if (skipped <= 1)
-			return 0;
+	if (*start >= *end) {
+		fprintf(stderr, "Range %llu..%llu doesn't make "
+			"sense\n", (unsigned long long)*start,
+			(unsigned long long)*end);
+		return 1;
 	}
 
+	if (skipped <= 1)
+		return 0;
+
 	return 1;
 }
 
Signature · 1 line
2.6.1
author maintainer
#2 lore raw

PATCH 2/7 btrfs-progs: extend parse_range API to accept a relaxed range

In reply to David Sterba

In some cases we want to accept a range of type [a..a]. Add a new function to do the 'a < b' check for the caller and use it.

---
 cmds-balance.c | 30 +++++++++++++++++++++++++-----
 1 file changed, 25 insertions(+), 5 deletions(-)
cmds-balance.c +25 -5
index 798b533aa7d6..62bee3cc78b6 100644
@@ -126,9 +126,10 @@ static int parse_range(const char *range, u64 *start, u64 *end)
 			return 1;
 	}
 
-	if (*start >= *end) {
-		fprintf(stderr, "Range %llu..%llu doesn't make "
-			"sense\n", (unsigned long long)*start,
+	if (*start > *end) {
+		fprintf(stderr,
+			"ERROR: range %llu..%llu doesn't make sense\n",
+			(unsigned long long)*start,
 			(unsigned long long)*end);
 		return 1;
 	}
@@ -139,6 +140,25 @@ static int parse_range(const char *range, u64 *start, u64 *end)
 	return 1;
 }
 
+/*
+ * Parse range and check if start < end
+ */
+static int parse_range_strict(const char *range, u64 *start, u64 *end)
+{
+	if (parse_range(range, start, end) == 0) {
+		if (*start >= *end) {
+			fprintf(stderr,
+				"ERROR: range %llu..%llu not allowed\n",
+				(unsigned long long)*start,
+				(unsigned long long)*end);
+			return 1;
+		}
+		return 0;
+	}
+
+	return 1;
+}
+
 static int parse_filters(char *filters, struct btrfs_balance_args *args)
 {
 	char *this_char;
@@ -196,7 +216,7 @@ static int parse_filters(char *filters, struct btrfs_balance_args *args)
 				       "an argument\n");
 				return 1;
 			}
-			if (parse_range(value, &args->pstart, &args->pend)) {
+			if (parse_range_strict(value, &args->pstart, &args->pend)) {
 				fprintf(stderr, "Invalid drange argument\n");
 				return 1;
 			}
@@ -207,7 +227,7 @@ static int parse_filters(char *filters, struct btrfs_balance_args *args)
 				       "an argument\n");
 				return 1;
 			}
-			if (parse_range(value, &args->vstart, &args->vend)) {
+			if (parse_range_strict(value, &args->vstart, &args->vend)) {
 				fprintf(stderr, "Invalid vrange argument\n");
 				return 1;
 			}
Signature · 1 line
2.6.1
author maintainer
#3 lore raw

PATCH 3/7 btrfs-progs: add helpers for parsing 32bit ranges

In reply to David Sterba
---
 cmds-balance.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
cmds-balance.c +31 -0
index 62bee3cc78b6..72714b23b45c 100644
@@ -159,6 +159,37 @@ static int parse_range_strict(const char *range, u64 *start, u64 *end)
 	return 1;
 }
 
+/*
+ * Convert 64bit range to 32bit with boundary checkso
+ */
+static int range_to_u32(u64 start, u64 end, u32 *start32, u32 *end32)
+{
+	if (start > (u32)-1)
+		return 1;
+
+	if (end != (u64)-1 && end > (u32)-1)
+		return 1;
+
+	*start32 = (u32)start;
+	*end32 = (u32)end;
+
+	return 0;
+}
+
+static int parse_range_u32(const char *range, u32 *start, u32 *end)
+{
+	u64 tmp_start;
+	u64 tmp_end;
+
+	if (parse_range(range, &tmp_start, &tmp_end))
+		return 1;
+
+	if (range_to_u32(tmp_start, tmp_end, start, end))
+		return 1;
+
+	return 0;
+}
+
 static int parse_filters(char *filters, struct btrfs_balance_args *args)
 {
 	char *this_char;
Signature · 1 line
2.6.1
author maintainer
#4 lore raw

PATCH 4/7 btrfs-progs: add helpers to print ranges

In reply to David Sterba
---
 cmds-balance.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
cmds-balance.c +19 -0
index 72714b23b45c..dba6613b1540 100644
@@ -190,6 +190,25 @@ static int parse_range_u32(const char *range, u32 *start, u32 *end)
 	return 0;
 }
 
+__attribute__ ((unused))
+static void print_range(u64 start, u64 end)
+{
+	if (start)
+		printf("%llu", (unsigned long long)start);
+	printf("..");
+	if (end != (u64)-1)
+		printf("%llu", (unsigned long long)end);
+}
+
+static void print_range_u32(u32 start, u32 end)
+{
+	if (start)
+		printf("%u", start);
+	printf("..");
+	if (end != (u32)-1)
+		printf("%u", end);
+}
+
 static int parse_filters(char *filters, struct btrfs_balance_args *args)
 {
 	char *this_char;
Signature · 1 line
2.6.1
author maintainer
#5 lore raw

PATCH 5/7 btrfs-progs: extend balance args to take min/max limit filter

In reply to David Sterba

Add the overlapping limit and [limit_min, limit_max] members to the balance args. The min/max values are interpreted iff the corresponding flag BTRFS_BALANCE_ARGS_LIMITS is set.

Note that the values are only 32bit, but this should be enough for the foreseeable future.

---
 Documentation/btrfs-balance.asciidoc |  4 ++++
 cmds-balance.c                       |  4 ++++
 ioctl.h                              | 13 ++++++++++++-
 volumes.h                            |  1 +
 4 files changed, 21 insertions(+), 1 deletion(-)
Documentation/btrfs-balance.asciidoc +4 -0
index 6d2fd0c36086..61517461ca90 100644
@@ -109,6 +109,10 @@ parameters.
 Process only given number of chunks, after all filters apply. This can be used
 to specifically target a chunk in connection with other filters (drange,
 vrange) or just simply limit the amount of work done by a single balance run.
++
+The argument may be a single value or a range. The single value *N* means *at
+most N chunks*, equivalent to *..N* range syntax. Kernels prior to 4.4 accept
+only the single value format.
 
 *soft*::
 Takes no parameters. Only has meaning when converting between profiles.
cmds-balance.c +4 -0
index dba6613b1540..1eadba417abc 100644
@@ -343,6 +343,10 @@ static void dump_balance_args(struct btrfs_balance_args *args)
 		       (unsigned long long)args->vend);
 	if (args->flags & BTRFS_BALANCE_ARGS_LIMIT)
 		printf(", limit=%llu", (unsigned long long)args->limit);
+	if (args->flags & BTRFS_BALANCE_ARGS_LIMITS) {
+		printf(", limit=");
+		print_range_u32(args->limit_min, args->limit_max);
+	}
 
 	printf("\n");
 }
ioctl.h +12 -1
index dff015a52b43..ff7a1a0610a1 100644
@@ -227,7 +227,18 @@ struct btrfs_balance_args {
 
 	__u64 flags;
 
-	__u64 limit;		/* limit number of processed chunks */
+	/*
+	 * BTRFS_BALANCE_ARGS_LIMIT with value 'limit'
+	 * BTRFS_BALANCE_ARGS_LIMITS - the extend version can use minimum and
+	 * maximum
+	 */
+	union {
+		__u64 limit;		/* limit number of processed chunks */
+		struct {
+			__u32 limit_min;
+			__u32 limit_max;
+		};
+	};
 	__u64 unused[7];
 } __attribute__ ((__packed__));
 
volumes.h +1 -0
index 4ecb99314a0c..cb6f5752cdda 100644
@@ -136,6 +136,7 @@ struct map_lookup {
 #define BTRFS_BALANCE_ARGS_DRANGE	(1ULL << 3)
 #define BTRFS_BALANCE_ARGS_VRANGE	(1ULL << 4)
 #define BTRFS_BALANCE_ARGS_LIMIT	(1ULL << 5)
+#define BTRFS_BALANCE_ARGS_LIMITS	(1ULL << 6)
 
 /*
  * Profile changing flags.  When SOFT is set we won't relocate chunk if
Signature · 1 line
2.6.1
author maintainer
#6 lore raw

PATCH 6/7 btrfs-progs: balance: enhance the limit fiter with range

In reply to David Sterba

We can do more with the balance filer. Enhance it so we can specify also the minimum number of block groups to process. The 'limit' filter now accepts a range (a..b, can be partial) and needs kernel support.

The 'limit=value' filter is equivalent to 'limit=..value' but works on older kernels as well.

The min/max values are 32bit, unlike the single-value limit which is 64bit.

---
 cmds-balance.c | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)
cmds-balance.c +17 -5
index 1eadba417abc..7aaf33d03630 100644
@@ -301,12 +301,24 @@ static int parse_filters(char *filters, struct btrfs_balance_args *args)
 					"the limit filter requires an argument\n");
 				return 1;
 			}
-			if (parse_u64(value, &args->limit)) {
-				fprintf(stderr, "Invalid limit argument: %s\n",
-				       value);
-				return 1;
+			/*
+			 * Try to parse the range first. A single value is not
+			 * a valid range
+			 */
+			if (parse_range_u32(value, &args->limit_min,
+					    &args->limit_max) == 0) {
+				args->flags &= ~BTRFS_BALANCE_ARGS_LIMIT;
+				args->flags |= BTRFS_BALANCE_ARGS_LIMITS;
+			} else {
+				if (parse_u64(value, &args->limit)) {
+					fprintf(stderr,
+						"Invalid limit argument: %s\n",
+					       value);
+					return 1;
+				}
+				args->flags &= ~BTRFS_BALANCE_ARGS_LIMITS;
+				args->flags |= BTRFS_BALANCE_ARGS_LIMIT;
 			}
-			args->flags |= BTRFS_BALANCE_ARGS_LIMIT;
 		} else {
 			fprintf(stderr, "Unrecognized balance option '%s'\n",
 				this_char);
Signature · 1 line
2.6.1
author maintainer
#7 lore raw

PATCH 7/7 btrfs-progs: balance: add stripes filter

In reply to David Sterba

From: Gabríel Arthúr Pétursson <[email protected]>

Add new balance filter 'stripes=<range>' to process only chunks that are spread accross given number of chunks.

The range must be specified with both values, but they can be the same to denote exact number of stripes.

[ reworked a bit to use the range helpers, dropped the single value
for stripes ]

---
 Documentation/btrfs-balance.asciidoc |  4 ++++
 cmds-balance.c                       | 17 +++++++++++++++++
 ioctl.h                              |  4 +++-
 volumes.h                            |  1 +
 4 files changed, 25 insertions(+), 1 deletion(-)
Documentation/btrfs-balance.asciidoc +4 -0
index 61517461ca90..6bb9fffdf188 100644
@@ -114,6 +114,10 @@ The argument may be a single value or a range. The single value *N* means *at
 most N chunks*, equivalent to *..N* range syntax. Kernels prior to 4.4 accept
 only the single value format.
 
+*stripes*::
+Balances only block groups which have the given number of stripes. The
+parameter is a range specified as <start..end>.
+
 *soft*::
 Takes no parameters. Only has meaning when converting between profiles.
 When doing convert from one profile to another and soft mode is on,
cmds-balance.c +17 -0
index 7aaf33d03630..a958e584eeb5 100644
@@ -319,6 +319,19 @@ static int parse_filters(char *filters, struct btrfs_balance_args *args)
 				args->flags &= ~BTRFS_BALANCE_ARGS_LIMITS;
 				args->flags |= BTRFS_BALANCE_ARGS_LIMIT;
 			}
+			args->flags |= BTRFS_BALANCE_ARGS_LIMIT;
+		} else if (!strcmp(this_char, "stripes")) {
+			if (!value || !*value) {
+				fprintf(stderr,
+					"the stripes filter requires an argument\n");
+				return 1;
+			}
+			if (parse_range_u32(value, &args->stripes_min,
+					    &args->stripes_max)) {
+				fprintf(stderr, "Invalid stripes argument\n");
+				return 1;
+			}
+			args->flags |= BTRFS_BALANCE_ARGS_STRIPES;
 		} else {
 			fprintf(stderr, "Unrecognized balance option '%s'\n",
 				this_char);
@@ -359,6 +372,10 @@ static void dump_balance_args(struct btrfs_balance_args *args)
 		printf(", limit=");
 		print_range_u32(args->limit_min, args->limit_max);
 	}
+	if (args->flags & BTRFS_BALANCE_ARGS_STRIPES) {
+		printf(", stripes=");
+		print_range_u32(args->stripes_min, args->stripes_max);
+	}
 
 	printf("\n");
 }
ioctl.h +3 -1
index ff7a1a0610a1..50f9e1485a30 100644
@@ -239,7 +239,9 @@ struct btrfs_balance_args {
 			__u32 limit_max;
 		};
 	};
-	__u64 unused[7];
+	__u32 stripes_min;
+	__u32 stripes_max;
+	__u64 unused[6];
 } __attribute__ ((__packed__));
 
 /* report balance progress to userspace */
volumes.h +1 -0
index cb6f5752cdda..150ea7f31659 100644
@@ -137,6 +137,7 @@ struct map_lookup {
 #define BTRFS_BALANCE_ARGS_VRANGE	(1ULL << 4)
 #define BTRFS_BALANCE_ARGS_LIMIT	(1ULL << 5)
 #define BTRFS_BALANCE_ARGS_LIMITS	(1ULL << 6)
+#define BTRFS_BALANCE_ARGS_STRIPES	(1ULL << 7)
 
 /*
  * Profile changing flags.  When SOFT is set we won't relocate chunk if
Signature · 1 line
2.6.1