Btrfs: use RCU instead of a spinlock to protect the root node
authorChris Mason <chris.mason@oracle.com>
Wed, 23 Mar 2011 18:54:42 +0000 (14:54 -0400)
committerroot <Chris Mason chris.mason@oracle.com>
Mon, 28 Mar 2011 09:37:22 +0000 (05:37 -0400)
The pointer to the extent buffer for the root of each tree
is protected by a spinlock so that we can safely read the pointer
and take a reference on the extent buffer.

But now that the extent buffers are freed via RCU, we can safely
use rcu_read_lock instead.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.c

index 73e53009e126d8174c22828e107300386a82cf51..8680110f0a5a18712d8d98c4165ffbb4c418458b 100644 (file)
@@ -147,10 +147,11 @@ noinline void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p)
 struct extent_buffer *btrfs_root_node(struct btrfs_root *root)
 {
        struct extent_buffer *eb;
-       spin_lock(&root->node_lock);
-       eb = root->node;
+
+       rcu_read_lock();
+       eb = rcu_dereference(root->node);
        extent_buffer_get(eb);
-       spin_unlock(&root->node_lock);
+       rcu_read_unlock();
        return eb;
 }
 
@@ -165,14 +166,8 @@ struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root)
        while (1) {
                eb = btrfs_root_node(root);
                btrfs_tree_lock(eb);
-
-               spin_lock(&root->node_lock);
-               if (eb == root->node) {
-                       spin_unlock(&root->node_lock);
+               if (eb == root->node)
                        break;
-               }
-               spin_unlock(&root->node_lock);
-
                btrfs_tree_unlock(eb);
                free_extent_buffer(eb);
        }
@@ -458,10 +453,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                else
                        parent_start = 0;
 
-               spin_lock(&root->node_lock);
-               root->node = cow;
                extent_buffer_get(cow);
-               spin_unlock(&root->node_lock);
+               rcu_assign_pointer(root->node, cow);
 
                btrfs_free_tree_block(trans, root, buf, parent_start,
                                      last_ref);
@@ -930,9 +923,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                        goto enospc;
                }
 
-               spin_lock(&root->node_lock);
-               root->node = child;
-               spin_unlock(&root->node_lock);
+               rcu_assign_pointer(root->node, child);
 
                add_root_to_dirty_list(root);
                btrfs_tree_unlock(child);
@@ -2007,10 +1998,8 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
 
        btrfs_mark_buffer_dirty(c);
 
-       spin_lock(&root->node_lock);
        old = root->node;
-       root->node = c;
-       spin_unlock(&root->node_lock);
+       rcu_assign_pointer(root->node, c);
 
        /* the super has an extra ref to root->node */
        free_extent_buffer(old);