* [PATCH 1/3] btrfs: extend balance filter limit to take minimum and maximum
2015-10-20 17:13 [PATCH 0/3 v3] Balance filters: stripes, enhanced limit and usage David Sterba
@ 2015-10-20 17:13 ` David Sterba
2015-10-20 17:13 ` [PATCH 2/3] btrfs: add balance filter for stripes David Sterba
2015-10-20 17:13 ` [PATCH 3/3] btrfs: extend balance filter usage to take minimum and maximum David Sterba
2 siblings, 0 replies; 6+ messages in thread
From: David Sterba @ 2015-10-20 17:13 UTC (permalink / raw)
To: linux-btrfs; +Cc: David Sterba
The 'limit' filter is underdesigned, it should have been a range for
[min,max], with some relaxed semantics when one of the bounds is
missing. Besides that, using a full u64 for a single value is a waste of
bytes.
Let's fix both by extending the use of the u64 bytes for the [min,max]
range. This can be done in a backward compatible way, the range will be
interpreted only if the appropriate flag is set
(BTRFS_BALANCE_ARGS_LIMIT_RANGE).
Signed-off-by: David Sterba <dsterba@suse.com>
---
fs/btrfs/ctree.h | 14 ++++++++++++--
fs/btrfs/volumes.c | 42 ++++++++++++++++++++++++++++++++++++++++++
fs/btrfs/volumes.h | 1 +
include/uapi/linux/btrfs.h | 13 ++++++++++++-
4 files changed, 67 insertions(+), 3 deletions(-)
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 938efe33be80..852c738d6954 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -846,8 +846,18 @@ struct btrfs_disk_balance_args {
/* BTRFS_BALANCE_ARGS_* */
__le64 flags;
- /* BTRFS_BALANCE_ARGS_LIMIT value */
- __le64 limit;
+ /*
+ * BTRFS_BALANCE_ARGS_LIMIT with value 'limit'
+ * BTRFS_BALANCE_ARGS_LIMIT_RANGE - the extend version can use minimum
+ * and maximum
+ */
+ union {
+ __le64 limit;
+ struct {
+ __le32 limit_min;
+ __le32 limit_max;
+ };
+ };
__le64 unused[7];
} __attribute__ ((__packed__));
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 6fc735869c18..b90a79c2bcf9 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3250,6 +3250,16 @@ static int should_balance_chunk(struct btrfs_root *root,
return 0;
else
bargs->limit--;
+ } else if ((bargs->flags & BTRFS_BALANCE_ARGS_LIMIT_RANGE)) {
+ /*
+ * Same logic as the 'limit' filter; the minimum cannot be
+ * determined here because we do not have the global informatoin
+ * about the count of all chunks that satisfy the filters.
+ */
+ if (bargs->limit_max == 0)
+ return 0;
+ else
+ bargs->limit_max--;
}
return 1;
@@ -3264,6 +3274,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
struct btrfs_device *device;
u64 old_size;
u64 size_to_free;
+ u64 chunk_type;
struct btrfs_chunk *chunk;
struct btrfs_path *path;
struct btrfs_key key;
@@ -3274,9 +3285,13 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
int ret;
int enospc_errors = 0;
bool counting = true;
+ /* The single value limit and min/max limits use the same bytes in the */
u64 limit_data = bctl->data.limit;
u64 limit_meta = bctl->meta.limit;
u64 limit_sys = bctl->sys.limit;
+ u32 count_data = 0;
+ u32 count_meta = 0;
+ u32 count_sys = 0;
/* step one make some room on all the devices */
devices = &fs_info->fs_devices->devices;
@@ -3317,6 +3332,10 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
spin_unlock(&fs_info->balance_lock);
again:
if (!counting) {
+ /*
+ * The single value limit and min/max limits use the same bytes
+ * in the
+ */
bctl->data.limit = limit_data;
bctl->meta.limit = limit_meta;
bctl->sys.limit = limit_sys;
@@ -3364,6 +3383,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
}
chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
+ chunk_type = btrfs_chunk_type(leaf, chunk);
if (!counting) {
spin_lock(&fs_info->balance_lock);
@@ -3384,6 +3404,28 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
spin_lock(&fs_info->balance_lock);
bctl->stat.expected++;
spin_unlock(&fs_info->balance_lock);
+
+ if (chunk_type & BTRFS_BLOCK_GROUP_DATA)
+ count_data++;
+ else if (chunk_type & BTRFS_BLOCK_GROUP_SYSTEM)
+ count_sys++;
+ else if (chunk_type & BTRFS_BLOCK_GROUP_METADATA)
+ count_meta++;
+
+ goto loop;
+ }
+
+ /*
+ * Apply limit_min filter, no need to check if the LIMITS
+ * filter is used, limit_min is 0 by default
+ */
+ if (((chunk_type & BTRFS_BLOCK_GROUP_DATA) &&
+ count_data < bctl->data.limit_min)
+ || ((chunk_type & BTRFS_BLOCK_GROUP_METADATA) &&
+ count_meta < bctl->meta.limit_min)
+ || ((chunk_type & BTRFS_BLOCK_GROUP_SYSTEM) &&
+ count_sys < bctl->sys.limit_min)) {
+ mutex_unlock(&fs_info->delete_unused_bgs_mutex);
goto loop;
}
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 2ca784a14e84..c34578ee49f9 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -375,6 +375,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_LIMIT_RANGE (1ULL << 6)
/*
* Profile changing flags. When SOFT is set we won't relocate chunk if
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
index b6dec05c7196..11f13108b78b 100644
--- a/include/uapi/linux/btrfs.h
+++ b/include/uapi/linux/btrfs.h
@@ -217,7 +217,18 @@ struct btrfs_balance_args {
__u64 flags;
- __u64 limit; /* limit number of processed chunks */
+ /*
+ * BTRFS_BALANCE_ARGS_LIMIT with value 'limit'
+ * BTRFS_BALANCE_ARGS_LIMIT_RANGE - 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__));
--
2.6.2
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/3] btrfs: add balance filter for stripes
2015-10-20 17:13 [PATCH 0/3 v3] Balance filters: stripes, enhanced limit and usage David Sterba
2015-10-20 17:13 ` [PATCH 1/3] btrfs: extend balance filter limit to take minimum and maximum David Sterba
@ 2015-10-20 17:13 ` David Sterba
2016-01-14 16:02 ` Christian Rohmann
2015-10-20 17:13 ` [PATCH 3/3] btrfs: extend balance filter usage to take minimum and maximum David Sterba
2 siblings, 1 reply; 6+ messages in thread
From: David Sterba @ 2015-10-20 17:13 UTC (permalink / raw)
To: linux-btrfs; +Cc: Gabríel Arthúr Pétursson, David Sterba
From: Gabríel Arthúr Pétursson <gabriel@system.is>
Balance block groups which have the given number of stripes, defined by
a range min..max. This is useful to selectively rebalance only chunks
that do not span enough devices, applies to RAID0/10/5/6.
Signed-off-by: Gabríel Arthúr Pétursson <gabriel@system.is>
[ renamed bargs members, added to the UAPI, wrote the changelog ]
Signed-off-by: David Sterba <dsterba@suse.com>
---
fs/btrfs/ctree.h | 9 ++++++++-
fs/btrfs/volumes.c | 19 +++++++++++++++++++
fs/btrfs/volumes.h | 1 +
include/uapi/linux/btrfs.h | 10 +++++++++-
4 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 852c738d6954..76055a8317e9 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -859,7 +859,14 @@ struct btrfs_disk_balance_args {
};
};
- __le64 unused[7];
+ /*
+ * Process chunks that cross stripes_min..stripes_max devices,
+ * BTRFS_BALANCE_ARGS_STRIPES_RANGE
+ */
+ __le32 stripes_min;
+ __le32 stripes_max;
+
+ __le64 unused[6];
} __attribute__ ((__packed__));
/*
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index b90a79c2bcf9..8d88a8737c79 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3170,6 +3170,19 @@ static int chunk_vrange_filter(struct extent_buffer *leaf,
return 1;
}
+static int chunk_stripes_range_filter(struct extent_buffer *leaf,
+ struct btrfs_chunk *chunk,
+ struct btrfs_balance_args *bargs)
+{
+ int num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
+
+ if (bargs->stripes_min <= num_stripes
+ && num_stripes <= bargs->stripes_max)
+ return 0;
+
+ return 1;
+}
+
static int chunk_soft_convert_filter(u64 chunk_type,
struct btrfs_balance_args *bargs)
{
@@ -3236,6 +3249,12 @@ static int should_balance_chunk(struct btrfs_root *root,
return 0;
}
+ /* stripes filter */
+ if ((bargs->flags & BTRFS_BALANCE_ARGS_STRIPES_RANGE) &&
+ chunk_stripes_range_filter(leaf, chunk, bargs)) {
+ return 0;
+ }
+
/* soft profile changing mode */
if ((bargs->flags & BTRFS_BALANCE_ARGS_SOFT) &&
chunk_soft_convert_filter(chunk_type, bargs)) {
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index c34578ee49f9..1d823ad3b914 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -376,6 +376,7 @@ struct map_lookup {
#define BTRFS_BALANCE_ARGS_VRANGE (1ULL << 4)
#define BTRFS_BALANCE_ARGS_LIMIT (1ULL << 5)
#define BTRFS_BALANCE_ARGS_LIMIT_RANGE (1ULL << 6)
+#define BTRFS_BALANCE_ARGS_STRIPES_RANGE (1ULL << 7)
/*
* Profile changing flags. When SOFT is set we won't relocate chunk if
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
index 11f13108b78b..17a94704b183 100644
--- a/include/uapi/linux/btrfs.h
+++ b/include/uapi/linux/btrfs.h
@@ -229,7 +229,15 @@ struct btrfs_balance_args {
__u32 limit_max;
};
};
- __u64 unused[7];
+
+ /*
+ * Process chunks that cross stripes_min..stripes_max devices,
+ * BTRFS_BALANCE_ARGS_STRIPES_RANGE
+ */
+ __le32 stripes_min;
+ __le32 stripes_max;
+
+ __u64 unused[6];
} __attribute__ ((__packed__));
/* report balance progress to userspace */
--
2.6.2
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH 2/3] btrfs: add balance filter for stripes
2015-10-20 17:13 ` [PATCH 2/3] btrfs: add balance filter for stripes David Sterba
@ 2016-01-14 16:02 ` Christian Rohmann
2016-01-15 17:40 ` David Sterba
0 siblings, 1 reply; 6+ messages in thread
From: Christian Rohmann @ 2016-01-14 16:02 UTC (permalink / raw)
To: David Sterba, linux-btrfs; +Cc: Gabríel Arthúr Pétursson
On 10/20/2015 07:13 PM, David Sterba wrote:
> Balance block groups which have the given number of stripes, defined by
> a range min..max. This is useful to selectively rebalance only chunks
> that do not span enough devices, applies to RAID0/10/5/6.
This sounds like an awesome improvement to re-balance a filesystem with
newly added devices which don't have any data chunks yet. So in theory
for RAID6 I would simple need to execute
btrfs balance start -dstripes=0..$devicecount-1 /filesystem
to have btrfs balance those chunks which are not spread across all
devices yet?
Regards
Christian
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/3] btrfs: add balance filter for stripes
2016-01-14 16:02 ` Christian Rohmann
@ 2016-01-15 17:40 ` David Sterba
0 siblings, 0 replies; 6+ messages in thread
From: David Sterba @ 2016-01-15 17:40 UTC (permalink / raw)
To: Christian Rohmann; +Cc: linux-btrfs, gabriel
On Thu, Jan 14, 2016 at 05:02:35PM +0100, Christian Rohmann wrote:
>
>
> On 10/20/2015 07:13 PM, David Sterba wrote:
> > Balance block groups which have the given number of stripes, defined by
> > a range min..max. This is useful to selectively rebalance only chunks
> > that do not span enough devices, applies to RAID0/10/5/6.
>
> This sounds like an awesome improvement to re-balance a filesystem with
> newly added devices which don't have any data chunks yet. So in theory
> for RAID6 I would simple need to execute
>
> btrfs balance start -dstripes=0..$devicecount-1 /filesystem
>
>
> to have btrfs balance those chunks which are not spread across all
> devices yet?
Exactly.
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 3/3] btrfs: extend balance filter usage to take minimum and maximum
2015-10-20 17:13 [PATCH 0/3 v3] Balance filters: stripes, enhanced limit and usage David Sterba
2015-10-20 17:13 ` [PATCH 1/3] btrfs: extend balance filter limit to take minimum and maximum David Sterba
2015-10-20 17:13 ` [PATCH 2/3] btrfs: add balance filter for stripes David Sterba
@ 2015-10-20 17:13 ` David Sterba
2 siblings, 0 replies; 6+ messages in thread
From: David Sterba @ 2015-10-20 17:13 UTC (permalink / raw)
To: linux-btrfs; +Cc: David Sterba
Similar to the 'limit' filter, we can enhance the 'usage' filter to
accept a range. The change is backward compatible, the range is applied
only in connection with the BTRFS_BALANCE_ARGS_USAGE_RANGE flag.
We don't have a usecase yet, the current syntax has been sufficient. The
enhancement should provide parity with other range-like filters.
Signed-off-by: David Sterba <dsterba@suse.com>
---
fs/btrfs/ctree.h | 14 ++++++++++++--
fs/btrfs/volumes.c | 41 ++++++++++++++++++++++++++++++++++++++++-
fs/btrfs/volumes.h | 1 +
include/uapi/linux/btrfs.h | 8 +++++++-
4 files changed, 60 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 76055a8317e9..31e5a3ed0a5c 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -823,8 +823,18 @@ struct btrfs_disk_balance_args {
*/
__le64 profiles;
- /* usage filter */
- __le64 usage;
+ /*
+ * usage filter
+ * BTRFS_BALANCE_ARGS_USAGE with a single value means '0..N'
+ * BTRFS_BALANCE_ARGS_USAGE_RANGE - range syntax, min..max
+ */
+ union {
+ __le64 usage;
+ struct {
+ __le32 usage_min;
+ __le32 usage_max;
+ };
+ };
/* devid filter */
__le64 devid;
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 8d88a8737c79..61e49e0fd934 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3009,16 +3009,19 @@ static void update_balance_args(struct btrfs_balance_control *bctl)
* (albeit full) chunks.
*/
if (!(bctl->data.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+ !(bctl->data.flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) &&
!(bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT)) {
bctl->data.flags |= BTRFS_BALANCE_ARGS_USAGE;
bctl->data.usage = 90;
}
if (!(bctl->sys.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+ !(bctl->sys.flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) &&
!(bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT)) {
bctl->sys.flags |= BTRFS_BALANCE_ARGS_USAGE;
bctl->sys.usage = 90;
}
if (!(bctl->meta.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+ !(bctl->meta.flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) &&
!(bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT)) {
bctl->meta.flags |= BTRFS_BALANCE_ARGS_USAGE;
bctl->meta.usage = 90;
@@ -3074,13 +3077,46 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
struct btrfs_balance_args *bargs)
{
struct btrfs_block_group_cache *cache;
+ u64 chunk_used;
+ u64 user_thresh_min;
+ u64 user_thresh_max;
+ int ret = 1;
+
+ cache = btrfs_lookup_block_group(fs_info, chunk_offset);
+ chunk_used = btrfs_block_group_used(&cache->item);
+
+ if (bargs->usage_min == 0)
+ user_thresh_min = 0;
+ else
+ user_thresh_min = div_factor_fine(cache->key.offset,
+ bargs->usage_min);
+
+ if (bargs->usage_max == 0)
+ user_thresh_max = 1;
+ else if (bargs->usage_max > 100)
+ user_thresh_max = cache->key.offset;
+ else
+ user_thresh_max = div_factor_fine(cache->key.offset,
+ bargs->usage_max);
+
+ if (user_thresh_min <= chunk_used && chunk_used < user_thresh_max)
+ ret = 0;
+
+ btrfs_put_block_group(cache);
+ return ret;
+}
+
+static int chunk_usage_range_filter(struct btrfs_fs_info *fs_info,
+ u64 chunk_offset, struct btrfs_balance_args *bargs)
+{
+ struct btrfs_block_group_cache *cache;
u64 chunk_used, user_thresh;
int ret = 1;
cache = btrfs_lookup_block_group(fs_info, chunk_offset);
chunk_used = btrfs_block_group_used(&cache->item);
- if (bargs->usage == 0)
+ if (bargs->usage_min == 0)
user_thresh = 1;
else if (bargs->usage > 100)
user_thresh = cache->key.offset;
@@ -3229,6 +3265,9 @@ static int should_balance_chunk(struct btrfs_root *root,
if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE) &&
chunk_usage_filter(bctl->fs_info, chunk_offset, bargs)) {
return 0;
+ } else if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) &&
+ chunk_usage_range_filter(bctl->fs_info, chunk_offset, bargs)) {
+ return 0;
}
/* devid filter */
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 1d823ad3b914..d2be0872ce2f 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -377,6 +377,7 @@ struct map_lookup {
#define BTRFS_BALANCE_ARGS_LIMIT (1ULL << 5)
#define BTRFS_BALANCE_ARGS_LIMIT_RANGE (1ULL << 6)
#define BTRFS_BALANCE_ARGS_STRIPES_RANGE (1ULL << 7)
+#define BTRFS_BALANCE_ARGS_USAGE_RANGE (1ULL << 8)
/*
* Profile changing flags. When SOFT is set we won't relocate chunk if
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
index 17a94704b183..dea893199257 100644
--- a/include/uapi/linux/btrfs.h
+++ b/include/uapi/linux/btrfs.h
@@ -206,7 +206,13 @@ struct btrfs_ioctl_feature_flags {
*/
struct btrfs_balance_args {
__u64 profiles;
- __u64 usage;
+ union {
+ __le64 usage;
+ struct {
+ __le32 usage_min;
+ __le32 usage_max;
+ };
+ };
__u64 devid;
__u64 pstart;
__u64 pend;
--
2.6.2
^ permalink raw reply related [flat|nested] 6+ messages in thread