aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2011-02-14 12:52:08 -0500
committerChris Mason <chris.mason@oracle.com>2011-02-14 13:04:01 -0500
commite3f24cc521cb7ba60ac137abd1939e4e03435e80 (patch)
treee054136e5b2cf6a2bc9a62dd616393676cd316dd /fs/btrfs
parenteb14ab8ed24a0405fd056068b28c33a1cd846024 (diff)
Btrfs: don't release pages when we can't clear the uptodate bits
Btrfs tracks uptodate state in an rbtree as well as in the page bits. This is supposed to enable us to use block sizes other than the page size, but there are a few parts still missing before that completely works. But, our readpage routine trusts this additional range based tracking of uptodateness, much in the same way the buffer head up to date bits are trusted for the other filesystems. The problem is that sometimes we need to allocate memory in order to split records in the rbtree, even when we are just clearing bits. This can be difficult when our clearing function is called GFP_ATOMIC, which can happen in the releasepage path. So, what happens today looks like this: releasepage called with GFP_ATOMIC btrfs_releasepage calls clear_extent_bit clear_extent_bit fails to allocate ram, leaving the up to date bit set btrfs_releasepage returns success The end result is the page being gone, but btrfs thinking the range is up to date. Later on if someone tries to read that same page, the btrfs readpage code will return immediately thinking the page is already up to date. This commit fixes things to fail the releasepage when we can't clear the extent state bits. It covers both data pages and metadata tree blocks. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/extent_io.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 0418bf2c9757..e7aeba242701 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -2822,9 +2822,17 @@ int try_release_extent_state(struct extent_map_tree *map,
2822 * at this point we can safely clear everything except the 2822 * at this point we can safely clear everything except the
2823 * locked bit and the nodatasum bit 2823 * locked bit and the nodatasum bit
2824 */ 2824 */
2825 clear_extent_bit(tree, start, end, 2825 ret = clear_extent_bit(tree, start, end,
2826 ~(EXTENT_LOCKED | EXTENT_NODATASUM), 2826 ~(EXTENT_LOCKED | EXTENT_NODATASUM),
2827 0, 0, NULL, mask); 2827 0, 0, NULL, mask);
2828
2829 /* if clear_extent_bit failed for enomem reasons,
2830 * we can't allow the release to continue.
2831 */
2832 if (ret < 0)
2833 ret = 0;
2834 else
2835 ret = 1;
2828 } 2836 }
2829 return ret; 2837 return ret;
2830} 2838}