[PATCH 02/33] xfs: fix isize update in xfs_iomap_write_unwritten to track conversion progress

Dave Chinner <[email protected]> Wed, 29 Jul 2026 20:01:46 +1000
Newsgroups org.kernel.vger.linux-xfs
Message-ID <[email protected]>
xfs_iomap_write_unwritten() updates i_disk_size using the end of
the entire unwritten range (offset_fsb + count_fsb) rather than the
end of the extent that was actually converted in each iteration
(imap.br_startoff + imap.br_blockcount).

If the conversion requires multiple iterations and a crash occurs
partway through, recovery would replay the first transaction which
set i_disk_size to the end of the full range. This exposes
unwritten extents to userspace reads as zeroes rather than the
data that was written, because those extents have not yet been
converted from unwritten to written state.

Fix this by computing i_size from the extent that was actually
converted (imap), so i_disk_size advances incrementally as each
extent is converted. On crash, recovery only exposes data in
extents that have been both written and converted.

Fixes: 84803fb78237 ("xfs: log file size updates as part of unwritten extent conversion")
Assisted-by: LLM
Signed-off-by: Dave Chinner <[email protected]>
---
 fs/xfs/xfs_iomap.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 225c3de88d03..1437ea93563c 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -682,11 +682,15 @@ xfs_iomap_write_unwritten(
 			goto error_on_bmapi_transaction;
 
 		/*
-		 * Log the updated inode size as we go.  We have to be careful
-		 * to only log it up to the actual write offset if it is
-		 * halfway into a block.
+		 * Update the inode size to reflect the extent that was
+		 * converted in this iteration. We must not advance isize
+		 * beyond the extent we just converted, otherwise a crash
+		 * before the next conversion exposes unwritten extents
+		 * (zeroes) to userspace instead of the written data.
+		 * Clamp to the byte-level write end in case the converted
+		 * extent extends past the write boundary.
 		 */
-		i_size = XFS_FSB_TO_B(mp, offset_fsb + count_fsb);
+		i_size = XFS_FSB_TO_B(mp, imap.br_startoff + imap.br_blockcount);
 		if (i_size > offset + count)
 			i_size = offset + count;
 		if (update_isize && i_size > i_size_read(inode))
-- 
2.55.0