diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 47 |
1 files changed, 36 insertions, 11 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 4a4f2d810d9f..a6969538bca2 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -365,8 +365,9 @@ error: | |||
365 | * | 365 | * |
366 | * returns 0 if everything worked, non-zero otherwise. | 366 | * returns 0 if everything worked, non-zero otherwise. |
367 | */ | 367 | */ |
368 | int alloc_extent(struct btrfs_root *root, u64 num_blocks, u64 search_start, | 368 | static int alloc_extent(struct btrfs_root *root, u64 num_blocks, |
369 | u64 search_end, u64 owner, struct btrfs_key *ins) | 369 | u64 search_start, u64 search_end, u64 owner, |
370 | struct btrfs_key *ins) | ||
370 | { | 371 | { |
371 | int ret; | 372 | int ret; |
372 | int pending_ret; | 373 | int pending_ret; |
@@ -425,7 +426,12 @@ struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_root *root) | |||
425 | return buf; | 426 | return buf; |
426 | } | 427 | } |
427 | 428 | ||
428 | int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path, int *level) | 429 | /* |
430 | * helper function for drop_snapshot, this walks down the tree dropping ref | ||
431 | * counts as it goes. | ||
432 | */ | ||
433 | static int walk_down_tree(struct btrfs_root *root, | ||
434 | struct btrfs_path *path, int *level) | ||
429 | { | 435 | { |
430 | struct btrfs_buffer *next; | 436 | struct btrfs_buffer *next; |
431 | struct btrfs_buffer *cur; | 437 | struct btrfs_buffer *cur; |
@@ -437,6 +443,9 @@ int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path, int *level) | |||
437 | BUG_ON(ret); | 443 | BUG_ON(ret); |
438 | if (refs > 1) | 444 | if (refs > 1) |
439 | goto out; | 445 | goto out; |
446 | /* | ||
447 | * walk down to the last node level and free all the leaves | ||
448 | */ | ||
440 | while(*level > 0) { | 449 | while(*level > 0) { |
441 | cur = path->nodes[*level]; | 450 | cur = path->nodes[*level]; |
442 | if (path->slots[*level] >= | 451 | if (path->slots[*level] >= |
@@ -467,7 +476,13 @@ out: | |||
467 | return 0; | 476 | return 0; |
468 | } | 477 | } |
469 | 478 | ||
470 | int walk_up_tree(struct btrfs_root *root, struct btrfs_path *path, int *level) | 479 | /* |
480 | * helper for dropping snapshots. This walks back up the tree in the path | ||
481 | * to find the first node higher up where we haven't yet gone through | ||
482 | * all the slots | ||
483 | */ | ||
484 | static int walk_up_tree(struct btrfs_root *root, struct btrfs_path *path, | ||
485 | int *level) | ||
471 | { | 486 | { |
472 | int i; | 487 | int i; |
473 | int slot; | 488 | int slot; |
@@ -491,9 +506,15 @@ int walk_up_tree(struct btrfs_root *root, struct btrfs_path *path, int *level) | |||
491 | return 1; | 506 | return 1; |
492 | } | 507 | } |
493 | 508 | ||
509 | /* | ||
510 | * drop the reference count on the tree rooted at 'snap'. This traverses | ||
511 | * the tree freeing any blocks that have a ref count of zero after being | ||
512 | * decremented. | ||
513 | */ | ||
494 | int btrfs_drop_snapshot(struct btrfs_root *root, struct btrfs_buffer *snap) | 514 | int btrfs_drop_snapshot(struct btrfs_root *root, struct btrfs_buffer *snap) |
495 | { | 515 | { |
496 | int ret; | 516 | int ret = 0;; |
517 | int wret; | ||
497 | int level; | 518 | int level; |
498 | struct btrfs_path path; | 519 | struct btrfs_path path; |
499 | int i; | 520 | int i; |
@@ -506,18 +527,22 @@ int btrfs_drop_snapshot(struct btrfs_root *root, struct btrfs_buffer *snap) | |||
506 | path.nodes[level] = snap; | 527 | path.nodes[level] = snap; |
507 | path.slots[level] = 0; | 528 | path.slots[level] = 0; |
508 | while(1) { | 529 | while(1) { |
509 | ret = walk_down_tree(root, &path, &level); | 530 | wret = walk_down_tree(root, &path, &level); |
510 | if (ret > 0) | 531 | if (wret > 0) |
511 | break; | 532 | break; |
512 | ret = walk_up_tree(root, &path, &level); | 533 | if (wret < 0) |
513 | if (ret > 0) | 534 | ret = wret; |
535 | |||
536 | wret = walk_up_tree(root, &path, &level); | ||
537 | if (wret > 0) | ||
514 | break; | 538 | break; |
539 | if (wret < 0) | ||
540 | ret = wret; | ||
515 | } | 541 | } |
516 | for (i = 0; i <= orig_level; i++) { | 542 | for (i = 0; i <= orig_level; i++) { |
517 | if (path.nodes[i]) { | 543 | if (path.nodes[i]) { |
518 | btrfs_block_release(root, path.nodes[i]); | 544 | btrfs_block_release(root, path.nodes[i]); |
519 | } | 545 | } |
520 | } | 546 | } |
521 | 547 | return ret; | |
522 | return 0; | ||
523 | } | 548 | } |