From: Christoph Hellwig Date: Fri, 27 Oct 2023 07:58:24 +0000 (+0200) Subject: xfs: refine the unaligned check for always COW inodes in xfs_file_dio_write X-Git-Tag: v6.15-rc1~149^2~7^2~5^2~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6fff175279e4682b4eff25182808e0b1c90347cf;p=thirdparty%2Fkernel%2Fstable.git xfs: refine the unaligned check for always COW inodes in xfs_file_dio_write For always COW inodes we also must check the alignment of each individual iovec segment, as they could end up with different I/Os due to the way bio_iov_iter_get_pages works, and we'd then overwrite an already written block. The existing always_cow sysctl based code doesn't catch this because nothing enforces that blocks aren't rewritten, but for zoned XFS on sequential write required zones this is a hard error. Signed-off-by: Christoph Hellwig Reviewed-by: "Darrick J. Wong" --- diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index a81c3e943f206..d66eea31b60ab 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -721,7 +721,16 @@ xfs_file_dio_write( /* direct I/O must be aligned to device logical sector size */ if ((iocb->ki_pos | count) & target->bt_logical_sectormask) return -EINVAL; - if ((iocb->ki_pos | count) & ip->i_mount->m_blockmask) + + /* + * For always COW inodes we also must check the alignment of each + * individual iovec segment, as they could end up with different + * I/Os due to the way bio_iov_iter_get_pages works, and we'd + * then overwrite an already written block. + */ + if (((iocb->ki_pos | count) & ip->i_mount->m_blockmask) || + (xfs_is_always_cow_inode(ip) && + (iov_iter_alignment(from) & ip->i_mount->m_blockmask))) return xfs_file_dio_write_unaligned(ip, iocb, from); return xfs_file_dio_write_aligned(ip, iocb, from); }