]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
xfs: support sub-block aligned vectors in always COW mode
authorChristoph Hellwig <hch@lst.de>
Fri, 31 Oct 2025 13:10:27 +0000 (14:10 +0100)
committerChristian Brauner <brauner@kernel.org>
Wed, 5 Nov 2025 12:09:27 +0000 (13:09 +0100)
Now that the block layer and iomap have grown support to indicate
the bio sector size explicitly instead of assuming the device sector
size, we can ask for logical block size alignment and thus support
direct I/O writes where the overall size is logical block size
aligned, but the boundaries between vectors might not be.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Link: https://patch.msgid.link/20251031131045.1613229-3-hch@lst.de
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/xfs/xfs_file.c

index 5b9864c8582e5314abbaf9573547d7abd358ecae..6108612182e2fbdc39674358fff8aeab50963431 100644 (file)
@@ -676,8 +676,17 @@ xfs_file_dio_write_aligned(
        struct xfs_zone_alloc_ctx *ac)
 {
        unsigned int            iolock = XFS_IOLOCK_SHARED;
+       unsigned int            dio_flags = 0;
        ssize_t                 ret;
 
+       /*
+        * For always COW inodes, each bio must be aligned to the file system
+        * block size and not just the device sector size because we need to
+        * allocate a block-aligned amount of space for each write.
+        */
+       if (xfs_is_always_cow_inode(ip))
+               dio_flags |= IOMAP_DIO_FSBLOCK_ALIGNED;
+
        ret = xfs_ilock_iocb_for_write(iocb, &iolock);
        if (ret)
                return ret;
@@ -695,7 +704,7 @@ xfs_file_dio_write_aligned(
                iolock = XFS_IOLOCK_SHARED;
        }
        trace_xfs_file_direct_write(iocb, from);
-       ret = iomap_dio_rw(iocb, from, ops, dops, 0, ac, 0);
+       ret = iomap_dio_rw(iocb, from, ops, dops, dio_flags, ac, 0);
 out_unlock:
        xfs_iunlock(ip, iolock);
        return ret;
@@ -892,15 +901,7 @@ xfs_file_dio_write(
        if ((iocb->ki_pos | count) & target->bt_logical_sectormask)
                return -EINVAL;
 
-       /*
-        * 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)))
+       if ((iocb->ki_pos | count) & ip->i_mount->m_blockmask)
                return xfs_file_dio_write_unaligned(ip, iocb, from);
        if (xfs_is_zoned_inode(ip))
                return xfs_file_dio_write_zoned(ip, iocb, from);