Re: [PATCH] shmem: do not extend i_size when no data was copied

From: Kiryl Shutsemau

Date: Mon Oct 26 2026 - 11:40:54 EST


On Sun, Oct 25, 2026 at 04:46:19PM +0000, Hungyu Lin wrote:
> shmem_write_end() advances i_size to pos + copied even when copied is
> zero. A buffered write past EOF can therefore extend a tmpfs file
> without writing any data.

+ willy, jack, fsdevel.

This doesn't seem to be tmpfs-specific, right? I see the same with ext4.

simple_write_end() and generic_write_end() check pos + copied the same
way, so filesystems that use them through generic_perform_write() are
affected too.

It makes me think maybe generic_perform_write() is the right place to
fix it. Hm?

> Moving prefaulting to the slow write path makes this easy to reproduce:
> a one-byte pwrite() at offset 4096 into an empty memfd, with an unreadable
> source buffer, fails with EFAULT but leaves the file size at 4096.
> generic_perform_write() calls ->write_end() with copied == 0 before
> trying to fault in the source buffer.
>
> Only extend i_size when data was copied. Leave the existing folio
> handling unchanged so successful writes, retries and preallocated
> pages retain their current behavior.
>
> Fixes: 665575cff098 ("filemap: move prefaulting out of hot write path")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Hungyu Lin <dennylin0707@xxxxxxxxx>
> ---
> mm/shmem.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/mm/shmem.c b/mm/shmem.c
> index d97fc32e7c94..55287c370c73 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -3487,7 +3487,7 @@ shmem_write_end(const struct kiocb *iocb, struct address_space *mapping,
> {
> struct inode *inode = mapping->host;
>
> - if (pos + copied > inode->i_size)
> + if (copied && pos + copied > inode->i_size)
> i_size_write(inode, pos + copied);
>
> if (!folio_test_uptodate(folio)) {
> --
> 2.43.0
>

--
Kiryl Shutsemau / Kirill A. Shutemov