aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2015-10-13 11:36:09 -0400
committerFilipe Manana <fdmanana@suse.com>2015-10-13 23:37:00 -0400
commit5e6ecb362bd5950a3d8ce19c32829e4f8c7917d9 (patch)
tree2365f8d86e36339d46affaecaccf456e21343538
parent8039d87d9e473aeb740d4fdbd59b9d2f89b2ced9 (diff)
Btrfs: fix double range unlock of hole region when reading page
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>
-rw-r--r--fs/btrfs/extent_io.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index ecb1204468c3..6e6df34d74f0 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -3070,8 +3070,12 @@ static int __do_readpage(struct extent_io_tree *tree,
3070 3070
3071 set_extent_uptodate(tree, cur, cur + iosize - 1, 3071 set_extent_uptodate(tree, cur, cur + iosize - 1,
3072 &cached, GFP_NOFS); 3072 &cached, GFP_NOFS);
3073 unlock_extent_cached(tree, cur, cur + iosize - 1, 3073 if (parent_locked)
3074 &cached, GFP_NOFS); 3074 free_extent_state(cached);
3075 else
3076 unlock_extent_cached(tree, cur,
3077 cur + iosize - 1,
3078 &cached, GFP_NOFS);
3075 cur = cur + iosize; 3079 cur = cur + iosize;
3076 pg_offset += iosize; 3080 pg_offset += iosize;
3077 continue; 3081 continue;