aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2009-09-23 20:28:46 -0400
committerChris Mason <chris.mason@oracle.com>2009-09-23 20:30:53 -0400
commit11ef160fda9c150cd75db77194bcc66839709662 (patch)
tree2cd7577234c112177a06ad09c0c507c81cb9658a /fs/btrfs
parent46562cec98368623bcd18d7fd30f20c04afd5978 (diff)
Btrfs: fix releasepage to avoid unlocking extents we haven't locked
During releasepage, we try to drop any extent_state structs for the bye offsets of the page we're releaseing. But the code was incorrectly telling clear_extent_bit to delete the state struct unconditionallly. Normally this would be fine because we have the page locked, but other parts of btrfs will lock down an entire extent, the most common place being IO completion. releasepage was deleting the extent state without first locking the extent, which may result in removing a state struct that another process had locked down. The fix here is to leave the NODATASUM and EXTENT_LOCKED bits alone in releasepage. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/extent_io.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index dcce98d0ec4f..0cb88f8146ea 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -2809,8 +2809,13 @@ int try_release_extent_state(struct extent_map_tree *map,
2809 else { 2809 else {
2810 if ((mask & GFP_NOFS) == GFP_NOFS) 2810 if ((mask & GFP_NOFS) == GFP_NOFS)
2811 mask = GFP_NOFS; 2811 mask = GFP_NOFS;
2812 clear_extent_bit(tree, start, end, EXTENT_UPTODATE, 2812 /*
2813 1, 1, NULL, mask); 2813 * at this point we can safely clear everything except the
2814 * locked bit and the nodatasum bit
2815 */
2816 clear_extent_bit(tree, start, end,
2817 ~(EXTENT_LOCKED | EXTENT_NODATASUM),
2818 0, 0, NULL, mask);
2814 } 2819 }
2815 return ret; 2820 return ret;
2816} 2821}