Skip to contentSkip to conversation

Btrfs-progs, balance filters: stripes, limits

PATCH New David Sterba 1 participant 9 messages Oct 16, 2015

Subsystems (2)
lore
Share & tools
lore

David Sterba

author maintainer
#0 lore raw

v2 cover Btrfs-progs, balance filters: stripes, limits

An updated version that actually works.

David Sterba (7):
btrfs-progs: cleanup and comment parse_range
btrfs-progs: do not modify the string in 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                       | 167 +++++++++++++++++++++++++++++------
 ioctl.h                              |  17 +++-
 volumes.h                            |   2 +
 4 files changed, 164 insertions(+), 30 deletions(-)
Signature · 1 line
2.6.1
author maintainer
#1 lore raw

PATCH v2 1/8 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 v2 2/8 btrfs-progs: do not modify the string in parse_range

In reply to David Sterba

It's passed as const but we modify it through 'dots'. This would break parsing the string multiple times.

---
 cmds-balance.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
cmds-balance.c +5 -3
index 798b533aa7d6..0a1bf0cd0699 100644
@@ -101,6 +101,7 @@ static int parse_u64(const char *str, u64 *result)
 static int parse_range(const char *range, u64 *start, u64 *end)
 {
 	char *dots;
+	char *endptr;
 	const char *rest;
 	int skipped = 0;
 
@@ -109,20 +110,21 @@ static int parse_range(const char *range, u64 *start, u64 *end)
 		return 1;
 
 	rest = dots + 2;
-	*dots = 0;
 
 	if (!*rest) {
 		*end = (u64)-1;
 		skipped++;
 	} else {
-		if (parse_u64(rest, end))
+		*end = strtoull(rest, &endptr, 10);
+		if (*endptr)
 			return 1;
 	}
 	if (dots == range) {
 		*start = 0;
 		skipped++;
 	} else {
-		if (parse_u64(range, start))
+		*end = strtoull(range, &endptr, 10);
+		if (*endptr != 0 && *endptr != '.')
 			return 1;
 	}
 
Signature · 1 line
2.6.1
author maintainer
#3 lore raw

PATCH v2 3/8 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 0a1bf0cd0699..1fd8d2018b7a 100644
@@ -128,9 +128,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;
 	}
@@ -141,6 +142,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;
@@ -198,7 +218,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;
 			}
@@ -209,7 +229,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
#4 lore raw

PATCH v2 4/8 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 1fd8d2018b7a..457d693eec42 100644
@@ -161,6 +161,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
#5 lore raw

PATCH v2 5/8 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 457d693eec42..3166d7a73ba2 100644
@@ -192,6 +192,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
#6 lore raw

PATCH v2 6/8 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 3166d7a73ba2..148039bdc503 100644
@@ -345,6 +345,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
#7 lore raw

PATCH v2 7/8 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 | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)
cmds-balance.c +12 -4
index 148039bdc503..05d48651b0b7 100644
@@ -304,11 +304,19 @@ static int parse_filters(char *filters, struct btrfs_balance_args *args)
 				return 1;
 			}
 			if (parse_u64(value, &args->limit)) {
-				fprintf(stderr, "Invalid limit argument: %s\n",
-				       value);
-				return 1;
+				if (parse_range_u32(value, &args->limit_min,
+							&args->limit_max)) {
+					fprintf(stderr,
+						"Invalid limit argument: %s\n",
+					       value);
+					return 1;
+				}
+				args->flags &= ~BTRFS_BALANCE_ARGS_LIMIT;
+				args->flags |= BTRFS_BALANCE_ARGS_LIMITS;
+			} else {
+				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
#8 lore raw

PATCH v2 8/8 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                       | 16 ++++++++++++++++
 ioctl.h                              |  4 +++-
 volumes.h                            |  1 +
 4 files changed, 24 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 +16 -0
index 05d48651b0b7..eca160677cd0 100644
@@ -317,6 +317,18 @@ static int parse_filters(char *filters, struct btrfs_balance_args *args)
 				args->flags &= ~BTRFS_BALANCE_ARGS_LIMITS;
 				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);
@@ -357,6 +369,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