diff options
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 94 |
1 files changed, 6 insertions, 88 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 88d1b1eedc9c..1bcfcdb23cf4 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -2769,9 +2769,13 @@ again: | |||
2769 | * the commit roots are read only | 2769 | * the commit roots are read only |
2770 | * so we always do read locks | 2770 | * so we always do read locks |
2771 | */ | 2771 | */ |
2772 | if (p->need_commit_sem) | ||
2773 | down_read(&root->fs_info->commit_root_sem); | ||
2772 | b = root->commit_root; | 2774 | b = root->commit_root; |
2773 | extent_buffer_get(b); | 2775 | extent_buffer_get(b); |
2774 | level = btrfs_header_level(b); | 2776 | level = btrfs_header_level(b); |
2777 | if (p->need_commit_sem) | ||
2778 | up_read(&root->fs_info->commit_root_sem); | ||
2775 | if (!p->skip_locking) | 2779 | if (!p->skip_locking) |
2776 | btrfs_tree_read_lock(b); | 2780 | btrfs_tree_read_lock(b); |
2777 | } else { | 2781 | } else { |
@@ -5360,7 +5364,6 @@ int btrfs_compare_trees(struct btrfs_root *left_root, | |||
5360 | { | 5364 | { |
5361 | int ret; | 5365 | int ret; |
5362 | int cmp; | 5366 | int cmp; |
5363 | struct btrfs_trans_handle *trans = NULL; | ||
5364 | struct btrfs_path *left_path = NULL; | 5367 | struct btrfs_path *left_path = NULL; |
5365 | struct btrfs_path *right_path = NULL; | 5368 | struct btrfs_path *right_path = NULL; |
5366 | struct btrfs_key left_key; | 5369 | struct btrfs_key left_key; |
@@ -5378,9 +5381,6 @@ int btrfs_compare_trees(struct btrfs_root *left_root, | |||
5378 | u64 right_blockptr; | 5381 | u64 right_blockptr; |
5379 | u64 left_gen; | 5382 | u64 left_gen; |
5380 | u64 right_gen; | 5383 | u64 right_gen; |
5381 | u64 left_start_ctransid; | ||
5382 | u64 right_start_ctransid; | ||
5383 | u64 ctransid; | ||
5384 | 5384 | ||
5385 | left_path = btrfs_alloc_path(); | 5385 | left_path = btrfs_alloc_path(); |
5386 | if (!left_path) { | 5386 | if (!left_path) { |
@@ -5404,21 +5404,6 @@ int btrfs_compare_trees(struct btrfs_root *left_root, | |||
5404 | right_path->search_commit_root = 1; | 5404 | right_path->search_commit_root = 1; |
5405 | right_path->skip_locking = 1; | 5405 | right_path->skip_locking = 1; |
5406 | 5406 | ||
5407 | spin_lock(&left_root->root_item_lock); | ||
5408 | left_start_ctransid = btrfs_root_ctransid(&left_root->root_item); | ||
5409 | spin_unlock(&left_root->root_item_lock); | ||
5410 | |||
5411 | spin_lock(&right_root->root_item_lock); | ||
5412 | right_start_ctransid = btrfs_root_ctransid(&right_root->root_item); | ||
5413 | spin_unlock(&right_root->root_item_lock); | ||
5414 | |||
5415 | trans = btrfs_join_transaction(left_root); | ||
5416 | if (IS_ERR(trans)) { | ||
5417 | ret = PTR_ERR(trans); | ||
5418 | trans = NULL; | ||
5419 | goto out; | ||
5420 | } | ||
5421 | |||
5422 | /* | 5407 | /* |
5423 | * Strategy: Go to the first items of both trees. Then do | 5408 | * Strategy: Go to the first items of both trees. Then do |
5424 | * | 5409 | * |
@@ -5455,6 +5440,7 @@ int btrfs_compare_trees(struct btrfs_root *left_root, | |||
5455 | * the right if possible or go up and right. | 5440 | * the right if possible or go up and right. |
5456 | */ | 5441 | */ |
5457 | 5442 | ||
5443 | down_read(&left_root->fs_info->commit_root_sem); | ||
5458 | left_level = btrfs_header_level(left_root->commit_root); | 5444 | left_level = btrfs_header_level(left_root->commit_root); |
5459 | left_root_level = left_level; | 5445 | left_root_level = left_level; |
5460 | left_path->nodes[left_level] = left_root->commit_root; | 5446 | left_path->nodes[left_level] = left_root->commit_root; |
@@ -5464,6 +5450,7 @@ int btrfs_compare_trees(struct btrfs_root *left_root, | |||
5464 | right_root_level = right_level; | 5450 | right_root_level = right_level; |
5465 | right_path->nodes[right_level] = right_root->commit_root; | 5451 | right_path->nodes[right_level] = right_root->commit_root; |
5466 | extent_buffer_get(right_path->nodes[right_level]); | 5452 | extent_buffer_get(right_path->nodes[right_level]); |
5453 | up_read(&left_root->fs_info->commit_root_sem); | ||
5467 | 5454 | ||
5468 | if (left_level == 0) | 5455 | if (left_level == 0) |
5469 | btrfs_item_key_to_cpu(left_path->nodes[left_level], | 5456 | btrfs_item_key_to_cpu(left_path->nodes[left_level], |
@@ -5482,67 +5469,6 @@ int btrfs_compare_trees(struct btrfs_root *left_root, | |||
5482 | advance_left = advance_right = 0; | 5469 | advance_left = advance_right = 0; |
5483 | 5470 | ||
5484 | while (1) { | 5471 | while (1) { |
5485 | /* | ||
5486 | * We need to make sure the transaction does not get committed | ||
5487 | * while we do anything on commit roots. This means, we need to | ||
5488 | * join and leave transactions for every item that we process. | ||
5489 | */ | ||
5490 | if (trans && btrfs_should_end_transaction(trans, left_root)) { | ||
5491 | btrfs_release_path(left_path); | ||
5492 | btrfs_release_path(right_path); | ||
5493 | |||
5494 | ret = btrfs_end_transaction(trans, left_root); | ||
5495 | trans = NULL; | ||
5496 | if (ret < 0) | ||
5497 | goto out; | ||
5498 | } | ||
5499 | /* now rejoin the transaction */ | ||
5500 | if (!trans) { | ||
5501 | trans = btrfs_join_transaction(left_root); | ||
5502 | if (IS_ERR(trans)) { | ||
5503 | ret = PTR_ERR(trans); | ||
5504 | trans = NULL; | ||
5505 | goto out; | ||
5506 | } | ||
5507 | |||
5508 | spin_lock(&left_root->root_item_lock); | ||
5509 | ctransid = btrfs_root_ctransid(&left_root->root_item); | ||
5510 | spin_unlock(&left_root->root_item_lock); | ||
5511 | if (ctransid != left_start_ctransid) | ||
5512 | left_start_ctransid = 0; | ||
5513 | |||
5514 | spin_lock(&right_root->root_item_lock); | ||
5515 | ctransid = btrfs_root_ctransid(&right_root->root_item); | ||
5516 | spin_unlock(&right_root->root_item_lock); | ||
5517 | if (ctransid != right_start_ctransid) | ||
5518 | right_start_ctransid = 0; | ||
5519 | |||
5520 | if (!left_start_ctransid || !right_start_ctransid) { | ||
5521 | WARN(1, KERN_WARNING | ||
5522 | "BTRFS: btrfs_compare_tree detected " | ||
5523 | "a change in one of the trees while " | ||
5524 | "iterating. This is probably a " | ||
5525 | "bug.\n"); | ||
5526 | ret = -EIO; | ||
5527 | goto out; | ||
5528 | } | ||
5529 | |||
5530 | /* | ||
5531 | * the commit root may have changed, so start again | ||
5532 | * where we stopped | ||
5533 | */ | ||
5534 | left_path->lowest_level = left_level; | ||
5535 | right_path->lowest_level = right_level; | ||
5536 | ret = btrfs_search_slot(NULL, left_root, | ||
5537 | &left_key, left_path, 0, 0); | ||
5538 | if (ret < 0) | ||
5539 | goto out; | ||
5540 | ret = btrfs_search_slot(NULL, right_root, | ||
5541 | &right_key, right_path, 0, 0); | ||
5542 | if (ret < 0) | ||
5543 | goto out; | ||
5544 | } | ||
5545 | |||
5546 | if (advance_left && !left_end_reached) { | 5472 | if (advance_left && !left_end_reached) { |
5547 | ret = tree_advance(left_root, left_path, &left_level, | 5473 | ret = tree_advance(left_root, left_path, &left_level, |
5548 | left_root_level, | 5474 | left_root_level, |
@@ -5672,14 +5598,6 @@ out: | |||
5672 | btrfs_free_path(left_path); | 5598 | btrfs_free_path(left_path); |
5673 | btrfs_free_path(right_path); | 5599 | btrfs_free_path(right_path); |
5674 | kfree(tmp_buf); | 5600 | kfree(tmp_buf); |
5675 | |||
5676 | if (trans) { | ||
5677 | if (!ret) | ||
5678 | ret = btrfs_end_transaction(trans, left_root); | ||
5679 | else | ||
5680 | btrfs_end_transaction(trans, left_root); | ||
5681 | } | ||
5682 | |||
5683 | return ret; | 5601 | return ret; |
5684 | } | 5602 | } |
5685 | 5603 | ||