aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent_io.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@fusionio.com>2013-01-29 17:49:37 -0500
committerChris Mason <chris.mason@fusionio.com>2013-02-01 14:24:25 -0500
commit242e18c7c1a8ff3aa05c9fbb6e0bb427511152a6 (patch)
treeb284eaf8ef18253eb577078f14d542154d20dd94 /fs/btrfs/extent_io.c
parent8de972b4faa4be9b2a3c53103e18d86092a5da45 (diff)
Btrfs: reduce lock contention on extent buffer locks
The extent buffers have a refs_lock which we use to make coordinate freeing the extent buffer with operations on the radix tree. On tree roots and other extent buffers that very cache hot, this can be highly contended. These are also the extent buffers that are basically pinned in memory. This commit adds code to cmpxchg our way through the ref modifications, and as long as the result of the reference change is still pinned in ram, we skip the expensive spinlock. Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r--fs/btrfs/extent_io.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 3b9fb478b0d1..907ed0025dd4 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -4184,6 +4184,7 @@ static inline void btrfs_release_extent_buffer(struct extent_buffer *eb)
4184 4184
4185static void check_buffer_tree_ref(struct extent_buffer *eb) 4185static void check_buffer_tree_ref(struct extent_buffer *eb)
4186{ 4186{
4187 int refs;
4187 /* the ref bit is tricky. We have to make sure it is set 4188 /* the ref bit is tricky. We have to make sure it is set
4188 * if we have the buffer dirty. Otherwise the 4189 * if we have the buffer dirty. Otherwise the
4189 * code to free a buffer can end up dropping a dirty 4190 * code to free a buffer can end up dropping a dirty
@@ -4204,6 +4205,10 @@ static void check_buffer_tree_ref(struct extent_buffer *eb)
4204 * So bump the ref count first, then set the bit. If someone 4205 * So bump the ref count first, then set the bit. If someone
4205 * beat us to it, drop the ref we added. 4206 * beat us to it, drop the ref we added.
4206 */ 4207 */
4208 refs = atomic_read(&eb->refs);
4209 if (refs >= 2 && test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
4210 return;
4211
4207 spin_lock(&eb->refs_lock); 4212 spin_lock(&eb->refs_lock);
4208 if (!test_and_set_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)) 4213 if (!test_and_set_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
4209 atomic_inc(&eb->refs); 4214 atomic_inc(&eb->refs);
@@ -4405,9 +4410,20 @@ static int release_extent_buffer(struct extent_buffer *eb, gfp_t mask)
4405 4410
4406void free_extent_buffer(struct extent_buffer *eb) 4411void free_extent_buffer(struct extent_buffer *eb)
4407{ 4412{
4413 int refs;
4414 int old;
4408 if (!eb) 4415 if (!eb)
4409 return; 4416 return;
4410 4417
4418 while (1) {
4419 refs = atomic_read(&eb->refs);
4420 if (refs <= 3)
4421 break;
4422 old = atomic_cmpxchg(&eb->refs, refs, refs - 1);
4423 if (old == refs)
4424 return;
4425 }
4426
4411 spin_lock(&eb->refs_lock); 4427 spin_lock(&eb->refs_lock);
4412 if (atomic_read(&eb->refs) == 2 && 4428 if (atomic_read(&eb->refs) == 2 &&
4413 test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags)) 4429 test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags))