]> git.hungrycats.org Git - linux/commitdiff
btrfs: extend balance filter limit to take minimum and maximum
authorDavid Sterba <dsterba@suse.com>
Sat, 10 Oct 2015 15:16:50 +0000 (17:16 +0200)
committerZygo Blaxell <zblaxell@serenity.furryterror.org>
Thu, 29 Oct 2015 21:53:38 +0000 (17:53 -0400)
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>
Signed-off-by: Chris Mason <clm@fb.com>
(cherry picked from commit 12907fc79818a62a2478f84f7795afa774bf7f9c)
(cherry picked from commit 4bb1ea8aa68b82d3617ae56f820d9e079d34261d)

fs/btrfs/ctree.h
fs/btrfs/volumes.c
fs/btrfs/volumes.h
include/uapi/linux/btrfs.h

index 415a339090c0a8cbec7533a5c074001314e38440..67c4e68dd66ab2c312dd66d7d3472ab70134e73d 100644 (file)
@@ -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__));
index b380feb1879ef11b9ff29902f9b1f14af4324cd4..cd5eaec4a68d957f577d0d7e854324eaacbf7315 100644 (file)
@@ -3237,6 +3237,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;
@@ -3251,6 +3261,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;
@@ -3261,9 +3272,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;
@@ -3304,6 +3319,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;
@@ -3351,6 +3370,7 @@ again:
                }
 
                chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
+               chunk_type = btrfs_chunk_type(leaf, chunk);
 
                if (!counting) {
                        spin_lock(&fs_info->balance_lock);
@@ -3371,6 +3391,28 @@ again:
                        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;
                }
 
index de36732b18a5f8a521ca231309f7953da7836faa..9b9f50c2fb4b9af2324298b53dc77f9accd337fb 100644 (file)
@@ -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)
 
 #define BTRFS_BALANCE_ARGS_MASK                        \
        (BTRFS_BALANCE_ARGS_PROFILES |          \
index b6dec05c7196a22511e346242724406eef88265b..11f13108b78b2222b093419a66bc12b8e135be07 100644 (file)
@@ -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__));