1 ext4: fix reservation release on invalidatepage for delalloc fs
3 From: Lukas Czerner <lczerner@redhat.com>
5 On delalloc enabled file system on invalidatepage operation
6 in ext4_da_page_release_reservation() we want to clear the delayed
7 buffer and remove the extent covering the delayed buffer from the extent
10 However currently there is a bug where on the systems with page size >
11 block size we will always remove extents from the start of the page
12 regardless where the actual delayed buffers are positioned in the page.
13 This leads to the errors like this:
15 EXT4-fs warning (device loop0): ext4_da_release_space:1225:
16 ext4_da_release_space: ino 13, to_free 1 with only 0 reserved data
19 This however can cause data loss on writeback time if the file system is
20 in ENOSPC condition because we're releasing reservation for someones
23 Fix this by only removing extents that corresponds to the part of the
24 page we want to invalidate.
26 This problem is reproducible by the following fio receipt (however I was
27 only able to reproduce it with fio-2.1 or older.
78 Signed-off-by: Lukas Czerner <lczerner@redhat.com>
79 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
80 Reviewed-by: Jan Kara <jack@suse.cz>
81 Cc: stable@vger.kernel.org
83 fs/ext4/inode.c | 15 ++++++++++++---
84 1 file changed, 12 insertions(+), 3 deletions(-)
86 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
87 index 0554b0b..46f4a49 100644
90 @@ -1342,7 +1342,7 @@ static void ext4_da_page_release_reservation(struct page *page,
95 + int to_release = 0, contiguous_blks = 0;
96 struct buffer_head *head, *bh;
97 unsigned int curr_off = 0;
98 struct inode *inode = page->mapping->host;
99 @@ -1363,14 +1363,23 @@ static void ext4_da_page_release_reservation(struct page *page,
101 if ((offset <= curr_off) && (buffer_delay(bh))) {
104 clear_buffer_delay(bh);
105 + } else if (contiguous_blks) {
106 + lblk = page->index <<
107 + (PAGE_CACHE_SHIFT - inode->i_blkbits);
108 + lblk += (curr_off >> inode->i_blkbits) -
110 + ext4_es_remove_extent(inode, lblk, contiguous_blks);
111 + contiguous_blks = 0;
114 } while ((bh = bh->b_this_page) != head);
117 + if (contiguous_blks) {
118 lblk = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
119 - ext4_es_remove_extent(inode, lblk, to_release);
120 + lblk += (curr_off >> inode->i_blkbits) - contiguous_blks;
121 + ext4_es_remove_extent(inode, lblk, contiguous_blks);
124 /* If we have released all the blocks belonging to a cluster, then we
129 To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
130 the body of a message to majordomo@vger.kernel.org
131 More majordomo info at http://vger.kernel.org/majordomo-info.html