btrfs: extend balance filter limit to take minimum and maximum

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>
This commit is contained in:
David Sterba 2015-10-10 17:16:50 +02:00 committed by Chris Mason
parent 2849a85422
commit 12907fc798
4 changed files with 67 additions and 3 deletions

View File

@ -846,8 +846,18 @@ struct btrfs_disk_balance_args {
/* BTRFS_BALANCE_ARGS_* */ /* BTRFS_BALANCE_ARGS_* */
__le64 flags; __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]; __le64 unused[7];
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));

View File

@ -3300,6 +3300,16 @@ static int should_balance_chunk(struct btrfs_root *root,
return 0; return 0;
else else
bargs->limit--; 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; return 1;
@ -3314,6 +3324,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
struct btrfs_device *device; struct btrfs_device *device;
u64 old_size; u64 old_size;
u64 size_to_free; u64 size_to_free;
u64 chunk_type;
struct btrfs_chunk *chunk; struct btrfs_chunk *chunk;
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_key key; struct btrfs_key key;
@ -3324,9 +3335,13 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
int ret; int ret;
int enospc_errors = 0; int enospc_errors = 0;
bool counting = true; 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_data = bctl->data.limit;
u64 limit_meta = bctl->meta.limit; u64 limit_meta = bctl->meta.limit;
u64 limit_sys = bctl->sys.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 */ /* step one make some room on all the devices */
devices = &fs_info->fs_devices->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); spin_unlock(&fs_info->balance_lock);
again: again:
if (!counting) { if (!counting) {
/*
* The single value limit and min/max limits use the same bytes
* in the
*/
bctl->data.limit = limit_data; bctl->data.limit = limit_data;
bctl->meta.limit = limit_meta; bctl->meta.limit = limit_meta;
bctl->sys.limit = limit_sys; bctl->sys.limit = limit_sys;
@ -3414,6 +3433,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
} }
chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk); chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
chunk_type = btrfs_chunk_type(leaf, chunk);
if (!counting) { if (!counting) {
spin_lock(&fs_info->balance_lock); spin_lock(&fs_info->balance_lock);
@ -3434,6 +3454,28 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
spin_lock(&fs_info->balance_lock); spin_lock(&fs_info->balance_lock);
bctl->stat.expected++; bctl->stat.expected++;
spin_unlock(&fs_info->balance_lock); 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; goto loop;
} }

View File

@ -380,6 +380,7 @@ struct map_lookup {
#define BTRFS_BALANCE_ARGS_DRANGE (1ULL << 3) #define BTRFS_BALANCE_ARGS_DRANGE (1ULL << 3)
#define BTRFS_BALANCE_ARGS_VRANGE (1ULL << 4) #define BTRFS_BALANCE_ARGS_VRANGE (1ULL << 4)
#define BTRFS_BALANCE_ARGS_LIMIT (1ULL << 5) #define BTRFS_BALANCE_ARGS_LIMIT (1ULL << 5)
#define BTRFS_BALANCE_ARGS_LIMIT_RANGE (1ULL << 6)
#define BTRFS_BALANCE_ARGS_MASK \ #define BTRFS_BALANCE_ARGS_MASK \
(BTRFS_BALANCE_ARGS_PROFILES | \ (BTRFS_BALANCE_ARGS_PROFILES | \

View File

@ -217,7 +217,18 @@ struct btrfs_balance_args {
__u64 flags; __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]; __u64 unused[7];
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));