diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 76 |
1 files changed, 62 insertions, 14 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 1497ff98f0d3..e3c6bfea3751 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -12,6 +12,33 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct | |||
12 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct | 12 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct |
13 | btrfs_root *extent_root); | 13 | btrfs_root *extent_root); |
14 | 14 | ||
15 | static void reada_extent_leaves(struct btrfs_root *root, | ||
16 | struct btrfs_path *path, u64 limit) | ||
17 | { | ||
18 | struct btrfs_node *node; | ||
19 | int i; | ||
20 | int nritems; | ||
21 | u64 item_objectid; | ||
22 | u64 blocknr; | ||
23 | int slot; | ||
24 | int ret; | ||
25 | |||
26 | if (!path->nodes[1]) | ||
27 | return; | ||
28 | node = btrfs_buffer_node(path->nodes[1]); | ||
29 | slot = path->slots[1] + 1; | ||
30 | nritems = btrfs_header_nritems(&node->header); | ||
31 | for (i = slot; i < nritems && i < slot + 8; i++) { | ||
32 | item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key); | ||
33 | if (item_objectid > limit) | ||
34 | break; | ||
35 | blocknr = btrfs_node_blockptr(node, i); | ||
36 | ret = readahead_tree_block(root, blocknr); | ||
37 | if (ret) | ||
38 | break; | ||
39 | } | ||
40 | } | ||
41 | |||
15 | static int cache_block_group(struct btrfs_root *root, | 42 | static int cache_block_group(struct btrfs_root *root, |
16 | struct btrfs_block_group_cache *block_group) | 43 | struct btrfs_block_group_cache *block_group) |
17 | { | 44 | { |
@@ -24,6 +51,7 @@ static int cache_block_group(struct btrfs_root *root, | |||
24 | u64 i; | 51 | u64 i; |
25 | u64 last = 0; | 52 | u64 last = 0; |
26 | u64 hole_size; | 53 | u64 hole_size; |
54 | u64 limit; | ||
27 | int found = 0; | 55 | int found = 0; |
28 | 56 | ||
29 | root = root->fs_info->extent_root; | 57 | root = root->fs_info->extent_root; |
@@ -46,14 +74,17 @@ printk("cache block group %Lu\n", block_group->key.objectid); | |||
46 | return ret; | 74 | return ret; |
47 | if (ret && path->slots[0] > 0) | 75 | if (ret && path->slots[0] > 0) |
48 | path->slots[0]--; | 76 | path->slots[0]--; |
77 | limit = block_group->key.objectid + block_group->key.offset; | ||
78 | reada_extent_leaves(root, path, limit); | ||
49 | while(1) { | 79 | while(1) { |
50 | leaf = btrfs_buffer_leaf(path->nodes[0]); | 80 | leaf = btrfs_buffer_leaf(path->nodes[0]); |
51 | slot = path->slots[0]; | 81 | slot = path->slots[0]; |
52 | if (slot >= btrfs_header_nritems(&leaf->header)) { | 82 | if (slot >= btrfs_header_nritems(&leaf->header)) { |
83 | reada_extent_leaves(root, path, limit); | ||
53 | ret = btrfs_next_leaf(root, path); | 84 | ret = btrfs_next_leaf(root, path); |
54 | if (ret == 0) | 85 | if (ret == 0) { |
55 | continue; | 86 | continue; |
56 | else { | 87 | } else { |
57 | if (found) { | 88 | if (found) { |
58 | hole_size = block_group->key.objectid + | 89 | hole_size = block_group->key.objectid + |
59 | block_group->key.offset - last; | 90 | block_group->key.offset - last; |
@@ -187,7 +218,7 @@ new_group: | |||
187 | return max((*cache_ret)->last_alloc, search_start); | 218 | return max((*cache_ret)->last_alloc, search_start); |
188 | } | 219 | } |
189 | cache = btrfs_find_block_group(root, cache, | 220 | cache = btrfs_find_block_group(root, cache, |
190 | last + cache->key.offset - 1, 0); | 221 | last + cache->key.offset - 1, 0, 0); |
191 | *cache_ret = cache; | 222 | *cache_ret = cache; |
192 | goto again; | 223 | goto again; |
193 | } | 224 | } |
@@ -195,7 +226,7 @@ new_group: | |||
195 | struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | 226 | struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, |
196 | struct btrfs_block_group_cache | 227 | struct btrfs_block_group_cache |
197 | *hint, u64 search_start, | 228 | *hint, u64 search_start, |
198 | int data) | 229 | int data, int owner) |
199 | { | 230 | { |
200 | struct btrfs_block_group_cache *cache[8]; | 231 | struct btrfs_block_group_cache *cache[8]; |
201 | struct btrfs_block_group_cache *found_group = NULL; | 232 | struct btrfs_block_group_cache *found_group = NULL; |
@@ -207,6 +238,10 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
207 | int i; | 238 | int i; |
208 | int ret; | 239 | int ret; |
209 | int full_search = 0; | 240 | int full_search = 0; |
241 | int factor = 8; | ||
242 | |||
243 | if (!owner) | ||
244 | factor = 5; | ||
210 | 245 | ||
211 | if (data) | 246 | if (data) |
212 | radix = &info->block_group_data_radix; | 247 | radix = &info->block_group_data_radix; |
@@ -219,14 +254,14 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
219 | if (shint->data == data) { | 254 | if (shint->data == data) { |
220 | used = btrfs_block_group_used(&shint->item); | 255 | used = btrfs_block_group_used(&shint->item); |
221 | if (used + shint->pinned < | 256 | if (used + shint->pinned < |
222 | (shint->key.offset * 8) / 10) { | 257 | (shint->key.offset * factor) / 10) { |
223 | return shint; | 258 | return shint; |
224 | } | 259 | } |
225 | } | 260 | } |
226 | } | 261 | } |
227 | if (hint && hint->data == data) { | 262 | if (hint && hint->data == data) { |
228 | used = btrfs_block_group_used(&hint->item); | 263 | used = btrfs_block_group_used(&hint->item); |
229 | if (used + hint->pinned < (hint->key.offset * 8) / 10) { | 264 | if (used + hint->pinned < (hint->key.offset * factor) / 10) { |
230 | return hint; | 265 | return hint; |
231 | } | 266 | } |
232 | if (used >= (hint->key.offset * 8) / 10) { | 267 | if (used >= (hint->key.offset * 8) / 10) { |
@@ -261,7 +296,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
261 | cache[i]->key.offset; | 296 | cache[i]->key.offset; |
262 | used = btrfs_block_group_used(&cache[i]->item); | 297 | used = btrfs_block_group_used(&cache[i]->item); |
263 | if (used + cache[i]->pinned < | 298 | if (used + cache[i]->pinned < |
264 | (cache[i]->key.offset * 8) / 10) { | 299 | (cache[i]->key.offset * factor) / 10) { |
265 | found_group = cache[i]; | 300 | found_group = cache[i]; |
266 | goto found; | 301 | goto found; |
267 | } | 302 | } |
@@ -272,6 +307,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
272 | BTRFS_BLOCK_GROUP_AVAIL); | 307 | BTRFS_BLOCK_GROUP_AVAIL); |
273 | } | 308 | } |
274 | } | 309 | } |
310 | cond_resched(); | ||
275 | } | 311 | } |
276 | last = hint_last; | 312 | last = hint_last; |
277 | again: | 313 | again: |
@@ -295,13 +331,16 @@ again: | |||
295 | BTRFS_BLOCK_GROUP_AVAIL); | 331 | BTRFS_BLOCK_GROUP_AVAIL); |
296 | } | 332 | } |
297 | } | 333 | } |
334 | cond_resched(); | ||
298 | } | 335 | } |
299 | if (!full_search) { | 336 | if (!full_search) { |
337 | printk("find block group doing full search data %d start %Lu\n", data, search_start); | ||
300 | last = search_start; | 338 | last = search_start; |
301 | full_search = 1; | 339 | full_search = 1; |
302 | goto again; | 340 | goto again; |
303 | } | 341 | } |
304 | if (!found_group) { | 342 | if (!found_group) { |
343 | printk("find block group bailing to zero data %d\n", data); | ||
305 | ret = radix_tree_gang_lookup(radix, | 344 | ret = radix_tree_gang_lookup(radix, |
306 | (void **)&found_group, 0, 1); | 345 | (void **)&found_group, 0, 1); |
307 | BUG_ON(ret != 1); | 346 | BUG_ON(ret != 1); |
@@ -554,8 +593,8 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
554 | blocknr + i); | 593 | blocknr + i); |
555 | } | 594 | } |
556 | } | 595 | } |
557 | if (old_val < (cache->key.offset * 6) / 10 && | 596 | if (old_val < (cache->key.offset * 5) / 10 && |
558 | old_val + num >= (cache->key.offset * 6) / 10) { | 597 | old_val + num >= (cache->key.offset * 5) / 10) { |
559 | printk("group %Lu now available\n", cache->key.objectid); | 598 | printk("group %Lu now available\n", cache->key.objectid); |
560 | radix_tree_tag_set(cache->radix, | 599 | radix_tree_tag_set(cache->radix, |
561 | cache->key.objectid + | 600 | cache->key.objectid + |
@@ -842,6 +881,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
842 | int level; | 881 | int level; |
843 | struct btrfs_block_group_cache *block_group; | 882 | struct btrfs_block_group_cache *block_group; |
844 | int full_scan = 0; | 883 | int full_scan = 0; |
884 | u64 limit; | ||
845 | 885 | ||
846 | path = btrfs_alloc_path(); | 886 | path = btrfs_alloc_path(); |
847 | ins->flags = 0; | 887 | ins->flags = 0; |
@@ -858,11 +898,11 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
858 | if (search_start) { | 898 | if (search_start) { |
859 | block_group = lookup_block_group(info, search_start); | 899 | block_group = lookup_block_group(info, search_start); |
860 | block_group = btrfs_find_block_group(root, block_group, | 900 | block_group = btrfs_find_block_group(root, block_group, |
861 | search_start, data); | 901 | search_start, data, 1); |
862 | } else { | 902 | } else { |
863 | block_group = btrfs_find_block_group(root, | 903 | block_group = btrfs_find_block_group(root, |
864 | trans->block_group, 0, | 904 | trans->block_group, 0, |
865 | data); | 905 | data, 1); |
866 | } | 906 | } |
867 | 907 | ||
868 | check_failed: | 908 | check_failed: |
@@ -916,6 +956,12 @@ check_failed: | |||
916 | info->extent_tree_prealloc_nr = 0; | 956 | info->extent_tree_prealloc_nr = 0; |
917 | total_found = 0; | 957 | total_found = 0; |
918 | } | 958 | } |
959 | if (start_found) | ||
960 | limit = last_block + | ||
961 | block_group->key.offset / 2; | ||
962 | else | ||
963 | limit = search_start + | ||
964 | block_group->key.offset / 2; | ||
919 | ret = btrfs_next_leaf(root, path); | 965 | ret = btrfs_next_leaf(root, path); |
920 | if (ret == 0) | 966 | if (ret == 0) |
921 | continue; | 967 | continue; |
@@ -960,6 +1006,7 @@ check_failed: | |||
960 | } | 1006 | } |
961 | next: | 1007 | next: |
962 | path->slots[0]++; | 1008 | path->slots[0]++; |
1009 | cond_resched(); | ||
963 | } | 1010 | } |
964 | // FIXME -ENOSPC | 1011 | // FIXME -ENOSPC |
965 | check_pending: | 1012 | check_pending: |
@@ -1049,7 +1096,8 @@ printk("doing full scan!\n"); | |||
1049 | block_group = lookup_block_group(info, search_start); | 1096 | block_group = lookup_block_group(info, search_start); |
1050 | if (!full_scan) | 1097 | if (!full_scan) |
1051 | block_group = btrfs_find_block_group(root, block_group, | 1098 | block_group = btrfs_find_block_group(root, block_group, |
1052 | search_start, data); | 1099 | search_start, data, 0); |
1100 | cond_resched(); | ||
1053 | goto check_failed; | 1101 | goto check_failed; |
1054 | 1102 | ||
1055 | error: | 1103 | error: |
@@ -1102,7 +1150,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1102 | * in the correct block group. | 1150 | * in the correct block group. |
1103 | */ | 1151 | */ |
1104 | if (data) { | 1152 | if (data) { |
1105 | ret = find_free_extent(trans, root, 0, search_start, | 1153 | ret = find_free_extent(trans, root, 0, 0, |
1106 | search_end, &prealloc_key, 0); | 1154 | search_end, &prealloc_key, 0); |
1107 | if (ret) { | 1155 | if (ret) { |
1108 | return ret; | 1156 | return ret; |
@@ -1173,7 +1221,7 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
1173 | struct buffer_head *buf; | 1221 | struct buffer_head *buf; |
1174 | 1222 | ||
1175 | ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, | 1223 | ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, |
1176 | 1, 0, (unsigned long)-1, &ins, 0); | 1224 | 1, hint, (unsigned long)-1, &ins, 0); |
1177 | if (ret) { | 1225 | if (ret) { |
1178 | BUG(); | 1226 | BUG(); |
1179 | return NULL; | 1227 | return NULL; |