aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2009-07-24 16:41:41 -0400
committerChris Mason <chris.mason@oracle.com>2009-07-24 16:41:41 -0400
commit9779b72f0584fd53e0de53f62f205bf0dc0db553 (patch)
treefc05718a138dbcf64069e0a2b4ffc84bf9abf5e7
parent283bb1979fa8580c4037d8df251449368c292a3b (diff)
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>
-rw-r--r--fs/btrfs/volumes.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 074c1c56d8c4..5dbefd11b4af 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -721,7 +721,8 @@ error:
721 */ 721 */
722static noinline int find_free_dev_extent(struct btrfs_trans_handle *trans, 722static noinline int find_free_dev_extent(struct btrfs_trans_handle *trans,
723 struct btrfs_device *device, 723 struct btrfs_device *device,
724 u64 num_bytes, u64 *start) 724 u64 num_bytes, u64 *start,
725 u64 *max_avail)
725{ 726{
726 struct btrfs_key key; 727 struct btrfs_key key;
727 struct btrfs_root *root = device->dev_root; 728 struct btrfs_root *root = device->dev_root;
@@ -807,6 +808,10 @@ no_more_items:
807 if (last_byte < search_start) 808 if (last_byte < search_start)
808 last_byte = search_start; 809 last_byte = search_start;
809 hole_size = key.offset - last_byte; 810 hole_size = key.offset - last_byte;
811
812 if (hole_size > *max_avail)
813 *max_avail = hole_size;
814
810 if (key.offset > last_byte && 815 if (key.offset > last_byte &&
811 hole_size >= num_bytes) { 816 hole_size >= num_bytes) {
812 *start = last_byte; 817 *start = last_byte;
@@ -1625,6 +1630,7 @@ static int __btrfs_grow_device(struct btrfs_trans_handle *trans,
1625 device->fs_devices->total_rw_bytes += diff; 1630 device->fs_devices->total_rw_bytes += diff;
1626 1631
1627 device->total_bytes = new_size; 1632 device->total_bytes = new_size;
1633 device->disk_total_bytes = new_size;
1628 btrfs_clear_space_info_full(device->dev_root->fs_info); 1634 btrfs_clear_space_info_full(device->dev_root->fs_info);
1629 1635
1630 return btrfs_update_device(trans, device); 1636 return btrfs_update_device(trans, device);
@@ -2175,6 +2181,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
2175 max_chunk_size); 2181 max_chunk_size);
2176 2182
2177again: 2183again:
2184 max_avail = 0;
2178 if (!map || map->num_stripes != num_stripes) { 2185 if (!map || map->num_stripes != num_stripes) {
2179 kfree(map); 2186 kfree(map);
2180 map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS); 2187 map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
@@ -2223,7 +2230,8 @@ again:
2223 2230
2224 if (device->in_fs_metadata && avail >= min_free) { 2231 if (device->in_fs_metadata && avail >= min_free) {
2225 ret = find_free_dev_extent(trans, device, 2232 ret = find_free_dev_extent(trans, device,
2226 min_free, &dev_offset); 2233 min_free, &dev_offset,
2234 &max_avail);
2227 if (ret == 0) { 2235 if (ret == 0) {
2228 list_move_tail(&device->dev_alloc_list, 2236 list_move_tail(&device->dev_alloc_list,
2229 &private_devs); 2237 &private_devs);