diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-03-10 06:35:47 -0500 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-03-10 06:35:47 -0500 |
commit | 20524f02260910db1e67bd5335d3854e5e555efc (patch) | |
tree | 3fd221fbd79201e5d49ca23bc262c54dad5899f4 /fs/btrfs/extent-tree.c | |
parent | 0579da4280812f34f382fb0f8004d7b0219e7a33 (diff) |
Btrfs: recursion free-first pass
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 98 |
1 files changed, 96 insertions, 2 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index dd11532cb2f6..6fbaece43ff6 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -50,7 +50,7 @@ static int inc_block_ref(struct ctree_root *root, u64 blocknr) | |||
50 | return 0; | 50 | return 0; |
51 | } | 51 | } |
52 | 52 | ||
53 | static int lookup_block_ref(struct ctree_root *root, u64 blocknr, int *refs) | 53 | static int lookup_block_ref(struct ctree_root *root, u64 blocknr, u32 *refs) |
54 | { | 54 | { |
55 | struct ctree_path path; | 55 | struct ctree_path path; |
56 | int ret; | 56 | int ret; |
@@ -415,6 +415,100 @@ struct tree_buffer *alloc_free_block(struct ctree_root *root) | |||
415 | return buf; | 415 | return buf; |
416 | } | 416 | } |
417 | 417 | ||
418 | int walk_down_tree(struct ctree_root *root, struct ctree_path *path, int *level) | ||
419 | { | ||
420 | struct tree_buffer *next; | ||
421 | struct tree_buffer *cur; | ||
422 | u64 blocknr; | ||
423 | int ret; | ||
424 | u32 refs; | ||
425 | |||
426 | ret = lookup_block_ref(root, path->nodes[*level]->blocknr, &refs); | ||
427 | BUG_ON(ret); | ||
428 | if (refs > 1) | ||
429 | goto out; | ||
430 | while(*level > 0) { | ||
431 | cur = path->nodes[*level]; | ||
432 | if (path->slots[*level] >= cur->node.header.nritems) | ||
433 | break; | ||
434 | blocknr = cur->node.blockptrs[path->slots[*level]]; | ||
435 | ret = lookup_block_ref(root, blocknr, &refs); | ||
436 | if (refs != 1 || *level == 1) { | ||
437 | path->slots[*level]++; | ||
438 | ret = free_extent(root, blocknr, 1); | ||
439 | BUG_ON(ret); | ||
440 | continue; | ||
441 | } | ||
442 | BUG_ON(ret); | ||
443 | next = read_tree_block(root, blocknr); | ||
444 | if (path->nodes[*level-1]) { | ||
445 | tree_block_release(root, path->nodes[*level-1]); | ||
446 | } | ||
447 | path->nodes[*level-1] = next; | ||
448 | *level = node_level(next->node.header.flags); | ||
449 | path->slots[*level] = 0; | ||
450 | } | ||
451 | out: | ||
452 | ret = free_extent(root, path->nodes[*level]->blocknr, 1); | ||
453 | path->nodes[*level] = NULL; | ||
454 | *level += 1; | ||
455 | BUG_ON(ret); | ||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | int walk_up_tree(struct ctree_root *root, struct ctree_path *path, int *level) | ||
460 | { | ||
461 | int i; | ||
462 | int slot; | ||
463 | int ret; | ||
464 | for(i = *level; i < MAX_LEVEL - 1 && path->nodes[i]; i++) { | ||
465 | slot = path->slots[i]; | ||
466 | if (slot < path->nodes[i]->node.header.nritems - 1) { | ||
467 | path->slots[i]++; | ||
468 | *level = i; | ||
469 | return 0; | ||
470 | } else { | ||
471 | ret = free_extent(root, | ||
472 | path->nodes[*level]->blocknr, 1); | ||
473 | *level = i + 1; | ||
474 | BUG_ON(ret); | ||
475 | } | ||
476 | } | ||
477 | return 1; | ||
478 | } | ||
479 | |||
480 | int btrfs_drop_snapshot(struct ctree_root *root, struct tree_buffer *snap) | ||
481 | { | ||
482 | int ret; | ||
483 | int level; | ||
484 | struct ctree_path path; | ||
485 | int i; | ||
486 | int orig_level; | ||
487 | |||
488 | init_path(&path); | ||
489 | |||
490 | level = node_level(snap->node.header.flags); | ||
491 | orig_level = level; | ||
492 | path.nodes[level] = snap; | ||
493 | path.slots[level] = 0; | ||
494 | while(1) { | ||
495 | ret = walk_down_tree(root, &path, &level); | ||
496 | if (ret > 0) | ||
497 | break; | ||
498 | ret = walk_up_tree(root, &path, &level); | ||
499 | if (ret > 0) | ||
500 | break; | ||
501 | } | ||
502 | for (i = 0; i < orig_level; i++) { | ||
503 | if (path.nodes[i]) | ||
504 | tree_block_release(root, path.nodes[i]); | ||
505 | } | ||
506 | |||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | |||
511 | #if 0 | ||
418 | int btrfs_drop_snapshot(struct ctree_root *root, struct tree_buffer *snap) | 512 | int btrfs_drop_snapshot(struct ctree_root *root, struct tree_buffer *snap) |
419 | { | 513 | { |
420 | int ret; | 514 | int ret; |
@@ -441,4 +535,4 @@ int btrfs_drop_snapshot(struct ctree_root *root, struct tree_buffer *snap) | |||
441 | BUG_ON(ret); | 535 | BUG_ON(ret); |
442 | return 0; | 536 | return 0; |
443 | } | 537 | } |
444 | 538 | #endif | |