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