aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-10-15 16:14:48 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:03:56 -0400
commitf510cfecfc98759d75283823cfccf0cc0d59a4c6 (patch)
treedfc2f788df4e2a437d976f78a2a2a675375f7134 /fs/btrfs/extent-tree.c
parentae5252bd51a252b7b8b02289337c36774835101c (diff)
Btrfs: Fix extent_buffer and extent_state leaks
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c126
1 files changed, 58 insertions, 68 deletions
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;
122err: 121err:
@@ -150,47 +149,33 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(struct
150 return NULL; 149 return NULL;
151} 150}
152 151
153static 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
161static u64 find_search_start(struct btrfs_root *root, 152static 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;
172again: 162again:
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 }
195out: 180out:
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
1019check_failed: 1002check_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) {
1124printk("\tcached was %Lu found %Lu\n", cached_search_start, ins->objectid);
1125 }
1141 return 0; 1126 return 0;
1142 1127
1143new_group: 1128new_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}