[PATCH RFC 4/7] fs: Add initial buffered atomic write support info to statx

From: John Garry
Date: Mon Apr 22 2024 - 10:41:50 EST


Extend statx system call to return additional info for buffered atomic
write support for a file. Currently only direct IO is supported.

New flags STATX_WRITE_ATOMIC_BUF and STATX_ATTR_WRITE_ATOMIC_BUF are for
indicating whether the file knows and supports buffered atomic writes.

Structure statx members stx_atomic_write_unit_{min, max, segments_max} will
be reused for bufferd atomic writes. Flags STATX_WRITE_ATOMIC_DIO and
STATX_WRITE_ATOMIC_BUF are mutually exclusive. With both flags set, neither
fields in statx.result_mask will be set.

For buffered atomic writes, stx_atomic_write_unit_{min, max} must hold the
same value.

Signed-off-by: John Garry <john.g.garry@xxxxxxxxxx>
---
block/bdev.c | 3 ++-
fs/stat.c | 26 ++++++++++++++++++--------
fs/xfs/xfs_iops.c | 2 +-
include/linux/fs.h | 3 ++-
include/uapi/linux/stat.h | 2 ++
5 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/block/bdev.c b/block/bdev.c
index e2a9951bd2e9..b80c78aed9f6 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -1213,7 +1213,8 @@ void bdev_statx(struct inode *backing_inode, struct kstat *stat,

generic_fill_statx_atomic_writes(stat,
queue_atomic_write_unit_min_bytes(bd_queue),
- queue_atomic_write_unit_max_bytes(bd_queue));
+ queue_atomic_write_unit_max_bytes(bd_queue),
+ true);
}

blkdev_put_no_open(bdev);
diff --git a/fs/stat.c b/fs/stat.c
index 0c0c4c22c563..cb8283534616 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -94,19 +94,26 @@ EXPORT_SYMBOL(generic_fill_statx_attr);
* @stat: Where to fill in the attribute flags
* @unit_min: Minimum supported atomic write length in bytes
* @unit_max: Maximum supported atomic write length in bytes
+ * @dio: Whether filling in the fields for direct-IO
*
- * Fill in the STATX{_ATTR}_WRITE_ATOMIC_DIO flags in the kstat structure
- * from atomic write unit_min and unit_max values.
+ * Fill in the STATX{_ATTR}_WRITE_ATOMIC_{DIO, BUF} flags in the kstat
+ * structure from atomic write unit_min and unit_max values.
*/
void generic_fill_statx_atomic_writes(struct kstat *stat,
unsigned int unit_min,
- unsigned int unit_max)
+ unsigned int unit_max,
+ bool dio)
{
/* Confirm that the request type is known */
- stat->result_mask |= STATX_WRITE_ATOMIC_DIO;
-
- /* Confirm that the file attribute type is known */
- stat->attributes_mask |= STATX_ATTR_WRITE_ATOMIC_DIO;
+ if (dio) {
+ /* Confirm that the request type is known */
+ stat->result_mask |= STATX_WRITE_ATOMIC_DIO;
+ /* Confirm that the file attribute type is known */
+ stat->attributes_mask |= STATX_ATTR_WRITE_ATOMIC_DIO;
+ } else {
+ stat->attributes_mask |= STATX_ATTR_WRITE_ATOMIC_BUF;
+ stat->result_mask |= STATX_WRITE_ATOMIC_BUF;
+ }

if (unit_min) {
stat->atomic_write_unit_min = unit_min;
@@ -115,7 +122,10 @@ void generic_fill_statx_atomic_writes(struct kstat *stat,
stat->atomic_write_segments_max = 1;

/* Confirm atomic writes are actually supported */
- stat->attributes |= STATX_ATTR_WRITE_ATOMIC_DIO;
+ if (dio)
+ stat->attributes |= STATX_ATTR_WRITE_ATOMIC_DIO;
+ else
+ stat->attributes |= STATX_ATTR_WRITE_ATOMIC_BUF;
}
}
EXPORT_SYMBOL_GPL(generic_fill_statx_atomic_writes);
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 37076176db67..05b20c88ff77 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -655,7 +655,7 @@ xfs_vn_getattr(

xfs_get_atomic_write_attr(ip, &unit_min, &unit_max);
generic_fill_statx_atomic_writes(stat,
- unit_min, unit_max);
+ unit_min, unit_max, true);
}
fallthrough;
default:
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 08a0b9a4da93..1147d031d5bd 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3243,7 +3243,8 @@ void generic_fillattr(struct mnt_idmap *, u32, struct inode *, struct kstat *);
void generic_fill_statx_attr(struct inode *inode, struct kstat *stat);
void generic_fill_statx_atomic_writes(struct kstat *stat,
unsigned int unit_min,
- unsigned int unit_max);
+ unsigned int unit_max,
+ bool dio);
extern int vfs_getattr_nosec(const struct path *, struct kstat *, u32, unsigned int);
extern int vfs_getattr(const struct path *, struct kstat *, u32, unsigned int);
void __inode_add_bytes(struct inode *inode, loff_t bytes);
diff --git a/include/uapi/linux/stat.h b/include/uapi/linux/stat.h
index 05f9720d4030..9eef921b3942 100644
--- a/include/uapi/linux/stat.h
+++ b/include/uapi/linux/stat.h
@@ -161,6 +161,7 @@ struct statx {
#define STATX_DIOALIGN 0x00002000U /* Want/got direct I/O alignment info */
#define STATX_MNT_ID_UNIQUE 0x00004000U /* Want/got extended stx_mount_id */
#define STATX_WRITE_ATOMIC_DIO 0x00008000U /* Want/got atomic_write_* fields for dio */
+#define STATX_WRITE_ATOMIC_BUF 0x00010000U /* Want/got atomic_write_* fields for non-dio */

#define STATX__RESERVED 0x80000000U /* Reserved for future struct statx expansion */

@@ -197,6 +198,7 @@ struct statx {
#define STATX_ATTR_VERITY 0x00100000 /* [I] Verity protected file */
#define STATX_ATTR_DAX 0x00200000 /* File is currently in DAX state */
#define STATX_ATTR_WRITE_ATOMIC_DIO 0x00400000 /* File supports atomic write dio operations */
+#define STATX_ATTR_WRITE_ATOMIC_BUF 0x00800000 /* File supports atomic write non-dio operations */


#endif /* _UAPI_LINUX_STAT_H */
--
2.31.1