Commit 8d54eacd authored by Darrick J. Wong's avatar Darrick J. Wong Committed by Carlos Maiolino
Browse files

xfs: fix delalloc write failures in software-provided atomic writes



With the 20 Oct 2025 release of fstests, generic/521 fails for me on
regular (aka non-block-atomic-writes) storage:

QA output created by 521
dowrite: write: Input/output error
LOG DUMP (8553 total operations):
1(  1 mod 256): SKIPPED (no operation)
2(  2 mod 256): WRITE    0x7e000 thru 0x8dfff	(0x10000 bytes) HOLE
3(  3 mod 256): READ     0x69000 thru 0x79fff	(0x11000 bytes)
4(  4 mod 256): FALLOC   0x53c38 thru 0x5e853	(0xac1b bytes) INTERIOR
5(  5 mod 256): COPY 0x55000 thru 0x59fff	(0x5000 bytes) to 0x25000 thru 0x29fff
6(  6 mod 256): WRITE    0x74000 thru 0x88fff	(0x15000 bytes)
7(  7 mod 256): ZERO     0xedb1 thru 0x11693	(0x28e3 bytes)

with a warning in dmesg from iomap about XFS trying to give it a
delalloc mapping for a directio write.  Fix the software atomic write
iomap_begin code to convert the reservation into a written mapping.
This doesn't fix the data corruption problems reported by generic/760,
but it's a start.

Cc: stable@vger.kernel.org # v6.16
Fixes: bd1d2c21 ("xfs: add xfs_atomic_write_cow_iomap_begin()")
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarJohn Garry <john.g.garry@oracle.com>
Signed-off-by: default avatarCarlos Maiolino <cem@kernel.org>
parent 0db22d7e
Loading
Loading
Loading
Loading
+19 −2
Original line number Diff line number Diff line
@@ -1130,7 +1130,7 @@ xfs_atomic_write_cow_iomap_begin(
		return -EAGAIN;

	trace_xfs_iomap_atomic_write_cow(ip, offset, length);

retry:
	xfs_ilock(ip, XFS_ILOCK_EXCL);

	if (!ip->i_cowfp) {
@@ -1141,6 +1141,8 @@ xfs_atomic_write_cow_iomap_begin(
	if (!xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &cmap))
		cmap.br_startoff = end_fsb;
	if (cmap.br_startoff <= offset_fsb) {
		if (isnullstartblock(cmap.br_startblock))
			goto convert_delay;
		xfs_trim_extent(&cmap, offset_fsb, count_fsb);
		goto found;
	}
@@ -1169,8 +1171,10 @@ xfs_atomic_write_cow_iomap_begin(
	if (!xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &cmap))
		cmap.br_startoff = end_fsb;
	if (cmap.br_startoff <= offset_fsb) {
		xfs_trim_extent(&cmap, offset_fsb, count_fsb);
		xfs_trans_cancel(tp);
		if (isnullstartblock(cmap.br_startblock))
			goto convert_delay;
		xfs_trim_extent(&cmap, offset_fsb, count_fsb);
		goto found;
	}

@@ -1210,6 +1214,19 @@ xfs_atomic_write_cow_iomap_begin(
	xfs_iunlock(ip, XFS_ILOCK_EXCL);
	return xfs_bmbt_to_iomap(ip, iomap, &cmap, flags, IOMAP_F_SHARED, seq);

convert_delay:
	xfs_iunlock(ip, XFS_ILOCK_EXCL);
	error = xfs_bmapi_convert_delalloc(ip, XFS_COW_FORK, offset, iomap,
			NULL);
	if (error)
		return error;

	/*
	 * Try the lookup again, because the delalloc conversion might have
	 * turned the COW mapping into unwritten, but we need it to be in
	 * written state.
	 */
	goto retry;
out_unlock:
	xfs_iunlock(ip, XFS_ILOCK_EXCL);
	return error;