aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-03-07 11:50:24 -0500
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-03-07 11:50:24 -0500
commit037e6390488af8ab96137e1e5cccc15ad14ef887 (patch)
tree8bcde2f20af3b7b0bdb37376d78902d1ea5e74fa /fs/btrfs/extent-tree.c
parenta28ec19775d62d673b034082128aca95780d3737 (diff)
Btrfs: get rid of add recursion
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c209
1 files changed, 95 insertions, 114 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 0723b7f3f0c3..8a2b8aaf9b86 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -6,6 +6,11 @@
6#include "disk-io.h" 6#include "disk-io.h"
7#include "print-tree.h" 7#include "print-tree.h"
8 8
9static int find_free_extent(struct ctree_root *orig_root, u64 num_blocks,
10 u64 search_start, u64 search_end, struct key *ins);
11static int finish_current_insert(struct ctree_root *extent_root);
12static int run_pending(struct ctree_root *extent_root);
13
9/* 14/*
10 * pending extents are blocks that we're trying to allocate in the extent 15 * pending extents are blocks that we're trying to allocate in the extent
11 * map while trying to grow the map because of other allocations. To avoid 16 * map while trying to grow the map because of other allocations. To avoid
@@ -13,8 +18,7 @@
13 * other allocations are done. The pending tag is also used in the same 18 * other allocations are done. The pending tag is also used in the same
14 * manner for deletes. 19 * manner for deletes.
15 */ 20 */
16#define CTREE_EXTENT_PENDING_ADD 0 21#define CTREE_EXTENT_PENDING_DEL 0
17#define CTREE_EXTENT_PENDING_DEL 1
18 22
19static int inc_block_ref(struct ctree_root *root, u64 blocknr) 23static int inc_block_ref(struct ctree_root *root, u64 blocknr)
20{ 24{
@@ -23,6 +27,9 @@ static int inc_block_ref(struct ctree_root *root, u64 blocknr)
23 struct key key; 27 struct key key;
24 struct leaf *l; 28 struct leaf *l;
25 struct extent_item *item; 29 struct extent_item *item;
30 struct key ins;
31
32 find_free_extent(root->extent_root, 0, 0, (u64)-1, &ins);
26 init_path(&path); 33 init_path(&path);
27 key.objectid = blocknr; 34 key.objectid = blocknr;
28 key.flags = 0; 35 key.flags = 0;
@@ -38,6 +45,8 @@ static int inc_block_ref(struct ctree_root *root, u64 blocknr)
38 45
39 BUG_ON(list_empty(&path.nodes[0]->dirty)); 46 BUG_ON(list_empty(&path.nodes[0]->dirty));
40 release_path(root->extent_root, &path); 47 release_path(root->extent_root, &path);
48 finish_current_insert(root->extent_root);
49 run_pending(root->extent_root);
41 return 0; 50 return 0;
42} 51}
43 52
@@ -99,6 +108,28 @@ int btrfs_finish_extent_commit(struct ctree_root *root)
99 return 0; 108 return 0;
100} 109}
101 110
111static int finish_current_insert(struct ctree_root *extent_root)
112{
113 struct key ins;
114 struct extent_item extent_item;
115 int i;
116 int ret;
117
118 extent_item.refs = 1;
119 extent_item.owner = extent_root->node->node.header.parentid;
120 ins.offset = 1;
121 ins.flags = 0;
122
123 for (i = 0; i < extent_root->current_insert.flags; i++) {
124 ins.objectid = extent_root->current_insert.objectid + i;
125 ret = insert_item(extent_root, &ins, &extent_item,
126 sizeof(extent_item));
127 BUG_ON(ret);
128 }
129 extent_root->current_insert.offset = 0;
130 return 0;
131}
132
102/* 133/*
103 * remove an extent from the root, returns 0 on success 134 * remove an extent from the root, returns 0 on success
104 */ 135 */
@@ -110,10 +141,13 @@ int __free_extent(struct ctree_root *root, u64 blocknr, u64 num_blocks)
110 int ret; 141 int ret;
111 struct item *item; 142 struct item *item;
112 struct extent_item *ei; 143 struct extent_item *ei;
144 struct key ins;
145
113 key.objectid = blocknr; 146 key.objectid = blocknr;
114 key.flags = 0; 147 key.flags = 0;
115 key.offset = num_blocks; 148 key.offset = num_blocks;
116 149
150 find_free_extent(root, 0, 0, (u64)-1, &ins);
117 init_path(&path); 151 init_path(&path);
118 ret = search_slot(extent_root, &key, &path, -1, 1); 152 ret = search_slot(extent_root, &key, &path, -1, 1);
119 if (ret) { 153 if (ret) {
@@ -140,54 +174,11 @@ int __free_extent(struct ctree_root *root, u64 blocknr, u64 num_blocks)
140 BUG(); 174 BUG();
141 } 175 }
142 release_path(extent_root, &path); 176 release_path(extent_root, &path);
177 finish_current_insert(extent_root);
143 return ret; 178 return ret;
144} 179}
145 180
146/* 181/*
147 * insert all of the pending extents reserved during the original
148 * allocation. (CTREE_EXTENT_PENDING). Returns zero if it all worked out
149 */
150static int insert_pending_extents(struct ctree_root *extent_root)
151{
152 int ret;
153 struct key key;
154 struct extent_item item;
155 struct tree_buffer *gang[4];
156 int i;
157
158 // FIXME -ENOSPC
159 item.owner = extent_root->node->node.header.parentid;
160 item.refs = 1;
161 while(1) {
162 ret = radix_tree_gang_lookup_tag(&extent_root->cache_radix,
163 (void **)gang, 0,
164 ARRAY_SIZE(gang),
165 CTREE_EXTENT_PENDING_ADD);
166 if (!ret)
167 break;
168 for (i = 0; i < ret; i++) {
169 key.objectid = gang[i]->blocknr;
170 key.flags = 0;
171 key.offset = 1;
172 ret = insert_item(extent_root, &key, &item,
173 sizeof(item));
174 if (ret) {
175 printf("%Lu already in tree\n", key.objectid);
176 print_tree(extent_root, extent_root->node);
177 BUG();
178 // FIXME undo it and return sane
179 return ret;
180 }
181 radix_tree_tag_clear(&extent_root->cache_radix,
182 gang[i]->blocknr,
183 CTREE_EXTENT_PENDING_ADD);
184 tree_block_release(extent_root, gang[i]);
185 }
186 }
187 return 0;
188}
189
190/*
191 * find all the blocks marked as pending in the radix tree and remove 182 * find all the blocks marked as pending in the radix tree and remove
192 * them from the extent map 183 * them from the extent map
193 */ 184 */
@@ -218,12 +209,8 @@ static int del_pending_extents(struct ctree_root *extent_root)
218static int run_pending(struct ctree_root *extent_root) 209static int run_pending(struct ctree_root *extent_root)
219{ 210{
220 while(radix_tree_tagged(&extent_root->cache_radix, 211 while(radix_tree_tagged(&extent_root->cache_radix,
221 CTREE_EXTENT_PENDING_DEL) || 212 CTREE_EXTENT_PENDING_DEL))
222 radix_tree_tagged(&extent_root->cache_radix,
223 CTREE_EXTENT_PENDING_ADD)) {
224 insert_pending_extents(extent_root);
225 del_pending_extents(extent_root); 213 del_pending_extents(extent_root);
226 }
227 return 0; 214 return 0;
228} 215}
229 216
@@ -241,19 +228,8 @@ int free_extent(struct ctree_root *root, u64 blocknr, u64 num_blocks)
241 228
242 if (root == extent_root) { 229 if (root == extent_root) {
243 t = find_tree_block(root, blocknr); 230 t = find_tree_block(root, blocknr);
244 if (radix_tree_tag_get(&root->cache_radix, blocknr, 231 radix_tree_tag_set(&root->cache_radix, blocknr,
245 CTREE_EXTENT_PENDING_ADD)) {
246 radix_tree_tag_clear(&root->cache_radix,
247 blocknr,
248 CTREE_EXTENT_PENDING_ADD);
249 /* once for us */
250 tree_block_release(root, t);
251 /* once for the pending add */
252 tree_block_release(root, t);
253 } else {
254 radix_tree_tag_set(&root->cache_radix, blocknr,
255 CTREE_EXTENT_PENDING_DEL); 232 CTREE_EXTENT_PENDING_DEL);
256 }
257 return 0; 233 return 0;
258 } 234 }
259 key.objectid = blocknr; 235 key.objectid = blocknr;
@@ -281,9 +257,11 @@ static int find_free_extent(struct ctree_root *orig_root, u64 num_blocks,
281 u64 hole_size = 0; 257 u64 hole_size = 0;
282 int slot = 0; 258 int slot = 0;
283 u64 last_block; 259 u64 last_block;
260 u64 test_block;
284 int start_found; 261 int start_found;
285 struct leaf *l; 262 struct leaf *l;
286 struct ctree_root * root = orig_root->extent_root; 263 struct ctree_root * root = orig_root->extent_root;
264 int total_needed = num_blocks + MAX_LEVEL * 3;
287 265
288check_failed: 266check_failed:
289 init_path(&path); 267 init_path(&path);
@@ -306,22 +284,34 @@ check_failed:
306 goto error; 284 goto error;
307 if (!start_found) { 285 if (!start_found) {
308 ins->objectid = search_start; 286 ins->objectid = search_start;
309 ins->offset = num_blocks; 287 ins->offset = (u64)-1;
310 start_found = 1; 288 start_found = 1;
311 goto check_pending; 289 goto check_pending;
312 } 290 }
313 ins->objectid = last_block > search_start ? 291 ins->objectid = last_block > search_start ?
314 last_block : search_start; 292 last_block : search_start;
315 ins->offset = num_blocks; 293 ins->offset = (u64)-1;
316 goto check_pending; 294 goto check_pending;
317 } 295 }
296 if (slot == 0) {
297 int last_slot = l->header.nritems - 1;
298 u64 span = l->items[last_slot].key.objectid;
299 span -= l->items[slot].key.objectid;
300 if (span + total_needed > last_slot - slot) {
301 path.slots[0] = last_slot + 1;
302 key = &l->items[last_slot].key;
303 last_block = key->objectid + key->offset;
304 start_found = 1;
305 continue;
306 }
307 }
318 key = &l->items[slot].key; 308 key = &l->items[slot].key;
319 if (key->objectid >= search_start) { 309 if (key->objectid >= search_start) {
320 if (start_found) { 310 if (start_found) {
321 hole_size = key->objectid - last_block; 311 hole_size = key->objectid - last_block;
322 if (hole_size > num_blocks) { 312 if (hole_size > total_needed) {
323 ins->objectid = last_block; 313 ins->objectid = last_block;
324 ins->offset = num_blocks; 314 ins->offset = hole_size;
325 goto check_pending; 315 goto check_pending;
326 } 316 }
327 } else 317 } else
@@ -337,23 +327,18 @@ check_pending:
337 */ 327 */
338 release_path(root, &path); 328 release_path(root, &path);
339 BUG_ON(ins->objectid < search_start); 329 BUG_ON(ins->objectid < search_start);
340 if (1 || orig_root->extent_root == orig_root) { 330 for (test_block = ins->objectid;
341 BUG_ON(num_blocks != 1); 331 test_block < ins->objectid + total_needed; test_block++) {
342 if ((root->current_insert.objectid <= ins->objectid && 332 if (radix_tree_lookup(&root->pinned_radix, test_block)) {
343 root->current_insert.objectid + 333 search_start = test_block + 1;
344 root->current_insert.offset > ins->objectid) ||
345 (root->current_insert.objectid > ins->objectid &&
346 root->current_insert.objectid <= ins->objectid +
347 ins->offset) ||
348 radix_tree_lookup(&root->pinned_radix, ins->objectid) ||
349 radix_tree_tag_get(&root->cache_radix, ins->objectid,
350 CTREE_EXTENT_PENDING_ADD)) {
351 search_start = ins->objectid + 1;
352 goto check_failed; 334 goto check_failed;
353 } 335 }
354 } 336 }
355 if (ins->offset != 1) 337 BUG_ON(root->current_insert.offset);
356 BUG(); 338 root->current_insert.offset = total_needed;
339 root->current_insert.objectid = ins->objectid + num_blocks;
340 root->current_insert.flags = 0;
341 ins->offset = num_blocks;
357 return 0; 342 return 0;
358error: 343error:
359 release_path(root, &path); 344 release_path(root, &path);
@@ -368,43 +353,41 @@ error:
368 * returns 0 if everything worked, non-zero otherwise. 353 * returns 0 if everything worked, non-zero otherwise.
369 */ 354 */
370int alloc_extent(struct ctree_root *root, u64 num_blocks, u64 search_start, 355int alloc_extent(struct ctree_root *root, u64 num_blocks, u64 search_start,
371 u64 search_end, u64 owner, struct key *ins, 356 u64 search_end, u64 owner, struct key *ins)
372 struct tree_buffer **buf)
373{ 357{
374 int ret; 358 int ret;
375 int pending_ret; 359 int pending_ret;
360 struct ctree_root *extent_root = root->extent_root;
376 struct extent_item extent_item; 361 struct extent_item extent_item;
362
377 extent_item.refs = 1; 363 extent_item.refs = 1;
378 extent_item.owner = owner; 364 extent_item.owner = owner;
379 365
380 ret = find_free_extent(root, num_blocks, search_start, search_end, ins); 366 if (root == extent_root) {
381 if (ret) 367 BUG_ON(extent_root->current_insert.offset == 0);
382 return ret; 368 BUG_ON(num_blocks != 1);
383 if (root != root->extent_root) { 369 BUG_ON(extent_root->current_insert.flags ==
384 memcpy(&root->extent_root->current_insert, ins, sizeof(*ins)); 370 extent_root->current_insert.offset);
385 ret = insert_item(root->extent_root, ins, &extent_item, 371 ins->offset = 1;
386 sizeof(extent_item)); 372 ins->objectid = extent_root->current_insert.objectid +
387 memset(&root->extent_root->current_insert, 0, 373 extent_root->current_insert.flags++;
388 sizeof(struct key));
389 pending_ret = run_pending(root->extent_root);
390 if (ret)
391 return ret;
392 if (pending_ret)
393 return pending_ret;
394 *buf = find_tree_block(root, ins->objectid);
395 dirty_tree_block(root, *buf);
396 return 0; 374 return 0;
397 } 375 }
398 /* we're allocating an extent for the extent tree, don't recurse */ 376 ret = find_free_extent(root, num_blocks, search_start,
399 BUG_ON(ins->offset != 1); 377 search_end, ins);
400 *buf = find_tree_block(root, ins->objectid); 378 if (ret)
401 BUG_ON(!*buf); 379 return ret;
402 radix_tree_tag_set(&root->cache_radix, ins->objectid,
403 CTREE_EXTENT_PENDING_ADD);
404 (*buf)->count++;
405 dirty_tree_block(root, *buf);
406 return 0;
407 380
381 ret = insert_item(extent_root, ins, &extent_item,
382 sizeof(extent_item));
383
384 finish_current_insert(extent_root);
385 pending_ret = run_pending(extent_root);
386 if (ret)
387 return ret;
388 if (pending_ret)
389 return pending_ret;
390 return 0;
408} 391}
409 392
410/* 393/*
@@ -415,19 +398,17 @@ struct tree_buffer *alloc_free_block(struct ctree_root *root)
415{ 398{
416 struct key ins; 399 struct key ins;
417 int ret; 400 int ret;
418 struct tree_buffer *buf = NULL; 401 struct tree_buffer *buf;
419 402
420 ret = alloc_extent(root, 1, 0, (unsigned long)-1, 403 ret = alloc_extent(root, 1, 0, (unsigned long)-1,
421 root->node->node.header.parentid, 404 root->node->node.header.parentid,
422 &ins, &buf); 405 &ins);
423 if (ret) { 406 if (ret) {
424 BUG(); 407 BUG();
425 return NULL; 408 return NULL;
426 } 409 }
427 if (root != root->extent_root) 410 buf = find_tree_block(root, ins.objectid);
428 BUG_ON(radix_tree_tag_get(&root->extent_root->cache_radix, 411 dirty_tree_block(root, buf);
429 buf->blocknr,
430 CTREE_EXTENT_PENDING_ADD));
431 return buf; 412 return buf;
432} 413}
433 414