btrfs: extend balance filter limit to take minimum and maximum
[cascardo/linux.git] / fs / btrfs / volumes.c
index f86d838..e2fdd2e 100644 (file)
@@ -3300,6 +3300,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;
@@ -3314,6 +3324,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;
@@ -3324,9 +3335,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;
@@ -3367,6 +3382,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;
@@ -3414,6 +3433,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);
@@ -3434,6 +3454,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;
                }