Btrfs: preserve commit_root for async caching
authorYan Zheng <zheng.yan@oracle.com>
Thu, 30 Jul 2009 13:40:40 +0000 (09:40 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 30 Jul 2009 13:40:40 +0000 (09:40 -0400)
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>
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/transaction.c

index 17ad92c29cfd2d71009a91380f40bc9a39d4ffb0..38eeb6c49c8a02277c252c6e2e16507cae24ff73 100644 (file)
@@ -827,6 +827,7 @@ struct btrfs_fs_info {
        struct mutex drop_mutex;
        struct mutex volume_mutex;
        struct mutex tree_reloc_mutex;
+       struct rw_semaphore extent_commit_sem;
 
        /*
         * this protects the ordered operations list only while we are
@@ -961,9 +962,6 @@ struct btrfs_root {
        /* the node lock is held while changing the node pointer */
        spinlock_t node_lock;
 
-       /* taken when updating the commit root */
-       struct rw_semaphore commit_root_sem;
-
        struct extent_buffer *commit_root;
        struct btrfs_root *log_root;
        struct btrfs_root *reloc_root;
index 3a9b8875988018bd2782f919631f54335de1e0d1..3cf4cfa575c803def86078bbaca6e32b8d0c4c8f 100644 (file)
@@ -907,7 +907,6 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
        spin_lock_init(&root->inode_lock);
        mutex_init(&root->objectid_mutex);
        mutex_init(&root->log_mutex);
-       init_rwsem(&root->commit_root_sem);
        init_waitqueue_head(&root->log_writer_wait);
        init_waitqueue_head(&root->log_commit_wait[0]);
        init_waitqueue_head(&root->log_commit_wait[1]);
@@ -1624,6 +1623,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        mutex_init(&fs_info->cleaner_mutex);
        mutex_init(&fs_info->volume_mutex);
        mutex_init(&fs_info->tree_reloc_mutex);
+       init_rwsem(&fs_info->extent_commit_sem);
 
        btrfs_init_free_cluster(&fs_info->meta_alloc_cluster);
        btrfs_init_free_cluster(&fs_info->data_alloc_cluster);
index fadf69a2764b316828f82d31be8490c0dcf57739..2fe21fa74913448431847ef7c3090ced37df61d4 100644 (file)
@@ -267,7 +267,7 @@ static int caching_kthread(void *data)
        last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET);
 again:
        /* need to make sure the commit_root doesn't disappear */
-       down_read(&fs_info->extent_root->commit_root_sem);
+       down_read(&fs_info->extent_commit_sem);
 
        /*
         * We don't want to deadlock with somebody trying to allocate a new
@@ -304,7 +304,7 @@ again:
 
                        if (need_resched()) {
                                btrfs_release_path(fs_info->extent_root, path);
-                               up_read(&fs_info->extent_root->commit_root_sem);
+                               up_read(&fs_info->extent_commit_sem);
                                cond_resched();
                                goto again;
                        }
@@ -345,7 +345,7 @@ next:
 
 err:
        btrfs_free_path(path);
-       up_read(&fs_info->extent_root->commit_root_sem);
+       up_read(&fs_info->extent_commit_sem);
        atomic_dec(&block_group->space_info->caching_threads);
        wake_up(&block_group->caching_q);
 
index e51d2bc532f8fa95a0febf2ab4682547f133b746..de48e4ec808cd6e600bc1d32a65840035dcdf37d 100644 (file)
@@ -42,10 +42,8 @@ static noinline void put_transaction(struct btrfs_transaction *transaction)
 
 static noinline void switch_commit_root(struct btrfs_root *root)
 {
-       down_write(&root->commit_root_sem);
        free_extent_buffer(root->commit_root);
        root->commit_root = btrfs_root_node(root);
-       up_write(&root->commit_root_sem);
 }
 
 /*
@@ -466,7 +464,10 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
                ret = btrfs_write_dirty_block_groups(trans, root);
                BUG_ON(ret);
        }
-       switch_commit_root(root);
+
+       if (root != root->fs_info->extent_root)
+               switch_commit_root(root);
+
        return 0;
 }
 
@@ -499,6 +500,11 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
 
                update_cowonly_root(trans, root);
        }
+
+       down_write(&fs_info->extent_commit_sem);
+       switch_commit_root(fs_info->extent_root);
+       up_write(&fs_info->extent_commit_sem);
+
        return 0;
 }