Skip to content

Commit

Permalink
Btrfs: find smallest available device extent during chunk allocation
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Chris Mason committed Jul 24, 2009
1 parent 283bb19 commit 9779b72
Showing 1 changed file with 10 additions and 2 deletions.
12 changes: 10 additions & 2 deletions fs/btrfs/volumes.c
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,8 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
*/
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;
Expand Down Expand Up @@ -807,6 +808,10 @@ static noinline int find_free_dev_extent(struct btrfs_trans_handle *trans,
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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -2223,7 +2230,8 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,

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);
Expand Down

0 comments on commit 9779b72

Please sign in to comment.