aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r--fs/btrfs/extent_io.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 43af5a61ad25..c32d226bfecc 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -4772,6 +4772,25 @@ struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info,
4772 start >> PAGE_CACHE_SHIFT); 4772 start >> PAGE_CACHE_SHIFT);
4773 if (eb && atomic_inc_not_zero(&eb->refs)) { 4773 if (eb && atomic_inc_not_zero(&eb->refs)) {
4774 rcu_read_unlock(); 4774 rcu_read_unlock();
4775 /*
4776 * Lock our eb's refs_lock to avoid races with
4777 * free_extent_buffer. When we get our eb it might be flagged
4778 * with EXTENT_BUFFER_STALE and another task running
4779 * free_extent_buffer might have seen that flag set,
4780 * eb->refs == 2, that the buffer isn't under IO (dirty and
4781 * writeback flags not set) and it's still in the tree (flag
4782 * EXTENT_BUFFER_TREE_REF set), therefore being in the process
4783 * of decrementing the extent buffer's reference count twice.
4784 * So here we could race and increment the eb's reference count,
4785 * clear its stale flag, mark it as dirty and drop our reference
4786 * before the other task finishes executing free_extent_buffer,
4787 * which would later result in an attempt to free an extent
4788 * buffer that is dirty.
4789 */
4790 if (test_bit(EXTENT_BUFFER_STALE, &eb->bflags)) {
4791 spin_lock(&eb->refs_lock);
4792 spin_unlock(&eb->refs_lock);
4793 }
4775 mark_extent_buffer_accessed(eb, NULL); 4794 mark_extent_buffer_accessed(eb, NULL);
4776 return eb; 4795 return eb;
4777 } 4796 }