aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorEric Whitney <enwlinux@gmail.com>2015-04-03 00:13:42 -0400
committerTheodore Ts'o <tytso@mit.edu>2015-04-03 00:13:42 -0400
commit94426f4b9648154dc5a6760b59e6953e640ab3b1 (patch)
tree7f8828061434c4de38d99fb4e94289467b6b355c /fs
parent0f2af21aae11972fa924374ddcf52e88347cf5a8 (diff)
ext4: fix loss of delalloc extent info in ext4_zero_range()
In ext4_zero_range(), removing a file's entire block range from the extent status tree removes all records of that file's delalloc extents. The delalloc accounting code uses this information, and its loss can then lead to accounting errors and kernel warnings at writeback time and subsequent file system damage. This is most noticeable on bigalloc file systems where code in ext4_ext_map_blocks() handles cases where delalloc extents share clusters with a newly allocated extent. Because we're not deleting a block range and are correctly updating the status of its associated extent, there is no need to remove anything from the extent status tree. When this patch is combined with an unrelated bug fix for ext4_zero_range(), kernel warnings and e2fsck errors reported during xfstests runs on bigalloc filesystems are greatly reduced without introducing regressions on other xfstests-bld test scenarios. Signed-off-by: Eric Whitney <enwlinux@gmail.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/extents.c13
1 files changed, 0 insertions, 13 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 3cc17aacc4c7..e5fafa7324c8 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4848,19 +4848,6 @@ static long ext4_zero_range(struct file *file, loff_t offset,
4848 flags, mode); 4848 flags, mode);
4849 if (ret) 4849 if (ret)
4850 goto out_dio; 4850 goto out_dio;
4851 /*
4852 * Remove entire range from the extent status tree.
4853 *
4854 * ext4_es_remove_extent(inode, lblk, max_blocks) is
4855 * NOT sufficient. I'm not sure why this is the case,
4856 * but let's be conservative and remove the extent
4857 * status tree for the entire inode. There should be
4858 * no outstanding delalloc extents thanks to the
4859 * filemap_write_and_wait_range() call above.
4860 */
4861 ret = ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
4862 if (ret)
4863 goto out_dio;
4864 } 4851 }
4865 if (!partial_begin && !partial_end) 4852 if (!partial_begin && !partial_end)
4866 goto out_dio; 4853 goto out_dio;