1 ext4: allocate entire range in zero range
3 From: Lukas Czerner <lczerner@redhat.com>
5 Currently there is a bug in zero range code which causes zero range
6 calls to only allocate block aligned portion of the range, while
7 ignoring the rest in some cases.
9 In some cases, namely if the end of the range is past i_size, we do
10 attempt to preallocate the last nonaligned block. However this might
11 cause kernel to BUG() in some carefully designed zero range requests
12 on setups where page size > block size.
14 Fix this problem by first preallocating the entire range, including
15 the nonaligned edges and converting the written extents to unwritten
16 in the next step. This approach will also give us the advantage of
17 having the range to be as linearly contiguous as possible.
19 Signed-off-by: Lukas Czerner <lczerner@redhat.com>
20 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
22 fs/ext4/extents.c | 31 +++++++++++++++++++------------
23 1 file changed, 19 insertions(+), 12 deletions(-)
25 diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
26 index bed4308..aa52242 100644
27 --- a/fs/ext4/extents.c
28 +++ b/fs/ext4/extents.c
29 @@ -4803,12 +4803,6 @@ static long ext4_zero_range(struct file *file, loff_t offset,
33 - flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT |
34 - EXT4_GET_BLOCKS_CONVERT_UNWRITTEN |
36 - if (mode & FALLOC_FL_KEEP_SIZE)
37 - flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
39 mutex_lock(&inode->i_mutex);
42 @@ -4825,15 +4819,28 @@ static long ext4_zero_range(struct file *file, loff_t offset,
43 ret = inode_newsize_ok(inode, new_size);
47 - * If we have a partial block after EOF we have to allocate
54 + flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
55 + if (mode & FALLOC_FL_KEEP_SIZE)
56 + flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
58 + /* Preallocate the range including the unaligned edges */
59 + if (partial_begin || partial_end) {
60 + ret = ext4_alloc_file_blocks(file,
61 + round_down(offset, 1 << blkbits) >> blkbits,
62 + (round_up((offset + len), 1 << blkbits) -
63 + round_down(offset, 1 << blkbits)) >> blkbits,
64 + new_size, flags, mode);
70 + /* Zero range excluding the unaligned edges */
72 + flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN |
75 /* Now release the pages and zero block aligned part of pages*/
76 truncate_pagecache_range(inode, start, end - 1);
81 To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
82 the body of a message to majordomo@vger.kernel.org
83 More majordomo info at http://vger.kernel.org/majordomo-info.html