diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 93 |
1 files changed, 39 insertions, 54 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 369b960fce45..b14104276eea 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -1,5 +1,4 @@ | |||
1 | #include <linux/module.h> | 1 | #include <linux/module.h> |
2 | #include <linux/radix-tree.h> | ||
3 | #include "ctree.h" | 2 | #include "ctree.h" |
4 | #include "disk-io.h" | 3 | #include "disk-io.h" |
5 | #include "print-tree.h" | 4 | #include "print-tree.h" |
@@ -12,15 +11,6 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct | |||
12 | btrfs_root *extent_root); | 11 | btrfs_root *extent_root); |
13 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct | 12 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct |
14 | btrfs_root *extent_root); | 13 | btrfs_root *extent_root); |
15 | /* | ||
16 | * pending extents are blocks that we're trying to allocate in the extent | ||
17 | * map while trying to grow the map because of other allocations. To avoid | ||
18 | * recursing, they are tagged in the radix tree and cleaned up after | ||
19 | * other allocations are done. The pending tag is also used in the same | ||
20 | * manner for deletes. | ||
21 | */ | ||
22 | #define CTREE_EXTENT_PENDING_DEL 0 | ||
23 | #define CTREE_EXTENT_PINNED 1 | ||
24 | 14 | ||
25 | static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root | 15 | static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root |
26 | *root, u64 blocknr) | 16 | *root, u64 blocknr) |
@@ -104,24 +94,21 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
104 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | 94 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct |
105 | btrfs_root *root) | 95 | btrfs_root *root) |
106 | { | 96 | { |
107 | struct buffer_head *gang[8]; | 97 | unsigned long gang[8]; |
108 | u64 first = 0; | 98 | u64 first = 0; |
109 | int ret; | 99 | int ret; |
110 | int i; | 100 | int i; |
101 | struct radix_tree_root *pinned_radix = &root->fs_info->pinned_radix; | ||
111 | 102 | ||
112 | while(1) { | 103 | while(1) { |
113 | ret = radix_tree_gang_lookup_tag(&root->fs_info->pinned_radix, | 104 | ret = find_first_radix_bit(pinned_radix, gang, |
114 | (void **)gang, 0, | 105 | ARRAY_SIZE(gang)); |
115 | ARRAY_SIZE(gang), | ||
116 | CTREE_EXTENT_PINNED); | ||
117 | if (!ret) | 106 | if (!ret) |
118 | break; | 107 | break; |
119 | if (!first) | 108 | if (!first) |
120 | first = gang[0]->b_blocknr; | 109 | first = gang[0]; |
121 | for (i = 0; i < ret; i++) { | 110 | for (i = 0; i < ret; i++) { |
122 | radix_tree_delete(&root->fs_info->pinned_radix, | 111 | clear_radix_bit(pinned_radix, gang[i]); |
123 | gang[i]->b_blocknr); | ||
124 | brelse(gang[i]); | ||
125 | } | 112 | } |
126 | } | 113 | } |
127 | if (root->fs_info->last_insert.objectid > first) | 114 | if (root->fs_info->last_insert.objectid > first) |
@@ -161,29 +148,27 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct | |||
161 | return 0; | 148 | return 0; |
162 | } | 149 | } |
163 | 150 | ||
164 | static int pin_down_block(struct btrfs_root *root, u64 blocknr, int tag) | 151 | static int pin_down_block(struct btrfs_root *root, u64 blocknr, int pending) |
165 | { | 152 | { |
166 | int err; | 153 | int err; |
167 | struct buffer_head *bh = sb_getblk(root->fs_info->sb, blocknr); | ||
168 | struct btrfs_header *header; | 154 | struct btrfs_header *header; |
169 | BUG_ON(!bh); | 155 | struct buffer_head *bh; |
170 | 156 | ||
171 | header = btrfs_buffer_header(bh); | 157 | bh = sb_find_get_block(root->fs_info->sb, blocknr); |
172 | if (btrfs_header_generation(header) == | 158 | if (bh) { |
173 | root->fs_info->running_transaction->transid) { | 159 | header = btrfs_buffer_header(bh); |
174 | return 0; | 160 | if (btrfs_header_generation(header) == |
175 | } | 161 | root->fs_info->running_transaction->transid) { |
176 | 162 | brelse(bh); | |
177 | err = radix_tree_insert(&root->fs_info->pinned_radix, | 163 | return 0; |
178 | blocknr, bh); | 164 | } |
179 | if (err && err != -EEXIST) { | ||
180 | BUG(); | ||
181 | return err; | ||
182 | } | ||
183 | if (err == -EEXIST) | ||
184 | brelse(bh); | 165 | brelse(bh); |
185 | radix_tree_tag_set(&root->fs_info->pinned_radix, blocknr, | 166 | } |
186 | tag); | 167 | if (pending) |
168 | err = set_radix_bit(&root->fs_info->pending_del_radix, blocknr); | ||
169 | else | ||
170 | err = set_radix_bit(&root->fs_info->pinned_radix, blocknr); | ||
171 | BUG_ON(err); | ||
187 | return 0; | 172 | return 0; |
188 | } | 173 | } |
189 | 174 | ||
@@ -225,8 +210,7 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
225 | u64 super_blocks_used; | 210 | u64 super_blocks_used; |
226 | 211 | ||
227 | if (pin) { | 212 | if (pin) { |
228 | ret = pin_down_block(root, blocknr, | 213 | ret = pin_down_block(root, blocknr, 0); |
229 | CTREE_EXTENT_PINNED); | ||
230 | BUG_ON(ret); | 214 | BUG_ON(ret); |
231 | } | 215 | } |
232 | 216 | ||
@@ -255,25 +239,26 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct | |||
255 | int ret; | 239 | int ret; |
256 | int wret; | 240 | int wret; |
257 | int err = 0; | 241 | int err = 0; |
258 | struct buffer_head *gang[4]; | 242 | unsigned long gang[4]; |
259 | int i; | 243 | int i; |
260 | struct radix_tree_root *radix = &extent_root->fs_info->pinned_radix; | 244 | struct radix_tree_root *pending_radix; |
245 | struct radix_tree_root *pinned_radix; | ||
246 | |||
247 | pending_radix = &extent_root->fs_info->pending_del_radix; | ||
248 | pinned_radix = &extent_root->fs_info->pinned_radix; | ||
261 | 249 | ||
262 | while(1) { | 250 | while(1) { |
263 | ret = radix_tree_gang_lookup_tag( | 251 | ret = find_first_radix_bit(pending_radix, gang, |
264 | &extent_root->fs_info->pinned_radix, | 252 | ARRAY_SIZE(gang)); |
265 | (void **)gang, 0, | ||
266 | ARRAY_SIZE(gang), | ||
267 | CTREE_EXTENT_PENDING_DEL); | ||
268 | if (!ret) | 253 | if (!ret) |
269 | break; | 254 | break; |
270 | for (i = 0; i < ret; i++) { | 255 | for (i = 0; i < ret; i++) { |
271 | radix_tree_tag_set(radix, gang[i]->b_blocknr, | 256 | wret = set_radix_bit(pinned_radix, gang[i]); |
272 | CTREE_EXTENT_PINNED); | 257 | BUG_ON(wret); |
273 | radix_tree_tag_clear(radix, gang[i]->b_blocknr, | 258 | wret = clear_radix_bit(pending_radix, gang[i]); |
274 | CTREE_EXTENT_PENDING_DEL); | 259 | BUG_ON(wret); |
275 | wret = __free_extent(trans, extent_root, | 260 | wret = __free_extent(trans, extent_root, |
276 | gang[i]->b_blocknr, 1, 0); | 261 | gang[i], 1, 0); |
277 | if (wret) | 262 | if (wret) |
278 | err = wret; | 263 | err = wret; |
279 | } | 264 | } |
@@ -294,7 +279,7 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
294 | 279 | ||
295 | if (root == extent_root) { | 280 | if (root == extent_root) { |
296 | t = find_tree_block(root, blocknr); | 281 | t = find_tree_block(root, blocknr); |
297 | pin_down_block(root, blocknr, CTREE_EXTENT_PENDING_DEL); | 282 | pin_down_block(root, blocknr, 1); |
298 | return 0; | 283 | return 0; |
299 | } | 284 | } |
300 | ret = __free_extent(trans, root, blocknr, num_blocks, pin); | 285 | ret = __free_extent(trans, root, blocknr, num_blocks, pin); |
@@ -393,7 +378,7 @@ check_pending: | |||
393 | BUG_ON(ins->objectid < search_start); | 378 | BUG_ON(ins->objectid < search_start); |
394 | for (test_block = ins->objectid; | 379 | for (test_block = ins->objectid; |
395 | test_block < ins->objectid + total_needed; test_block++) { | 380 | test_block < ins->objectid + total_needed; test_block++) { |
396 | if (radix_tree_lookup(&root->fs_info->pinned_radix, | 381 | if (test_radix_bit(&root->fs_info->pinned_radix, |
397 | test_block)) { | 382 | test_block)) { |
398 | search_start = test_block + 1; | 383 | search_start = test_block + 1; |
399 | goto check_failed; | 384 | goto check_failed; |