diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 95 |
1 files changed, 48 insertions, 47 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 0e20d1c42fca..c5ae51893f78 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -6,7 +6,7 @@ | |||
6 | 6 | ||
7 | static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | 7 | static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root |
8 | *orig_root, u64 num_blocks, u64 search_start, u64 | 8 | *orig_root, u64 num_blocks, u64 search_start, u64 |
9 | search_end, struct btrfs_key *ins); | 9 | search_end, struct btrfs_key *ins, int data); |
10 | static int finish_current_insert(struct btrfs_trans_handle *trans, struct | 10 | static int finish_current_insert(struct btrfs_trans_handle *trans, struct |
11 | btrfs_root *extent_root); | 11 | btrfs_root *extent_root); |
12 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct | 12 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct |
@@ -25,7 +25,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
25 | int i; | 25 | int i; |
26 | int ret; | 26 | int ret; |
27 | int full_search = 0; | 27 | int full_search = 0; |
28 | if (hint) { | 28 | if (!data && hint) { |
29 | used = btrfs_block_group_used(&hint->item); | 29 | used = btrfs_block_group_used(&hint->item); |
30 | if (used < (hint->key.offset * 2) / 3) { | 30 | if (used < (hint->key.offset * 2) / 3) { |
31 | return hint; | 31 | return hint; |
@@ -47,6 +47,14 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
47 | if (!ret) | 47 | if (!ret) |
48 | break; | 48 | break; |
49 | for (i = 0; i < ret; i++) { | 49 | for (i = 0; i < ret; i++) { |
50 | last = cache[i]->key.objectid + | ||
51 | 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; | ||
50 | used = btrfs_block_group_used(&cache[i]->item); | 58 | used = btrfs_block_group_used(&cache[i]->item); |
51 | if (used < (cache[i]->key.offset * 2) / 3) { | 59 | if (used < (cache[i]->key.offset * 2) / 3) { |
52 | info->block_group_cache = cache[i]; | 60 | info->block_group_cache = cache[i]; |
@@ -57,8 +65,6 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
57 | cache[i]->key.objectid + | 65 | cache[i]->key.objectid + |
58 | cache[i]->key.offset - 1, | 66 | cache[i]->key.offset - 1, |
59 | BTRFS_BLOCK_GROUP_AVAIL); | 67 | BTRFS_BLOCK_GROUP_AVAIL); |
60 | last = cache[i]->key.objectid + | ||
61 | cache[i]->key.offset; | ||
62 | } | 68 | } |
63 | } | 69 | } |
64 | last = hint_last; | 70 | last = hint_last; |
@@ -70,6 +76,14 @@ again: | |||
70 | if (!ret) | 76 | if (!ret) |
71 | break; | 77 | break; |
72 | for (i = 0; i < ret; i++) { | 78 | for (i = 0; i < ret; i++) { |
79 | last = cache[i]->key.objectid + | ||
80 | 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; | ||
73 | used = btrfs_block_group_used(&cache[i]->item); | 87 | used = btrfs_block_group_used(&cache[i]->item); |
74 | if (used < cache[i]->key.offset) { | 88 | if (used < cache[i]->key.offset) { |
75 | info->block_group_cache = cache[i]; | 89 | info->block_group_cache = cache[i]; |
@@ -80,8 +94,6 @@ again: | |||
80 | cache[i]->key.objectid + | 94 | cache[i]->key.objectid + |
81 | cache[i]->key.offset - 1, | 95 | cache[i]->key.offset - 1, |
82 | BTRFS_BLOCK_GROUP_AVAIL); | 96 | BTRFS_BLOCK_GROUP_AVAIL); |
83 | last = cache[i]->key.objectid + | ||
84 | cache[i]->key.offset; | ||
85 | } | 97 | } |
86 | } | 98 | } |
87 | info->block_group_cache = NULL; | 99 | info->block_group_cache = NULL; |
@@ -112,7 +124,7 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, | |||
112 | u32 refs; | 124 | u32 refs; |
113 | 125 | ||
114 | find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1, | 126 | find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1, |
115 | &ins); | 127 | &ins, 0); |
116 | path = btrfs_alloc_path(); | 128 | path = btrfs_alloc_path(); |
117 | BUG_ON(!path); | 129 | BUG_ON(!path); |
118 | btrfs_init_path(path); | 130 | btrfs_init_path(path); |
@@ -225,7 +237,7 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans, | |||
225 | struct btrfs_block_group_item *bi; | 237 | struct btrfs_block_group_item *bi; |
226 | struct btrfs_key ins; | 238 | struct btrfs_key ins; |
227 | 239 | ||
228 | find_free_extent(trans, extent_root, 0, 0, (u64)-1, &ins); | 240 | find_free_extent(trans, extent_root, 0, 0, (u64)-1, &ins, 0); |
229 | ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1); | 241 | ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1); |
230 | BUG_ON(ret); | 242 | BUG_ON(ret); |
231 | bi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], | 243 | bi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], |
@@ -322,10 +334,18 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
322 | return 0; | 334 | return 0; |
323 | } | 335 | } |
324 | 336 | ||
337 | static int try_remove_page(struct address_space *mapping, unsigned long index) | ||
338 | { | ||
339 | int ret; | ||
340 | ret = invalidate_mapping_pages(mapping, index, index); | ||
341 | return ret; | ||
342 | } | ||
343 | |||
325 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | 344 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct |
326 | btrfs_root *root) | 345 | btrfs_root *root) |
327 | { | 346 | { |
328 | unsigned long gang[8]; | 347 | unsigned long gang[8]; |
348 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
329 | u64 first = 0; | 349 | u64 first = 0; |
330 | int ret; | 350 | int ret; |
331 | int i; | 351 | int i; |
@@ -340,6 +360,9 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | |||
340 | first = gang[0]; | 360 | first = gang[0]; |
341 | for (i = 0; i < ret; i++) { | 361 | for (i = 0; i < ret; i++) { |
342 | clear_radix_bit(pinned_radix, gang[i]); | 362 | clear_radix_bit(pinned_radix, gang[i]); |
363 | try_remove_page(btree_inode->i_mapping, | ||
364 | gang[i] << (PAGE_CACHE_SHIFT - | ||
365 | btree_inode->i_blkbits)); | ||
343 | } | 366 | } |
344 | } | 367 | } |
345 | return 0; | 368 | return 0; |
@@ -424,7 +447,7 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
424 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); | 447 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); |
425 | key.offset = num_blocks; | 448 | key.offset = num_blocks; |
426 | 449 | ||
427 | find_free_extent(trans, root, 0, 0, (u64)-1, &ins); | 450 | find_free_extent(trans, root, 0, 0, (u64)-1, &ins, 0); |
428 | path = btrfs_alloc_path(); | 451 | path = btrfs_alloc_path(); |
429 | BUG_ON(!path); | 452 | BUG_ON(!path); |
430 | btrfs_init_path(path); | 453 | btrfs_init_path(path); |
@@ -531,7 +554,7 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
531 | */ | 554 | */ |
532 | static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | 555 | static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root |
533 | *orig_root, u64 num_blocks, u64 search_start, u64 | 556 | *orig_root, u64 num_blocks, u64 search_start, u64 |
534 | search_end, struct btrfs_key *ins) | 557 | search_end, struct btrfs_key *ins, int data) |
535 | { | 558 | { |
536 | struct btrfs_path *path; | 559 | struct btrfs_path *path; |
537 | struct btrfs_key key; | 560 | struct btrfs_key key; |
@@ -548,43 +571,21 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
548 | int total_found = 0; | 571 | int total_found = 0; |
549 | int fill_prealloc = 0; | 572 | int fill_prealloc = 0; |
550 | int level; | 573 | int level; |
551 | int update_block_group = 0; | 574 | struct btrfs_block_group_cache *block_group; |
552 | struct btrfs_block_group_cache *hint_block_group; | ||
553 | 575 | ||
554 | path = btrfs_alloc_path(); | 576 | path = btrfs_alloc_path(); |
555 | ins->flags = 0; | 577 | ins->flags = 0; |
556 | btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); | 578 | btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); |
557 | 579 | ||
558 | level = btrfs_header_level(btrfs_buffer_header(root->node)); | 580 | level = btrfs_header_level(btrfs_buffer_header(root->node)); |
559 | /* find search start here */ | ||
560 | if (0 && search_start && num_blocks) { | ||
561 | u64 used; | ||
562 | ret = radix_tree_gang_lookup(&info->block_group_radix, | ||
563 | (void **)&hint_block_group, | ||
564 | search_start, 1); | ||
565 | if (ret) { | ||
566 | used = btrfs_block_group_used(&hint_block_group->item); | ||
567 | if (used > (hint_block_group->key.offset * 9) / 10) | ||
568 | search_start = 0; | ||
569 | else if (search_start < hint_block_group->last_alloc) | ||
570 | search_start = hint_block_group->last_alloc; | ||
571 | } else { | ||
572 | search_start = 0; | ||
573 | } | ||
574 | } | ||
575 | if (num_blocks == 0) { | 581 | if (num_blocks == 0) { |
576 | fill_prealloc = 1; | 582 | fill_prealloc = 1; |
577 | num_blocks = 1; | 583 | num_blocks = 1; |
578 | total_needed = (min(level + 1, BTRFS_MAX_LEVEL) + 2) * 3; | 584 | total_needed = (min(level + 1, BTRFS_MAX_LEVEL) + 2) * 3; |
579 | } | 585 | } |
580 | if (1 || !search_start) { | 586 | block_group = btrfs_find_block_group(root, trans->block_group, data); |
581 | trans->block_group = btrfs_find_block_group(root, | 587 | if (block_group->last_alloc > search_start) |
582 | trans->block_group, | 588 | search_start = block_group->last_alloc; |
583 | 0); | ||
584 | if (trans->block_group->last_alloc > search_start) | ||
585 | search_start = trans->block_group->last_alloc; | ||
586 | update_block_group = 1; | ||
587 | } | ||
588 | check_failed: | 589 | check_failed: |
589 | btrfs_init_path(path); | 590 | btrfs_init_path(path); |
590 | ins->objectid = search_start; | 591 | ins->objectid = search_start; |
@@ -699,13 +700,13 @@ check_pending: | |||
699 | } | 700 | } |
700 | info->extent_tree_prealloc_nr = total_found; | 701 | info->extent_tree_prealloc_nr = total_found; |
701 | } | 702 | } |
702 | if (update_block_group) { | 703 | ret = radix_tree_gang_lookup(&info->block_group_radix, |
703 | ret = radix_tree_gang_lookup(&info->block_group_radix, | 704 | (void **)&block_group, |
704 | (void **)&trans->block_group, | 705 | ins->objectid, 1); |
705 | ins->objectid, 1); | 706 | if (ret) { |
706 | if (ret) { | 707 | block_group->last_alloc = ins->objectid; |
707 | trans->block_group->last_alloc = ins->objectid; | 708 | if (!data) |
708 | } | 709 | trans->block_group = block_group; |
709 | } | 710 | } |
710 | ins->offset = num_blocks; | 711 | ins->offset = num_blocks; |
711 | btrfs_free_path(path); | 712 | btrfs_free_path(path); |
@@ -725,7 +726,7 @@ error: | |||
725 | int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | 726 | int btrfs_alloc_extent(struct btrfs_trans_handle *trans, |
726 | struct btrfs_root *root, u64 owner, | 727 | struct btrfs_root *root, u64 owner, |
727 | u64 num_blocks, u64 search_start, | 728 | u64 num_blocks, u64 search_start, |
728 | u64 search_end, struct btrfs_key *ins) | 729 | u64 search_end, struct btrfs_key *ins, int data) |
729 | { | 730 | { |
730 | int ret; | 731 | int ret; |
731 | int pending_ret; | 732 | int pending_ret; |
@@ -755,13 +756,13 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
755 | } | 756 | } |
756 | /* do the real allocation */ | 757 | /* do the real allocation */ |
757 | ret = find_free_extent(trans, root, num_blocks, search_start, | 758 | ret = find_free_extent(trans, root, num_blocks, search_start, |
758 | search_end, ins); | 759 | search_end, ins, data); |
759 | if (ret) | 760 | if (ret) |
760 | return ret; | 761 | return ret; |
761 | 762 | ||
762 | /* then do prealloc for the extent tree */ | 763 | /* then do prealloc for the extent tree */ |
763 | ret = find_free_extent(trans, root, 0, ins->objectid + ins->offset, | 764 | ret = find_free_extent(trans, root, 0, ins->objectid + ins->offset, |
764 | search_end, &prealloc_key); | 765 | search_end, &prealloc_key, 0); |
765 | if (ret) | 766 | if (ret) |
766 | return ret; | 767 | return ret; |
767 | 768 | ||
@@ -793,7 +794,7 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
793 | struct buffer_head *buf; | 794 | struct buffer_head *buf; |
794 | 795 | ||
795 | ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, | 796 | ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, |
796 | 1, hint, (unsigned long)-1, &ins); | 797 | 1, 0, (unsigned long)-1, &ins, 0); |
797 | if (ret) { | 798 | if (ret) { |
798 | BUG(); | 799 | BUG(); |
799 | return NULL; | 800 | return NULL; |