summaryrefslogtreecommitdiffstats
path: root/fs/ext4/inode.c
diff options
context:
space:
mode:
authorLukas Czerner <lczerner@redhat.com>2015-07-03 21:13:55 -0400
committerTheodore Ts'o <tytso@mit.edu>2015-07-03 21:13:55 -0400
commit9705acd63b125dee8b15c705216d7186daea4625 (patch)
tree5dda377f1a9382b6925ab0641632923e6e5cfa2d /fs/ext4/inode.c
parentc45653c341f5c8a0ce19c8f0ad4678640849cb86 (diff)
ext4: fix reservation release on invalidatepage for delalloc fs
On delalloc enabled file system on invalidatepage operation in ext4_da_page_release_reservation() we want to clear the delayed buffer and remove the extent covering the delayed buffer from the extent status tree. However currently there is a bug where on the systems with page size > block size we will always remove extents from the start of the page regardless where the actual delayed buffers are positioned in the page. This leads to the errors like this: EXT4-fs warning (device loop0): ext4_da_release_space:1225: ext4_da_release_space: ino 13, to_free 1 with only 0 reserved data blocks This however can cause data loss on writeback time if the file system is in ENOSPC condition because we're releasing reservation for someones else delayed buffer. Fix this by only removing extents that corresponds to the part of the page we want to invalidate. This problem is reproducible by the following fio receipt (however I was only able to reproduce it with fio-2.1 or older. [global] bs=8k iodepth=1024 iodepth_batch=60 randrepeat=1 size=1m directory=/mnt/test numjobs=20 [job1] ioengine=sync bs=1k direct=1 rw=randread filename=file1:file2 [job2] ioengine=libaio rw=randwrite direct=1 filename=file1:file2 [job3] bs=1k ioengine=posixaio rw=randwrite direct=1 filename=file1:file2 [job5] bs=1k ioengine=sync rw=randread filename=file1:file2 [job7] ioengine=libaio rw=randwrite filename=file1:file2 [job8] ioengine=posixaio rw=randwrite filename=file1:file2 [job10] ioengine=mmap rw=randwrite bs=1k filename=file1:file2 [job11] ioengine=mmap rw=randwrite direct=1 filename=file1:file2 Signed-off-by: Lukas Czerner <lczerner@redhat.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Reviewed-by: Jan Kara <jack@suse.cz> Cc: stable@vger.kernel.org
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r--fs/ext4/inode.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 4ad73d3c1003..2334e86d7447 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1330,7 +1330,7 @@ static void ext4_da_page_release_reservation(struct page *page,
1330 unsigned int offset, 1330 unsigned int offset,
1331 unsigned int length) 1331 unsigned int length)
1332{ 1332{
1333 int to_release = 0; 1333 int to_release = 0, contiguous_blks = 0;
1334 struct buffer_head *head, *bh; 1334 struct buffer_head *head, *bh;
1335 unsigned int curr_off = 0; 1335 unsigned int curr_off = 0;
1336 struct inode *inode = page->mapping->host; 1336 struct inode *inode = page->mapping->host;
@@ -1351,14 +1351,23 @@ static void ext4_da_page_release_reservation(struct page *page,
1351 1351
1352 if ((offset <= curr_off) && (buffer_delay(bh))) { 1352 if ((offset <= curr_off) && (buffer_delay(bh))) {
1353 to_release++; 1353 to_release++;
1354 contiguous_blks++;
1354 clear_buffer_delay(bh); 1355 clear_buffer_delay(bh);
1356 } else if (contiguous_blks) {
1357 lblk = page->index <<
1358 (PAGE_CACHE_SHIFT - inode->i_blkbits);
1359 lblk += (curr_off >> inode->i_blkbits) -
1360 contiguous_blks;
1361 ext4_es_remove_extent(inode, lblk, contiguous_blks);
1362 contiguous_blks = 0;
1355 } 1363 }
1356 curr_off = next_off; 1364 curr_off = next_off;
1357 } while ((bh = bh->b_this_page) != head); 1365 } while ((bh = bh->b_this_page) != head);
1358 1366
1359 if (to_release) { 1367 if (contiguous_blks) {
1360 lblk = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); 1368 lblk = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
1361 ext4_es_remove_extent(inode, lblk, to_release); 1369 lblk += (curr_off >> inode->i_blkbits) - contiguous_blks;
1370 ext4_es_remove_extent(inode, lblk, contiguous_blks);
1362 } 1371 }
1363 1372
1364 /* If we have released all the blocks belonging to a cluster, then we 1373 /* If we have released all the blocks belonging to a cluster, then we