]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: refine atomic write size check in xfs_file_write_iter()
authorJohn Garry <john.g.garry@oracle.com>
Wed, 7 May 2025 21:18:28 +0000 (14:18 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 7 May 2025 21:25:31 +0000 (14:25 -0700)
Currently the size of atomic write allowed is fixed at the blocksize.

To start to lift this restriction, partly refactor
xfs_report_atomic_write() to into helpers -
xfs_get_atomic_write_{min, max}() - and use those helpers to find the
per-inode atomic write limits and check according to that.

Also add xfs_get_atomic_write_max_opt() to return the optimal limit, and
just return 0 since large atomics aren't supported yet.

Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: John Garry <john.g.garry@oracle.com>
fs/xfs/xfs_file.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_iops.h

index 55bdae44e42a9908b01d00640c9efd5946dcd67a..e8acd6ca8f278656ca688ee3dc50572f1ee8a87a 100644 (file)
@@ -1032,14 +1032,12 @@ xfs_file_write_iter(
                return xfs_file_dax_write(iocb, from);
 
        if (iocb->ki_flags & IOCB_ATOMIC) {
-               /*
-                * Currently only atomic writing of a single FS block is
-                * supported. It would be possible to atomic write smaller than
-                * a FS block, but there is no requirement to support this.
-                * Note that iomap also does not support this yet.
-                */
-               if (ocount != ip->i_mount->m_sb.sb_blocksize)
+               if (ocount < xfs_get_atomic_write_min(ip))
                        return -EINVAL;
+
+               if (ocount > xfs_get_atomic_write_max(ip))
+                       return -EINVAL;
+
                ret = generic_atomic_write_valid(iocb, from);
                if (ret)
                        return ret;
index 22432c300fd7e31501d65f38f8da4eb42d4bac0a..77a0606e9dc9c311cb6a78b6152a61c4c0e16249 100644 (file)
@@ -601,16 +601,42 @@ xfs_report_dioalign(
                stat->dio_offset_align = stat->dio_read_offset_align;
 }
 
+unsigned int
+xfs_get_atomic_write_min(
+       struct xfs_inode        *ip)
+{
+       if (!xfs_inode_can_hw_atomic_write(ip))
+               return 0;
+
+       return ip->i_mount->m_sb.sb_blocksize;
+}
+
+unsigned int
+xfs_get_atomic_write_max(
+       struct xfs_inode        *ip)
+{
+       if (!xfs_inode_can_hw_atomic_write(ip))
+               return 0;
+
+       return ip->i_mount->m_sb.sb_blocksize;
+}
+
+unsigned int
+xfs_get_atomic_write_max_opt(
+       struct xfs_inode        *ip)
+{
+       return 0;
+}
+
 static void
 xfs_report_atomic_write(
        struct xfs_inode        *ip,
        struct kstat            *stat)
 {
-       unsigned int            unit_min = 0, unit_max = 0;
-
-       if (xfs_inode_can_hw_atomic_write(ip))
-               unit_min = unit_max = ip->i_mount->m_sb.sb_blocksize;
-       generic_fill_statx_atomic_writes(stat, unit_min, unit_max, 0);
+       generic_fill_statx_atomic_writes(stat,
+                       xfs_get_atomic_write_min(ip),
+                       xfs_get_atomic_write_max(ip),
+                       xfs_get_atomic_write_max_opt(ip));
 }
 
 STATIC int
index 3c1a2605ffd2b8778ad25eb0b36819adea8673ca..0896f6b8b3b8a1842bbd91e2127334dd83a2ea36 100644 (file)
@@ -19,5 +19,8 @@ int xfs_inode_init_security(struct inode *inode, struct inode *dir,
 extern void xfs_setup_inode(struct xfs_inode *ip);
 extern void xfs_setup_iops(struct xfs_inode *ip);
 extern void xfs_diflags_to_iflags(struct xfs_inode *ip, bool init);
+unsigned int xfs_get_atomic_write_min(struct xfs_inode *ip);
+unsigned int xfs_get_atomic_write_max(struct xfs_inode *ip);
+unsigned int xfs_get_atomic_write_max_opt(struct xfs_inode *ip);
 
 #endif /* __XFS_IOPS_H__ */