Commit 242e18c7 authored by Chris Mason's avatar Chris Mason

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: default avatarChris Mason <chris.mason@fusionio.com>
parent 8de972b4
...@@ -4184,6 +4184,7 @@ static inline void btrfs_release_extent_buffer(struct extent_buffer *eb) ...@@ -4184,6 +4184,7 @@ static inline void btrfs_release_extent_buffer(struct extent_buffer *eb)
static void check_buffer_tree_ref(struct extent_buffer *eb) static void check_buffer_tree_ref(struct extent_buffer *eb)
{ {
int refs;
/* the ref bit is tricky. We have to make sure it is set /* the ref bit is tricky. We have to make sure it is set
* if we have the buffer dirty. Otherwise the * if we have the buffer dirty. Otherwise the
* code to free a buffer can end up dropping a dirty * 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,6 +4205,10 @@ static void check_buffer_tree_ref(struct extent_buffer *eb)
* So bump the ref count first, then set the bit. If someone * So bump the ref count first, then set the bit. If someone
* beat us to it, drop the ref we added. * beat us to it, drop the ref we added.
*/ */
refs = atomic_read(&eb->refs);
if (refs >= 2 && test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
return;
spin_lock(&eb->refs_lock); spin_lock(&eb->refs_lock);
if (!test_and_set_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)) if (!test_and_set_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
atomic_inc(&eb->refs); atomic_inc(&eb->refs);
...@@ -4405,9 +4410,20 @@ static int release_extent_buffer(struct extent_buffer *eb, gfp_t mask) ...@@ -4405,9 +4410,20 @@ static int release_extent_buffer(struct extent_buffer *eb, gfp_t mask)
void free_extent_buffer(struct extent_buffer *eb) void free_extent_buffer(struct extent_buffer *eb)
{ {
int refs;
int old;
if (!eb) if (!eb)
return; return;
while (1) {
refs = atomic_read(&eb->refs);
if (refs <= 3)
break;
old = atomic_cmpxchg(&eb->refs, refs, refs - 1);
if (old == refs)
return;
}
spin_lock(&eb->refs_lock); spin_lock(&eb->refs_lock);
if (atomic_read(&eb->refs) == 2 && if (atomic_read(&eb->refs) == 2 &&
test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags)) test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment