Commit 7bfc837d authored by Miao Xie's avatar Miao Xie Committed by Chris Mason

btrfs: restructure find_free_dev_extent()

- make it return the start position and length of the max free space when it can
  not find a suitable free space.
- make it more readability
Signed-off-by: default avatarMiao Xie <miaox@cn.fujitsu.com>
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 1974a3b4
...@@ -8099,7 +8099,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) ...@@ -8099,7 +8099,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
mutex_lock(&root->fs_info->chunk_mutex); mutex_lock(&root->fs_info->chunk_mutex);
list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) { list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) {
u64 min_free = btrfs_block_group_used(&block_group->item); u64 min_free = btrfs_block_group_used(&block_group->item);
u64 dev_offset, max_avail; u64 dev_offset;
/* /*
* check to make sure we can actually find a chunk with enough * check to make sure we can actually find a chunk with enough
...@@ -8107,7 +8107,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) ...@@ -8107,7 +8107,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
*/ */
if (device->total_bytes > device->bytes_used + min_free) { if (device->total_bytes > device->bytes_used + min_free) {
ret = find_free_dev_extent(NULL, device, min_free, ret = find_free_dev_extent(NULL, device, min_free,
&dev_offset, &max_avail); &dev_offset, NULL);
if (!ret) if (!ret)
break; break;
ret = -1; ret = -1;
......
...@@ -729,58 +729,82 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, ...@@ -729,58 +729,82 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
} }
/* /*
* find_free_dev_extent - find free space in the specified device
* @trans: transaction handler
* @device: the device which we search the free space in
* @num_bytes: the size of the free space that we need
* @start: store the start of the free space.
* @len: the size of the free space. that we find, or the size of the max
* free space if we don't find suitable free space
*
* this uses a pretty simple search, the expectation is that it is * this uses a pretty simple search, the expectation is that it is
* called very infrequently and that a given device has a small number * called very infrequently and that a given device has a small number
* of extents * of extents
*
* @start is used to store the start of the free space if we find. But if we
* don't find suitable free space, it will be used to store the start position
* of the max free space.
*
* @len is used to store the size of the free space that we find.
* But if we don't find suitable free space, it is used to store the size of
* the max free space.
*/ */
int find_free_dev_extent(struct btrfs_trans_handle *trans, int find_free_dev_extent(struct btrfs_trans_handle *trans,
struct btrfs_device *device, u64 num_bytes, struct btrfs_device *device, u64 num_bytes,
u64 *start, u64 *max_avail) u64 *start, u64 *len)
{ {
struct btrfs_key key; struct btrfs_key key;
struct btrfs_root *root = device->dev_root; struct btrfs_root *root = device->dev_root;
struct btrfs_dev_extent *dev_extent = NULL; struct btrfs_dev_extent *dev_extent;
struct btrfs_path *path; struct btrfs_path *path;
u64 hole_size = 0; u64 hole_size;
u64 last_byte = 0; u64 max_hole_start;
u64 search_start = 0; u64 max_hole_size;
u64 extent_end;
u64 search_start;
u64 search_end = device->total_bytes; u64 search_end = device->total_bytes;
int ret; int ret;
int slot = 0; int slot;
int start_found;
struct extent_buffer *l; struct extent_buffer *l;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
path->reada = 2;
start_found = 0;
/* FIXME use last free of some kind */ /* FIXME use last free of some kind */
/* we don't want to overwrite the superblock on the drive, /* we don't want to overwrite the superblock on the drive,
* so we make sure to start at an offset of at least 1MB * so we make sure to start at an offset of at least 1MB
*/ */
search_start = max((u64)1024 * 1024, search_start); search_start = 1024 * 1024;
if (root->fs_info->alloc_start + num_bytes <= device->total_bytes) if (root->fs_info->alloc_start + num_bytes <= search_end)
search_start = max(root->fs_info->alloc_start, search_start); search_start = max(root->fs_info->alloc_start, search_start);
max_hole_start = search_start;
max_hole_size = 0;
if (search_start >= search_end) {
ret = -ENOSPC;
goto error;
}
path = btrfs_alloc_path();
if (!path) {
ret = -ENOMEM;
goto error;
}
path->reada = 2;
key.objectid = device->devid; key.objectid = device->devid;
key.offset = search_start; key.offset = search_start;
key.type = BTRFS_DEV_EXTENT_KEY; key.type = BTRFS_DEV_EXTENT_KEY;
ret = btrfs_search_slot(trans, root, &key, path, 0, 0); ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
if (ret < 0) if (ret < 0)
goto error; goto out;
if (ret > 0) { if (ret > 0) {
ret = btrfs_previous_item(root, path, key.objectid, key.type); ret = btrfs_previous_item(root, path, key.objectid, key.type);
if (ret < 0) if (ret < 0)
goto error; goto out;
if (ret > 0)
start_found = 1;
} }
l = path->nodes[0];
btrfs_item_key_to_cpu(l, &key, path->slots[0]);
while (1) { while (1) {
l = path->nodes[0]; l = path->nodes[0];
slot = path->slots[0]; slot = path->slots[0];
...@@ -789,24 +813,9 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans, ...@@ -789,24 +813,9 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans,
if (ret == 0) if (ret == 0)
continue; continue;
if (ret < 0) if (ret < 0)
goto error; goto out;
no_more_items:
if (!start_found) { break;
if (search_start >= search_end) {
ret = -ENOSPC;
goto error;
}
*start = search_start;
start_found = 1;
goto check_pending;
}
*start = last_byte > search_start ?
last_byte : search_start;
if (search_end <= *start) {
ret = -ENOSPC;
goto error;
}
goto check_pending;
} }
btrfs_item_key_to_cpu(l, &key, slot); btrfs_item_key_to_cpu(l, &key, slot);
...@@ -814,48 +823,62 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans, ...@@ -814,48 +823,62 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans,
goto next; goto next;
if (key.objectid > device->devid) if (key.objectid > device->devid)
goto no_more_items; break;
if (key.offset >= search_start && key.offset > last_byte && if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY)
start_found) { goto next;
if (last_byte < search_start)
last_byte = search_start;
hole_size = key.offset - last_byte;
if (hole_size > *max_avail) if (key.offset > search_start) {
*max_avail = hole_size; hole_size = key.offset - search_start;
if (key.offset > last_byte && if (hole_size > max_hole_size) {
hole_size >= num_bytes) { max_hole_start = search_start;
*start = last_byte; max_hole_size = hole_size;
goto check_pending; }
/*
* If this free space is greater than which we need,
* it must be the max free space that we have found
* until now, so max_hole_start must point to the start
* of this free space and the length of this free space
* is stored in max_hole_size. Thus, we return
* max_hole_start and max_hole_size and go back to the
* caller.
*/
if (hole_size >= num_bytes) {
ret = 0;
goto out;
} }
} }
if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY)
goto next;
start_found = 1;
dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
last_byte = key.offset + btrfs_dev_extent_length(l, dev_extent); extent_end = key.offset + btrfs_dev_extent_length(l,
dev_extent);
if (extent_end > search_start)
search_start = extent_end;
next: next:
path->slots[0]++; path->slots[0]++;
cond_resched(); cond_resched();
} }
check_pending:
/* we have to make sure we didn't find an extent that has already
* been allocated by the map tree or the original allocation
*/
BUG_ON(*start < search_start);
if (*start + num_bytes > search_end) { hole_size = search_end- search_start;
ret = -ENOSPC; if (hole_size > max_hole_size) {
goto error; max_hole_start = search_start;
max_hole_size = hole_size;
} }
/* check for pending inserts here */
/* See above. */
if (hole_size < num_bytes)
ret = -ENOSPC;
else
ret = 0; ret = 0;
error: out:
btrfs_free_path(path); btrfs_free_path(path);
error:
*start = max_hole_start;
if (len && max_hole_size > *len)
*len = max_hole_size;
return ret; return ret;
} }
......
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