aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c93
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);
13static int del_pending_extents(struct btrfs_trans_handle *trans, struct 12static 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
25static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root 15static 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,
104int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct 94int 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
164static int pin_down_block(struct btrfs_root *root, u64 blocknr, int tag) 151static 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;