Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: bd1d2c21d5d249 ("xfs: add xfs_atomic_write_cow_iomap_begin()")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: John Garry <john.g.garry@oracle.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>

authored by

Darrick J. Wong and committed by
Carlos Maiolino
8d54eacd 0db22d7e

+19 -2
+19 -2
fs/xfs/xfs_iomap.c
··· 1130 1130 return -EAGAIN; 1131 1131 1132 1132 trace_xfs_iomap_atomic_write_cow(ip, offset, length); 1133 - 1133 + retry: 1134 1134 xfs_ilock(ip, XFS_ILOCK_EXCL); 1135 1135 1136 1136 if (!ip->i_cowfp) { ··· 1141 1141 if (!xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &cmap)) 1142 1142 cmap.br_startoff = end_fsb; 1143 1143 if (cmap.br_startoff <= offset_fsb) { 1144 + if (isnullstartblock(cmap.br_startblock)) 1145 + goto convert_delay; 1144 1146 xfs_trim_extent(&cmap, offset_fsb, count_fsb); 1145 1147 goto found; 1146 1148 } ··· 1171 1169 if (!xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &cmap)) 1172 1170 cmap.br_startoff = end_fsb; 1173 1171 if (cmap.br_startoff <= offset_fsb) { 1174 - xfs_trim_extent(&cmap, offset_fsb, count_fsb); 1175 1172 xfs_trans_cancel(tp); 1173 + if (isnullstartblock(cmap.br_startblock)) 1174 + goto convert_delay; 1175 + xfs_trim_extent(&cmap, offset_fsb, count_fsb); 1176 1176 goto found; 1177 1177 } 1178 1178 ··· 1214 1210 xfs_iunlock(ip, XFS_ILOCK_EXCL); 1215 1211 return xfs_bmbt_to_iomap(ip, iomap, &cmap, flags, IOMAP_F_SHARED, seq); 1216 1212 1213 + convert_delay: 1214 + xfs_iunlock(ip, XFS_ILOCK_EXCL); 1215 + error = xfs_bmapi_convert_delalloc(ip, XFS_COW_FORK, offset, iomap, 1216 + NULL); 1217 + if (error) 1218 + return error; 1219 + 1220 + /* 1221 + * Try the lookup again, because the delalloc conversion might have 1222 + * turned the COW mapping into unwritten, but we need it to be in 1223 + * written state. 1224 + */ 1225 + goto retry; 1217 1226 out_unlock: 1218 1227 xfs_iunlock(ip, XFS_ILOCK_EXCL); 1219 1228 return error;