Btrfs: don't return true in releasepage unless we actually freed the eb
authorJosef Bacik <jbacik@fusionio.com>
Fri, 20 Jul 2012 20:05:36 +0000 (16:05 -0400)
committerChris Mason <chris.mason@fusionio.com>
Mon, 23 Jul 2012 20:28:08 +0000 (16:28 -0400)
I noticed while looking at an extent_buffer race that we will
unconditionally return 1 if we get down to release_extent_buffer after
clearing the tree ref.  However we can easily race in here and get a ref on
the eb and not actually free the eb.  So make release_extent_buffer return 1
if it free'd the eb and 0 if not so we can be a little kinder to the vm.
Thanks,

Signed-off-by: Josef Bacik <jbacik@fusionio.com>
fs/btrfs/extent_io.c

index f08206fcfb2278208dec45c633876f84ddd69763..e6243f787434627ccd7b18c993b9681fdb7814bb 100644 (file)
@@ -4300,7 +4300,7 @@ static inline void btrfs_release_extent_buffer_rcu(struct rcu_head *head)
 }
 
 /* Expects to have eb->eb_lock already held */
-static void release_extent_buffer(struct extent_buffer *eb, gfp_t mask)
+static int release_extent_buffer(struct extent_buffer *eb, gfp_t mask)
 {
        WARN_ON(atomic_read(&eb->refs) == 0);
        if (atomic_dec_and_test(&eb->refs)) {
@@ -4321,9 +4321,11 @@ static void release_extent_buffer(struct extent_buffer *eb, gfp_t mask)
                btrfs_release_extent_buffer_page(eb, 0);
 
                call_rcu(&eb->rcu_head, btrfs_release_extent_buffer_rcu);
-               return;
+               return 1;
        }
        spin_unlock(&eb->refs_lock);
+
+       return 0;
 }
 
 void free_extent_buffer(struct extent_buffer *eb)
@@ -4962,7 +4964,6 @@ int try_release_extent_buffer(struct page *page, gfp_t mask)
                spin_unlock(&eb->refs_lock);
                return 0;
        }
-       release_extent_buffer(eb, mask);
 
-       return 1;
+       return release_extent_buffer(eb, mask);
 }