aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/backref.c33
-rw-r--r--fs/btrfs/ctree.c88
-rw-r--r--fs/btrfs/ctree.h3
-rw-r--r--fs/btrfs/disk-io.c3
-rw-r--r--fs/btrfs/extent-tree.c20
-rw-r--r--fs/btrfs/inode-map.c14
-rw-r--r--fs/btrfs/send.c57
-rw-r--r--fs/btrfs/transaction.c45
-rw-r--r--fs/btrfs/transaction.h1
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 */
1102int btrfs_find_all_roots(struct btrfs_trans_handle *trans, 1105static 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
1143int 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)
419again: 419again:
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
424next: 424next:
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
514err: 514err:
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;
56again: 56again:
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);
128out: 128out:
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 */
255void btrfs_unpin_free_ino(struct btrfs_root *root) 255void 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:
5367static int full_send_tree(struct send_ctx *sctx) 5369static 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
5392join_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
5466out: 5419out:
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
78static noinline void switch_commit_root(struct btrfs_root *root) 78static 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
84static inline void extwriter_counter_inc(struct btrfs_transaction *trans, 95static 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};