* [PATCHv2 1/5] fs: add direct io attributes to file_getattr
2026-07-10 21:06 [PATCHv2 0/5] direct-io file extended attributes Keith Busch
@ 2026-07-10 21:06 ` Keith Busch
2026-07-10 21:06 ` [PATCHv2 2/5] block: report direct io attributes through file_getattr Keith Busch
` (4 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Keith Busch @ 2026-07-10 21:06 UTC (permalink / raw)
To: linux-block, linux-ext4, linux-f2fs-devel, linux-fsdevel,
linux-xfs
Cc: axboe, jack, brauner, cem, jaegeuk, aalbersh, tytso, Keith Busch
From: Keith Busch <kbusch@kernel.org>
Direct I/O imposes alignment and layout constraints that come from both
the filesystem and its backing storage. statx() reports some of these,
but not all, and it can no longer be extended. Report the complete set
through file_getattr() in new struct file_attr fields so applications
can know the constraints they have to work with.
The fields are valid only when FS_XFLAG_DIO is set in fa_xflags. When it
is clear the file does not report direct I/O geometry, for example,
because the filesystem configuration does not allow direct I/O, does not
support file_getatter, or is using the legacy block sized alignment
constraints.
The new fields are defined as follows:
- fa_dio_mem_align: byte alignment required for each I/O memory
buffer. The starting address and length of each buffer vector must
be a multiple of this value.
- fa_dio_offset_align: alignment required for the file offset and
total length of a write.
- fa_dio_read_offset_align: the same, but for reads. It may be
smaller than the write alignment allowing reads at a finer
granularity, but will be at most the same as writes.
- fa_dio_virt_boundary_align: alignment required at the boundary
between adjacent memory segments of a multi-segment transfer. The
previous segment must end on that boundary and the next must start
on it; otherwise, the kernel will split the command at that vector
if possible, or return an error if not (the accumulated length
is shorter than "offset_align"). A value of 1 means there is no such
constraint.
- fa_dio_offset_align_max_vecs: the maximum number of io vectors that
may compose a single fa_dio_offset_align unit. Buffers too small to
reach that unit within this many vectors can not form a valid I/O
and will be rejected by the kernel.
The fields are read only; file_setattr() ignores them.
The fa_pad field is introduced as a reserved field to account for an
implicit padding on 64-bit architectures and to make the struct the same
size for 32-bit. It must be zero to keep the space available for future
use.
Signed-off-by: Keith Busch <kbusch@kernel.org>
---
fs/file_attr.c | 7 +++++++
include/linux/fileattr.h | 10 ++++++++--
include/uapi/linux/fs.h | 10 +++++++++-
3 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/fs/file_attr.c b/fs/file_attr.c
index bfb00d256dd56..b37a55f54a449 100644
--- a/fs/file_attr.c
+++ b/fs/file_attr.c
@@ -110,6 +110,11 @@ static void fileattr_to_file_attr(const struct file_kattr *fa,
fattr->fa_nextents = fa->fsx_nextents;
fattr->fa_projid = fa->fsx_projid;
fattr->fa_cowextsize = fa->fsx_cowextsize;
+ fattr->fa_dio_mem_align = fa->fsx_dio_mem_align;
+ fattr->fa_dio_offset_align = fa->fsx_dio_offset_align;
+ fattr->fa_dio_read_offset_align = fa->fsx_dio_read_offset_align;
+ fattr->fa_dio_virt_boundary_align = fa->fsx_dio_virt_boundary_align;
+ fattr->fa_dio_offset_align_max_vecs = fa->fsx_dio_offset_align_max_vecs;
}
/**
@@ -145,6 +150,8 @@ static int file_attr_to_fileattr(const struct file_attr *fattr,
if (fattr->fa_xflags & ~mask)
return -EINVAL;
+ if (fattr->fa_pad)
+ return -EINVAL;
fileattr_fill_xflags(fa, fattr->fa_xflags & ~FS_XFLAG_RDONLY_MASK);
fa->fsx_extsize = fattr->fa_extsize;
diff --git a/include/linux/fileattr.h b/include/linux/fileattr.h
index 58044b5980162..3d5384c79398e 100644
--- a/include/linux/fileattr.h
+++ b/include/linux/fileattr.h
@@ -17,11 +17,11 @@
/* Read-only inode flags */
#define FS_XFLAG_RDONLY_MASK \
(FS_XFLAG_PREALLOC | FS_XFLAG_HASATTR | FS_XFLAG_VERITY | \
- FS_XFLAG_CASEFOLD | FS_XFLAG_CASENONPRESERVING)
+ FS_XFLAG_CASEFOLD | FS_XFLAG_CASENONPRESERVING | FS_XFLAG_DIO)
/* Flags to indicate valid value of fsx_ fields */
#define FS_XFLAG_VALUES_MASK \
- (FS_XFLAG_EXTSIZE | FS_XFLAG_COWEXTSIZE)
+ (FS_XFLAG_EXTSIZE | FS_XFLAG_COWEXTSIZE | FS_XFLAG_DIO)
/* Flags for directories */
#define FS_XFLAG_DIRONLY_MASK \
@@ -49,6 +49,12 @@ struct file_kattr {
u32 fsx_nextents; /* nextents field value (get) */
u32 fsx_projid; /* project identifier (get/set) */
u32 fsx_cowextsize; /* CoW extsize field value (get/set)*/
+ /* struct file_attr dio alignment: */
+ u32 fsx_dio_mem_align;
+ u32 fsx_dio_offset_align;
+ u32 fsx_dio_read_offset_align;
+ u32 fsx_dio_virt_boundary_align;
+ u32 fsx_dio_offset_align_max_vecs;
/* selectors: */
bool flags_valid:1;
bool fsx_valid:1;
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index bd87262f2e349..a49572fab3726 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -229,10 +229,17 @@ struct file_attr {
__u32 fa_nextents; /* nextents field value (get) */
__u32 fa_projid; /* project identifier (get/set) */
__u32 fa_cowextsize; /* CoW extsize field value (get/set) */
+ __u32 fa_dio_mem_align; /* DIO memory buffer align (get) */
+ __u32 fa_dio_offset_align; /* DIO file offset align (get) */
+ __u32 fa_dio_read_offset_align; /* DIO read offset align (get) */
+ __u32 fa_dio_virt_boundary_align; /* DIO virt boundary (get) */
+ __u32 fa_dio_offset_align_max_vecs; /* DIO vecs per unit (get) */
+ __u32 fa_pad; /* alignment padding, reserved for future use */
};
#define FILE_ATTR_SIZE_VER0 24
-#define FILE_ATTR_SIZE_LATEST FILE_ATTR_SIZE_VER0
+#define FILE_ATTR_SIZE_VER1 48
+#define FILE_ATTR_SIZE_LATEST FILE_ATTR_SIZE_VER1
/*
* Flags for the fsx_xflags field
@@ -261,6 +268,7 @@ struct file_attr {
*/
#define FS_XFLAG_CASEFOLD 0x00040000 /* case-insensitive lookups */
#define FS_XFLAG_CASENONPRESERVING 0x00080000 /* case not preserved */
+#define FS_XFLAG_DIO 0x00100000 /* DIO alignment info valid */
#define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
/* the read-only stuff doesn't really belong here, but any other place is
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCHv2 2/5] block: report direct io attributes through file_getattr
2026-07-10 21:06 [PATCHv2 0/5] direct-io file extended attributes Keith Busch
2026-07-10 21:06 ` [PATCHv2 1/5] fs: add direct io attributes to file_getattr Keith Busch
@ 2026-07-10 21:06 ` Keith Busch
2026-07-10 21:06 ` [PATCHv2 3/5] xfs: " Keith Busch
` (3 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Keith Busch @ 2026-07-10 21:06 UTC (permalink / raw)
To: linux-block, linux-ext4, linux-f2fs-devel, linux-fsdevel,
linux-xfs
Cc: axboe, jack, brauner, cem, jaegeuk, aalbersh, tytso, Keith Busch
From: Keith Busch <kbusch@kernel.org>
Add bdev_fill_dio_attr() to fill the file_attr direct io alignment
fields from a block device's queue limits, so filesystems can share the
derivation. Use it to report the attributes for block devices opened
directly.
Signed-off-by: Keith Busch <kbusch@kernel.org>
---
block/bdev.c | 37 +++++++++++++++++++++++++++++++++++++
fs/file_attr.c | 6 +++++-
include/linux/blkdev.h | 14 ++++++++++++++
3 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/block/bdev.c b/block/bdev.c
index 85ce57bd2ae4f..3b56f6696d3a3 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -28,6 +28,7 @@
#include <linux/part_stat.h>
#include <linux/uaccess.h>
#include <linux/stat.h>
+#include <linux/fileattr.h>
#include "../fs/internal.h"
#include "blk.h"
@@ -1353,6 +1354,42 @@ void bdev_statx(const struct path *path, struct kstat *stat, u32 request_mask)
blkdev_put_no_open(bdev);
}
+/*
+ * Fill the direct I/O alignment attributes derived from a block device's
+ * queue limits. Filesystems override the offset alignments as needed and
+ * set FS_XFLAG_DIO once they have decided direct I/O is supported.
+ */
+void bdev_fill_dio_attr(struct block_device *bdev, struct file_kattr *fa)
+{
+ fa->fsx_dio_mem_align = bdev_dma_alignment(bdev) + 1;
+ fa->fsx_dio_offset_align = bdev_logical_block_size(bdev);
+ fa->fsx_dio_read_offset_align = bdev_logical_block_size(bdev);
+ fa->fsx_dio_virt_boundary_align = bdev_virt_boundary_alignment(bdev);
+ fa->fsx_dio_offset_align_max_vecs = bdev_max_segments(bdev);
+}
+EXPORT_SYMBOL_GPL(bdev_fill_dio_attr);
+
+/*
+ * Handle DIO alignment for block devices via fileattr.
+ */
+int bdev_fileattr(const struct inode *inode, struct file_kattr *fa)
+{
+ struct block_device *bdev;
+
+ bdev = blkdev_get_no_open(inode->i_rdev, false);
+ if (!bdev)
+ return -ENODEV;
+
+ memset(fa, 0, sizeof(*fa));
+ bdev_fill_dio_attr(bdev, fa);
+ fa->fsx_valid = true;
+ fa->flags_valid = true;
+ fa->fsx_xflags |= FS_XFLAG_DIO;
+
+ blkdev_put_no_open(bdev);
+ return 0;
+}
+
bool disk_live(struct gendisk *disk)
{
return !inode_unhashed(BD_INODE(disk->part0));
diff --git a/fs/file_attr.c b/fs/file_attr.c
index b37a55f54a449..b637eff9081aa 100644
--- a/fs/file_attr.c
+++ b/fs/file_attr.c
@@ -7,6 +7,7 @@
#include <linux/export.h>
#include <linux/syscalls.h>
#include <linux/namei.h>
+#include <linux/blkdev.h>
#include "internal.h"
@@ -88,13 +89,16 @@ int vfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
struct inode *inode = d_inode(dentry);
int error;
- if (!inode->i_op->fileattr_get)
+ if (!inode->i_op->fileattr_get && !S_ISBLK(inode->i_mode))
return -ENOIOCTLCMD;
error = security_inode_file_getattr(dentry, fa);
if (error)
return error;
+ if (!inode->i_op->fileattr_get)
+ return bdev_fileattr(inode, fa);
+
return inode->i_op->fileattr_get(dentry, fa);
}
EXPORT_SYMBOL(vfs_fileattr_get);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 9213a5716f95a..2d435fadfdcb9 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1607,6 +1607,17 @@ static inline unsigned int bdev_dma_alignment(struct block_device *bdev)
return queue_dma_alignment(bdev_get_queue(bdev));
}
+static inline unsigned long bdev_virt_boundary_mask(struct block_device *bdev)
+{
+ return bdev_get_queue(bdev)->limits.virt_boundary_mask;
+}
+
+static inline unsigned int
+bdev_virt_boundary_alignment(struct block_device *bdev)
+{
+ return bdev_virt_boundary_mask(bdev) + 1;
+}
+
static inline unsigned int
blk_lim_dma_alignment_and_pad(struct queue_limits *lim)
{
@@ -1805,6 +1816,9 @@ int sync_blockdev_range(struct block_device *bdev, loff_t lstart, loff_t lend);
int sync_blockdev_nowait(struct block_device *bdev);
void sync_bdevs(bool wait);
void bdev_statx(const struct path *path, struct kstat *stat, u32 request_mask);
+struct file_kattr;
+void bdev_fill_dio_attr(struct block_device *bdev, struct file_kattr *fa);
+int bdev_fileattr(const struct inode *inode, struct file_kattr *fa);
void printk_all_partitions(void);
int __init early_lookup_bdev(const char *pathname, dev_t *dev);
#else
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCHv2 3/5] xfs: report direct io attributes through file_getattr
2026-07-10 21:06 [PATCHv2 0/5] direct-io file extended attributes Keith Busch
2026-07-10 21:06 ` [PATCHv2 1/5] fs: add direct io attributes to file_getattr Keith Busch
2026-07-10 21:06 ` [PATCHv2 2/5] block: report direct io attributes through file_getattr Keith Busch
@ 2026-07-10 21:06 ` Keith Busch
2026-07-10 21:06 ` [PATCHv2 4/5] ext4: " Keith Busch
` (2 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Keith Busch @ 2026-07-10 21:06 UTC (permalink / raw)
To: linux-block, linux-ext4, linux-f2fs-devel, linux-fsdevel,
linux-xfs
Cc: axboe, jack, brauner, cem, jaegeuk, aalbersh, tytso, Keith Busch
From: Keith Busch <kbusch@kernel.org>
Fill in the direct io alignment attributes for regular files, reporting
the larger write alignment for CoW inodes.
Signed-off-by: Keith Busch <kbusch@kernel.org>
---
fs/xfs/xfs_ioctl.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 1b53701bebea1..d585242a8fe9f 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -49,6 +49,7 @@
#include <linux/mount.h>
#include <linux/fileattr.h>
+#include <linux/blkdev.h>
/* Return 0 on success or positive error */
int
@@ -468,6 +469,29 @@ xfs_ioc_rtgroup_geometry(
* Linux extended inode flags interface.
*/
+static void
+xfs_fill_fsxattr_dio(
+ struct xfs_inode *ip,
+ int whichfork,
+ struct file_kattr *fa)
+{
+ struct xfs_buftarg *target;
+
+ if (whichfork != XFS_DATA_FORK || !S_ISREG(VFS_I(ip)->i_mode))
+ return;
+
+ target = xfs_inode_buftarg(ip);
+ bdev_fill_dio_attr(target->bt_bdev, fa);
+ /*
+ * CoW inodes must write whole allocation units out of place, so report
+ * the larger write alignment while leaving the smaller read alignment
+ * from the queue limits in place.
+ */
+ if (xfs_is_cow_inode(ip))
+ fa->fsx_dio_offset_align = xfs_inode_alloc_unitsize(ip);
+ fa->fsx_xflags |= FS_XFLAG_DIO;
+}
+
static void
xfs_fill_fsxattr(
struct xfs_inode *ip,
@@ -517,6 +541,8 @@ xfs_fill_fsxattr(
fa->fsx_nextents = xfs_iext_count(ifp);
else
fa->fsx_nextents = xfs_ifork_nextents(ifp);
+
+ xfs_fill_fsxattr_dio(ip, whichfork, fa);
}
STATIC int
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCHv2 4/5] ext4: report direct io attributes through file_getattr
2026-07-10 21:06 [PATCHv2 0/5] direct-io file extended attributes Keith Busch
` (2 preceding siblings ...)
2026-07-10 21:06 ` [PATCHv2 3/5] xfs: " Keith Busch
@ 2026-07-10 21:06 ` Keith Busch
2026-07-10 21:06 ` [PATCHv2 5/5] f2fs: " Keith Busch
2026-07-10 21:53 ` [f2fs-dev] [PATCHv2 0/5] direct-io file extended attributes Eric Biggers
5 siblings, 0 replies; 10+ messages in thread
From: Keith Busch @ 2026-07-10 21:06 UTC (permalink / raw)
To: linux-block, linux-ext4, linux-f2fs-devel, linux-fsdevel,
linux-xfs
Cc: axboe, jack, brauner, cem, jaegeuk, aalbersh, tytso, Keith Busch
From: Keith Busch <kbusch@kernel.org>
Fill in the direct io alignment attributes for regular files, using the
block helper and overriding the offset alignment for the cases where ext4
requires filesystem block alignment.
Signed-off-by: Keith Busch <kbusch@kernel.org>
---
fs/ext4/ioctl.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index c8387e6a2c6e9..01617edff17a8 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -21,6 +21,7 @@
#include <linux/iversion.h>
#include <linux/fileattr.h>
#include <linux/uuid.h>
+#include <linux/blkdev.h>
#include "ext4_jbd2.h"
#include "ext4.h"
#include <linux/fsmap.h>
@@ -992,6 +993,27 @@ static long ext4_ioctl_group_add(struct file *file,
return err;
}
+static void ext4_fileattr_get_dio(struct inode *inode, struct file_kattr *fa)
+{
+ u32 dio_align;
+
+ if (!S_ISREG(inode->i_mode))
+ return;
+
+ dio_align = ext4_dio_alignment(inode);
+ if (!dio_align)
+ return;
+
+ bdev_fill_dio_attr(inode->i_sb->s_bdev, fa);
+ if (dio_align != 1) {
+ fa->fsx_dio_mem_align = dio_align;
+ fa->fsx_dio_offset_align = dio_align;
+ fa->fsx_dio_read_offset_align = dio_align;
+ }
+
+ fa->fsx_xflags |= FS_XFLAG_DIO;
+}
+
int ext4_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
{
struct inode *inode = d_inode(dentry);
@@ -1005,6 +1027,7 @@ int ext4_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
if (ext4_has_feature_project(inode->i_sb))
fa->fsx_projid = from_kprojid(&init_user_ns, ei->i_projid);
+ ext4_fileattr_get_dio(inode, fa);
return 0;
}
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCHv2 5/5] f2fs: report direct io attributes through file_getattr
2026-07-10 21:06 [PATCHv2 0/5] direct-io file extended attributes Keith Busch
` (3 preceding siblings ...)
2026-07-10 21:06 ` [PATCHv2 4/5] ext4: " Keith Busch
@ 2026-07-10 21:06 ` Keith Busch
2026-07-10 21:53 ` [f2fs-dev] [PATCHv2 0/5] direct-io file extended attributes Eric Biggers
5 siblings, 0 replies; 10+ messages in thread
From: Keith Busch @ 2026-07-10 21:06 UTC (permalink / raw)
To: linux-block, linux-ext4, linux-f2fs-devel, linux-fsdevel,
linux-xfs
Cc: axboe, jack, brauner, cem, jaegeuk, aalbersh, tytso, Keith Busch
From: Keith Busch <kbusch@kernel.org>
Fill in the direct io alignment attributes for regular files that support
direct writes.
Signed-off-by: Keith Busch <kbusch@kernel.org>
---
fs/f2fs/file.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 4b52c56d71f07..230b0dca06251 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -3452,6 +3452,25 @@ static int f2fs_ioc_setproject(struct inode *inode, __u32 projid)
}
#endif
+static void f2fs_fileattr_get_dio(struct inode *inode, struct file_kattr *fa)
+{
+ struct block_device *bdev;
+ unsigned int bsize;
+
+ if (!S_ISREG(inode->i_mode) || f2fs_force_buffered_io(inode, WRITE))
+ return;
+
+ bdev = inode->i_sb->s_bdev;
+ if (bdev)
+ bdev_fill_dio_attr(bdev, fa);
+
+ bsize = i_blocksize(inode);
+ fa->fsx_dio_mem_align = bsize;
+ fa->fsx_dio_offset_align = bsize;
+ fa->fsx_dio_read_offset_align = bsize;
+ fa->fsx_xflags |= FS_XFLAG_DIO;
+}
+
int f2fs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
{
struct inode *inode = d_inode(dentry);
@@ -3472,6 +3491,7 @@ int f2fs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
if (f2fs_sb_has_project_quota(F2FS_I_SB(inode)))
fa->fsx_projid = from_kprojid(&init_user_ns, fi->i_projid);
+ f2fs_fileattr_get_dio(inode, fa);
return 0;
}
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [f2fs-dev] [PATCHv2 0/5] direct-io file extended attributes
2026-07-10 21:06 [PATCHv2 0/5] direct-io file extended attributes Keith Busch
` (4 preceding siblings ...)
2026-07-10 21:06 ` [PATCHv2 5/5] f2fs: " Keith Busch
@ 2026-07-10 21:53 ` Eric Biggers
2026-07-10 22:58 ` Keith Busch
5 siblings, 1 reply; 10+ messages in thread
From: Eric Biggers @ 2026-07-10 21:53 UTC (permalink / raw)
To: Keith Busch
Cc: linux-block, linux-ext4, linux-f2fs-devel, linux-fsdevel,
linux-xfs, axboe, brauner, aalbersh, jack, tytso, Keith Busch,
jaegeuk, cem
On Fri, Jul 10, 2026 at 02:06:41PM -0700, Keith Busch via Linux-f2fs-devel wrote:
> From: Keith Busch <kbusch@kernel.org>
>
> The attributes reported through statx are incomplete for applications to
> fully know exactly how IO construction is valid or not. The statx call
> can report minimum memory alignment and total granularity, but it
> doesn't show the underlying gap boundary requirements or max segments
> per granule.
>
> This series adds the minimum to the extended file attributes through
> file_getattr. I hear this is the preferred interface for reporting such
> things over adding more fields to statx. In order to get everything
> under a single syscall, some of the attributes are duplicated from
> statx.
Okay, in v2 we at least now know that the existing statx UAPI was
considered. Could you give a specific real-world example (with the
actual values of each parameter) where it's not sufficient? Without
that there isn't really any way to evaluate this proposal.
- Eric
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [f2fs-dev] [PATCHv2 0/5] direct-io file extended attributes
2026-07-10 21:53 ` [f2fs-dev] [PATCHv2 0/5] direct-io file extended attributes Eric Biggers
@ 2026-07-10 22:58 ` Keith Busch
2026-07-11 0:24 ` Eric Biggers
0 siblings, 1 reply; 10+ messages in thread
From: Keith Busch @ 2026-07-10 22:58 UTC (permalink / raw)
To: Eric Biggers
Cc: Keith Busch, linux-block, linux-ext4, linux-f2fs-devel,
linux-fsdevel, linux-xfs, axboe, brauner, aalbersh, jack, tytso,
jaegeuk, cem
On Fri, Jul 10, 2026 at 05:53:28PM -0400, Eric Biggers wrote:
> On Fri, Jul 10, 2026 at 02:06:41PM -0700, Keith Busch via Linux-f2fs-devel wrote:
> > From: Keith Busch <kbusch@kernel.org>
> >
> > The attributes reported through statx are incomplete for applications to
> > fully know exactly how IO construction is valid or not. The statx call
> > can report minimum memory alignment and total granularity, but it
> > doesn't show the underlying gap boundary requirements or max segments
> > per granule.
> >
> > This series adds the minimum to the extended file attributes through
> > file_getattr. I hear this is the preferred interface for reporting such
> > things over adding more fields to statx. In order to get everything
> > under a single syscall, some of the attributes are duplicated from
> > statx.
>
> Okay, in v2 we at least now know that the existing statx UAPI was
> considered. Could you give a specific real-world example (with the
> actual values of each parameter) where it's not sufficient? Without
> that there isn't really any way to evaluate this proposal.
Yes, we can consider nvme. This protocol supports two different transfer
modes called PRP and SGL. PRP requires 4k aligned segments, though you
can have an arbitrary 4-byte aligned offset at the start. SGL on the
other hand allows completely arbitrary size and alignments for each
segment.
statx reports information sufficient to know that you can have dword
aligned page offsets for a virtually contiguous buffer, but it doesn't
report PRP's boundary gap requirement, so applications can't tell if the
file follows PRP or SGL rules for direct-io.
And if you have a device using SGL, statx doesn't report the max number
of sub-sector segments you can submit in a single command.
This series provides both limits so user space has the complete picture.
A typical nvme that supports only PRP has a DMA alignment of 4 bytes, a
dio offset alignment of 4k, and a virtual boundary of 4k.
If SGL were supported, there would be no virtual boundary gap, and max
segments is 256.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCHv2 0/5] direct-io file extended attributes
2026-07-10 22:58 ` Keith Busch
@ 2026-07-11 0:24 ` Eric Biggers
2026-07-11 1:06 ` Keith Busch
0 siblings, 1 reply; 10+ messages in thread
From: Eric Biggers @ 2026-07-11 0:24 UTC (permalink / raw)
To: Keith Busch
Cc: Keith Busch, linux-block, linux-ext4, linux-f2fs-devel,
linux-fsdevel, linux-xfs, axboe, brauner, aalbersh, jack, tytso,
jaegeuk, cem
On Fri, Jul 10, 2026 at 04:58:12PM -0600, Keith Busch wrote:
> On Fri, Jul 10, 2026 at 05:53:28PM -0400, Eric Biggers wrote:
> > On Fri, Jul 10, 2026 at 02:06:41PM -0700, Keith Busch via Linux-f2fs-devel wrote:
> > > From: Keith Busch <kbusch@kernel.org>
> > >
> > > The attributes reported through statx are incomplete for applications to
> > > fully know exactly how IO construction is valid or not. The statx call
> > > can report minimum memory alignment and total granularity, but it
> > > doesn't show the underlying gap boundary requirements or max segments
> > > per granule.
> > >
> > > This series adds the minimum to the extended file attributes through
> > > file_getattr. I hear this is the preferred interface for reporting such
> > > things over adding more fields to statx. In order to get everything
> > > under a single syscall, some of the attributes are duplicated from
> > > statx.
> >
> > Okay, in v2 we at least now know that the existing statx UAPI was
> > considered. Could you give a specific real-world example (with the
> > actual values of each parameter) where it's not sufficient? Without
> > that there isn't really any way to evaluate this proposal.
>
> Yes, we can consider nvme. This protocol supports two different transfer
> modes called PRP and SGL. PRP requires 4k aligned segments, though you
> can have an arbitrary 4-byte aligned offset at the start. SGL on the
> other hand allows completely arbitrary size and alignments for each
> segment.
>
> statx reports information sufficient to know that you can have dword
> aligned page offsets for a virtually contiguous buffer, but it doesn't
> report PRP's boundary gap requirement, so applications can't tell if the
> file follows PRP or SGL rules for direct-io.
>
> And if you have a device using SGL, statx doesn't report the max number
> of sub-sector segments you can submit in a single command.
>
> This series provides both limits so user space has the complete picture.
>
> A typical nvme that supports only PRP has a DMA alignment of 4 bytes, a
> dio offset alignment of 4k, and a virtual boundary of 4k.
So each segment's length has to be a multiple of 4k, *and* it has to end
on a 4k aligned memory address? That implies the segment begins at a 4k
aligned memory address as well, which is just stx_dio_mem_align=4k.
What am I missing?
What is a specific example of an I/O request that you'd like to be able
to submit that the existing UAPI can't declare support for?
> If SGL were supported, there would be no virtual boundary gap, and max
> segments is 256.
Can you elaborate on why DIO users need to know max_segments?
I'm worried about the UAPI duplication, as well as it going to be very
difficult for userspace to correctly use this information. With just
the two alignments there's at least a chance of them getting it right.
If we throw virt_boundary_mask and max_segments into the mix, I don't
think there's much chance.
- Eric
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCHv2 0/5] direct-io file extended attributes
2026-07-11 0:24 ` Eric Biggers
@ 2026-07-11 1:06 ` Keith Busch
0 siblings, 0 replies; 10+ messages in thread
From: Keith Busch @ 2026-07-11 1:06 UTC (permalink / raw)
To: Eric Biggers
Cc: Keith Busch, linux-block, linux-ext4, linux-f2fs-devel,
linux-fsdevel, linux-xfs, axboe, brauner, aalbersh, jack, tytso,
jaegeuk, cem
On Fri, Jul 10, 2026 at 08:24:12PM -0400, Eric Biggers wrote:
> On Fri, Jul 10, 2026 at 04:58:12PM -0600, Keith Busch wrote:
> > dio offset alignment of 4k, and a virtual boundary of 4k.
>
> So each segment's length has to be a multiple of 4k, *and* it has to end
> on a 4k aligned memory address? That implies the segment begins at a 4k
> aligned memory address as well, which is just stx_dio_mem_align=4k.
>
> What am I missing?
I'm apparently poorly explaining PRPs, but I hear this is a common
experience.
Simply put, any virtually contiguous buffer that starts at a dword
aligned address is a valid io vector, no matter how many pages it spans.
It doesn't matter where it starts or where it ends, but every page in
the middle obviously starts and ends on their page boundary.
Simple case: pread/pwrite. You can consult statx to know you can provide
any dword aligned buffer with an aligned length, and that's a valid
direct IO.
What I'm trying to enable here is the vectored preadv/pwritev type paths
for hardware that don't need to subscribe to PRP constraints.
> What is a specific example of an I/O request that you'd like to be able
> to submit that the existing UAPI can't declare support for?
I want to support NVMe SGL. This allows virtually *discontiguous*
segments that we currently can't distinguish with what statx reports.
I'm trying to report limits that let applications know what constraints
they're dealing with.
> > If SGL were supported, there would be no virtual boundary gap, and max
> > segments is 256.
>
> Can you elaborate on why DIO users need to know max_segments?
* Logical block is 4k.
* DMA granule is 4 bytes.
* Max segments is 256.
That's very typical NVMe device contraints under SGL capabilities with
the linux driver.
You can provide 4 byte vectors as needed, but you'll hit the max
segments limit before you have a valid IO if they're all that small.
The average size needs to be larger, so we need to communicate that
somehow.
To be clear, I'm not interested in trying to enable applications
dispatching thousands of 4-byte vectors to do an IO. That's a stupid
application. The applications I'm trying to enable have unpredictable
offsets such that a tiny fraction of vectors are indeed that small, but
that's not a typical vector for the payload. But I can't enable just
some without generically enabling all.
> I'm worried about the UAPI duplication, as well as it going to be very
> difficult for userspace to correctly use this information. With just
> the two alignments there's at least a chance of them getting it right.
> If we throw virt_boundary_mask and max_segments into the mix, I don't
> think there's much chance.
The blktests framework test case "block/043" does this with great
success with these exact parameters, but it takes these paramters from
the sysfs attributes. The same test works with filesystems too, but I
haven't gotten around to porting it to fstests because it's gating on
having this series.
^ permalink raw reply [flat|nested] 10+ messages in thread