ext4: fix ext4_writepages() in presence of truncate
authorJan Kara <jack@suse.cz>
Sat, 17 Aug 2013 14:02:33 +0000 (10:02 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 27 Sep 2013 00:21:44 +0000 (17:21 -0700)
commit666ee8c487d27e27e3b215cf1b8d79e2b16944c6
tree172cf6cb2bc124181e74b7cd994e977abafa35be
parent2a73161d42a658393f0a4dbb2286c125b516670e
ext4: fix ext4_writepages() in presence of truncate

commit 5f1132b2ba8c873f25982cf45917e8455fb6c962 upstream.

Inode size can arbitrarily change while writeback is in progress. When
ext4_writepages() has prepared a long extent for mapping and truncate
then reduces i_size, mpage_map_and_submit_buffers() will always map just
one buffer in a page instead of all of them due to lblk < blocks check.
So we end up not using all blocks we've allocated (thus leaking them)
and also delalloc accounting goes wrong manifesting as a warning like:

ext4_da_release_space:1333: ext4_da_release_space: ino 12, to_free 1
with only 0 reserved data blocks

Note that the problem can happen only when blocksize < pagesize because
otherwise we have only a single buffer in the page.

Fix the problem by removing the size check from the mapping loop. We
have an extent allocated so we have to use it all before checking for
i_size. We also rename add_page_bufs_to_extent() to
mpage_process_page_bufs() and make that function submit the page for IO
if all buffers (upto EOF) in it are mapped.

Reported-by: Dave Jones <davej@redhat.com>
Reported-by: Zheng Liu <gnehzuil.liu@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/ext4/inode.c