diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-10-15 16:15:19 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:56 -0400 |
commit | 96b5179d0d9b6368c203856f2ad6e8e12a8b2a2c (patch) | |
tree | 58b22f106bb06902c280c66af661d9e9d6a65597 /fs/btrfs/extent-tree.c | |
parent | f510cfecfc98759d75283823cfccf0cc0d59a4c6 (diff) |
Btrfs: Stop using radix trees for the block group cache
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 | 362 |
1 files changed, 148 insertions, 214 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 74cfbee2ff33..4bc639565d1c 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -22,6 +22,10 @@ | |||
22 | #include "print-tree.h" | 22 | #include "print-tree.h" |
23 | #include "transaction.h" | 23 | #include "transaction.h" |
24 | 24 | ||
25 | #define BLOCK_GROUP_DATA EXTENT_WRITEBACK | ||
26 | #define BLOCK_GROUP_METADATA EXTENT_UPTODATE | ||
27 | #define BLOCK_GROUP_DIRTY EXTENT_DIRTY | ||
28 | |||
25 | static int finish_current_insert(struct btrfs_trans_handle *trans, struct | 29 | static int finish_current_insert(struct btrfs_trans_handle *trans, struct |
26 | btrfs_root *extent_root); | 30 | btrfs_root *extent_root); |
27 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct | 31 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct |
@@ -127,25 +131,31 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(struct | |||
127 | btrfs_fs_info *info, | 131 | btrfs_fs_info *info, |
128 | u64 blocknr) | 132 | u64 blocknr) |
129 | { | 133 | { |
130 | struct btrfs_block_group_cache *block_group; | 134 | struct extent_map_tree *block_group_cache; |
135 | struct btrfs_block_group_cache *block_group = NULL; | ||
136 | u64 ptr; | ||
137 | u64 start; | ||
138 | u64 end; | ||
131 | int ret; | 139 | int ret; |
132 | 140 | ||
133 | ret = radix_tree_gang_lookup(&info->block_group_radix, | 141 | block_group_cache = &info->block_group_cache; |
134 | (void **)&block_group, | 142 | ret = find_first_extent_bit(block_group_cache, |
135 | blocknr, 1); | 143 | blocknr, &start, &end, |
144 | BLOCK_GROUP_DATA | BLOCK_GROUP_METADATA); | ||
136 | if (ret) { | 145 | if (ret) { |
137 | if (block_group->key.objectid <= blocknr && blocknr <= | 146 | return NULL; |
138 | block_group->key.objectid + block_group->key.offset) | ||
139 | return block_group; | ||
140 | } | ||
141 | ret = radix_tree_gang_lookup(&info->block_group_data_radix, | ||
142 | (void **)&block_group, | ||
143 | blocknr, 1); | ||
144 | if (ret) { | ||
145 | if (block_group->key.objectid <= blocknr && blocknr <= | ||
146 | block_group->key.objectid + block_group->key.offset) | ||
147 | return block_group; | ||
148 | } | 147 | } |
148 | ret = get_state_private(block_group_cache, start, &ptr); | ||
149 | if (ret) | ||
150 | return NULL; | ||
151 | |||
152 | block_group = (struct btrfs_block_group_cache *)ptr; | ||
153 | |||
154 | |||
155 | if (block_group->key.objectid <= blocknr && blocknr <= | ||
156 | block_group->key.objectid + block_group->key.offset) | ||
157 | return block_group; | ||
158 | |||
149 | return NULL; | 159 | return NULL; |
150 | } | 160 | } |
151 | 161 | ||
@@ -173,7 +183,7 @@ again: | |||
173 | last = end + 1; | 183 | last = end + 1; |
174 | if (end + 1 - start < num) | 184 | if (end + 1 - start < num) |
175 | continue; | 185 | continue; |
176 | if (start + num > cache->key.objectid + cache->key.offset) | 186 | if (start + num >= cache->key.objectid + cache->key.offset) |
177 | goto new_group; | 187 | goto new_group; |
178 | return start; | 188 | return start; |
179 | } | 189 | } |
@@ -189,6 +199,7 @@ new_group: | |||
189 | cache = btrfs_find_block_group(root, cache, | 199 | cache = btrfs_find_block_group(root, cache, |
190 | last + cache->key.offset - 1, data, 0); | 200 | last + cache->key.offset - 1, data, 0); |
191 | *cache_ret = cache; | 201 | *cache_ret = cache; |
202 | last = min(cache->key.objectid, last); | ||
192 | goto again; | 203 | goto again; |
193 | } | 204 | } |
194 | 205 | ||
@@ -204,30 +215,32 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
204 | *hint, u64 search_start, | 215 | *hint, u64 search_start, |
205 | int data, int owner) | 216 | int data, int owner) |
206 | { | 217 | { |
207 | struct btrfs_block_group_cache *cache[8]; | 218 | struct btrfs_block_group_cache *cache; |
219 | struct extent_map_tree *block_group_cache; | ||
208 | struct btrfs_block_group_cache *found_group = NULL; | 220 | struct btrfs_block_group_cache *found_group = NULL; |
209 | struct btrfs_fs_info *info = root->fs_info; | 221 | struct btrfs_fs_info *info = root->fs_info; |
210 | struct radix_tree_root *radix; | ||
211 | struct radix_tree_root *swap_radix; | ||
212 | u64 used; | 222 | u64 used; |
213 | u64 last = 0; | 223 | u64 last = 0; |
214 | u64 hint_last; | 224 | u64 hint_last; |
215 | int i; | 225 | u64 start; |
226 | u64 end; | ||
227 | u64 free_check; | ||
228 | u64 ptr; | ||
229 | int bit; | ||
216 | int ret; | 230 | int ret; |
217 | int full_search = 0; | 231 | int full_search = 0; |
218 | int factor = 8; | 232 | int factor = 8; |
219 | int data_swap = 0; | 233 | int data_swap = 0; |
220 | 234 | ||
235 | block_group_cache = &info->block_group_cache; | ||
236 | |||
221 | if (!owner) | 237 | if (!owner) |
222 | factor = 5; | 238 | factor = 5; |
223 | 239 | ||
224 | if (data) { | 240 | if (data) |
225 | radix = &info->block_group_data_radix; | 241 | bit = BLOCK_GROUP_DATA; |
226 | swap_radix = &info->block_group_radix; | 242 | else |
227 | } else { | 243 | bit = BLOCK_GROUP_METADATA; |
228 | radix = &info->block_group_radix; | ||
229 | swap_radix = &info->block_group_data_radix; | ||
230 | } | ||
231 | 244 | ||
232 | if (search_start) { | 245 | if (search_start) { |
233 | struct btrfs_block_group_cache *shint; | 246 | struct btrfs_block_group_cache *shint; |
@@ -246,12 +259,6 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
246 | div_factor(hint->key.offset, factor)) { | 259 | div_factor(hint->key.offset, factor)) { |
247 | return hint; | 260 | return hint; |
248 | } | 261 | } |
249 | if (used >= div_factor(hint->key.offset, 8)) { | ||
250 | radix_tree_tag_clear(radix, | ||
251 | hint->key.objectid + | ||
252 | hint->key.offset - 1, | ||
253 | BTRFS_BLOCK_GROUP_AVAIL); | ||
254 | } | ||
255 | last = hint->key.offset * 3; | 262 | last = hint->key.offset * 3; |
256 | if (hint->key.objectid >= last) | 263 | if (hint->key.objectid >= last) |
257 | last = max(search_start + hint->key.offset - 1, | 264 | last = max(search_start + hint->key.offset - 1, |
@@ -267,51 +274,29 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
267 | 274 | ||
268 | last = hint_last; | 275 | last = hint_last; |
269 | } | 276 | } |
270 | while(1) { | ||
271 | ret = radix_tree_gang_lookup_tag(radix, (void **)cache, | ||
272 | last, ARRAY_SIZE(cache), | ||
273 | BTRFS_BLOCK_GROUP_AVAIL); | ||
274 | if (!ret) | ||
275 | break; | ||
276 | for (i = 0; i < ret; i++) { | ||
277 | last = cache[i]->key.objectid + | ||
278 | cache[i]->key.offset; | ||
279 | used = btrfs_block_group_used(&cache[i]->item); | ||
280 | if (used + cache[i]->pinned < | ||
281 | div_factor(cache[i]->key.offset, factor)) { | ||
282 | found_group = cache[i]; | ||
283 | goto found; | ||
284 | } | ||
285 | if (used >= div_factor(cache[i]->key.offset, 8)) { | ||
286 | radix_tree_tag_clear(radix, | ||
287 | cache[i]->key.objectid + | ||
288 | cache[i]->key.offset - 1, | ||
289 | BTRFS_BLOCK_GROUP_AVAIL); | ||
290 | } | ||
291 | } | ||
292 | cond_resched(); | ||
293 | } | ||
294 | last = hint_last; | ||
295 | again: | 277 | again: |
296 | while(1) { | 278 | while(1) { |
297 | ret = radix_tree_gang_lookup(radix, (void **)cache, | 279 | ret = find_first_extent_bit(block_group_cache, last, |
298 | last, ARRAY_SIZE(cache)); | 280 | &start, &end, bit); |
299 | if (!ret) | 281 | if (ret) |
300 | break; | 282 | break; |
301 | for (i = 0; i < ret; i++) { | 283 | |
302 | last = cache[i]->key.objectid + | 284 | ret = get_state_private(block_group_cache, start, &ptr); |
303 | cache[i]->key.offset; | 285 | if (ret) |
304 | used = btrfs_block_group_used(&cache[i]->item); | 286 | break; |
305 | if (used + cache[i]->pinned < cache[i]->key.offset) { | 287 | |
306 | found_group = cache[i]; | 288 | cache = (struct btrfs_block_group_cache *)ptr; |
307 | goto found; | 289 | last = cache->key.objectid + cache->key.offset; |
308 | } | 290 | used = btrfs_block_group_used(&cache->item); |
309 | if (used >= cache[i]->key.offset) { | 291 | |
310 | radix_tree_tag_clear(radix, | 292 | if (full_search) |
311 | cache[i]->key.objectid + | 293 | free_check = cache->key.offset; |
312 | cache[i]->key.offset - 1, | 294 | else |
313 | BTRFS_BLOCK_GROUP_AVAIL); | 295 | free_check = div_factor(cache->key.offset, factor); |
314 | } | 296 | |
297 | if (used + cache->pinned < free_check) { | ||
298 | found_group = cache; | ||
299 | goto found; | ||
315 | } | 300 | } |
316 | cond_resched(); | 301 | cond_resched(); |
317 | } | 302 | } |
@@ -321,23 +306,11 @@ again: | |||
321 | goto again; | 306 | goto again; |
322 | } | 307 | } |
323 | if (!data_swap) { | 308 | if (!data_swap) { |
324 | struct radix_tree_root *tmp = radix; | ||
325 | data_swap = 1; | 309 | data_swap = 1; |
326 | radix = swap_radix; | 310 | bit = BLOCK_GROUP_DATA | BLOCK_GROUP_METADATA; |
327 | swap_radix = tmp; | ||
328 | last = search_start; | 311 | last = search_start; |
329 | goto again; | 312 | goto again; |
330 | } | 313 | } |
331 | if (!found_group) { | ||
332 | ret = radix_tree_gang_lookup(radix, | ||
333 | (void **)&found_group, 0, 1); | ||
334 | if (ret == 0) { | ||
335 | ret = radix_tree_gang_lookup(swap_radix, | ||
336 | (void **)&found_group, | ||
337 | 0, 1); | ||
338 | } | ||
339 | BUG_ON(ret != 1); | ||
340 | } | ||
341 | found: | 314 | found: |
342 | return found_group; | 315 | return found_group; |
343 | } | 316 | } |
@@ -538,68 +511,55 @@ fail: | |||
538 | 511 | ||
539 | } | 512 | } |
540 | 513 | ||
541 | static int write_dirty_block_radix(struct btrfs_trans_handle *trans, | 514 | int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, |
542 | struct btrfs_root *root, | 515 | struct btrfs_root *root) |
543 | struct radix_tree_root *radix) | ||
544 | { | 516 | { |
545 | struct btrfs_block_group_cache *cache[8]; | 517 | struct extent_map_tree *block_group_cache; |
518 | struct btrfs_block_group_cache *cache; | ||
546 | int ret; | 519 | int ret; |
547 | int err = 0; | 520 | int err = 0; |
548 | int werr = 0; | 521 | int werr = 0; |
549 | int i; | ||
550 | struct btrfs_path *path; | 522 | struct btrfs_path *path; |
551 | unsigned long off = 0; | 523 | u64 last = 0; |
524 | u64 start; | ||
525 | u64 end; | ||
526 | u64 ptr; | ||
552 | 527 | ||
528 | block_group_cache = &root->fs_info->block_group_cache; | ||
553 | path = btrfs_alloc_path(); | 529 | path = btrfs_alloc_path(); |
554 | if (!path) | 530 | if (!path) |
555 | return -ENOMEM; | 531 | return -ENOMEM; |
556 | 532 | ||
557 | while(1) { | 533 | while(1) { |
558 | ret = radix_tree_gang_lookup_tag(radix, (void **)cache, | 534 | ret = find_first_extent_bit(block_group_cache, last, |
559 | off, ARRAY_SIZE(cache), | 535 | &start, &end, BLOCK_GROUP_DIRTY); |
560 | BTRFS_BLOCK_GROUP_DIRTY); | 536 | if (ret) |
561 | if (!ret) | ||
562 | break; | 537 | break; |
563 | for (i = 0; i < ret; i++) { | ||
564 | err = write_one_cache_group(trans, root, | ||
565 | path, cache[i]); | ||
566 | /* | ||
567 | * if we fail to write the cache group, we want | ||
568 | * to keep it marked dirty in hopes that a later | ||
569 | * write will work | ||
570 | */ | ||
571 | if (err) { | ||
572 | werr = err; | ||
573 | off = cache[i]->key.objectid + | ||
574 | cache[i]->key.offset; | ||
575 | continue; | ||
576 | } | ||
577 | 538 | ||
578 | radix_tree_tag_clear(radix, cache[i]->key.objectid + | 539 | last = end + 1; |
579 | cache[i]->key.offset - 1, | 540 | ret = get_state_private(block_group_cache, start, &ptr); |
580 | BTRFS_BLOCK_GROUP_DIRTY); | 541 | if (ret) |
542 | break; | ||
543 | |||
544 | cache = (struct btrfs_block_group_cache *)ptr; | ||
545 | err = write_one_cache_group(trans, root, | ||
546 | path, cache); | ||
547 | /* | ||
548 | * if we fail to write the cache group, we want | ||
549 | * to keep it marked dirty in hopes that a later | ||
550 | * write will work | ||
551 | */ | ||
552 | if (err) { | ||
553 | werr = err; | ||
554 | continue; | ||
581 | } | 555 | } |
556 | clear_extent_bits(block_group_cache, start, end, | ||
557 | BLOCK_GROUP_DIRTY, GFP_NOFS); | ||
582 | } | 558 | } |
583 | btrfs_free_path(path); | 559 | btrfs_free_path(path); |
584 | return werr; | 560 | return werr; |
585 | } | 561 | } |
586 | 562 | ||
587 | int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | ||
588 | struct btrfs_root *root) | ||
589 | { | ||
590 | int ret; | ||
591 | int ret2; | ||
592 | ret = write_dirty_block_radix(trans, root, | ||
593 | &root->fs_info->block_group_radix); | ||
594 | ret2 = write_dirty_block_radix(trans, root, | ||
595 | &root->fs_info->block_group_data_radix); | ||
596 | if (ret) | ||
597 | return ret; | ||
598 | if (ret2) | ||
599 | return ret2; | ||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | static int update_block_group(struct btrfs_trans_handle *trans, | 563 | static int update_block_group(struct btrfs_trans_handle *trans, |
604 | struct btrfs_root *root, | 564 | struct btrfs_root *root, |
605 | u64 blocknr, u64 num, int alloc, int mark_free, | 565 | u64 blocknr, u64 num, int alloc, int mark_free, |
@@ -610,7 +570,8 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
610 | u64 total = num; | 570 | u64 total = num; |
611 | u64 old_val; | 571 | u64 old_val; |
612 | u64 block_in_group; | 572 | u64 block_in_group; |
613 | int ret; | 573 | u64 start; |
574 | u64 end; | ||
614 | 575 | ||
615 | while(total) { | 576 | while(total) { |
616 | cache = btrfs_lookup_block_group(info, blocknr); | 577 | cache = btrfs_lookup_block_group(info, blocknr); |
@@ -619,9 +580,10 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
619 | } | 580 | } |
620 | block_in_group = blocknr - cache->key.objectid; | 581 | block_in_group = blocknr - cache->key.objectid; |
621 | WARN_ON(block_in_group > cache->key.offset); | 582 | WARN_ON(block_in_group > cache->key.offset); |
622 | radix_tree_tag_set(cache->radix, cache->key.objectid + | 583 | start = cache->key.objectid; |
623 | cache->key.offset - 1, | 584 | end = start + cache->key.offset - 1; |
624 | BTRFS_BLOCK_GROUP_DIRTY); | 585 | set_extent_bits(&info->block_group_cache, start, end, |
586 | BLOCK_GROUP_DIRTY, GFP_NOFS); | ||
625 | 587 | ||
626 | old_val = btrfs_block_group_used(&cache->item); | 588 | old_val = btrfs_block_group_used(&cache->item); |
627 | num = min(total, cache->key.offset - block_in_group); | 589 | num = min(total, cache->key.offset - block_in_group); |
@@ -630,25 +592,27 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
630 | cache->last_alloc = blocknr; | 592 | cache->last_alloc = blocknr; |
631 | if (cache->data != data && | 593 | if (cache->data != data && |
632 | old_val < (cache->key.offset >> 1)) { | 594 | old_val < (cache->key.offset >> 1)) { |
633 | cache->data = data; | 595 | int bit_to_clear; |
634 | radix_tree_delete(cache->radix, | 596 | int bit_to_set; |
635 | cache->key.objectid + | ||
636 | cache->key.offset - 1); | ||
637 | 597 | ||
598 | cache->data = data; | ||
638 | if (data) { | 599 | if (data) { |
639 | cache->radix = | 600 | bit_to_clear = BLOCK_GROUP_DATA; |
640 | &info->block_group_data_radix; | 601 | bit_to_set = BLOCK_GROUP_METADATA; |
641 | cache->item.flags |= | 602 | cache->item.flags |= |
642 | BTRFS_BLOCK_GROUP_DATA; | 603 | BTRFS_BLOCK_GROUP_DATA; |
643 | } else { | 604 | } else { |
644 | cache->radix = &info->block_group_radix; | 605 | bit_to_clear = BLOCK_GROUP_METADATA; |
606 | bit_to_set = BLOCK_GROUP_DATA; | ||
645 | cache->item.flags &= | 607 | cache->item.flags &= |
646 | ~BTRFS_BLOCK_GROUP_DATA; | 608 | ~BTRFS_BLOCK_GROUP_DATA; |
647 | } | 609 | } |
648 | ret = radix_tree_insert(cache->radix, | 610 | clear_extent_bits(&info->block_group_cache, |
649 | cache->key.objectid + | 611 | start, end, bit_to_clear, |
650 | cache->key.offset - 1, | 612 | GFP_NOFS); |
651 | (void *)cache); | 613 | set_extent_bits(&info->block_group_cache, |
614 | start, end, bit_to_set, | ||
615 | GFP_NOFS); | ||
652 | } | 616 | } |
653 | old_val += num; | 617 | old_val += num; |
654 | } else { | 618 | } else { |
@@ -660,13 +624,6 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
660 | blocknr, blocknr + num - 1, | 624 | blocknr, blocknr + num - 1, |
661 | GFP_NOFS); | 625 | GFP_NOFS); |
662 | } | 626 | } |
663 | if (old_val < (cache->key.offset >> 1) && | ||
664 | old_val + num >= (cache->key.offset >> 1)) { | ||
665 | radix_tree_tag_set(cache->radix, | ||
666 | cache->key.objectid + | ||
667 | cache->key.offset - 1, | ||
668 | BTRFS_BLOCK_GROUP_AVAIL); | ||
669 | } | ||
670 | } | 627 | } |
671 | btrfs_set_block_group_used(&cache->item, old_val); | 628 | btrfs_set_block_group_used(&cache->item, old_val); |
672 | total -= num; | 629 | total -= num; |
@@ -730,11 +687,8 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, | |||
730 | block_group->pinned--; | 687 | block_group->pinned--; |
731 | if (gang[i] < block_group->last_alloc) | 688 | if (gang[i] < block_group->last_alloc) |
732 | block_group->last_alloc = gang[i]; | 689 | block_group->last_alloc = gang[i]; |
733 | if (!block_group->data) { | 690 | set_extent_dirty(free_space_cache, |
734 | set_extent_dirty(free_space_cache, | 691 | gang[i], gang[i], GFP_NOFS); |
735 | gang[i], gang[i], | ||
736 | GFP_NOFS); | ||
737 | } | ||
738 | } | 692 | } |
739 | } | 693 | } |
740 | } | 694 | } |
@@ -1059,8 +1013,8 @@ check_failed: | |||
1059 | ins->offset = search_end - ins->objectid; | 1013 | ins->offset = search_end - ins->objectid; |
1060 | goto check_pending; | 1014 | goto check_pending; |
1061 | } | 1015 | } |
1062 | |||
1063 | btrfs_item_key_to_cpu(l, &key, slot); | 1016 | btrfs_item_key_to_cpu(l, &key, slot); |
1017 | |||
1064 | if (key.objectid >= search_start && key.objectid > last_block && | 1018 | if (key.objectid >= search_start && key.objectid > last_block && |
1065 | start_found) { | 1019 | start_found) { |
1066 | if (last_block < search_start) | 1020 | if (last_block < search_start) |
@@ -1072,9 +1026,14 @@ check_failed: | |||
1072 | goto check_pending; | 1026 | goto check_pending; |
1073 | } | 1027 | } |
1074 | } | 1028 | } |
1075 | 1029 | if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY) { | |
1076 | if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY) | 1030 | if (!start_found) { |
1031 | last_block = key.objectid; | ||
1032 | start_found = 1; | ||
1033 | } | ||
1077 | goto next; | 1034 | goto next; |
1035 | } | ||
1036 | |||
1078 | 1037 | ||
1079 | start_found = 1; | 1038 | start_found = 1; |
1080 | last_block = key.objectid + key.offset; | 1039 | last_block = key.objectid + key.offset; |
@@ -1120,9 +1079,6 @@ check_pending: | |||
1120 | } | 1079 | } |
1121 | ins->offset = num_blocks; | 1080 | ins->offset = num_blocks; |
1122 | btrfs_free_path(path); | 1081 | btrfs_free_path(path); |
1123 | if (0 && ins->objectid != cached_search_start) { | ||
1124 | printk("\tcached was %Lu found %Lu\n", cached_search_start, ins->objectid); | ||
1125 | } | ||
1126 | return 0; | 1082 | return 0; |
1127 | 1083 | ||
1128 | new_group: | 1084 | new_group: |
@@ -1529,40 +1485,20 @@ out: | |||
1529 | return ret; | 1485 | return ret; |
1530 | } | 1486 | } |
1531 | 1487 | ||
1532 | static int free_block_group_radix(struct radix_tree_root *radix) | 1488 | int btrfs_free_block_groups(struct btrfs_fs_info *info) |
1533 | { | 1489 | { |
1490 | u64 start; | ||
1491 | u64 end; | ||
1534 | int ret; | 1492 | int ret; |
1535 | struct btrfs_block_group_cache *cache[8]; | ||
1536 | int i; | ||
1537 | 1493 | ||
1538 | while(1) { | 1494 | while(1) { |
1539 | ret = radix_tree_gang_lookup(radix, (void **)cache, 0, | 1495 | ret = find_first_extent_bit(&info->block_group_cache, 0, |
1540 | ARRAY_SIZE(cache)); | 1496 | &start, &end, (unsigned int)-1); |
1541 | if (!ret) | 1497 | if (ret) |
1542 | break; | 1498 | break; |
1543 | for (i = 0; i < ret; i++) { | 1499 | clear_extent_bits(&info->block_group_cache, start, |
1544 | radix_tree_delete(radix, cache[i]->key.objectid + | 1500 | end, (unsigned int)-1, GFP_NOFS); |
1545 | cache[i]->key.offset - 1); | ||
1546 | kfree(cache[i]); | ||
1547 | } | ||
1548 | } | 1501 | } |
1549 | return 0; | ||
1550 | } | ||
1551 | |||
1552 | int btrfs_free_block_groups(struct btrfs_fs_info *info) | ||
1553 | { | ||
1554 | int ret; | ||
1555 | int ret2; | ||
1556 | u64 start; | ||
1557 | u64 end; | ||
1558 | |||
1559 | ret = free_block_group_radix(&info->block_group_radix); | ||
1560 | ret2 = free_block_group_radix(&info->block_group_data_radix); | ||
1561 | if (ret) | ||
1562 | return ret; | ||
1563 | if (ret2) | ||
1564 | return ret2; | ||
1565 | |||
1566 | while(1) { | 1502 | while(1) { |
1567 | ret = find_first_extent_bit(&info->free_space_cache, 0, | 1503 | ret = find_first_extent_bit(&info->free_space_cache, 0, |
1568 | &start, &end, EXTENT_DIRTY); | 1504 | &start, &end, EXTENT_DIRTY); |
@@ -1579,17 +1515,20 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
1579 | struct btrfs_path *path; | 1515 | struct btrfs_path *path; |
1580 | int ret; | 1516 | int ret; |
1581 | int err = 0; | 1517 | int err = 0; |
1518 | int bit; | ||
1582 | struct btrfs_block_group_cache *cache; | 1519 | struct btrfs_block_group_cache *cache; |
1583 | struct btrfs_fs_info *info = root->fs_info; | 1520 | struct btrfs_fs_info *info = root->fs_info; |
1584 | struct radix_tree_root *radix; | 1521 | struct extent_map_tree *block_group_cache; |
1585 | struct btrfs_key key; | 1522 | struct btrfs_key key; |
1586 | struct btrfs_key found_key; | 1523 | struct btrfs_key found_key; |
1587 | struct extent_buffer *leaf; | 1524 | struct extent_buffer *leaf; |
1588 | u64 group_size_blocks; | 1525 | u64 group_size_blocks; |
1589 | u64 used; | 1526 | |
1527 | block_group_cache = &info->block_group_cache; | ||
1590 | 1528 | ||
1591 | group_size_blocks = BTRFS_BLOCK_GROUP_SIZE >> | 1529 | group_size_blocks = BTRFS_BLOCK_GROUP_SIZE >> |
1592 | root->fs_info->sb->s_blocksize_bits; | 1530 | info->sb->s_blocksize_bits; |
1531 | |||
1593 | root = info->extent_root; | 1532 | root = info->extent_root; |
1594 | key.objectid = 0; | 1533 | key.objectid = 0; |
1595 | key.offset = group_size_blocks; | 1534 | key.offset = group_size_blocks; |
@@ -1617,35 +1556,30 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
1617 | read_extent_buffer(leaf, &cache->item, | 1556 | read_extent_buffer(leaf, &cache->item, |
1618 | btrfs_item_ptr_offset(leaf, path->slots[0]), | 1557 | btrfs_item_ptr_offset(leaf, path->slots[0]), |
1619 | sizeof(cache->item)); | 1558 | sizeof(cache->item)); |
1620 | if (cache->item.flags & BTRFS_BLOCK_GROUP_DATA) { | ||
1621 | radix = &info->block_group_data_radix; | ||
1622 | cache->data = 1; | ||
1623 | } else { | ||
1624 | radix = &info->block_group_radix; | ||
1625 | cache->data = 0; | ||
1626 | } | ||
1627 | |||
1628 | memcpy(&cache->key, &found_key, sizeof(found_key)); | 1559 | memcpy(&cache->key, &found_key, sizeof(found_key)); |
1629 | cache->last_alloc = cache->key.objectid; | 1560 | cache->last_alloc = cache->key.objectid; |
1630 | cache->first_free = cache->key.objectid; | 1561 | cache->first_free = cache->key.objectid; |
1631 | cache->pinned = 0; | 1562 | cache->pinned = 0; |
1632 | cache->cached = 0; | 1563 | cache->cached = 0; |
1633 | 1564 | ||
1634 | cache->radix = radix; | ||
1635 | |||
1636 | key.objectid = found_key.objectid + found_key.offset; | 1565 | key.objectid = found_key.objectid + found_key.offset; |
1637 | btrfs_release_path(root, path); | 1566 | btrfs_release_path(root, path); |
1638 | 1567 | ||
1639 | ret = radix_tree_insert(radix, found_key.objectid + | 1568 | if (cache->item.flags & BTRFS_BLOCK_GROUP_DATA) { |
1640 | found_key.offset - 1, | 1569 | bit = BLOCK_GROUP_DATA; |
1641 | (void *)cache); | 1570 | cache->data = 1; |
1642 | BUG_ON(ret); | 1571 | } else { |
1643 | used = btrfs_block_group_used(&cache->item); | 1572 | bit = BLOCK_GROUP_METADATA; |
1644 | if (used < div_factor(key.offset, 8)) { | 1573 | cache->data = 0; |
1645 | radix_tree_tag_set(radix, found_key.objectid + | ||
1646 | found_key.offset - 1, | ||
1647 | BTRFS_BLOCK_GROUP_AVAIL); | ||
1648 | } | 1574 | } |
1575 | |||
1576 | /* use EXTENT_LOCKED to prevent merging */ | ||
1577 | set_extent_bits(block_group_cache, found_key.objectid, | ||
1578 | found_key.objectid + found_key.offset - 1, | ||
1579 | bit | EXTENT_LOCKED, GFP_NOFS); | ||
1580 | set_state_private(block_group_cache, found_key.objectid, | ||
1581 | (u64)cache); | ||
1582 | |||
1649 | if (key.objectid >= | 1583 | if (key.objectid >= |
1650 | btrfs_super_total_blocks(&info->super_copy)) | 1584 | btrfs_super_total_blocks(&info->super_copy)) |
1651 | break; | 1585 | break; |