aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Sterba <dsterba@suse.com>2015-10-10 11:16:50 -0400
committerChris Mason <clm@fb.com>2015-10-26 22:38:28 -0400
commit12907fc79818a62a2478f84f7795afa774bf7f9c (patch)
treec7df6fd783c99feef090a00c38e7268515488430
parent2849a854224487bc578b73b64422c3cb3ef93ff5 (diff)
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>
-rw-r--r--fs/btrfs/ctree.h14
-rw-r--r--fs/btrfs/volumes.c42
-rw-r--r--fs/btrfs/volumes.h1
-rw-r--r--include/uapi/linux/btrfs.h13
4 files changed, 67 insertions, 3 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 3fa3c3b7bb66..460cd69b405e 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -846,8 +846,18 @@ struct btrfs_disk_balance_args {
846 /* BTRFS_BALANCE_ARGS_* */ 846 /* BTRFS_BALANCE_ARGS_* */
847 __le64 flags; 847 __le64 flags;
848 848
849 /* BTRFS_BALANCE_ARGS_LIMIT value */ 849 /*
850 __le64 limit; 850 * BTRFS_BALANCE_ARGS_LIMIT with value 'limit'
851 * BTRFS_BALANCE_ARGS_LIMIT_RANGE - the extend version can use minimum
852 * and maximum
853 */
854 union {
855 __le64 limit;
856 struct {
857 __le32 limit_min;
858 __le32 limit_max;
859 };
860 };
851 861
852 __le64 unused[7]; 862 __le64 unused[7];
853} __attribute__ ((__packed__)); 863} __attribute__ ((__packed__));
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index f86d83805b44..e2fdd2e01104 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3300,6 +3300,16 @@ static int should_balance_chunk(struct btrfs_root *root,
3300 return 0; 3300 return 0;
3301 else 3301 else
3302 bargs->limit--; 3302 bargs->limit--;
3303 } else if ((bargs->flags & BTRFS_BALANCE_ARGS_LIMIT_RANGE)) {
3304 /*
3305 * Same logic as the 'limit' filter; the minimum cannot be
3306 * determined here because we do not have the global informatoin
3307 * about the count of all chunks that satisfy the filters.
3308 */
3309 if (bargs->limit_max == 0)
3310 return 0;
3311 else
3312 bargs->limit_max--;
3303 } 3313 }
3304 3314
3305 return 1; 3315 return 1;
@@ -3314,6 +3324,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
3314 struct btrfs_device *device; 3324 struct btrfs_device *device;
3315 u64 old_size; 3325 u64 old_size;
3316 u64 size_to_free; 3326 u64 size_to_free;
3327 u64 chunk_type;
3317 struct btrfs_chunk *chunk; 3328 struct btrfs_chunk *chunk;
3318 struct btrfs_path *path; 3329 struct btrfs_path *path;
3319 struct btrfs_key key; 3330 struct btrfs_key key;
@@ -3324,9 +3335,13 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
3324 int ret; 3335 int ret;
3325 int enospc_errors = 0; 3336 int enospc_errors = 0;
3326 bool counting = true; 3337 bool counting = true;
3338 /* The single value limit and min/max limits use the same bytes in the */
3327 u64 limit_data = bctl->data.limit; 3339 u64 limit_data = bctl->data.limit;
3328 u64 limit_meta = bctl->meta.limit; 3340 u64 limit_meta = bctl->meta.limit;
3329 u64 limit_sys = bctl->sys.limit; 3341 u64 limit_sys = bctl->sys.limit;
3342 u32 count_data = 0;
3343 u32 count_meta = 0;
3344 u32 count_sys = 0;
3330 3345
3331 /* step one make some room on all the devices */ 3346 /* step one make some room on all the devices */
3332 devices = &fs_info->fs_devices->devices; 3347 devices = &fs_info->fs_devices->devices;
@@ -3367,6 +3382,10 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
3367 spin_unlock(&fs_info->balance_lock); 3382 spin_unlock(&fs_info->balance_lock);
3368again: 3383again:
3369 if (!counting) { 3384 if (!counting) {
3385 /*
3386 * The single value limit and min/max limits use the same bytes
3387 * in the
3388 */
3370 bctl->data.limit = limit_data; 3389 bctl->data.limit = limit_data;
3371 bctl->meta.limit = limit_meta; 3390 bctl->meta.limit = limit_meta;
3372 bctl->sys.limit = limit_sys; 3391 bctl->sys.limit = limit_sys;
@@ -3414,6 +3433,7 @@ again:
3414 } 3433 }
3415 3434
3416 chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk); 3435 chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
3436 chunk_type = btrfs_chunk_type(leaf, chunk);
3417 3437
3418 if (!counting) { 3438 if (!counting) {
3419 spin_lock(&fs_info->balance_lock); 3439 spin_lock(&fs_info->balance_lock);
@@ -3434,6 +3454,28 @@ again:
3434 spin_lock(&fs_info->balance_lock); 3454 spin_lock(&fs_info->balance_lock);
3435 bctl->stat.expected++; 3455 bctl->stat.expected++;
3436 spin_unlock(&fs_info->balance_lock); 3456 spin_unlock(&fs_info->balance_lock);
3457
3458 if (chunk_type & BTRFS_BLOCK_GROUP_DATA)
3459 count_data++;
3460 else if (chunk_type & BTRFS_BLOCK_GROUP_SYSTEM)
3461 count_sys++;
3462 else if (chunk_type & BTRFS_BLOCK_GROUP_METADATA)
3463 count_meta++;
3464
3465 goto loop;
3466 }
3467
3468 /*
3469 * Apply limit_min filter, no need to check if the LIMITS
3470 * filter is used, limit_min is 0 by default
3471 */
3472 if (((chunk_type & BTRFS_BLOCK_GROUP_DATA) &&
3473 count_data < bctl->data.limit_min)
3474 || ((chunk_type & BTRFS_BLOCK_GROUP_METADATA) &&
3475 count_meta < bctl->meta.limit_min)
3476 || ((chunk_type & BTRFS_BLOCK_GROUP_SYSTEM) &&
3477 count_sys < bctl->sys.limit_min)) {
3478 mutex_unlock(&fs_info->delete_unused_bgs_mutex);
3437 goto loop; 3479 goto loop;
3438 } 3480 }
3439 3481
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index b8e64ea984f1..628d4e17019d 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -380,6 +380,7 @@ struct map_lookup {
380#define BTRFS_BALANCE_ARGS_DRANGE (1ULL << 3) 380#define BTRFS_BALANCE_ARGS_DRANGE (1ULL << 3)
381#define BTRFS_BALANCE_ARGS_VRANGE (1ULL << 4) 381#define BTRFS_BALANCE_ARGS_VRANGE (1ULL << 4)
382#define BTRFS_BALANCE_ARGS_LIMIT (1ULL << 5) 382#define BTRFS_BALANCE_ARGS_LIMIT (1ULL << 5)
383#define BTRFS_BALANCE_ARGS_LIMIT_RANGE (1ULL << 6)
383 384
384#define BTRFS_BALANCE_ARGS_MASK \ 385#define BTRFS_BALANCE_ARGS_MASK \
385 (BTRFS_BALANCE_ARGS_PROFILES | \ 386 (BTRFS_BALANCE_ARGS_PROFILES | \
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 {
217 217
218 __u64 flags; 218 __u64 flags;
219 219
220 __u64 limit; /* limit number of processed chunks */ 220 /*
221 * BTRFS_BALANCE_ARGS_LIMIT with value 'limit'
222 * BTRFS_BALANCE_ARGS_LIMIT_RANGE - the extend version can use minimum
223 * and maximum
224 */
225 union {
226 __u64 limit; /* limit number of processed chunks */
227 struct {
228 __u32 limit_min;
229 __u32 limit_max;
230 };
231 };
221 __u64 unused[7]; 232 __u64 unused[7];
222} __attribute__ ((__packed__)); 233} __attribute__ ((__packed__));
223 234