diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-05-06 10:15:01 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-05-06 10:15:01 -0400 |
commit | be74417553f4b2ee46be2088007a674ef2f02330 (patch) | |
tree | f3c3e0f3d15b2c638699f3c8305a090c88e16c8b /fs/btrfs/extent-tree.c | |
parent | be08c1b9f8e679d45e086728445ac36cf250e92e (diff) |
Btrfs: more allocator enhancements
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 317 |
1 files changed, 238 insertions, 79 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index c5ae51893f78..2937fd9aba74 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -12,36 +12,88 @@ 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 struct btrfs_block_group_cache *lookup_block_group(struct | ||
16 | btrfs_fs_info *info, | ||
17 | u64 blocknr) | ||
18 | { | ||
19 | struct btrfs_block_group_cache *block_group; | ||
20 | int ret; | ||
21 | |||
22 | ret = radix_tree_gang_lookup(&info->block_group_radix, | ||
23 | (void **)&block_group, | ||
24 | blocknr, 1); | ||
25 | if (ret) { | ||
26 | if (block_group->key.objectid <= blocknr && blocknr < | ||
27 | block_group->key.objectid + block_group->key.offset) | ||
28 | return block_group; | ||
29 | } | ||
30 | ret = radix_tree_gang_lookup(&info->block_group_data_radix, | ||
31 | (void **)&block_group, | ||
32 | blocknr, 1); | ||
33 | if (ret) { | ||
34 | if (block_group->key.objectid <= blocknr && blocknr < | ||
35 | block_group->key.objectid + block_group->key.offset) | ||
36 | return block_group; | ||
37 | } | ||
38 | printk("lookup_block_group fails for blocknr %Lu\n", blocknr); | ||
39 | return NULL; | ||
40 | } | ||
41 | |||
15 | struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | 42 | struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, |
16 | struct btrfs_block_group_cache | 43 | struct btrfs_block_group_cache |
17 | *hint, int data) | 44 | *hint, u64 search_start, |
45 | int data) | ||
18 | { | 46 | { |
19 | struct btrfs_block_group_cache *cache[8]; | 47 | struct btrfs_block_group_cache *cache[8]; |
20 | struct btrfs_block_group_cache *found_group = NULL; | 48 | struct btrfs_block_group_cache *found_group = NULL; |
21 | struct btrfs_fs_info *info = root->fs_info; | 49 | struct btrfs_fs_info *info = root->fs_info; |
50 | struct radix_tree_root *radix; | ||
22 | u64 used; | 51 | u64 used; |
23 | u64 last = 0; | 52 | u64 last = 0; |
24 | u64 hint_last; | 53 | u64 hint_last; |
25 | int i; | 54 | int i; |
26 | int ret; | 55 | int ret; |
27 | int full_search = 0; | 56 | int full_search = 0; |
28 | if (!data && hint) { | 57 | |
58 | if (data) | ||
59 | radix = &info->block_group_data_radix; | ||
60 | else | ||
61 | radix = &info->block_group_radix; | ||
62 | |||
63 | if (search_start) { | ||
64 | struct btrfs_block_group_cache *shint; | ||
65 | shint = lookup_block_group(info, search_start); | ||
66 | if (shint->data == data) { | ||
67 | used = btrfs_block_group_used(&shint->item); | ||
68 | if (used + shint->pinned < | ||
69 | (shint->key.offset * 8) / 10) { | ||
70 | return shint; | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | if (hint && hint->data == data) { | ||
29 | used = btrfs_block_group_used(&hint->item); | 75 | used = btrfs_block_group_used(&hint->item); |
30 | if (used < (hint->key.offset * 2) / 3) { | 76 | if (used + hint->pinned < (hint->key.offset * 8) / 10) { |
31 | return hint; | 77 | return hint; |
32 | } | 78 | } |
33 | radix_tree_tag_clear(&info->block_group_radix, | 79 | if (used >= (hint->key.offset * 8) / 10) { |
34 | hint->key.objectid + hint->key.offset - 1, | 80 | radix_tree_tag_clear(radix, |
35 | BTRFS_BLOCK_GROUP_AVAIL); | 81 | hint->key.objectid + |
36 | last = hint->key.objectid + hint->key.offset; | 82 | hint->key.offset - 1, |
83 | BTRFS_BLOCK_GROUP_AVAIL); | ||
84 | } | ||
85 | last = hint->key.offset * 2; | ||
86 | if (hint->key.objectid >= last) | ||
87 | last = max(search_start, hint->key.objectid - last); | ||
88 | else | ||
89 | last = hint->key.objectid + hint->key.offset; | ||
37 | hint_last = last; | 90 | hint_last = last; |
38 | } else { | 91 | } else { |
39 | hint_last = 0; | 92 | hint_last = search_start; |
40 | last = 0; | 93 | last = search_start; |
41 | } | 94 | } |
42 | while(1) { | 95 | while(1) { |
43 | ret = radix_tree_gang_lookup_tag(&info->block_group_radix, | 96 | ret = radix_tree_gang_lookup_tag(radix, (void **)cache, |
44 | (void **)cache, | ||
45 | last, ARRAY_SIZE(cache), | 97 | last, ARRAY_SIZE(cache), |
46 | BTRFS_BLOCK_GROUP_AVAIL); | 98 | BTRFS_BLOCK_GROUP_AVAIL); |
47 | if (!ret) | 99 | if (!ret) |
@@ -49,65 +101,54 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
49 | for (i = 0; i < ret; i++) { | 101 | for (i = 0; i < ret; i++) { |
50 | last = cache[i]->key.objectid + | 102 | last = cache[i]->key.objectid + |
51 | cache[i]->key.offset; | 103 | cache[i]->key.offset; |
52 | if (!full_search && !data && | ||
53 | (cache[i]->key.objectid & cache[i]->key.offset)) | ||
54 | continue; | ||
55 | if (!full_search && data && | ||
56 | (cache[i]->key.objectid & cache[i]->key.offset) == 0) | ||
57 | continue; | ||
58 | used = btrfs_block_group_used(&cache[i]->item); | 104 | used = btrfs_block_group_used(&cache[i]->item); |
59 | if (used < (cache[i]->key.offset * 2) / 3) { | 105 | if (used + cache[i]->pinned < |
60 | info->block_group_cache = cache[i]; | 106 | (cache[i]->key.offset * 8) / 10) { |
61 | found_group = cache[i]; | 107 | found_group = cache[i]; |
62 | goto found; | 108 | goto found; |
63 | } | 109 | } |
64 | radix_tree_tag_clear(&info->block_group_radix, | 110 | if (used >= (cache[i]->key.offset * 8) / 10) { |
65 | cache[i]->key.objectid + | 111 | radix_tree_tag_clear(radix, |
66 | cache[i]->key.offset - 1, | 112 | cache[i]->key.objectid + |
67 | BTRFS_BLOCK_GROUP_AVAIL); | 113 | cache[i]->key.offset - 1, |
114 | BTRFS_BLOCK_GROUP_AVAIL); | ||
115 | } | ||
68 | } | 116 | } |
69 | } | 117 | } |
70 | last = hint_last; | 118 | last = hint_last; |
71 | again: | 119 | again: |
72 | while(1) { | 120 | while(1) { |
73 | ret = radix_tree_gang_lookup(&info->block_group_radix, | 121 | ret = radix_tree_gang_lookup(radix, (void **)cache, |
74 | (void **)cache, | 122 | last, ARRAY_SIZE(cache)); |
75 | last, ARRAY_SIZE(cache)); | ||
76 | if (!ret) | 123 | if (!ret) |
77 | break; | 124 | break; |
78 | for (i = 0; i < ret; i++) { | 125 | for (i = 0; i < ret; i++) { |
79 | last = cache[i]->key.objectid + | 126 | last = cache[i]->key.objectid + |
80 | cache[i]->key.offset; | 127 | cache[i]->key.offset; |
81 | if (!full_search && !data && | ||
82 | (cache[i]->key.objectid & cache[i]->key.offset)) | ||
83 | continue; | ||
84 | if (!full_search && data && | ||
85 | (cache[i]->key.objectid & cache[i]->key.offset) == 0) | ||
86 | continue; | ||
87 | used = btrfs_block_group_used(&cache[i]->item); | 128 | used = btrfs_block_group_used(&cache[i]->item); |
88 | if (used < cache[i]->key.offset) { | 129 | if (used + cache[i]->pinned < cache[i]->key.offset) { |
89 | info->block_group_cache = cache[i]; | ||
90 | found_group = cache[i]; | 130 | found_group = cache[i]; |
91 | goto found; | 131 | goto found; |
92 | } | 132 | } |
93 | radix_tree_tag_clear(&info->block_group_radix, | 133 | if (used >= cache[i]->key.offset) { |
94 | cache[i]->key.objectid + | 134 | radix_tree_tag_clear(radix, |
95 | cache[i]->key.offset - 1, | 135 | cache[i]->key.objectid + |
96 | BTRFS_BLOCK_GROUP_AVAIL); | 136 | cache[i]->key.offset - 1, |
137 | BTRFS_BLOCK_GROUP_AVAIL); | ||
138 | } | ||
97 | } | 139 | } |
98 | } | 140 | } |
99 | info->block_group_cache = NULL; | ||
100 | if (!full_search) { | 141 | if (!full_search) { |
101 | last = 0; | 142 | last = search_start; |
102 | full_search = 1; | 143 | full_search = 1; |
103 | goto again; | 144 | goto again; |
104 | } | 145 | } |
105 | found: | ||
106 | if (!found_group) { | 146 | if (!found_group) { |
107 | ret = radix_tree_gang_lookup(&info->block_group_radix, | 147 | ret = radix_tree_gang_lookup(radix, |
108 | (void **)&found_group, 0, 1); | 148 | (void **)&found_group, 0, 1); |
109 | BUG_ON(ret != 1); | 149 | BUG_ON(ret != 1); |
110 | } | 150 | } |
151 | found: | ||
111 | return found_group; | 152 | return found_group; |
112 | } | 153 | } |
113 | 154 | ||
@@ -252,18 +293,20 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans, | |||
252 | return ret; | 293 | return ret; |
253 | if (pending_ret) | 294 | if (pending_ret) |
254 | return pending_ret; | 295 | return pending_ret; |
296 | if (cache->data) | ||
297 | cache->last_alloc = cache->first_free; | ||
255 | return 0; | 298 | return 0; |
256 | 299 | ||
257 | } | 300 | } |
258 | 301 | ||
259 | int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | 302 | static int write_dirty_block_radix(struct btrfs_trans_handle *trans, |
260 | struct btrfs_root *root) | 303 | struct btrfs_root *root, |
304 | struct radix_tree_root *radix) | ||
261 | { | 305 | { |
262 | struct btrfs_block_group_cache *cache[8]; | 306 | struct btrfs_block_group_cache *cache[8]; |
263 | int ret; | 307 | int ret; |
264 | int err = 0; | 308 | int err = 0; |
265 | int werr = 0; | 309 | int werr = 0; |
266 | struct radix_tree_root *radix = &root->fs_info->block_group_radix; | ||
267 | int i; | 310 | int i; |
268 | struct btrfs_path *path; | 311 | struct btrfs_path *path; |
269 | 312 | ||
@@ -285,35 +328,74 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | |||
285 | path, cache[i]); | 328 | path, cache[i]); |
286 | if (err) | 329 | if (err) |
287 | werr = err; | 330 | werr = err; |
288 | cache[i]->last_alloc = cache[i]->first_free; | ||
289 | } | 331 | } |
290 | } | 332 | } |
291 | btrfs_free_path(path); | 333 | btrfs_free_path(path); |
292 | return werr; | 334 | return werr; |
293 | } | 335 | } |
294 | 336 | ||
337 | int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | ||
338 | struct btrfs_root *root) | ||
339 | { | ||
340 | int ret; | ||
341 | int ret2; | ||
342 | ret = write_dirty_block_radix(trans, root, | ||
343 | &root->fs_info->block_group_radix); | ||
344 | ret2 = write_dirty_block_radix(trans, root, | ||
345 | &root->fs_info->block_group_data_radix); | ||
346 | if (ret) | ||
347 | return ret; | ||
348 | if (ret2) | ||
349 | return ret2; | ||
350 | return 0; | ||
351 | } | ||
352 | |||
295 | static int update_block_group(struct btrfs_trans_handle *trans, | 353 | static int update_block_group(struct btrfs_trans_handle *trans, |
296 | struct btrfs_root *root, | 354 | struct btrfs_root *root, |
297 | u64 blocknr, u64 num, int alloc) | 355 | u64 blocknr, u64 num, int alloc) |
298 | { | 356 | { |
299 | struct btrfs_block_group_cache *cache; | 357 | struct btrfs_block_group_cache *cache; |
300 | struct btrfs_fs_info *info = root->fs_info; | 358 | struct btrfs_fs_info *info = root->fs_info; |
359 | struct radix_tree_root *radix; | ||
301 | u64 total = num; | 360 | u64 total = num; |
302 | u64 old_val; | 361 | u64 old_val; |
303 | u64 block_in_group; | 362 | u64 block_in_group; |
304 | int ret; | 363 | int ret; |
364 | if (num != 1) | ||
365 | radix = &info->block_group_data_radix; | ||
366 | else | ||
367 | radix = &info->block_group_radix; | ||
305 | while(total) { | 368 | while(total) { |
306 | ret = radix_tree_gang_lookup(&info->block_group_radix, | 369 | ret = radix_tree_gang_lookup(radix, (void **)&cache, |
307 | (void **)&cache, blocknr, 1); | 370 | blocknr, 1); |
308 | if (!ret) { | 371 | if (!ret) { |
309 | printk(KERN_CRIT "blocknr %Lu lookup failed\n", | 372 | printk(KERN_CRIT "blocknr %Lu lookup failed\n", |
310 | blocknr); | 373 | blocknr); |
311 | return -1; | 374 | return -1; |
312 | } | 375 | } |
313 | block_in_group = blocknr - cache->key.objectid; | 376 | block_in_group = blocknr - cache->key.objectid; |
377 | if (block_in_group > cache->key.offset || cache->key.objectid > | ||
378 | blocknr) { | ||
379 | if (radix == &info->block_group_data_radix) | ||
380 | radix = &info->block_group_radix; | ||
381 | else | ||
382 | radix = &info->block_group_data_radix; | ||
383 | ret = radix_tree_gang_lookup(radix, (void **)&cache, | ||
384 | blocknr, 1); | ||
385 | if (!ret) { | ||
386 | printk(KERN_CRIT "blocknr %Lu lookup failed\n", | ||
387 | blocknr); | ||
388 | return -1; | ||
389 | } | ||
390 | block_in_group = blocknr - cache->key.objectid; | ||
391 | if (block_in_group > cache->key.offset || | ||
392 | cache->key.objectid > blocknr) { | ||
393 | BUG(); | ||
394 | } | ||
395 | } | ||
314 | WARN_ON(block_in_group > cache->key.offset); | 396 | WARN_ON(block_in_group > cache->key.offset); |
315 | radix_tree_tag_set(&info->block_group_radix, | 397 | radix_tree_tag_set(radix, cache->key.objectid + |
316 | cache->key.objectid + cache->key.offset - 1, | 398 | cache->key.offset - 1, |
317 | BTRFS_BLOCK_GROUP_DIRTY); | 399 | BTRFS_BLOCK_GROUP_DIRTY); |
318 | 400 | ||
319 | old_val = btrfs_block_group_used(&cache->item); | 401 | old_val = btrfs_block_group_used(&cache->item); |
@@ -346,6 +428,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | |||
346 | { | 428 | { |
347 | unsigned long gang[8]; | 429 | unsigned long gang[8]; |
348 | struct inode *btree_inode = root->fs_info->btree_inode; | 430 | struct inode *btree_inode = root->fs_info->btree_inode; |
431 | struct btrfs_block_group_cache *block_group; | ||
349 | u64 first = 0; | 432 | u64 first = 0; |
350 | int ret; | 433 | int ret; |
351 | int i; | 434 | int i; |
@@ -360,6 +443,14 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | |||
360 | first = gang[0]; | 443 | first = gang[0]; |
361 | for (i = 0; i < ret; i++) { | 444 | for (i = 0; i < ret; i++) { |
362 | clear_radix_bit(pinned_radix, gang[i]); | 445 | clear_radix_bit(pinned_radix, gang[i]); |
446 | block_group = lookup_block_group(root->fs_info, | ||
447 | gang[i]); | ||
448 | if (block_group) { | ||
449 | WARN_ON(block_group->pinned == 0); | ||
450 | block_group->pinned--; | ||
451 | if (gang[i] < block_group->last_alloc) | ||
452 | block_group->last_alloc = gang[i]; | ||
453 | } | ||
363 | try_remove_page(btree_inode->i_mapping, | 454 | try_remove_page(btree_inode->i_mapping, |
364 | gang[i] << (PAGE_CACHE_SHIFT - | 455 | gang[i] << (PAGE_CACHE_SHIFT - |
365 | btree_inode->i_blkbits)); | 456 | btree_inode->i_blkbits)); |
@@ -420,10 +511,16 @@ static int pin_down_block(struct btrfs_root *root, u64 blocknr, int pending) | |||
420 | btrfs_block_release(root, bh); | 511 | btrfs_block_release(root, bh); |
421 | } | 512 | } |
422 | err = set_radix_bit(&root->fs_info->pinned_radix, blocknr); | 513 | err = set_radix_bit(&root->fs_info->pinned_radix, blocknr); |
514 | if (!err) { | ||
515 | struct btrfs_block_group_cache *cache; | ||
516 | cache = lookup_block_group(root->fs_info, blocknr); | ||
517 | if (cache) | ||
518 | cache->pinned++; | ||
519 | } | ||
423 | } else { | 520 | } else { |
424 | err = set_radix_bit(&root->fs_info->pending_del_radix, blocknr); | 521 | err = set_radix_bit(&root->fs_info->pending_del_radix, blocknr); |
425 | } | 522 | } |
426 | BUG_ON(err); | 523 | BUG_ON(err < 0); |
427 | return 0; | 524 | return 0; |
428 | } | 525 | } |
429 | 526 | ||
@@ -502,6 +599,7 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct | |||
502 | int i; | 599 | int i; |
503 | struct radix_tree_root *pending_radix; | 600 | struct radix_tree_root *pending_radix; |
504 | struct radix_tree_root *pinned_radix; | 601 | struct radix_tree_root *pinned_radix; |
602 | struct btrfs_block_group_cache *cache; | ||
505 | 603 | ||
506 | pending_radix = &extent_root->fs_info->pending_del_radix; | 604 | pending_radix = &extent_root->fs_info->pending_del_radix; |
507 | pinned_radix = &extent_root->fs_info->pinned_radix; | 605 | pinned_radix = &extent_root->fs_info->pinned_radix; |
@@ -513,7 +611,17 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct | |||
513 | break; | 611 | break; |
514 | for (i = 0; i < ret; i++) { | 612 | for (i = 0; i < ret; i++) { |
515 | wret = set_radix_bit(pinned_radix, gang[i]); | 613 | wret = set_radix_bit(pinned_radix, gang[i]); |
516 | BUG_ON(wret); | 614 | if (wret == 0) { |
615 | cache = lookup_block_group(extent_root->fs_info, | ||
616 | gang[i]); | ||
617 | if (cache) | ||
618 | cache->pinned++; | ||
619 | } | ||
620 | if (wret < 0) { | ||
621 | printk(KERN_CRIT "set_radix_bit, err %d\n", | ||
622 | wret); | ||
623 | BUG_ON(wret < 0); | ||
624 | } | ||
517 | wret = clear_radix_bit(pending_radix, gang[i]); | 625 | wret = clear_radix_bit(pending_radix, gang[i]); |
518 | BUG_ON(wret); | 626 | BUG_ON(wret); |
519 | wret = __free_extent(trans, extent_root, | 627 | wret = __free_extent(trans, extent_root, |
@@ -563,6 +671,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
563 | int slot = 0; | 671 | int slot = 0; |
564 | u64 last_block = 0; | 672 | u64 last_block = 0; |
565 | u64 test_block; | 673 | u64 test_block; |
674 | u64 orig_search_start = search_start; | ||
566 | int start_found; | 675 | int start_found; |
567 | struct btrfs_leaf *l; | 676 | struct btrfs_leaf *l; |
568 | struct btrfs_root * root = orig_root->fs_info->extent_root; | 677 | struct btrfs_root * root = orig_root->fs_info->extent_root; |
@@ -572,6 +681,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
572 | int fill_prealloc = 0; | 681 | int fill_prealloc = 0; |
573 | int level; | 682 | int level; |
574 | struct btrfs_block_group_cache *block_group; | 683 | struct btrfs_block_group_cache *block_group; |
684 | int full_scan = 0; | ||
575 | 685 | ||
576 | path = btrfs_alloc_path(); | 686 | path = btrfs_alloc_path(); |
577 | ins->flags = 0; | 687 | ins->flags = 0; |
@@ -583,10 +693,21 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
583 | num_blocks = 1; | 693 | num_blocks = 1; |
584 | total_needed = (min(level + 1, BTRFS_MAX_LEVEL) + 2) * 3; | 694 | total_needed = (min(level + 1, BTRFS_MAX_LEVEL) + 2) * 3; |
585 | } | 695 | } |
586 | block_group = btrfs_find_block_group(root, trans->block_group, data); | 696 | if (search_start) { |
697 | block_group = lookup_block_group(info, search_start); | ||
698 | block_group = btrfs_find_block_group(root, block_group, | ||
699 | search_start, data); | ||
700 | } else { | ||
701 | block_group = btrfs_find_block_group(root, | ||
702 | trans->block_group, 0, | ||
703 | data); | ||
704 | } | ||
705 | |||
706 | check_failed: | ||
707 | if (block_group->data != data) | ||
708 | WARN_ON(1); | ||
587 | if (block_group->last_alloc > search_start) | 709 | if (block_group->last_alloc > search_start) |
588 | search_start = block_group->last_alloc; | 710 | search_start = block_group->last_alloc; |
589 | check_failed: | ||
590 | btrfs_init_path(path); | 711 | btrfs_init_path(path); |
591 | ins->objectid = search_start; | 712 | ins->objectid = search_start; |
592 | ins->offset = 0; | 713 | ins->offset = 0; |
@@ -639,6 +760,13 @@ check_failed: | |||
639 | } | 760 | } |
640 | start_found = 1; | 761 | start_found = 1; |
641 | last_block = key.objectid + key.offset; | 762 | last_block = key.objectid + key.offset; |
763 | if (last_block >= block_group->key.objectid + | ||
764 | block_group->key.offset) { | ||
765 | btrfs_release_path(root, path); | ||
766 | search_start = block_group->key.objectid + | ||
767 | block_group->key.offset * 2; | ||
768 | goto new_group; | ||
769 | } | ||
642 | next: | 770 | next: |
643 | path->slots[0]++; | 771 | path->slots[0]++; |
644 | } | 772 | } |
@@ -650,16 +778,17 @@ check_pending: | |||
650 | btrfs_release_path(root, path); | 778 | btrfs_release_path(root, path); |
651 | BUG_ON(ins->objectid < search_start); | 779 | BUG_ON(ins->objectid < search_start); |
652 | if (ins->objectid >= btrfs_super_total_blocks(info->disk_super)) { | 780 | if (ins->objectid >= btrfs_super_total_blocks(info->disk_super)) { |
653 | if (search_start == 0) | 781 | if (full_scan) |
654 | return -ENOSPC; | 782 | return -ENOSPC; |
655 | search_start = 0; | 783 | search_start = orig_search_start; |
656 | goto check_failed; | 784 | full_scan = 1; |
785 | goto new_group; | ||
657 | } | 786 | } |
658 | for (test_block = ins->objectid; | 787 | for (test_block = ins->objectid; |
659 | test_block < ins->objectid + num_blocks; test_block++) { | 788 | test_block < ins->objectid + num_blocks; test_block++) { |
660 | if (test_radix_bit(&info->pinned_radix, test_block)) { | 789 | if (test_radix_bit(&info->pinned_radix, test_block)) { |
661 | search_start = test_block + 1; | 790 | search_start = test_block + 1; |
662 | goto check_failed; | 791 | goto new_group; |
663 | } | 792 | } |
664 | } | 793 | } |
665 | if (!fill_prealloc && info->extent_tree_insert_nr) { | 794 | if (!fill_prealloc && info->extent_tree_insert_nr) { |
@@ -670,7 +799,7 @@ check_pending: | |||
670 | ins->objectid <= last) { | 799 | ins->objectid <= last) { |
671 | search_start = last + 1; | 800 | search_start = last + 1; |
672 | WARN_ON(1); | 801 | WARN_ON(1); |
673 | goto check_failed; | 802 | goto new_group; |
674 | } | 803 | } |
675 | } | 804 | } |
676 | if (!fill_prealloc && info->extent_tree_prealloc_nr) { | 805 | if (!fill_prealloc && info->extent_tree_prealloc_nr) { |
@@ -680,7 +809,7 @@ check_pending: | |||
680 | ins->objectid <= info->extent_tree_prealloc[0]) { | 809 | ins->objectid <= info->extent_tree_prealloc[0]) { |
681 | search_start = info->extent_tree_prealloc[0] + 1; | 810 | search_start = info->extent_tree_prealloc[0] + 1; |
682 | WARN_ON(1); | 811 | WARN_ON(1); |
683 | goto check_failed; | 812 | goto new_group; |
684 | } | 813 | } |
685 | } | 814 | } |
686 | if (fill_prealloc) { | 815 | if (fill_prealloc) { |
@@ -696,14 +825,12 @@ check_pending: | |||
696 | } | 825 | } |
697 | if (total_found < total_needed) { | 826 | if (total_found < total_needed) { |
698 | search_start = test_block; | 827 | search_start = test_block; |
699 | goto check_failed; | 828 | goto new_group; |
700 | } | 829 | } |
701 | info->extent_tree_prealloc_nr = total_found; | 830 | info->extent_tree_prealloc_nr = total_found; |
702 | } | 831 | } |
703 | ret = radix_tree_gang_lookup(&info->block_group_radix, | 832 | block_group = lookup_block_group(info, ins->objectid); |
704 | (void **)&block_group, | 833 | if (block_group) { |
705 | ins->objectid, 1); | ||
706 | if (ret) { | ||
707 | block_group->last_alloc = ins->objectid; | 834 | block_group->last_alloc = ins->objectid; |
708 | if (!data) | 835 | if (!data) |
709 | trans->block_group = block_group; | 836 | trans->block_group = block_group; |
@@ -711,6 +838,18 @@ check_pending: | |||
711 | ins->offset = num_blocks; | 838 | ins->offset = num_blocks; |
712 | btrfs_free_path(path); | 839 | btrfs_free_path(path); |
713 | return 0; | 840 | return 0; |
841 | |||
842 | new_group: | ||
843 | if (search_start >= btrfs_super_total_blocks(info->disk_super)) { | ||
844 | search_start = orig_search_start; | ||
845 | full_scan = 1; | ||
846 | } | ||
847 | block_group = lookup_block_group(info, search_start); | ||
848 | if (!full_scan) | ||
849 | block_group = btrfs_find_block_group(root, block_group, | ||
850 | search_start, data); | ||
851 | goto check_failed; | ||
852 | |||
714 | error: | 853 | error: |
715 | btrfs_release_path(root, path); | 854 | btrfs_release_path(root, path); |
716 | btrfs_free_path(path); | 855 | btrfs_free_path(path); |
@@ -794,7 +933,7 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
794 | struct buffer_head *buf; | 933 | struct buffer_head *buf; |
795 | 934 | ||
796 | ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, | 935 | ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, |
797 | 1, 0, (unsigned long)-1, &ins, 0); | 936 | 1, hint, (unsigned long)-1, &ins, 0); |
798 | if (ret) { | 937 | if (ret) { |
799 | BUG(); | 938 | BUG(); |
800 | return NULL; | 939 | return NULL; |
@@ -984,21 +1123,19 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
984 | return ret; | 1123 | return ret; |
985 | } | 1124 | } |
986 | 1125 | ||
987 | int btrfs_free_block_groups(struct btrfs_fs_info *info) | 1126 | static int free_block_group_radix(struct radix_tree_root *radix) |
988 | { | 1127 | { |
989 | int ret; | 1128 | int ret; |
990 | struct btrfs_block_group_cache *cache[8]; | 1129 | struct btrfs_block_group_cache *cache[8]; |
991 | int i; | 1130 | int i; |
992 | 1131 | ||
993 | while(1) { | 1132 | while(1) { |
994 | ret = radix_tree_gang_lookup(&info->block_group_radix, | 1133 | ret = radix_tree_gang_lookup(radix, (void **)cache, 0, |
995 | (void **)cache, 0, | ||
996 | ARRAY_SIZE(cache)); | 1134 | ARRAY_SIZE(cache)); |
997 | if (!ret) | 1135 | if (!ret) |
998 | break; | 1136 | break; |
999 | for (i = 0; i < ret; i++) { | 1137 | for (i = 0; i < ret; i++) { |
1000 | radix_tree_delete(&info->block_group_radix, | 1138 | radix_tree_delete(radix, cache[i]->key.objectid + |
1001 | cache[i]->key.objectid + | ||
1002 | cache[i]->key.offset - 1); | 1139 | cache[i]->key.offset - 1); |
1003 | kfree(cache[i]); | 1140 | kfree(cache[i]); |
1004 | } | 1141 | } |
@@ -1006,6 +1143,20 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) | |||
1006 | return 0; | 1143 | return 0; |
1007 | } | 1144 | } |
1008 | 1145 | ||
1146 | int btrfs_free_block_groups(struct btrfs_fs_info *info) | ||
1147 | { | ||
1148 | int ret; | ||
1149 | int ret2; | ||
1150 | |||
1151 | ret = free_block_group_radix(&info->block_group_radix); | ||
1152 | ret2 = free_block_group_radix(&info->block_group_data_radix); | ||
1153 | if (ret) | ||
1154 | return ret; | ||
1155 | if (ret2) | ||
1156 | return ret2; | ||
1157 | return 0; | ||
1158 | } | ||
1159 | |||
1009 | int btrfs_read_block_groups(struct btrfs_root *root) | 1160 | int btrfs_read_block_groups(struct btrfs_root *root) |
1010 | { | 1161 | { |
1011 | struct btrfs_path *path; | 1162 | struct btrfs_path *path; |
@@ -1013,13 +1164,16 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
1013 | int err = 0; | 1164 | int err = 0; |
1014 | struct btrfs_block_group_item *bi; | 1165 | struct btrfs_block_group_item *bi; |
1015 | struct btrfs_block_group_cache *cache; | 1166 | struct btrfs_block_group_cache *cache; |
1167 | struct btrfs_fs_info *info = root->fs_info; | ||
1168 | struct radix_tree_root *radix; | ||
1016 | struct btrfs_key key; | 1169 | struct btrfs_key key; |
1017 | struct btrfs_key found_key; | 1170 | struct btrfs_key found_key; |
1018 | struct btrfs_leaf *leaf; | 1171 | struct btrfs_leaf *leaf; |
1019 | u64 group_size_blocks = BTRFS_BLOCK_GROUP_SIZE / root->blocksize; | 1172 | u64 group_size_blocks = BTRFS_BLOCK_GROUP_SIZE / root->blocksize; |
1020 | u64 used; | 1173 | u64 used; |
1174 | u64 nr = 0; | ||
1021 | 1175 | ||
1022 | root = root->fs_info->extent_root; | 1176 | root = info->extent_root; |
1023 | key.objectid = 0; | 1177 | key.objectid = 0; |
1024 | key.offset = group_size_blocks; | 1178 | key.offset = group_size_blocks; |
1025 | key.flags = 0; | 1179 | key.flags = 0; |
@@ -1030,7 +1184,7 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
1030 | return -ENOMEM; | 1184 | return -ENOMEM; |
1031 | 1185 | ||
1032 | while(1) { | 1186 | while(1) { |
1033 | ret = btrfs_search_slot(NULL, root->fs_info->extent_root, | 1187 | ret = btrfs_search_slot(NULL, info->extent_root, |
1034 | &key, path, 0, 0); | 1188 | &key, path, 0, 0); |
1035 | if (ret != 0) { | 1189 | if (ret != 0) { |
1036 | err = ret; | 1190 | err = ret; |
@@ -1050,23 +1204,28 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
1050 | memcpy(&cache->key, &found_key, sizeof(found_key)); | 1204 | memcpy(&cache->key, &found_key, sizeof(found_key)); |
1051 | cache->last_alloc = cache->key.objectid; | 1205 | cache->last_alloc = cache->key.objectid; |
1052 | cache->first_free = cache->key.objectid; | 1206 | cache->first_free = cache->key.objectid; |
1207 | cache->pinned = 0; | ||
1208 | cache->data = (nr & 1); | ||
1053 | key.objectid = found_key.objectid + found_key.offset; | 1209 | key.objectid = found_key.objectid + found_key.offset; |
1054 | btrfs_release_path(root, path); | 1210 | btrfs_release_path(root, path); |
1055 | ret = radix_tree_insert(&root->fs_info->block_group_radix, | 1211 | if (nr & 1) |
1056 | found_key.objectid + | 1212 | radix = &info->block_group_data_radix; |
1213 | else | ||
1214 | radix = &info->block_group_radix; | ||
1215 | ret = radix_tree_insert(radix, found_key.objectid + | ||
1057 | found_key.offset - 1, | 1216 | found_key.offset - 1, |
1058 | (void *)cache); | 1217 | (void *)cache); |
1059 | BUG_ON(ret); | 1218 | BUG_ON(ret); |
1060 | used = btrfs_block_group_used(bi); | 1219 | used = btrfs_block_group_used(bi); |
1061 | if (used < (key.offset * 2) / 3) { | 1220 | if (used < (key.offset * 8) / 10) { |
1062 | radix_tree_tag_set(&root->fs_info->block_group_radix, | 1221 | radix_tree_tag_set(radix, found_key.objectid + |
1063 | found_key.objectid + | ||
1064 | found_key.offset - 1, | 1222 | found_key.offset - 1, |
1065 | BTRFS_BLOCK_GROUP_AVAIL); | 1223 | BTRFS_BLOCK_GROUP_AVAIL); |
1066 | } | 1224 | } |
1067 | if (key.objectid >= | 1225 | if (key.objectid >= |
1068 | btrfs_super_total_blocks(root->fs_info->disk_super)) | 1226 | btrfs_super_total_blocks(info->disk_super)) |
1069 | break; | 1227 | break; |
1228 | nr++; | ||
1070 | } | 1229 | } |
1071 | 1230 | ||
1072 | btrfs_free_path(path); | 1231 | btrfs_free_path(path); |