diff options
-rw-r--r-- | fs/btrfs/backref.c | 33 | ||||
-rw-r--r-- | fs/btrfs/ctree.c | 88 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 3 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 3 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 20 | ||||
-rw-r--r-- | fs/btrfs/inode-map.c | 14 | ||||
-rw-r--r-- | fs/btrfs/send.c | 57 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 45 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 1 |
9 files changed, 77 insertions, 187 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index aad7201ad11b..10db21fa0926 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c | |||
@@ -330,7 +330,10 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | |||
330 | goto out; | 330 | goto out; |
331 | } | 331 | } |
332 | 332 | ||
333 | root_level = btrfs_old_root_level(root, time_seq); | 333 | if (path->search_commit_root) |
334 | root_level = btrfs_header_level(root->commit_root); | ||
335 | else | ||
336 | root_level = btrfs_old_root_level(root, time_seq); | ||
334 | 337 | ||
335 | if (root_level + 1 == level) { | 338 | if (root_level + 1 == level) { |
336 | srcu_read_unlock(&fs_info->subvol_srcu, index); | 339 | srcu_read_unlock(&fs_info->subvol_srcu, index); |
@@ -1099,9 +1102,9 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, | |||
1099 | * | 1102 | * |
1100 | * returns 0 on success, < 0 on error. | 1103 | * returns 0 on success, < 0 on error. |
1101 | */ | 1104 | */ |
1102 | int btrfs_find_all_roots(struct btrfs_trans_handle *trans, | 1105 | static int __btrfs_find_all_roots(struct btrfs_trans_handle *trans, |
1103 | struct btrfs_fs_info *fs_info, u64 bytenr, | 1106 | struct btrfs_fs_info *fs_info, u64 bytenr, |
1104 | u64 time_seq, struct ulist **roots) | 1107 | u64 time_seq, struct ulist **roots) |
1105 | { | 1108 | { |
1106 | struct ulist *tmp; | 1109 | struct ulist *tmp; |
1107 | struct ulist_node *node = NULL; | 1110 | struct ulist_node *node = NULL; |
@@ -1137,6 +1140,20 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans, | |||
1137 | return 0; | 1140 | return 0; |
1138 | } | 1141 | } |
1139 | 1142 | ||
1143 | int btrfs_find_all_roots(struct btrfs_trans_handle *trans, | ||
1144 | struct btrfs_fs_info *fs_info, u64 bytenr, | ||
1145 | u64 time_seq, struct ulist **roots) | ||
1146 | { | ||
1147 | int ret; | ||
1148 | |||
1149 | if (!trans) | ||
1150 | down_read(&fs_info->commit_root_sem); | ||
1151 | ret = __btrfs_find_all_roots(trans, fs_info, bytenr, time_seq, roots); | ||
1152 | if (!trans) | ||
1153 | up_read(&fs_info->commit_root_sem); | ||
1154 | return ret; | ||
1155 | } | ||
1156 | |||
1140 | /* | 1157 | /* |
1141 | * this makes the path point to (inum INODE_ITEM ioff) | 1158 | * this makes the path point to (inum INODE_ITEM ioff) |
1142 | */ | 1159 | */ |
@@ -1516,6 +1533,8 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, | |||
1516 | if (IS_ERR(trans)) | 1533 | if (IS_ERR(trans)) |
1517 | return PTR_ERR(trans); | 1534 | return PTR_ERR(trans); |
1518 | btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem); | 1535 | btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem); |
1536 | } else { | ||
1537 | down_read(&fs_info->commit_root_sem); | ||
1519 | } | 1538 | } |
1520 | 1539 | ||
1521 | ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid, | 1540 | ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid, |
@@ -1526,8 +1545,8 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, | |||
1526 | 1545 | ||
1527 | ULIST_ITER_INIT(&ref_uiter); | 1546 | ULIST_ITER_INIT(&ref_uiter); |
1528 | while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) { | 1547 | while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) { |
1529 | ret = btrfs_find_all_roots(trans, fs_info, ref_node->val, | 1548 | ret = __btrfs_find_all_roots(trans, fs_info, ref_node->val, |
1530 | tree_mod_seq_elem.seq, &roots); | 1549 | tree_mod_seq_elem.seq, &roots); |
1531 | if (ret) | 1550 | if (ret) |
1532 | break; | 1551 | break; |
1533 | ULIST_ITER_INIT(&root_uiter); | 1552 | ULIST_ITER_INIT(&root_uiter); |
@@ -1549,6 +1568,8 @@ out: | |||
1549 | if (!search_commit_root) { | 1568 | if (!search_commit_root) { |
1550 | btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem); | 1569 | btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem); |
1551 | btrfs_end_transaction(trans, fs_info->extent_root); | 1570 | btrfs_end_transaction(trans, fs_info->extent_root); |
1571 | } else { | ||
1572 | up_read(&fs_info->commit_root_sem); | ||
1552 | } | 1573 | } |
1553 | 1574 | ||
1554 | return ret; | 1575 | return ret; |
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 88d1b1eedc9c..9d89c1648e8e 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -5360,7 +5360,6 @@ int btrfs_compare_trees(struct btrfs_root *left_root, | |||
5360 | { | 5360 | { |
5361 | int ret; | 5361 | int ret; |
5362 | int cmp; | 5362 | int cmp; |
5363 | struct btrfs_trans_handle *trans = NULL; | ||
5364 | struct btrfs_path *left_path = NULL; | 5363 | struct btrfs_path *left_path = NULL; |
5365 | struct btrfs_path *right_path = NULL; | 5364 | struct btrfs_path *right_path = NULL; |
5366 | struct btrfs_key left_key; | 5365 | struct btrfs_key left_key; |
@@ -5378,9 +5377,6 @@ int btrfs_compare_trees(struct btrfs_root *left_root, | |||
5378 | u64 right_blockptr; | 5377 | u64 right_blockptr; |
5379 | u64 left_gen; | 5378 | u64 left_gen; |
5380 | u64 right_gen; | 5379 | u64 right_gen; |
5381 | u64 left_start_ctransid; | ||
5382 | u64 right_start_ctransid; | ||
5383 | u64 ctransid; | ||
5384 | 5380 | ||
5385 | left_path = btrfs_alloc_path(); | 5381 | left_path = btrfs_alloc_path(); |
5386 | if (!left_path) { | 5382 | if (!left_path) { |
@@ -5404,21 +5400,6 @@ int btrfs_compare_trees(struct btrfs_root *left_root, | |||
5404 | right_path->search_commit_root = 1; | 5400 | right_path->search_commit_root = 1; |
5405 | right_path->skip_locking = 1; | 5401 | right_path->skip_locking = 1; |
5406 | 5402 | ||
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 | /* | 5403 | /* |
5423 | * Strategy: Go to the first items of both trees. Then do | 5404 | * Strategy: Go to the first items of both trees. Then do |
5424 | * | 5405 | * |
@@ -5482,67 +5463,6 @@ int btrfs_compare_trees(struct btrfs_root *left_root, | |||
5482 | advance_left = advance_right = 0; | 5463 | advance_left = advance_right = 0; |
5483 | 5464 | ||
5484 | while (1) { | 5465 | 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) { | 5466 | if (advance_left && !left_end_reached) { |
5547 | ret = tree_advance(left_root, left_path, &left_level, | 5467 | ret = tree_advance(left_root, left_path, &left_level, |
5548 | left_root_level, | 5468 | left_root_level, |
@@ -5672,14 +5592,6 @@ out: | |||
5672 | btrfs_free_path(left_path); | 5592 | btrfs_free_path(left_path); |
5673 | btrfs_free_path(right_path); | 5593 | btrfs_free_path(right_path); |
5674 | kfree(tmp_buf); | 5594 | 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; | 5595 | return ret; |
5684 | } | 5596 | } |
5685 | 5597 | ||
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 2a9d32e193a5..4253ab257c9c 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1440,7 +1440,7 @@ struct btrfs_fs_info { | |||
1440 | */ | 1440 | */ |
1441 | struct mutex ordered_extent_flush_mutex; | 1441 | struct mutex ordered_extent_flush_mutex; |
1442 | 1442 | ||
1443 | struct rw_semaphore extent_commit_sem; | 1443 | struct rw_semaphore commit_root_sem; |
1444 | 1444 | ||
1445 | struct rw_semaphore cleanup_work_sem; | 1445 | struct rw_semaphore cleanup_work_sem; |
1446 | 1446 | ||
@@ -1711,7 +1711,6 @@ struct btrfs_root { | |||
1711 | struct btrfs_block_rsv *block_rsv; | 1711 | struct btrfs_block_rsv *block_rsv; |
1712 | 1712 | ||
1713 | /* free ino cache stuff */ | 1713 | /* free ino cache stuff */ |
1714 | struct mutex fs_commit_mutex; | ||
1715 | struct btrfs_free_space_ctl *free_ino_ctl; | 1714 | struct btrfs_free_space_ctl *free_ino_ctl; |
1716 | enum btrfs_caching_type cached; | 1715 | enum btrfs_caching_type cached; |
1717 | spinlock_t cache_lock; | 1716 | spinlock_t cache_lock; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 98fe70193397..6d1ac7d46f81 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -1567,7 +1567,6 @@ int btrfs_init_fs_root(struct btrfs_root *root) | |||
1567 | root->subv_writers = writers; | 1567 | root->subv_writers = writers; |
1568 | 1568 | ||
1569 | btrfs_init_free_ino_ctl(root); | 1569 | btrfs_init_free_ino_ctl(root); |
1570 | mutex_init(&root->fs_commit_mutex); | ||
1571 | spin_lock_init(&root->cache_lock); | 1570 | spin_lock_init(&root->cache_lock); |
1572 | init_waitqueue_head(&root->cache_wait); | 1571 | init_waitqueue_head(&root->cache_wait); |
1573 | 1572 | ||
@@ -2345,7 +2344,7 @@ int open_ctree(struct super_block *sb, | |||
2345 | mutex_init(&fs_info->transaction_kthread_mutex); | 2344 | mutex_init(&fs_info->transaction_kthread_mutex); |
2346 | mutex_init(&fs_info->cleaner_mutex); | 2345 | mutex_init(&fs_info->cleaner_mutex); |
2347 | mutex_init(&fs_info->volume_mutex); | 2346 | mutex_init(&fs_info->volume_mutex); |
2348 | init_rwsem(&fs_info->extent_commit_sem); | 2347 | init_rwsem(&fs_info->commit_root_sem); |
2349 | init_rwsem(&fs_info->cleanup_work_sem); | 2348 | init_rwsem(&fs_info->cleanup_work_sem); |
2350 | init_rwsem(&fs_info->subvol_sem); | 2349 | init_rwsem(&fs_info->subvol_sem); |
2351 | sema_init(&fs_info->uuid_tree_rescan_sem, 1); | 2350 | sema_init(&fs_info->uuid_tree_rescan_sem, 1); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index e09db2c2f3b4..4d2508bbf6f0 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -419,7 +419,7 @@ static noinline void caching_thread(struct btrfs_work *work) | |||
419 | again: | 419 | again: |
420 | mutex_lock(&caching_ctl->mutex); | 420 | mutex_lock(&caching_ctl->mutex); |
421 | /* need to make sure the commit_root doesn't disappear */ | 421 | /* need to make sure the commit_root doesn't disappear */ |
422 | down_read(&fs_info->extent_commit_sem); | 422 | down_read(&fs_info->commit_root_sem); |
423 | 423 | ||
424 | next: | 424 | next: |
425 | ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0); | 425 | ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0); |
@@ -443,10 +443,10 @@ next: | |||
443 | break; | 443 | break; |
444 | 444 | ||
445 | if (need_resched() || | 445 | if (need_resched() || |
446 | rwsem_is_contended(&fs_info->extent_commit_sem)) { | 446 | rwsem_is_contended(&fs_info->commit_root_sem)) { |
447 | caching_ctl->progress = last; | 447 | caching_ctl->progress = last; |
448 | btrfs_release_path(path); | 448 | btrfs_release_path(path); |
449 | up_read(&fs_info->extent_commit_sem); | 449 | up_read(&fs_info->commit_root_sem); |
450 | mutex_unlock(&caching_ctl->mutex); | 450 | mutex_unlock(&caching_ctl->mutex); |
451 | cond_resched(); | 451 | cond_resched(); |
452 | goto again; | 452 | goto again; |
@@ -513,7 +513,7 @@ next: | |||
513 | 513 | ||
514 | err: | 514 | err: |
515 | btrfs_free_path(path); | 515 | btrfs_free_path(path); |
516 | up_read(&fs_info->extent_commit_sem); | 516 | up_read(&fs_info->commit_root_sem); |
517 | 517 | ||
518 | free_excluded_extents(extent_root, block_group); | 518 | free_excluded_extents(extent_root, block_group); |
519 | 519 | ||
@@ -633,10 +633,10 @@ static int cache_block_group(struct btrfs_block_group_cache *cache, | |||
633 | return 0; | 633 | return 0; |
634 | } | 634 | } |
635 | 635 | ||
636 | down_write(&fs_info->extent_commit_sem); | 636 | down_write(&fs_info->commit_root_sem); |
637 | atomic_inc(&caching_ctl->count); | 637 | atomic_inc(&caching_ctl->count); |
638 | list_add_tail(&caching_ctl->list, &fs_info->caching_block_groups); | 638 | list_add_tail(&caching_ctl->list, &fs_info->caching_block_groups); |
639 | up_write(&fs_info->extent_commit_sem); | 639 | up_write(&fs_info->commit_root_sem); |
640 | 640 | ||
641 | btrfs_get_block_group(cache); | 641 | btrfs_get_block_group(cache); |
642 | 642 | ||
@@ -5471,7 +5471,7 @@ void btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans, | |||
5471 | struct btrfs_block_group_cache *cache; | 5471 | struct btrfs_block_group_cache *cache; |
5472 | struct btrfs_space_info *space_info; | 5472 | struct btrfs_space_info *space_info; |
5473 | 5473 | ||
5474 | down_write(&fs_info->extent_commit_sem); | 5474 | down_write(&fs_info->commit_root_sem); |
5475 | 5475 | ||
5476 | list_for_each_entry_safe(caching_ctl, next, | 5476 | list_for_each_entry_safe(caching_ctl, next, |
5477 | &fs_info->caching_block_groups, list) { | 5477 | &fs_info->caching_block_groups, list) { |
@@ -5490,7 +5490,7 @@ void btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans, | |||
5490 | else | 5490 | else |
5491 | fs_info->pinned_extents = &fs_info->freed_extents[0]; | 5491 | fs_info->pinned_extents = &fs_info->freed_extents[0]; |
5492 | 5492 | ||
5493 | up_write(&fs_info->extent_commit_sem); | 5493 | up_write(&fs_info->commit_root_sem); |
5494 | 5494 | ||
5495 | list_for_each_entry_rcu(space_info, &fs_info->space_info, list) | 5495 | list_for_each_entry_rcu(space_info, &fs_info->space_info, list) |
5496 | percpu_counter_set(&space_info->total_bytes_pinned, 0); | 5496 | percpu_counter_set(&space_info->total_bytes_pinned, 0); |
@@ -8256,14 +8256,14 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) | |||
8256 | struct btrfs_caching_control *caching_ctl; | 8256 | struct btrfs_caching_control *caching_ctl; |
8257 | struct rb_node *n; | 8257 | struct rb_node *n; |
8258 | 8258 | ||
8259 | down_write(&info->extent_commit_sem); | 8259 | down_write(&info->commit_root_sem); |
8260 | while (!list_empty(&info->caching_block_groups)) { | 8260 | while (!list_empty(&info->caching_block_groups)) { |
8261 | caching_ctl = list_entry(info->caching_block_groups.next, | 8261 | caching_ctl = list_entry(info->caching_block_groups.next, |
8262 | struct btrfs_caching_control, list); | 8262 | struct btrfs_caching_control, list); |
8263 | list_del(&caching_ctl->list); | 8263 | list_del(&caching_ctl->list); |
8264 | put_caching_control(caching_ctl); | 8264 | put_caching_control(caching_ctl); |
8265 | } | 8265 | } |
8266 | up_write(&info->extent_commit_sem); | 8266 | up_write(&info->commit_root_sem); |
8267 | 8267 | ||
8268 | spin_lock(&info->block_group_cache_lock); | 8268 | spin_lock(&info->block_group_cache_lock); |
8269 | while ((n = rb_last(&info->block_group_cache_tree)) != NULL) { | 8269 | while ((n = rb_last(&info->block_group_cache_tree)) != NULL) { |
diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index ab485e57b6fe..cc8ca193d830 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c | |||
@@ -55,7 +55,7 @@ static int caching_kthread(void *data) | |||
55 | key.type = BTRFS_INODE_ITEM_KEY; | 55 | key.type = BTRFS_INODE_ITEM_KEY; |
56 | again: | 56 | again: |
57 | /* need to make sure the commit_root doesn't disappear */ | 57 | /* need to make sure the commit_root doesn't disappear */ |
58 | mutex_lock(&root->fs_commit_mutex); | 58 | down_read(&fs_info->commit_root_sem); |
59 | 59 | ||
60 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 60 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
61 | if (ret < 0) | 61 | if (ret < 0) |
@@ -88,7 +88,7 @@ again: | |||
88 | btrfs_item_key_to_cpu(leaf, &key, 0); | 88 | btrfs_item_key_to_cpu(leaf, &key, 0); |
89 | btrfs_release_path(path); | 89 | btrfs_release_path(path); |
90 | root->cache_progress = last; | 90 | root->cache_progress = last; |
91 | mutex_unlock(&root->fs_commit_mutex); | 91 | up_read(&fs_info->commit_root_sem); |
92 | schedule_timeout(1); | 92 | schedule_timeout(1); |
93 | goto again; | 93 | goto again; |
94 | } else | 94 | } else |
@@ -127,7 +127,7 @@ next: | |||
127 | btrfs_unpin_free_ino(root); | 127 | btrfs_unpin_free_ino(root); |
128 | out: | 128 | out: |
129 | wake_up(&root->cache_wait); | 129 | wake_up(&root->cache_wait); |
130 | mutex_unlock(&root->fs_commit_mutex); | 130 | up_read(&fs_info->commit_root_sem); |
131 | 131 | ||
132 | btrfs_free_path(path); | 132 | btrfs_free_path(path); |
133 | 133 | ||
@@ -223,11 +223,11 @@ again: | |||
223 | * or the caching work is done. | 223 | * or the caching work is done. |
224 | */ | 224 | */ |
225 | 225 | ||
226 | mutex_lock(&root->fs_commit_mutex); | 226 | down_write(&root->fs_info->commit_root_sem); |
227 | spin_lock(&root->cache_lock); | 227 | spin_lock(&root->cache_lock); |
228 | if (root->cached == BTRFS_CACHE_FINISHED) { | 228 | if (root->cached == BTRFS_CACHE_FINISHED) { |
229 | spin_unlock(&root->cache_lock); | 229 | spin_unlock(&root->cache_lock); |
230 | mutex_unlock(&root->fs_commit_mutex); | 230 | up_write(&root->fs_info->commit_root_sem); |
231 | goto again; | 231 | goto again; |
232 | } | 232 | } |
233 | spin_unlock(&root->cache_lock); | 233 | spin_unlock(&root->cache_lock); |
@@ -240,7 +240,7 @@ again: | |||
240 | else | 240 | else |
241 | __btrfs_add_free_space(pinned, objectid, 1); | 241 | __btrfs_add_free_space(pinned, objectid, 1); |
242 | 242 | ||
243 | mutex_unlock(&root->fs_commit_mutex); | 243 | up_write(&root->fs_info->commit_root_sem); |
244 | } | 244 | } |
245 | } | 245 | } |
246 | 246 | ||
@@ -250,7 +250,7 @@ again: | |||
250 | * and others will just be dropped, because the commit root we were | 250 | * and others will just be dropped, because the commit root we were |
251 | * searching has changed. | 251 | * searching has changed. |
252 | * | 252 | * |
253 | * Must be called with root->fs_commit_mutex held | 253 | * Must be called with root->fs_info->commit_root_sem held |
254 | */ | 254 | */ |
255 | void btrfs_unpin_free_ino(struct btrfs_root *root) | 255 | void btrfs_unpin_free_ino(struct btrfs_root *root) |
256 | { | 256 | { |
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index d00534b78382..6b5f13659317 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c | |||
@@ -1268,8 +1268,10 @@ static int find_extent_clone(struct send_ctx *sctx, | |||
1268 | } | 1268 | } |
1269 | logical = disk_byte + btrfs_file_extent_offset(eb, fi); | 1269 | logical = disk_byte + btrfs_file_extent_offset(eb, fi); |
1270 | 1270 | ||
1271 | down_read(&sctx->send_root->fs_info->commit_root_sem); | ||
1271 | ret = extent_from_logical(sctx->send_root->fs_info, disk_byte, tmp_path, | 1272 | ret = extent_from_logical(sctx->send_root->fs_info, disk_byte, tmp_path, |
1272 | &found_key, &flags); | 1273 | &found_key, &flags); |
1274 | up_read(&sctx->send_root->fs_info->commit_root_sem); | ||
1273 | btrfs_release_path(tmp_path); | 1275 | btrfs_release_path(tmp_path); |
1274 | 1276 | ||
1275 | if (ret < 0) | 1277 | if (ret < 0) |
@@ -5367,57 +5369,21 @@ out: | |||
5367 | static int full_send_tree(struct send_ctx *sctx) | 5369 | static int full_send_tree(struct send_ctx *sctx) |
5368 | { | 5370 | { |
5369 | int ret; | 5371 | int ret; |
5370 | struct btrfs_trans_handle *trans = NULL; | ||
5371 | struct btrfs_root *send_root = sctx->send_root; | 5372 | struct btrfs_root *send_root = sctx->send_root; |
5372 | struct btrfs_key key; | 5373 | struct btrfs_key key; |
5373 | struct btrfs_key found_key; | 5374 | struct btrfs_key found_key; |
5374 | struct btrfs_path *path; | 5375 | struct btrfs_path *path; |
5375 | struct extent_buffer *eb; | 5376 | struct extent_buffer *eb; |
5376 | int slot; | 5377 | int slot; |
5377 | u64 start_ctransid; | ||
5378 | u64 ctransid; | ||
5379 | 5378 | ||
5380 | path = alloc_path_for_send(); | 5379 | path = alloc_path_for_send(); |
5381 | if (!path) | 5380 | if (!path) |
5382 | return -ENOMEM; | 5381 | return -ENOMEM; |
5383 | 5382 | ||
5384 | spin_lock(&send_root->root_item_lock); | ||
5385 | start_ctransid = btrfs_root_ctransid(&send_root->root_item); | ||
5386 | spin_unlock(&send_root->root_item_lock); | ||
5387 | |||
5388 | key.objectid = BTRFS_FIRST_FREE_OBJECTID; | 5383 | key.objectid = BTRFS_FIRST_FREE_OBJECTID; |
5389 | key.type = BTRFS_INODE_ITEM_KEY; | 5384 | key.type = BTRFS_INODE_ITEM_KEY; |
5390 | key.offset = 0; | 5385 | key.offset = 0; |
5391 | 5386 | ||
5392 | join_trans: | ||
5393 | /* | ||
5394 | * We need to make sure the transaction does not get committed | ||
5395 | * while we do anything on commit roots. Join a transaction to prevent | ||
5396 | * this. | ||
5397 | */ | ||
5398 | trans = btrfs_join_transaction(send_root); | ||
5399 | if (IS_ERR(trans)) { | ||
5400 | ret = PTR_ERR(trans); | ||
5401 | trans = NULL; | ||
5402 | goto out; | ||
5403 | } | ||
5404 | |||
5405 | /* | ||
5406 | * Make sure the tree has not changed after re-joining. We detect this | ||
5407 | * by comparing start_ctransid and ctransid. They should always match. | ||
5408 | */ | ||
5409 | spin_lock(&send_root->root_item_lock); | ||
5410 | ctransid = btrfs_root_ctransid(&send_root->root_item); | ||
5411 | spin_unlock(&send_root->root_item_lock); | ||
5412 | |||
5413 | if (ctransid != start_ctransid) { | ||
5414 | WARN(1, KERN_WARNING "BTRFS: the root that you're trying to " | ||
5415 | "send was modified in between. This is " | ||
5416 | "probably a bug.\n"); | ||
5417 | ret = -EIO; | ||
5418 | goto out; | ||
5419 | } | ||
5420 | |||
5421 | ret = btrfs_search_slot_for_read(send_root, &key, path, 1, 0); | 5387 | ret = btrfs_search_slot_for_read(send_root, &key, path, 1, 0); |
5422 | if (ret < 0) | 5388 | if (ret < 0) |
5423 | goto out; | 5389 | goto out; |
@@ -5425,19 +5391,6 @@ join_trans: | |||
5425 | goto out_finish; | 5391 | goto out_finish; |
5426 | 5392 | ||
5427 | while (1) { | 5393 | while (1) { |
5428 | /* | ||
5429 | * When someone want to commit while we iterate, end the | ||
5430 | * joined transaction and rejoin. | ||
5431 | */ | ||
5432 | if (btrfs_should_end_transaction(trans, send_root)) { | ||
5433 | ret = btrfs_end_transaction(trans, send_root); | ||
5434 | trans = NULL; | ||
5435 | if (ret < 0) | ||
5436 | goto out; | ||
5437 | btrfs_release_path(path); | ||
5438 | goto join_trans; | ||
5439 | } | ||
5440 | |||
5441 | eb = path->nodes[0]; | 5394 | eb = path->nodes[0]; |
5442 | slot = path->slots[0]; | 5395 | slot = path->slots[0]; |
5443 | btrfs_item_key_to_cpu(eb, &found_key, slot); | 5396 | btrfs_item_key_to_cpu(eb, &found_key, slot); |
@@ -5465,12 +5418,6 @@ out_finish: | |||
5465 | 5418 | ||
5466 | out: | 5419 | out: |
5467 | btrfs_free_path(path); | 5420 | btrfs_free_path(path); |
5468 | if (trans) { | ||
5469 | if (!ret) | ||
5470 | ret = btrfs_end_transaction(trans, send_root); | ||
5471 | else | ||
5472 | btrfs_end_transaction(trans, send_root); | ||
5473 | } | ||
5474 | return ret; | 5421 | return ret; |
5475 | } | 5422 | } |
5476 | 5423 | ||
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 038177cfabbb..7579f6d0b854 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -75,10 +75,21 @@ void btrfs_put_transaction(struct btrfs_transaction *transaction) | |||
75 | } | 75 | } |
76 | } | 76 | } |
77 | 77 | ||
78 | static noinline void switch_commit_root(struct btrfs_root *root) | 78 | static noinline void switch_commit_roots(struct btrfs_transaction *trans, |
79 | struct btrfs_fs_info *fs_info) | ||
79 | { | 80 | { |
80 | free_extent_buffer(root->commit_root); | 81 | struct btrfs_root *root, *tmp; |
81 | root->commit_root = btrfs_root_node(root); | 82 | |
83 | down_write(&fs_info->commit_root_sem); | ||
84 | list_for_each_entry_safe(root, tmp, &trans->switch_commits, | ||
85 | dirty_list) { | ||
86 | list_del_init(&root->dirty_list); | ||
87 | free_extent_buffer(root->commit_root); | ||
88 | root->commit_root = btrfs_root_node(root); | ||
89 | if (is_fstree(root->objectid)) | ||
90 | btrfs_unpin_free_ino(root); | ||
91 | } | ||
92 | up_write(&fs_info->commit_root_sem); | ||
82 | } | 93 | } |
83 | 94 | ||
84 | static inline void extwriter_counter_inc(struct btrfs_transaction *trans, | 95 | static inline void extwriter_counter_inc(struct btrfs_transaction *trans, |
@@ -208,6 +219,7 @@ loop: | |||
208 | INIT_LIST_HEAD(&cur_trans->pending_snapshots); | 219 | INIT_LIST_HEAD(&cur_trans->pending_snapshots); |
209 | INIT_LIST_HEAD(&cur_trans->ordered_operations); | 220 | INIT_LIST_HEAD(&cur_trans->ordered_operations); |
210 | INIT_LIST_HEAD(&cur_trans->pending_chunks); | 221 | INIT_LIST_HEAD(&cur_trans->pending_chunks); |
222 | INIT_LIST_HEAD(&cur_trans->switch_commits); | ||
211 | list_add_tail(&cur_trans->list, &fs_info->trans_list); | 223 | list_add_tail(&cur_trans->list, &fs_info->trans_list); |
212 | extent_io_tree_init(&cur_trans->dirty_pages, | 224 | extent_io_tree_init(&cur_trans->dirty_pages, |
213 | fs_info->btree_inode->i_mapping); | 225 | fs_info->btree_inode->i_mapping); |
@@ -920,9 +932,6 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans, | |||
920 | return ret; | 932 | return ret; |
921 | } | 933 | } |
922 | 934 | ||
923 | if (root != root->fs_info->extent_root) | ||
924 | switch_commit_root(root); | ||
925 | |||
926 | return 0; | 935 | return 0; |
927 | } | 936 | } |
928 | 937 | ||
@@ -978,15 +987,16 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans, | |||
978 | list_del_init(next); | 987 | list_del_init(next); |
979 | root = list_entry(next, struct btrfs_root, dirty_list); | 988 | root = list_entry(next, struct btrfs_root, dirty_list); |
980 | 989 | ||
990 | if (root != fs_info->extent_root) | ||
991 | list_add_tail(&root->dirty_list, | ||
992 | &trans->transaction->switch_commits); | ||
981 | ret = update_cowonly_root(trans, root); | 993 | ret = update_cowonly_root(trans, root); |
982 | if (ret) | 994 | if (ret) |
983 | return ret; | 995 | return ret; |
984 | } | 996 | } |
985 | 997 | ||
986 | down_write(&fs_info->extent_commit_sem); | 998 | list_add_tail(&fs_info->extent_root->dirty_list, |
987 | switch_commit_root(fs_info->extent_root); | 999 | &trans->transaction->switch_commits); |
988 | up_write(&fs_info->extent_commit_sem); | ||
989 | |||
990 | btrfs_after_dev_replace_commit(fs_info); | 1000 | btrfs_after_dev_replace_commit(fs_info); |
991 | 1001 | ||
992 | return 0; | 1002 | return 0; |
@@ -1043,11 +1053,8 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans, | |||
1043 | smp_wmb(); | 1053 | smp_wmb(); |
1044 | 1054 | ||
1045 | if (root->commit_root != root->node) { | 1055 | if (root->commit_root != root->node) { |
1046 | mutex_lock(&root->fs_commit_mutex); | 1056 | list_add_tail(&root->dirty_list, |
1047 | switch_commit_root(root); | 1057 | &trans->transaction->switch_commits); |
1048 | btrfs_unpin_free_ino(root); | ||
1049 | mutex_unlock(&root->fs_commit_mutex); | ||
1050 | |||
1051 | btrfs_set_root_node(&root->root_item, | 1058 | btrfs_set_root_node(&root->root_item, |
1052 | root->node); | 1059 | root->node); |
1053 | } | 1060 | } |
@@ -1858,11 +1865,15 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1858 | 1865 | ||
1859 | btrfs_set_root_node(&root->fs_info->tree_root->root_item, | 1866 | btrfs_set_root_node(&root->fs_info->tree_root->root_item, |
1860 | root->fs_info->tree_root->node); | 1867 | root->fs_info->tree_root->node); |
1861 | switch_commit_root(root->fs_info->tree_root); | 1868 | list_add_tail(&root->fs_info->tree_root->dirty_list, |
1869 | &cur_trans->switch_commits); | ||
1862 | 1870 | ||
1863 | btrfs_set_root_node(&root->fs_info->chunk_root->root_item, | 1871 | btrfs_set_root_node(&root->fs_info->chunk_root->root_item, |
1864 | root->fs_info->chunk_root->node); | 1872 | root->fs_info->chunk_root->node); |
1865 | switch_commit_root(root->fs_info->chunk_root); | 1873 | list_add_tail(&root->fs_info->chunk_root->dirty_list, |
1874 | &cur_trans->switch_commits); | ||
1875 | |||
1876 | switch_commit_roots(cur_trans, root->fs_info); | ||
1866 | 1877 | ||
1867 | assert_qgroups_uptodate(trans); | 1878 | assert_qgroups_uptodate(trans); |
1868 | update_super_roots(root); | 1879 | update_super_roots(root); |
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 2bcba89d952e..b57b924e8e03 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -57,6 +57,7 @@ struct btrfs_transaction { | |||
57 | struct list_head pending_snapshots; | 57 | struct list_head pending_snapshots; |
58 | struct list_head ordered_operations; | 58 | struct list_head ordered_operations; |
59 | struct list_head pending_chunks; | 59 | struct list_head pending_chunks; |
60 | struct list_head switch_commits; | ||
60 | struct btrfs_delayed_ref_root delayed_refs; | 61 | struct btrfs_delayed_ref_root delayed_refs; |
61 | int aborted; | 62 | int aborted; |
62 | }; | 63 | }; |