diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-10-15 16:14:48 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:56 -0400 |
commit | f510cfecfc98759d75283823cfccf0cc0d59a4c6 (patch) | |
tree | dfc2f788df4e2a437d976f78a2a2a675375f7134 /fs/btrfs | |
parent | ae5252bd51a252b7b8b02289337c36774835101c (diff) |
Btrfs: Fix extent_buffer and extent_state leaks
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/ctree.c | 10 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 2 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 17 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 126 | ||||
-rw-r--r-- | fs/btrfs/extent_map.c | 64 | ||||
-rw-r--r-- | fs/btrfs/extent_map.h | 2 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 5 |
7 files changed, 139 insertions, 87 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 9427b79c5d79..50ef351ef6b3 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -87,6 +87,7 @@ static int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
87 | if (IS_ERR(cow)) | 87 | if (IS_ERR(cow)) |
88 | return PTR_ERR(cow); | 88 | return PTR_ERR(cow); |
89 | 89 | ||
90 | cow->alloc_addr = (unsigned long)__builtin_return_address(0); | ||
90 | if (buf->len != root->sectorsize || cow->len != root->sectorsize) | 91 | if (buf->len != root->sectorsize || cow->len != root->sectorsize) |
91 | WARN_ON(1); | 92 | WARN_ON(1); |
92 | 93 | ||
@@ -132,6 +133,7 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
132 | struct extent_buffer **cow_ret) | 133 | struct extent_buffer **cow_ret) |
133 | { | 134 | { |
134 | u64 search_start; | 135 | u64 search_start; |
136 | int ret; | ||
135 | if (trans->transaction != root->fs_info->running_transaction) { | 137 | if (trans->transaction != root->fs_info->running_transaction) { |
136 | printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid, | 138 | printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid, |
137 | root->fs_info->running_transaction->transid); | 139 | root->fs_info->running_transaction->transid); |
@@ -148,8 +150,10 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
148 | } | 150 | } |
149 | 151 | ||
150 | search_start = extent_buffer_blocknr(buf) & ~((u64)65535); | 152 | search_start = extent_buffer_blocknr(buf) & ~((u64)65535); |
151 | return __btrfs_cow_block(trans, root, buf, parent, | 153 | ret = __btrfs_cow_block(trans, root, buf, parent, |
152 | parent_slot, cow_ret, search_start, 0); | 154 | parent_slot, cow_ret, search_start, 0); |
155 | (*cow_ret)->alloc_addr = (unsigned long)__builtin_return_address(0); | ||
156 | return ret; | ||
153 | } | 157 | } |
154 | 158 | ||
155 | static int close_blocks(u64 blocknr, u64 other) | 159 | static int close_blocks(u64 blocknr, u64 other) |
@@ -1013,8 +1017,10 @@ again: | |||
1013 | if (sret) | 1017 | if (sret) |
1014 | return sret; | 1018 | return sret; |
1015 | b = p->nodes[level]; | 1019 | b = p->nodes[level]; |
1016 | if (!b) | 1020 | if (!b) { |
1021 | btrfs_release_path(NULL, p); | ||
1017 | goto again; | 1022 | goto again; |
1023 | } | ||
1018 | slot = p->slots[level]; | 1024 | slot = p->slots[level]; |
1019 | BUG_ON(btrfs_header_nritems(b) == 1); | 1025 | BUG_ON(btrfs_header_nritems(b) == 1); |
1020 | } | 1026 | } |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index aed08618aca6..5262b28f468c 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -303,8 +303,8 @@ struct btrfs_fs_info { | |||
303 | struct radix_tree_root pinned_radix; | 303 | struct radix_tree_root pinned_radix; |
304 | struct radix_tree_root block_group_radix; | 304 | struct radix_tree_root block_group_radix; |
305 | struct radix_tree_root block_group_data_radix; | 305 | struct radix_tree_root block_group_data_radix; |
306 | struct radix_tree_root extent_map_radix; | ||
307 | struct radix_tree_root extent_ins_radix; | 306 | struct radix_tree_root extent_ins_radix; |
307 | struct extent_map_tree free_space_cache; | ||
308 | u64 generation; | 308 | u64 generation; |
309 | u64 last_trans_committed; | 309 | u64 last_trans_committed; |
310 | struct btrfs_transaction *running_transaction; | 310 | struct btrfs_transaction *running_transaction; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 8242933a1d8b..09f4e694624d 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -46,18 +46,25 @@ struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, | |||
46 | u64 blocknr) | 46 | u64 blocknr) |
47 | { | 47 | { |
48 | struct inode *btree_inode = root->fs_info->btree_inode; | 48 | struct inode *btree_inode = root->fs_info->btree_inode; |
49 | return find_extent_buffer(&BTRFS_I(btree_inode)->extent_tree, | 49 | struct extent_buffer *eb; |
50 | eb = find_extent_buffer(&BTRFS_I(btree_inode)->extent_tree, | ||
50 | blocknr * root->sectorsize, | 51 | blocknr * root->sectorsize, |
51 | root->sectorsize, GFP_NOFS); | 52 | root->sectorsize, GFP_NOFS); |
53 | if (eb) | ||
54 | eb->alloc_addr = (unsigned long)__builtin_return_address(0); | ||
55 | return eb; | ||
52 | } | 56 | } |
53 | 57 | ||
54 | struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, | 58 | struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, |
55 | u64 blocknr) | 59 | u64 blocknr) |
56 | { | 60 | { |
57 | struct inode *btree_inode = root->fs_info->btree_inode; | 61 | struct inode *btree_inode = root->fs_info->btree_inode; |
58 | return alloc_extent_buffer(&BTRFS_I(btree_inode)->extent_tree, | 62 | struct extent_buffer *eb; |
63 | eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->extent_tree, | ||
59 | blocknr * root->sectorsize, | 64 | blocknr * root->sectorsize, |
60 | root->sectorsize, GFP_NOFS); | 65 | root->sectorsize, GFP_NOFS); |
66 | eb->alloc_addr = (unsigned long)__builtin_return_address(0); | ||
67 | return eb; | ||
61 | } | 68 | } |
62 | 69 | ||
63 | struct extent_map *btree_get_extent(struct inode *inode, struct page *page, | 70 | struct extent_map *btree_get_extent(struct inode *inode, struct page *page, |
@@ -226,6 +233,7 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 blocknr) | |||
226 | return NULL; | 233 | return NULL; |
227 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, | 234 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, |
228 | buf, 1); | 235 | buf, 1); |
236 | buf->alloc_addr = (unsigned long)__builtin_return_address(0); | ||
229 | return buf; | 237 | return buf; |
230 | } | 238 | } |
231 | 239 | ||
@@ -426,7 +434,6 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
426 | } | 434 | } |
427 | init_bit_radix(&fs_info->pinned_radix); | 435 | init_bit_radix(&fs_info->pinned_radix); |
428 | init_bit_radix(&fs_info->pending_del_radix); | 436 | init_bit_radix(&fs_info->pending_del_radix); |
429 | init_bit_radix(&fs_info->extent_map_radix); | ||
430 | init_bit_radix(&fs_info->extent_ins_radix); | 437 | init_bit_radix(&fs_info->extent_ins_radix); |
431 | INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS); | 438 | INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS); |
432 | INIT_RADIX_TREE(&fs_info->block_group_radix, GFP_KERNEL); | 439 | INIT_RADIX_TREE(&fs_info->block_group_radix, GFP_KERNEL); |
@@ -449,6 +456,8 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
449 | extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree, | 456 | extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree, |
450 | fs_info->btree_inode->i_mapping, | 457 | fs_info->btree_inode->i_mapping, |
451 | GFP_NOFS); | 458 | GFP_NOFS); |
459 | extent_map_tree_init(&fs_info->free_space_cache, | ||
460 | fs_info->btree_inode->i_mapping, GFP_NOFS); | ||
452 | fs_info->do_barriers = 1; | 461 | fs_info->do_barriers = 1; |
453 | fs_info->closing = 0; | 462 | fs_info->closing = 0; |
454 | 463 | ||
@@ -594,8 +603,10 @@ int close_ctree(struct btrfs_root *root) | |||
594 | 603 | ||
595 | if (fs_info->extent_root->node) | 604 | if (fs_info->extent_root->node) |
596 | free_extent_buffer(fs_info->extent_root->node); | 605 | free_extent_buffer(fs_info->extent_root->node); |
606 | |||
597 | if (fs_info->tree_root->node) | 607 | if (fs_info->tree_root->node) |
598 | free_extent_buffer(fs_info->tree_root->node); | 608 | free_extent_buffer(fs_info->tree_root->node); |
609 | |||
599 | free_extent_buffer(fs_info->sb_buffer); | 610 | free_extent_buffer(fs_info->sb_buffer); |
600 | truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); | 611 | truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); |
601 | iput(fs_info->btree_inode); | 612 | iput(fs_info->btree_inode); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 089c41cbca74..74cfbee2ff33 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -34,21 +34,19 @@ static int cache_block_group(struct btrfs_root *root, | |||
34 | int ret; | 34 | int ret; |
35 | struct btrfs_key key; | 35 | struct btrfs_key key; |
36 | struct extent_buffer *leaf; | 36 | struct extent_buffer *leaf; |
37 | struct radix_tree_root *extent_radix; | 37 | struct extent_map_tree *free_space_cache; |
38 | int slot; | 38 | int slot; |
39 | u64 i; | ||
40 | u64 last = 0; | 39 | u64 last = 0; |
41 | u64 hole_size; | 40 | u64 hole_size; |
42 | u64 first_free; | 41 | u64 first_free; |
43 | int found = 0; | 42 | int found = 0; |
44 | 43 | ||
45 | root = root->fs_info->extent_root; | 44 | root = root->fs_info->extent_root; |
46 | extent_radix = &root->fs_info->extent_map_radix; | 45 | free_space_cache = &root->fs_info->free_space_cache; |
47 | 46 | ||
48 | if (block_group->cached) | 47 | if (block_group->cached) |
49 | return 0; | 48 | return 0; |
50 | if (block_group->data) | 49 | |
51 | return 0; | ||
52 | path = btrfs_alloc_path(); | 50 | path = btrfs_alloc_path(); |
53 | if (!path) | 51 | if (!path) |
54 | return -ENOMEM; | 52 | return -ENOMEM; |
@@ -98,9 +96,11 @@ static int cache_block_group(struct btrfs_root *root, | |||
98 | last = first_free; | 96 | last = first_free; |
99 | found = 1; | 97 | found = 1; |
100 | } | 98 | } |
101 | hole_size = key.objectid - last; | 99 | if (key.objectid > last) { |
102 | for (i = 0; i < hole_size; i++) { | 100 | hole_size = key.objectid - last; |
103 | set_radix_bit(extent_radix, last + i); | 101 | set_extent_dirty(free_space_cache, last, |
102 | last + hole_size - 1, | ||
103 | GFP_NOFS); | ||
104 | } | 104 | } |
105 | last = key.objectid + key.offset; | 105 | last = key.objectid + key.offset; |
106 | } | 106 | } |
@@ -114,9 +114,8 @@ next: | |||
114 | block_group->key.offset > last) { | 114 | block_group->key.offset > last) { |
115 | hole_size = block_group->key.objectid + | 115 | hole_size = block_group->key.objectid + |
116 | block_group->key.offset - last; | 116 | block_group->key.offset - last; |
117 | for (i = 0; i < hole_size; i++) { | 117 | set_extent_dirty(free_space_cache, last, |
118 | set_radix_bit(extent_radix, last + i); | 118 | last + hole_size - 1, GFP_NOFS); |
119 | } | ||
120 | } | 119 | } |
121 | block_group->cached = 1; | 120 | block_group->cached = 1; |
122 | err: | 121 | err: |
@@ -150,47 +149,33 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(struct | |||
150 | return NULL; | 149 | return NULL; |
151 | } | 150 | } |
152 | 151 | ||
153 | static u64 leaf_range(struct btrfs_root *root) | ||
154 | { | ||
155 | u64 size = BTRFS_LEAF_DATA_SIZE(root); | ||
156 | do_div(size, sizeof(struct btrfs_extent_item) + | ||
157 | sizeof(struct btrfs_item)); | ||
158 | return size; | ||
159 | } | ||
160 | |||
161 | static u64 find_search_start(struct btrfs_root *root, | 152 | static u64 find_search_start(struct btrfs_root *root, |
162 | struct btrfs_block_group_cache **cache_ret, | 153 | struct btrfs_block_group_cache **cache_ret, |
163 | u64 search_start, int num) | 154 | u64 search_start, int num, int data) |
164 | { | 155 | { |
165 | unsigned long gang[8]; | ||
166 | int ret; | 156 | int ret; |
167 | struct btrfs_block_group_cache *cache = *cache_ret; | 157 | struct btrfs_block_group_cache *cache = *cache_ret; |
168 | u64 last = max(search_start, cache->key.objectid); | 158 | u64 last = max(search_start, cache->key.objectid); |
159 | u64 start = 0; | ||
160 | u64 end = 0; | ||
169 | 161 | ||
170 | if (cache->data) | ||
171 | goto out; | ||
172 | again: | 162 | again: |
173 | ret = cache_block_group(root, cache); | 163 | ret = cache_block_group(root, cache); |
174 | if (ret) | 164 | if (ret) |
175 | goto out; | 165 | goto out; |
176 | while(1) { | 166 | while(1) { |
177 | ret = find_first_radix_bit(&root->fs_info->extent_map_radix, | 167 | ret = find_first_extent_bit(&root->fs_info->free_space_cache, |
178 | gang, last, ARRAY_SIZE(gang)); | 168 | last, &start, &end, EXTENT_DIRTY); |
179 | if (!ret) | 169 | if (ret) |
180 | goto out; | 170 | goto out; |
181 | last = gang[ret-1] + 1; | 171 | |
182 | if (num > 1) { | 172 | start = max(last, start); |
183 | if (ret != ARRAY_SIZE(gang)) { | 173 | last = end + 1; |
184 | goto new_group; | 174 | if (end + 1 - start < num) |
185 | } | 175 | continue; |
186 | if (gang[ret-1] - gang[0] > leaf_range(root)) { | 176 | if (start + num > cache->key.objectid + cache->key.offset) |
187 | continue; | ||
188 | } | ||
189 | } | ||
190 | if (gang[0] >= cache->key.objectid + cache->key.offset) { | ||
191 | goto new_group; | 177 | goto new_group; |
192 | } | 178 | return start; |
193 | return gang[0]; | ||
194 | } | 179 | } |
195 | out: | 180 | out: |
196 | return max(cache->last_alloc, search_start); | 181 | return max(cache->last_alloc, search_start); |
@@ -202,7 +187,7 @@ new_group: | |||
202 | return max((*cache_ret)->last_alloc, search_start); | 187 | return max((*cache_ret)->last_alloc, search_start); |
203 | } | 188 | } |
204 | cache = btrfs_find_block_group(root, cache, | 189 | cache = btrfs_find_block_group(root, cache, |
205 | last + cache->key.offset - 1, 0, 0); | 190 | last + cache->key.offset - 1, data, 0); |
206 | *cache_ret = cache; | 191 | *cache_ret = cache; |
207 | goto again; | 192 | goto again; |
208 | } | 193 | } |
@@ -625,7 +610,6 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
625 | u64 total = num; | 610 | u64 total = num; |
626 | u64 old_val; | 611 | u64 old_val; |
627 | u64 block_in_group; | 612 | u64 block_in_group; |
628 | u64 i; | ||
629 | int ret; | 613 | int ret; |
630 | 614 | ||
631 | while(total) { | 615 | while(total) { |
@@ -644,12 +628,6 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
644 | if (alloc) { | 628 | if (alloc) { |
645 | if (blocknr > cache->last_alloc) | 629 | if (blocknr > cache->last_alloc) |
646 | cache->last_alloc = blocknr; | 630 | cache->last_alloc = blocknr; |
647 | if (!cache->data) { | ||
648 | for (i = 0; i < num; i++) { | ||
649 | clear_radix_bit(&info->extent_map_radix, | ||
650 | blocknr + i); | ||
651 | } | ||
652 | } | ||
653 | if (cache->data != data && | 631 | if (cache->data != data && |
654 | old_val < (cache->key.offset >> 1)) { | 632 | old_val < (cache->key.offset >> 1)) { |
655 | cache->data = data; | 633 | cache->data = data; |
@@ -677,11 +655,10 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
677 | old_val -= num; | 655 | old_val -= num; |
678 | if (blocknr < cache->first_free) | 656 | if (blocknr < cache->first_free) |
679 | cache->first_free = blocknr; | 657 | cache->first_free = blocknr; |
680 | if (!cache->data && mark_free) { | 658 | if (mark_free) { |
681 | for (i = 0; i < num; i++) { | 659 | set_extent_dirty(&info->free_space_cache, |
682 | set_radix_bit(&info->extent_map_radix, | 660 | blocknr, blocknr + num - 1, |
683 | blocknr + i); | 661 | GFP_NOFS); |
684 | } | ||
685 | } | 662 | } |
686 | if (old_val < (cache->key.offset >> 1) && | 663 | if (old_val < (cache->key.offset >> 1) && |
687 | old_val + num >= (cache->key.offset >> 1)) { | 664 | old_val + num >= (cache->key.offset >> 1)) { |
@@ -732,7 +709,9 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, | |||
732 | int ret; | 709 | int ret; |
733 | int i; | 710 | int i; |
734 | struct radix_tree_root *pinned_radix = &root->fs_info->pinned_radix; | 711 | struct radix_tree_root *pinned_radix = &root->fs_info->pinned_radix; |
735 | struct radix_tree_root *extent_radix = &root->fs_info->extent_map_radix; | 712 | struct extent_map_tree *free_space_cache; |
713 | |||
714 | free_space_cache = &root->fs_info->free_space_cache; | ||
736 | 715 | ||
737 | while(1) { | 716 | while(1) { |
738 | ret = find_first_radix_bit(unpin_radix, gang, 0, | 717 | ret = find_first_radix_bit(unpin_radix, gang, 0, |
@@ -751,8 +730,11 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, | |||
751 | block_group->pinned--; | 730 | block_group->pinned--; |
752 | if (gang[i] < block_group->last_alloc) | 731 | if (gang[i] < block_group->last_alloc) |
753 | block_group->last_alloc = gang[i]; | 732 | block_group->last_alloc = gang[i]; |
754 | if (!block_group->data) | 733 | if (!block_group->data) { |
755 | set_radix_bit(extent_radix, gang[i]); | 734 | set_extent_dirty(free_space_cache, |
735 | gang[i], gang[i], | ||
736 | GFP_NOFS); | ||
737 | } | ||
756 | } | 738 | } |
757 | } | 739 | } |
758 | } | 740 | } |
@@ -995,6 +977,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
995 | struct btrfs_block_group_cache *block_group; | 977 | struct btrfs_block_group_cache *block_group; |
996 | int full_scan = 0; | 978 | int full_scan = 0; |
997 | int wrapped = 0; | 979 | int wrapped = 0; |
980 | u64 cached_search_start = 0; | ||
998 | 981 | ||
999 | WARN_ON(num_blocks < 1); | 982 | WARN_ON(num_blocks < 1); |
1000 | btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); | 983 | btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); |
@@ -1017,11 +1000,9 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1017 | path = btrfs_alloc_path(); | 1000 | path = btrfs_alloc_path(); |
1018 | 1001 | ||
1019 | check_failed: | 1002 | check_failed: |
1020 | if (!block_group->data) | 1003 | search_start = find_search_start(root, &block_group, |
1021 | search_start = find_search_start(root, &block_group, | 1004 | search_start, total_needed, data); |
1022 | search_start, total_needed); | 1005 | cached_search_start = search_start; |
1023 | else if (!full_scan) | ||
1024 | search_start = max(block_group->last_alloc, search_start); | ||
1025 | 1006 | ||
1026 | btrfs_init_path(path); | 1007 | btrfs_init_path(path); |
1027 | ins->objectid = search_start; | 1008 | ins->objectid = search_start; |
@@ -1097,6 +1078,7 @@ check_failed: | |||
1097 | 1078 | ||
1098 | start_found = 1; | 1079 | start_found = 1; |
1099 | last_block = key.objectid + key.offset; | 1080 | last_block = key.objectid + key.offset; |
1081 | |||
1100 | if (!full_scan && last_block >= block_group->key.objectid + | 1082 | if (!full_scan && last_block >= block_group->key.objectid + |
1101 | block_group->key.offset) { | 1083 | block_group->key.offset) { |
1102 | btrfs_release_path(root, path); | 1084 | btrfs_release_path(root, path); |
@@ -1138,6 +1120,9 @@ check_pending: | |||
1138 | } | 1120 | } |
1139 | ins->offset = num_blocks; | 1121 | ins->offset = num_blocks; |
1140 | btrfs_free_path(path); | 1122 | 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 | } | ||
1141 | return 0; | 1126 | return 0; |
1142 | 1127 | ||
1143 | new_group: | 1128 | new_group: |
@@ -1209,6 +1194,10 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1209 | btrfs_set_root_used(&root->root_item, root_blocks_used + | 1194 | btrfs_set_root_used(&root->root_item, root_blocks_used + |
1210 | num_blocks); | 1195 | num_blocks); |
1211 | 1196 | ||
1197 | clear_extent_dirty(&root->fs_info->free_space_cache, | ||
1198 | ins->objectid, ins->objectid + ins->offset - 1, | ||
1199 | GFP_NOFS); | ||
1200 | |||
1212 | if (root == extent_root) { | 1201 | if (root == extent_root) { |
1213 | BUG_ON(num_blocks != 1); | 1202 | BUG_ON(num_blocks != 1); |
1214 | set_radix_bit(&root->fs_info->extent_ins_radix, ins->objectid); | 1203 | set_radix_bit(&root->fs_info->extent_ins_radix, ins->objectid); |
@@ -1227,6 +1216,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1227 | BUG_ON(ret); | 1216 | BUG_ON(ret); |
1228 | finish_current_insert(trans, extent_root); | 1217 | finish_current_insert(trans, extent_root); |
1229 | pending_ret = del_pending_extents(trans, extent_root); | 1218 | pending_ret = del_pending_extents(trans, extent_root); |
1219 | |||
1230 | if (ret) { | 1220 | if (ret) { |
1231 | return ret; | 1221 | return ret; |
1232 | } | 1222 | } |
@@ -1265,6 +1255,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
1265 | return ERR_PTR(-ENOMEM); | 1255 | return ERR_PTR(-ENOMEM); |
1266 | } | 1256 | } |
1267 | btrfs_set_buffer_uptodate(buf); | 1257 | btrfs_set_buffer_uptodate(buf); |
1258 | buf->alloc_addr = (unsigned long)__builtin_return_address(0); | ||
1268 | set_extent_dirty(&trans->transaction->dirty_pages, buf->start, | 1259 | set_extent_dirty(&trans->transaction->dirty_pages, buf->start, |
1269 | buf->start + buf->len - 1, GFP_NOFS); | 1260 | buf->start + buf->len - 1, GFP_NOFS); |
1270 | /* | 1261 | /* |
@@ -1492,6 +1483,7 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1492 | orig_level = level; | 1483 | orig_level = level; |
1493 | if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) { | 1484 | if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) { |
1494 | path->nodes[level] = root->node; | 1485 | path->nodes[level] = root->node; |
1486 | extent_buffer_get(root->node); | ||
1495 | path->slots[level] = 0; | 1487 | path->slots[level] = 0; |
1496 | } else { | 1488 | } else { |
1497 | struct btrfs_key key; | 1489 | struct btrfs_key key; |
@@ -1524,7 +1516,6 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1524 | if (wret < 0) | 1516 | if (wret < 0) |
1525 | ret = wret; | 1517 | ret = wret; |
1526 | ret = -EAGAIN; | 1518 | ret = -EAGAIN; |
1527 | extent_buffer_get(root->node); | ||
1528 | break; | 1519 | break; |
1529 | } | 1520 | } |
1530 | for (i = 0; i <= orig_level; i++) { | 1521 | for (i = 0; i <= orig_level; i++) { |
@@ -1562,8 +1553,8 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) | |||
1562 | { | 1553 | { |
1563 | int ret; | 1554 | int ret; |
1564 | int ret2; | 1555 | int ret2; |
1565 | unsigned long gang[16]; | 1556 | u64 start; |
1566 | int i; | 1557 | u64 end; |
1567 | 1558 | ||
1568 | ret = free_block_group_radix(&info->block_group_radix); | 1559 | ret = free_block_group_radix(&info->block_group_radix); |
1569 | ret2 = free_block_group_radix(&info->block_group_data_radix); | 1560 | ret2 = free_block_group_radix(&info->block_group_data_radix); |
@@ -1573,13 +1564,12 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) | |||
1573 | return ret2; | 1564 | return ret2; |
1574 | 1565 | ||
1575 | while(1) { | 1566 | while(1) { |
1576 | ret = find_first_radix_bit(&info->extent_map_radix, | 1567 | ret = find_first_extent_bit(&info->free_space_cache, 0, |
1577 | gang, 0, ARRAY_SIZE(gang)); | 1568 | &start, &end, EXTENT_DIRTY); |
1578 | if (!ret) | 1569 | if (ret) |
1579 | break; | 1570 | break; |
1580 | for (i = 0; i < ret; i++) { | 1571 | clear_extent_dirty(&info->free_space_cache, start, |
1581 | clear_radix_bit(&info->extent_map_radix, gang[i]); | 1572 | end, GFP_NOFS); |
1582 | } | ||
1583 | } | 1573 | } |
1584 | return 0; | 1574 | return 0; |
1585 | } | 1575 | } |
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index f150188f621c..5b7dbcaacd11 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -19,8 +19,13 @@ struct kmem_cache *btrfs_cache_create(const char *name, size_t size, | |||
19 | static struct kmem_cache *extent_map_cache; | 19 | static struct kmem_cache *extent_map_cache; |
20 | static struct kmem_cache *extent_state_cache; | 20 | static struct kmem_cache *extent_state_cache; |
21 | static struct kmem_cache *extent_buffer_cache; | 21 | static struct kmem_cache *extent_buffer_cache; |
22 | |||
22 | static LIST_HEAD(extent_buffers); | 23 | static LIST_HEAD(extent_buffers); |
24 | static LIST_HEAD(buffers); | ||
25 | static LIST_HEAD(states); | ||
26 | |||
23 | static spinlock_t extent_buffers_lock; | 27 | static spinlock_t extent_buffers_lock; |
28 | static spinlock_t state_lock = SPIN_LOCK_UNLOCKED; | ||
24 | static int nr_extent_buffers; | 29 | static int nr_extent_buffers; |
25 | #define MAX_EXTENT_BUFFER_CACHE 128 | 30 | #define MAX_EXTENT_BUFFER_CACHE 128 |
26 | 31 | ||
@@ -48,6 +53,7 @@ void __init extent_map_init(void) | |||
48 | void __exit extent_map_exit(void) | 53 | void __exit extent_map_exit(void) |
49 | { | 54 | { |
50 | struct extent_buffer *eb; | 55 | struct extent_buffer *eb; |
56 | struct extent_state *state; | ||
51 | 57 | ||
52 | while (!list_empty(&extent_buffers)) { | 58 | while (!list_empty(&extent_buffers)) { |
53 | eb = list_entry(extent_buffers.next, | 59 | eb = list_entry(extent_buffers.next, |
@@ -55,6 +61,22 @@ void __exit extent_map_exit(void) | |||
55 | list_del(&eb->list); | 61 | list_del(&eb->list); |
56 | kmem_cache_free(extent_buffer_cache, eb); | 62 | kmem_cache_free(extent_buffer_cache, eb); |
57 | } | 63 | } |
64 | while (!list_empty(&states)) { | ||
65 | state = list_entry(states.next, struct extent_state, list); | ||
66 | printk("state leak: start %Lu end %Lu state %lu in tree %d refs %d\n", state->start, state->end, state->state, state->in_tree, atomic_read(&state->refs)); | ||
67 | list_del(&state->list); | ||
68 | kmem_cache_free(extent_state_cache, state); | ||
69 | |||
70 | } | ||
71 | while (!list_empty(&buffers)) { | ||
72 | eb = list_entry(buffers.next, | ||
73 | struct extent_buffer, leak_list); | ||
74 | printk("buffer leak start %Lu len %lu return %lX\n", eb->start, eb->len, eb->alloc_addr); | ||
75 | list_del(&eb->leak_list); | ||
76 | kmem_cache_free(extent_buffer_cache, eb); | ||
77 | } | ||
78 | |||
79 | |||
58 | if (extent_map_cache) | 80 | if (extent_map_cache) |
59 | kmem_cache_destroy(extent_map_cache); | 81 | kmem_cache_destroy(extent_map_cache); |
60 | if (extent_state_cache) | 82 | if (extent_state_cache) |
@@ -101,12 +123,19 @@ EXPORT_SYMBOL(free_extent_map); | |||
101 | struct extent_state *alloc_extent_state(gfp_t mask) | 123 | struct extent_state *alloc_extent_state(gfp_t mask) |
102 | { | 124 | { |
103 | struct extent_state *state; | 125 | struct extent_state *state; |
126 | unsigned long flags; | ||
127 | |||
104 | state = kmem_cache_alloc(extent_state_cache, mask); | 128 | state = kmem_cache_alloc(extent_state_cache, mask); |
105 | if (!state || IS_ERR(state)) | 129 | if (!state || IS_ERR(state)) |
106 | return state; | 130 | return state; |
107 | state->state = 0; | 131 | state->state = 0; |
108 | state->in_tree = 0; | 132 | state->in_tree = 0; |
109 | state->private = 0; | 133 | state->private = 0; |
134 | |||
135 | spin_lock_irqsave(&state_lock, flags); | ||
136 | list_add(&state->list, &states); | ||
137 | spin_unlock_irqrestore(&state_lock, flags); | ||
138 | |||
110 | atomic_set(&state->refs, 1); | 139 | atomic_set(&state->refs, 1); |
111 | init_waitqueue_head(&state->wq); | 140 | init_waitqueue_head(&state->wq); |
112 | return state; | 141 | return state; |
@@ -115,10 +144,14 @@ EXPORT_SYMBOL(alloc_extent_state); | |||
115 | 144 | ||
116 | void free_extent_state(struct extent_state *state) | 145 | void free_extent_state(struct extent_state *state) |
117 | { | 146 | { |
147 | unsigned long flags; | ||
118 | if (!state) | 148 | if (!state) |
119 | return; | 149 | return; |
120 | if (atomic_dec_and_test(&state->refs)) { | 150 | if (atomic_dec_and_test(&state->refs)) { |
121 | WARN_ON(state->in_tree); | 151 | WARN_ON(state->in_tree); |
152 | spin_lock_irqsave(&state_lock, flags); | ||
153 | list_del(&state->list); | ||
154 | spin_unlock_irqrestore(&state_lock, flags); | ||
122 | kmem_cache_free(extent_state_cache, state); | 155 | kmem_cache_free(extent_state_cache, state); |
123 | } | 156 | } |
124 | } | 157 | } |
@@ -361,10 +394,6 @@ static int insert_state(struct extent_map_tree *tree, | |||
361 | state->state |= bits; | 394 | state->state |= bits; |
362 | state->start = start; | 395 | state->start = start; |
363 | state->end = end; | 396 | state->end = end; |
364 | if ((end & 4095) == 0) { | ||
365 | printk("insert state %Lu %Lu strange end\n", start, end); | ||
366 | WARN_ON(1); | ||
367 | } | ||
368 | node = tree_insert(&tree->state, end, &state->rb_node); | 397 | node = tree_insert(&tree->state, end, &state->rb_node); |
369 | if (node) { | 398 | if (node) { |
370 | struct extent_state *found; | 399 | struct extent_state *found; |
@@ -399,11 +428,7 @@ static int split_state(struct extent_map_tree *tree, struct extent_state *orig, | |||
399 | prealloc->end = split - 1; | 428 | prealloc->end = split - 1; |
400 | prealloc->state = orig->state; | 429 | prealloc->state = orig->state; |
401 | orig->start = split; | 430 | orig->start = split; |
402 | if ((prealloc->end & 4095) == 0) { | 431 | |
403 | printk("insert state %Lu %Lu strange end\n", prealloc->start, | ||
404 | prealloc->end); | ||
405 | WARN_ON(1); | ||
406 | } | ||
407 | node = tree_insert(&tree->state, prealloc->end, &prealloc->rb_node); | 432 | node = tree_insert(&tree->state, prealloc->end, &prealloc->rb_node); |
408 | if (node) { | 433 | if (node) { |
409 | struct extent_state *found; | 434 | struct extent_state *found; |
@@ -957,6 +982,7 @@ int find_first_extent_bit(struct extent_map_tree *tree, u64 start, | |||
957 | *start_ret = state->start; | 982 | *start_ret = state->start; |
958 | *end_ret = state->end; | 983 | *end_ret = state->end; |
959 | ret = 0; | 984 | ret = 0; |
985 | break; | ||
960 | } | 986 | } |
961 | node = rb_next(node); | 987 | node = rb_next(node); |
962 | if (!node) | 988 | if (!node) |
@@ -1877,6 +1903,7 @@ sector_t extent_bmap(struct address_space *mapping, sector_t iblock, | |||
1877 | static struct extent_buffer *__alloc_extent_buffer(gfp_t mask) | 1903 | static struct extent_buffer *__alloc_extent_buffer(gfp_t mask) |
1878 | { | 1904 | { |
1879 | struct extent_buffer *eb = NULL; | 1905 | struct extent_buffer *eb = NULL; |
1906 | |||
1880 | spin_lock(&extent_buffers_lock); | 1907 | spin_lock(&extent_buffers_lock); |
1881 | if (!list_empty(&extent_buffers)) { | 1908 | if (!list_empty(&extent_buffers)) { |
1882 | eb = list_entry(extent_buffers.next, struct extent_buffer, | 1909 | eb = list_entry(extent_buffers.next, struct extent_buffer, |
@@ -1886,15 +1913,26 @@ static struct extent_buffer *__alloc_extent_buffer(gfp_t mask) | |||
1886 | nr_extent_buffers--; | 1913 | nr_extent_buffers--; |
1887 | } | 1914 | } |
1888 | spin_unlock(&extent_buffers_lock); | 1915 | spin_unlock(&extent_buffers_lock); |
1916 | |||
1889 | if (eb) { | 1917 | if (eb) { |
1890 | memset(eb, 0, sizeof(*eb)); | 1918 | memset(eb, 0, sizeof(*eb)); |
1891 | return eb; | 1919 | } else { |
1920 | eb = kmem_cache_zalloc(extent_buffer_cache, mask); | ||
1892 | } | 1921 | } |
1893 | return kmem_cache_zalloc(extent_buffer_cache, mask); | 1922 | spin_lock(&extent_buffers_lock); |
1923 | list_add(&eb->leak_list, &buffers); | ||
1924 | spin_unlock(&extent_buffers_lock); | ||
1925 | |||
1926 | return eb; | ||
1894 | } | 1927 | } |
1895 | 1928 | ||
1896 | static void __free_extent_buffer(struct extent_buffer *eb) | 1929 | static void __free_extent_buffer(struct extent_buffer *eb) |
1897 | { | 1930 | { |
1931 | |||
1932 | spin_lock(&extent_buffers_lock); | ||
1933 | list_del_init(&eb->leak_list); | ||
1934 | spin_unlock(&extent_buffers_lock); | ||
1935 | |||
1898 | if (nr_extent_buffers >= MAX_EXTENT_BUFFER_CACHE) { | 1936 | if (nr_extent_buffers >= MAX_EXTENT_BUFFER_CACHE) { |
1899 | kmem_cache_free(extent_buffer_cache, eb); | 1937 | kmem_cache_free(extent_buffer_cache, eb); |
1900 | } else { | 1938 | } else { |
@@ -1933,6 +1971,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, | |||
1933 | if (!eb || IS_ERR(eb)) | 1971 | if (!eb || IS_ERR(eb)) |
1934 | return NULL; | 1972 | return NULL; |
1935 | 1973 | ||
1974 | eb->alloc_addr = __builtin_return_address(0); | ||
1936 | eb->start = start; | 1975 | eb->start = start; |
1937 | eb->len = len; | 1976 | eb->len = len; |
1938 | atomic_set(&eb->refs, 1); | 1977 | atomic_set(&eb->refs, 1); |
@@ -1947,6 +1986,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, | |||
1947 | eb->start &= ~((u64)PAGE_CACHE_SIZE - 1); | 1986 | eb->start &= ~((u64)PAGE_CACHE_SIZE - 1); |
1948 | goto fail; | 1987 | goto fail; |
1949 | } | 1988 | } |
1989 | set_page_extent_mapped(p); | ||
1950 | if (i == 0) | 1990 | if (i == 0) |
1951 | eb->first_page = p; | 1991 | eb->first_page = p; |
1952 | if (!PageUptodate(p)) | 1992 | if (!PageUptodate(p)) |
@@ -1978,6 +2018,7 @@ struct extent_buffer *find_extent_buffer(struct extent_map_tree *tree, | |||
1978 | if (!eb || IS_ERR(eb)) | 2018 | if (!eb || IS_ERR(eb)) |
1979 | return NULL; | 2019 | return NULL; |
1980 | 2020 | ||
2021 | eb->alloc_addr = __builtin_return_address(0); | ||
1981 | eb->start = start; | 2022 | eb->start = start; |
1982 | eb->len = len; | 2023 | eb->len = len; |
1983 | atomic_set(&eb->refs, 1); | 2024 | atomic_set(&eb->refs, 1); |
@@ -1992,6 +2033,7 @@ struct extent_buffer *find_extent_buffer(struct extent_map_tree *tree, | |||
1992 | eb->start &= ~((u64)PAGE_CACHE_SIZE - 1); | 2033 | eb->start &= ~((u64)PAGE_CACHE_SIZE - 1); |
1993 | goto fail; | 2034 | goto fail; |
1994 | } | 2035 | } |
2036 | set_page_extent_mapped(p); | ||
1995 | if (i == 0) | 2037 | if (i == 0) |
1996 | eb->first_page = p; | 2038 | eb->first_page = p; |
1997 | } | 2039 | } |
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index 3b3abf34c403..d100f7c1476c 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h | |||
@@ -68,7 +68,9 @@ struct extent_buffer { | |||
68 | atomic_t refs; | 68 | atomic_t refs; |
69 | int flags; | 69 | int flags; |
70 | struct list_head list; | 70 | struct list_head list; |
71 | struct list_head leak_list; | ||
71 | struct page *first_page; | 72 | struct page *first_page; |
73 | unsigned long alloc_addr; | ||
72 | }; | 74 | }; |
73 | 75 | ||
74 | typedef struct extent_map *(get_extent_t)(struct inode *inode, | 76 | typedef struct extent_map *(get_extent_t)(struct inode *inode, |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 750f35a37aae..372b61f5733f 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -352,7 +352,7 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly) | |||
352 | return 0; | 352 | return 0; |
353 | 353 | ||
354 | trans = btrfs_start_transaction(root, 1); | 354 | trans = btrfs_start_transaction(root, 1); |
355 | while (1) { | 355 | while (0) { |
356 | root->defrag_running = 1; | 356 | root->defrag_running = 1; |
357 | ret = btrfs_defrag_leaves(trans, root, cacheonly); | 357 | ret = btrfs_defrag_leaves(trans, root, cacheonly); |
358 | nr = trans->blocks_used; | 358 | nr = trans->blocks_used; |
@@ -394,7 +394,7 @@ int btrfs_defrag_dirty_roots(struct btrfs_fs_info *info) | |||
394 | for (i = 0; i < ret; i++) { | 394 | for (i = 0; i < ret; i++) { |
395 | root = gang[i]; | 395 | root = gang[i]; |
396 | last = root->root_key.objectid + 1; | 396 | last = root->root_key.objectid + 1; |
397 | // btrfs_defrag_root(root, 1); | 397 | btrfs_defrag_root(root, 1); |
398 | } | 398 | } |
399 | } | 399 | } |
400 | // btrfs_defrag_root(info->extent_root, 1); | 400 | // btrfs_defrag_root(info->extent_root, 1); |
@@ -462,6 +462,7 @@ static int drop_dirty_roots(struct btrfs_root *tree_root, | |||
462 | ret = btrfs_end_transaction(trans, tree_root); | 462 | ret = btrfs_end_transaction(trans, tree_root); |
463 | BUG_ON(ret); | 463 | BUG_ON(ret); |
464 | 464 | ||
465 | free_extent_buffer(dirty->root->node); | ||
465 | kfree(dirty->root); | 466 | kfree(dirty->root); |
466 | kfree(dirty); | 467 | kfree(dirty); |
467 | mutex_unlock(&tree_root->fs_info->fs_mutex); | 468 | mutex_unlock(&tree_root->fs_info->fs_mutex); |