Btrfs: preserve commit_root for async caching

The async block group caching code uses the commit_root pointer
to get a stable version of the extent allocation tree for scanning.
This copy of the tree root isn't going to change and it significantly
reduces the complexity of the scanning code.

During a commit, we have a loop where we update the extent allocation
tree root. We need to loop because updating the root pointer in
the tree of tree roots may allocate blocks which may change the
extent allocation tree.

Right now the commit_root pointer is changed inside this loop. It
is more correct to change the commit_root pointer only after all the
looping is done.

Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>

authored by Yan Zheng and committed by Chris Mason 276e680d f25784b3

+14 -10
+1 -3
fs/btrfs/ctree.h
··· 827 827 struct mutex drop_mutex; 828 828 struct mutex volume_mutex; 829 829 struct mutex tree_reloc_mutex; 830 + struct rw_semaphore extent_commit_sem; 830 831 831 832 /* 832 833 * this protects the ordered operations list only while we are ··· 961 960 962 961 /* the node lock is held while changing the node pointer */ 963 962 spinlock_t node_lock; 964 - 965 - /* taken when updating the commit root */ 966 - struct rw_semaphore commit_root_sem; 967 963 968 964 struct extent_buffer *commit_root; 969 965 struct btrfs_root *log_root;
+1 -1
fs/btrfs/disk-io.c
··· 907 907 spin_lock_init(&root->inode_lock); 908 908 mutex_init(&root->objectid_mutex); 909 909 mutex_init(&root->log_mutex); 910 - init_rwsem(&root->commit_root_sem); 911 910 init_waitqueue_head(&root->log_writer_wait); 912 911 init_waitqueue_head(&root->log_commit_wait[0]); 913 912 init_waitqueue_head(&root->log_commit_wait[1]); ··· 1623 1624 mutex_init(&fs_info->cleaner_mutex); 1624 1625 mutex_init(&fs_info->volume_mutex); 1625 1626 mutex_init(&fs_info->tree_reloc_mutex); 1627 + init_rwsem(&fs_info->extent_commit_sem); 1626 1628 1627 1629 btrfs_init_free_cluster(&fs_info->meta_alloc_cluster); 1628 1630 btrfs_init_free_cluster(&fs_info->data_alloc_cluster);
+3 -3
fs/btrfs/extent-tree.c
··· 267 267 last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET); 268 268 again: 269 269 /* need to make sure the commit_root doesn't disappear */ 270 - down_read(&fs_info->extent_root->commit_root_sem); 270 + down_read(&fs_info->extent_commit_sem); 271 271 272 272 /* 273 273 * We don't want to deadlock with somebody trying to allocate a new ··· 304 304 305 305 if (need_resched()) { 306 306 btrfs_release_path(fs_info->extent_root, path); 307 - up_read(&fs_info->extent_root->commit_root_sem); 307 + up_read(&fs_info->extent_commit_sem); 308 308 cond_resched(); 309 309 goto again; 310 310 } ··· 345 345 346 346 err: 347 347 btrfs_free_path(path); 348 - up_read(&fs_info->extent_root->commit_root_sem); 348 + up_read(&fs_info->extent_commit_sem); 349 349 atomic_dec(&block_group->space_info->caching_threads); 350 350 wake_up(&block_group->caching_q); 351 351
+9 -3
fs/btrfs/transaction.c
··· 42 42 43 43 static noinline void switch_commit_root(struct btrfs_root *root) 44 44 { 45 - down_write(&root->commit_root_sem); 46 45 free_extent_buffer(root->commit_root); 47 46 root->commit_root = btrfs_root_node(root); 48 - up_write(&root->commit_root_sem); 49 47 } 50 48 51 49 /* ··· 464 466 ret = btrfs_write_dirty_block_groups(trans, root); 465 467 BUG_ON(ret); 466 468 } 467 - switch_commit_root(root); 469 + 470 + if (root != root->fs_info->extent_root) 471 + switch_commit_root(root); 472 + 468 473 return 0; 469 474 } 470 475 ··· 500 499 501 500 update_cowonly_root(trans, root); 502 501 } 502 + 503 + down_write(&fs_info->extent_commit_sem); 504 + switch_commit_root(fs_info->extent_root); 505 + up_write(&fs_info->extent_commit_sem); 506 + 503 507 return 0; 504 508 } 505 509