]> git.hungrycats.org Git - linux/commitdiff
Btrfs: fix double range unlock of hole region when reading page
authorFilipe Manana <fdmanana@suse.com>
Tue, 13 Oct 2015 15:36:09 +0000 (16:36 +0100)
committerZygo Blaxell <zblaxell@thirteen.furryterror.org>
Sat, 17 Oct 2015 03:18:13 +0000 (23:18 -0400)
If when reading a page we find a hole and our caller had already locked
the range (bio flags has the bit EXTENT_BIO_PARENT_LOCKED set), we end
up unlocking the hole's range and then later our caller unlocks it
again, which might have already been locked by some other task once
the first unlock happened.

Currently this can only happen during a call to the extent_same ioctl,
as it's the only caller of __do_readpage() that sets the bit
EXTENT_BIO_PARENT_LOCKED for bio flags.

Fix this by leaving the unlock exclusively to the caller.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
(cherry picked from commit 5e6ecb362bd5950a3d8ce19c32829e4f8c7917d9)
(cherry picked from commit 08dfd1e3b77565ab634dca8b06c4ab65caae4ad2)

fs/btrfs/extent_io.c

index 3fc4fec9b94e5c63645840c0a1974f627f220e92..63208fd58309a988afa9fd90071f95a9e8ca5c0b 100644 (file)
@@ -3069,8 +3069,12 @@ static int __do_readpage(struct extent_io_tree *tree,
 
                        set_extent_uptodate(tree, cur, cur + iosize - 1,
                                            &cached, GFP_NOFS);
-                       unlock_extent_cached(tree, cur, cur + iosize - 1,
-                                            &cached, GFP_NOFS);
+                       if (parent_locked)
+                               free_extent_state(cached);
+                       else
+                               unlock_extent_cached(tree, cur,
+                                                    cur + iosize - 1,
+                                                    &cached, GFP_NOFS);
                        cur = cur + iosize;
                        pg_offset += iosize;
                        continue;