]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: Support atomic write for statx
authorJohn Garry <john.g.garry@oracle.com>
Tue, 5 Nov 2024 00:14:03 +0000 (16:14 -0800)
committerDarrick J. Wong <djwong@djwong.org>
Tue, 5 Nov 2024 00:22:10 +0000 (16:22 -0800)
Support providing info on atomic write unit min and max for an inode.

For simplicity, currently we limit the min at the FS block size. As for
max, we limit also at FS block size, as there is no current method to
guarantee extent alignment or granularity for regular files.

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

index aa4dbda7b5365eaf6b80dfc152074ad4eace7cbc..e8196f5778e2aaa934e1cd835d91c255ce834e90 100644 (file)
@@ -2115,6 +2115,13 @@ xfs_alloc_buftarg(
        btp->bt_daxdev = fs_dax_get_by_bdev(btp->bt_bdev, &btp->bt_dax_part_off,
                                            mp, ops);
 
+       if (bdev_can_atomic_write(btp->bt_bdev)) {
+               btp->bt_bdev_awu_min = bdev_atomic_write_unit_min_bytes(
+                                               btp->bt_bdev);
+               btp->bt_bdev_awu_max = bdev_atomic_write_unit_max_bytes(
+                                               btp->bt_bdev);
+       }
+
        /*
         * When allocating the buftargs we have not yet read the super block and
         * thus don't know the file system sector size yet.
index 209a389f2abca82ce831a49d2d27a9ab13559969..3d56bc7a35cc51b4167264f7632221eddacb061e 100644 (file)
@@ -124,6 +124,10 @@ struct xfs_buftarg {
        struct percpu_counter   bt_io_count;
        struct ratelimit_state  bt_ioerror_rl;
 
+       /* Atomic write unit values */
+       unsigned int            bt_bdev_awu_min;
+       unsigned int            bt_bdev_awu_max;
+
        /* built-in cache, if we're not using the perag one */
        struct xfs_buf_cache    bt_cache[];
 };
index 97ed912306fd066c461b53fec450f1b4727c8682..73009a25a1195275c917c5c05992f52adce739b6 100644 (file)
@@ -327,6 +327,21 @@ static inline bool xfs_inode_has_bigrtalloc(struct xfs_inode *ip)
        (XFS_IS_REALTIME_INODE(ip) ? \
                (ip)->i_mount->m_rtdev_targp : (ip)->i_mount->m_ddev_targp)
 
+static inline bool
+xfs_inode_can_atomicwrite(
+       struct xfs_inode        *ip)
+{
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_buftarg      *target = xfs_inode_buftarg(ip);
+
+       if (mp->m_sb.sb_blocksize < target->bt_bdev_awu_min)
+               return false;
+       if (mp->m_sb.sb_blocksize > target->bt_bdev_awu_max)
+               return false;
+
+       return true;
+}
+
 /*
  * In-core inode flags.
  */
index ee79cf161312ca3d9688e3c359587df376c4e537..5cd804812efdce0eb4b5a9666156daa4c5776cc3 100644 (file)
@@ -570,6 +570,20 @@ xfs_stat_blksize(
        return max_t(uint32_t, PAGE_SIZE, mp->m_sb.sb_blocksize);
 }
 
+static void
+xfs_get_atomic_write_attr(
+       struct xfs_inode        *ip,
+       unsigned int            *unit_min,
+       unsigned int            *unit_max)
+{
+       if (!xfs_inode_can_atomicwrite(ip)) {
+               *unit_min = *unit_max = 0;
+               return;
+       }
+
+       *unit_min = *unit_max = ip->i_mount->m_sb.sb_blocksize;
+}
+
 STATIC int
 xfs_vn_getattr(
        struct mnt_idmap        *idmap,
@@ -643,6 +657,14 @@ xfs_vn_getattr(
                        stat->dio_mem_align = bdev_dma_alignment(bdev) + 1;
                        stat->dio_offset_align = bdev_logical_block_size(bdev);
                }
+               if (request_mask & STATX_WRITE_ATOMIC) {
+                       unsigned int    unit_min, unit_max;
+
+                       xfs_get_atomic_write_attr(ip, &unit_min,
+                                       &unit_max);
+                       generic_fill_statx_atomic_writes(stat,
+                                       unit_min, unit_max);
+               }
                fallthrough;
        default:
                stat->blksize = xfs_stat_blksize(ip);