diff options
-rw-r--r-- | fs/btrfs/extent_io.c | 16 |
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 | ||
4185 | static void check_buffer_tree_ref(struct extent_buffer *eb) | 4185 | static 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 | ||
4406 | void free_extent_buffer(struct extent_buffer *eb) | 4411 | void 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)) |