]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: refine the unaligned check for always COW inodes in xfs_file_dio_write
authorChristoph Hellwig <hch@lst.de>
Fri, 27 Oct 2023 07:58:24 +0000 (09:58 +0200)
committerChristoph Hellwig <hch@lst.de>
Mon, 3 Feb 2025 04:49:06 +0000 (05:49 +0100)
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 <hch@lst.de>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
fs/xfs/xfs_file.c

index 785f6bbf1406f1cc99ae416a305ff1617afd43a8..d88a771d4c23cf46269db8a7da902bd5d7fec200 100644 (file)
@@ -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);
 }