mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-11-20 16:46:23 +08:00
Btrfs: find smallest available device extent during chunk allocation
Allocating new block group is easy when the disk has plenty of space. But things get difficult as the disk fills up, especially if the FS has been run through btrfs-vol -b. The balance operation is likely to make the total bytes available on the device greater than the largest extent we'll actually be able to allocate. But the device extent allocation code incorrectly assumes that a device with 5G free will be able to allocate a 5G extent. It isn't normally a problem because device extents don't get freed unless btrfs-vol -b is run. This fixes the device extent allocator to remember the largest free extent it can find, and then uses that value as a fallback. Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
283bb1979f
commit
9779b72f05
@ -721,7 +721,8 @@ error:
|
||||
*/
|
||||
static noinline int find_free_dev_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_device *device,
|
||||
u64 num_bytes, u64 *start)
|
||||
u64 num_bytes, u64 *start,
|
||||
u64 *max_avail)
|
||||
{
|
||||
struct btrfs_key key;
|
||||
struct btrfs_root *root = device->dev_root;
|
||||
@ -807,6 +808,10 @@ no_more_items:
|
||||
if (last_byte < search_start)
|
||||
last_byte = search_start;
|
||||
hole_size = key.offset - last_byte;
|
||||
|
||||
if (hole_size > *max_avail)
|
||||
*max_avail = hole_size;
|
||||
|
||||
if (key.offset > last_byte &&
|
||||
hole_size >= num_bytes) {
|
||||
*start = last_byte;
|
||||
@ -1625,6 +1630,7 @@ static int __btrfs_grow_device(struct btrfs_trans_handle *trans,
|
||||
device->fs_devices->total_rw_bytes += diff;
|
||||
|
||||
device->total_bytes = new_size;
|
||||
device->disk_total_bytes = new_size;
|
||||
btrfs_clear_space_info_full(device->dev_root->fs_info);
|
||||
|
||||
return btrfs_update_device(trans, device);
|
||||
@ -2175,6 +2181,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
|
||||
max_chunk_size);
|
||||
|
||||
again:
|
||||
max_avail = 0;
|
||||
if (!map || map->num_stripes != num_stripes) {
|
||||
kfree(map);
|
||||
map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
|
||||
@ -2223,7 +2230,8 @@ again:
|
||||
|
||||
if (device->in_fs_metadata && avail >= min_free) {
|
||||
ret = find_free_dev_extent(trans, device,
|
||||
min_free, &dev_offset);
|
||||
min_free, &dev_offset,
|
||||
&max_avail);
|
||||
if (ret == 0) {
|
||||
list_move_tail(&device->dev_alloc_list,
|
||||
&private_devs);
|
||||
|
Loading…
Reference in New Issue
Block a user