Commit 4a5e98f5 authored by Ilya Dryomov's avatar Ilya Dryomov

Btrfs: improve the logic in btrfs_can_relocate()

Currently if we don't have enough space allocated we go ahead and loop
though devices in the hopes of finding enough space for a chunk of the
*same* type as the one we are trying to relocate.  The problem with that
is that if we are trying to restripe the chunk its target type can be
more relaxed than the current one (eg require less devices or less
space).  So, when restriping, run checks against the target profile
instead of the current one.
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent 7738a53a
...@@ -7136,6 +7136,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) ...@@ -7136,6 +7136,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
u64 min_free; u64 min_free;
u64 dev_min = 1; u64 dev_min = 1;
u64 dev_nr = 0; u64 dev_nr = 0;
u64 target;
int index; int index;
int full = 0; int full = 0;
int ret = 0; int ret = 0;
...@@ -7176,13 +7177,11 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) ...@@ -7176,13 +7177,11 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
/* /*
* ok we don't have enough space, but maybe we have free space on our * ok we don't have enough space, but maybe we have free space on our
* devices to allocate new chunks for relocation, so loop through our * devices to allocate new chunks for relocation, so loop through our
* alloc devices and guess if we have enough space. However, if we * alloc devices and guess if we have enough space. if this block
* were marked as full, then we know there aren't enough chunks, and we * group is going to be restriped, run checks against the target
* can just return. * profile instead of the current one.
*/ */
ret = -1; ret = -1;
if (full)
goto out;
/* /*
* index: * index:
...@@ -7192,7 +7191,20 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) ...@@ -7192,7 +7191,20 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
* 3: raid0 * 3: raid0
* 4: single * 4: single
*/ */
index = get_block_group_index(block_group); target = get_restripe_target(root->fs_info, block_group->flags);
if (target) {
index = __get_block_group_index(extended_to_chunk(target));
} else {
/*
* this is just a balance, so if we were marked as full
* we know there is no space for a new chunk
*/
if (full)
goto out;
index = get_block_group_index(block_group);
}
if (index == 0) { if (index == 0) {
dev_min = 4; dev_min = 4;
/* Divide by 2 */ /* Divide by 2 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment