All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Zhang Yi" <yi.zhang@huaweicloud.com>
Cc: linux-ext4@vger.kernel.org, tytso@mit.edu
Subject: Re: [PATCH -next v5 15/32] ext4: implement buffered write path using iomap
Date: Fri, 14 Aug 2026 10:40:55 +0000	[thread overview]
Message-ID: <20260814104055.7F2C21F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260814093331.1703882-16-yi.zhang@huaweicloud.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] Extending a file within an already-allocated block does not update the on-disk `i_disksize` or mark the inode dirty, causing appended data to be lost on a crash or unmount.
- [High] The iomap non-delalloc buffered write path permanently leaks unwritten extents past `i_size` when a short write or failure occurs.
--

--- Patch [15]: [PATCH -next v5 15/32] ext4: implement buffered write path using iomap ---
commit 7a553e37ec457f0a485aa7c6fc378e68d6d66bfb
Author: Zhang Yi <yi.zhang@huawei.com>

ext4: implement buffered write path using iomap

This commit introduces two new iomap_ops instances for ext4 buffered writes:
one for delayed allocation mode and another for non-delayed allocation mode.
It also updates the folio lock and transaction start ordering for the new
iomap buffered write path.

> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index 9098d9a5fc05b..d831d1911a6ff 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c

[ ... ]

> @@ -3994,6 +4009,113 @@ static int ext4_iomap_buffered_read_begin(struct inode *inode, loff_t offset,
>  	return 0;
>  }
>  
> +static int ext4_iomap_buffered_do_write_begin(struct inode *inode,
> +		loff_t offset, loff_t length, unsigned int flags,
> +		struct iomap *iomap, struct iomap *srcmap, bool delalloc)
> +{
> +	int ret, retries = 0;
> +	struct ext4_map_blocks map;
> +	int map_flags;
> +
> +	ret = ext4_emergency_state(inode->i_sb);
> +	if (unlikely(ret))
> +		return ret;
> +
> +	/* Inline data and non-extent are not supported. */
> +	if (WARN_ON_ONCE(ext4_has_inline_data(inode)))
> +		return -ERANGE;
> +	if (WARN_ON_ONCE(!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
> +		return -EINVAL;
> +	if (WARN_ON_ONCE(!(flags & IOMAP_WRITE)))
> +		return -EINVAL;
> +
> +	map_flags = delalloc ? EXT4_GET_BLOCKS_DELALLOC_RESERVE :
> +			       EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
> +retry:
> +	ret = ext4_iomap_map_blocks(inode, offset, length, &map, map_flags);

[Severity: High]
Does this code permanently leak unwritten extents past i_size if a short
write or write failure occurs?

If the user memory copy subsequently fails (e.g. fault_in_iov_iter_readable()
returns -EFAULT), it results in a short write.

In the non-delalloc path, ext4_iomap_buffered_write_ops lacks an iomap_end
callback to clean up the allocated on-disk blocks, which could exhaust
disk space or quota.

> +	if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
> +		goto retry;
> +	if (ret < 0)
> +		return ret;
> +
> +	ext4_set_iomap(inode, iomap, &map, offset, length, flags);
> +	return 0;
> +}

[ ... ]

> +static int ext4_iomap_buffered_da_write_end(struct inode *inode, loff_t offset,
> +					    loff_t length, ssize_t written,
> +					    unsigned int flags,
> +					    struct iomap *iomap)
> +{
> +	loff_t start_byte, end_byte;
> +
> +	/* If we didn't reserve the blocks, we're not allowed to punch them. */
> +	if (iomap->type != IOMAP_DELALLOC || !(iomap->flags & IOMAP_F_NEW))
> +		return 0;

[Severity: Critical]
Will this silently lose data for extending writes within already-allocated
blocks?

If a buffered write appends data to a file within an extent that was already
allocated, iomap_write_iter() will update the in-memory i_size and set
IOMAP_F_SIZE_CHANGED.

However, this early return skips checking IOMAP_F_SIZE_CHANGED.

Without updating EXT4_I(inode)->i_disksize and calling ext4_mark_inode_dirty()
to persist the size change, appended data can be lost on a crash.

> +
> +	/* Nothing to do if we've written the entire delalloc extent */
> +	start_byte = iomap_last_written_block(inode, offset, written);
> +	end_byte = round_up(offset + length, i_blocksize(inode));
> +	if (start_byte >= end_byte)
> +		return 0;
> +
> +	filemap_invalidate_lock(inode->i_mapping);
> +	iomap_write_delalloc_release(inode, start_byte, end_byte, flags,
> +				     iomap, ext4_iomap_punch_delalloc);
> +	filemap_invalidate_unlock(inode->i_mapping);
> +	return 0;
> +}
> +
> +/*
> + * Since we always allocate unwritten extents, there is no need for
> + * iomap_end to clean up allocated blocks on a short write.
> + */
> +static DEFINE_IOMAP_ITER_NEXT(ext4_iomap_buffered_write_next,
> +			      ext4_iomap_buffered_write_begin);
> +
> +const struct iomap_ops ext4_iomap_buffered_write_ops = {
> +	.iomap_next = ext4_iomap_buffered_write_next,
> +};

[Severity: High]
Is it safe to omit an iomap_end callback here?

Without an iomap_end callback for the non-delalloc path, two issues appear
to occur:

1) Allocated unwritten extents past i_size are leaked if a write fails,
exhausting disk space or quota.

2) Extending writes into an already-allocated extent set IOMAP_F_SIZE_CHANGED
in the core iomap code, but without an iomap_end callback to update i_disksize
and mark the inode dirty, this size update is never persisted to disk.

> +
> +static DEFINE_IOMAP_ITER_NEXT_END(ext4_iomap_buffered_da_write_next,
> +				  ext4_iomap_buffered_da_write_begin,
> +				  ext4_iomap_buffered_da_write_end);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260814093331.1703882-1-yi.zhang@huaweicloud.com?part=15

  reply	other threads:[~2026-08-14 10:40 UTC|newest]

Thread overview: 65+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-14  9:32 [PATCH -next v5 00/32] ext4: use iomap for regular file's buffered I/O path Zhang Yi
2026-08-14  9:33 ` [PATCH -next v5 01/32] ext4: simplify size updating in ext4_setattr() Zhang Yi
2026-08-14 10:02   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 02/32] ext4: factor out ext4_truncate_[up|down]() Zhang Yi
2026-08-14 10:04   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 03/32] ext4: simplify error handling in ext4_setattr() Zhang Yi
2026-08-14 10:12   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 04/32] ext4: skip ordered I/O wait when zeroing beyond i_disksize block Zhang Yi
2026-08-14 10:14   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 05/32] ext4: set EXT4_MAP_NEW flag for delayed allocated blocks Zhang Yi
2026-08-14 10:08   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 06/32] ext4: recheck extent status tree before block allocation Zhang Yi
2026-08-14 10:15   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 07/32] ext4: fix orig_mlen initialization in ext4_map_blocks() Zhang Yi
2026-08-14 10:08   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 08/32] ext4: allow ext4_map_blocks() to start its own transaction handle Zhang Yi
2026-08-14 10:00   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 09/32] ext4: avoid unnecessary transaction in ext4_map_blocks() for unwritten extents Zhang Yi
2026-08-14 10:15   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 10/32] ext4: skip block allocation for holes in the data submission path Zhang Yi
2026-08-14 10:15   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 11/32] ext4: add iomap address space operations for buffered I/O Zhang Yi
2026-08-14 10:04   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 12/32] ext4: implement buffered read path using iomap Zhang Yi
2026-08-14 10:15   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 13/32] ext4: pass out extent seq counter when mapping da blocks Zhang Yi
2026-08-14 10:12   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 14/32] ext4: do not use data=ordered mode for inodes using buffered iomap path Zhang Yi
2026-08-14 10:12   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 15/32] ext4: implement buffered write path using iomap Zhang Yi
2026-08-14 10:40   ` sashiko-bot [this message]
2026-08-14  9:33 ` [PATCH -next v5 16/32] ext4: implement writeback " Zhang Yi
2026-08-14 10:19   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 17/32] ext4: implement mmap " Zhang Yi
2026-08-14 10:35   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 18/32] ext4: implement partial block zero range " Zhang Yi
2026-08-14 10:25   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 19/32] ext4: tolerate unexpected holes in ext4_convert_unwritten_extents() Zhang Yi
2026-08-14 10:09   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 20/32] ext4: add block mapping tracepoints for iomap buffered I/O path Zhang Yi
2026-08-14 10:08   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 21/32] ext4: disable online defrag when inode using " Zhang Yi
2026-08-14 10:08   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 22/32] ext4: add EXT4_STATE_DISKSIZE_GROW_PENDING state bit and helpers Zhang Yi
2026-08-14 10:09   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 23/32] ext4: submit and wait for pending disksize-grow I/O on writeback Zhang Yi
2026-08-14 10:25   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 24/32] ext4: advance i_disksize to i_size upon disksize-grow I/O completion Zhang Yi
2026-08-14 10:25   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 25/32] ext4: defer i_disksize update while DISKSIZE_GROW_PENDING is set Zhang Yi
2026-08-14 10:31   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 26/32] ext4: submit and wait for disksize-grow I/O in fallocate paths Zhang Yi
2026-08-14 10:28   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 27/32] ext4: clear DISKSIZE_GROW_PENDING on truncate or error Zhang Yi
2026-08-14 10:31   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 28/32] ext4: set DISKSIZE_GROW_PENDING after zeroing unaligned EOF block Zhang Yi
2026-08-14 10:18   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 29/32] ext4: add tracepoints for DISKSIZE_GROW_PENDING set, clear, and wait Zhang Yi
2026-08-14 10:18   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 30/32] ext4: add tracepoints for EOF block zeroing and disksize-grow I/O Zhang Yi
2026-08-14 10:19   ` sashiko-bot
2026-08-14  9:46 ` [PATCH -next v5 31/32] ext4: partially enable iomap for the buffered I/O path of regular files Zhang Yi
2026-08-14 10:39   ` sashiko-bot
2026-08-14  9:46 ` [PATCH -next v5 32/32] ext4: introduce a mount option for iomap buffered I/O path Zhang Yi
2026-08-14 10:25   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260814104055.7F2C21F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-ext4@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=tytso@mit.edu \
    --cc=yi.zhang@huaweicloud.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.