Linux block layer
 help / color / mirror / Atom feed
* Re: [PATCH] fs: report direct io constraints through file_getattr
From: Keith Busch @ 2026-07-10 15:22 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Keith Busch, linux-block, linux-ext4, linux-f2fs-devel,
	linux-fsdevel, linux-xfs, axboe, jack, brauner, cem, jaegeuk,
	aalbersh, tytso
In-Reply-To: <20260710043519.GA6205@lst.de>

On Fri, Jul 10, 2026 at 06:35:19AM +0200, Christoph Hellwig wrote:
> On Thu, Jul 09, 2026 at 07:46:42AM -0600, Keith Busch wrote:
> > On Thu, Jul 09, 2026 at 09:13:52AM +0200, Christoph Hellwig wrote:
> > > On Tue, Jul 07, 2026 at 06:18:43PM -0700, Keith Busch wrote:
> > > 
> > > > +	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_max_segments = bdev_max_segments(bdev);
> > > 
> > > How is the max_segments value defined in a way that is meaningful to
> > > userspace?
> > 
> > It tells you how many sub-sector vectors you can submit in your
> > readv/writev before it needs to add up to a logical block size.
> > 
> > Ex: 4k logical block size, 4 byte DMA, 256 max segments. You can define
> > 4-byte iov's in your command, but you'll hit the max segment count
> > before you have a valid IO if they're all that small.
> 
> Ah, makes sense.  But besides the missing documentation I think
> max_segments is a bit of a misleading name for that.
> 
> Something like max_vecs_per_block (although we don't expose blocks
> in the UAPI) or max_vecs_per_granularity (I think grammar wants a word
> with me for that, though...) might be a bit more suitable.

The granularity it has to add up to is defined by the
fsx_dio_offset_align attribute. This is a bit long, but to make that
relationship clear, how about:

  fsx_dio_max_vecs_per_offset_align

^ permalink raw reply

* [REGRESSION] commit b520c4eef83d ("block: split bio_alloc_bioset more clearly into a fast and slowpath") causes fsync to fail with pmem
From: Sven-Hendrik Haase @ 2026-07-10 18:07 UTC (permalink / raw)
  To: Jens Axboe, Christoph Hellwig
  Cc: regressions, linux-block, Li Chen, Joseph Qi


[-- Attachment #1.1.1: Type: text/plain, Size: 3275 bytes --]

Hey,

First of all, I don't do a lot of Linux development and so I hope that 
I'm submitting this issue to the right people and lists, please be gentle.

I noticed that starting with Linux 7.1, my pmem volumes inside of QEMU 
stopped working. My use case is this:

qemu-system-x86_64 ... tons of QEMU flags ...
-object 
memory-backend-file,id=pmem0,share=on,merge=on,discard-data=on,mem-path=/path/pmem0.pmem,size=100G
-device virtio-pmem-pci,memdev=pmem0,id=nv0

This used to work but inside the VM I'd get this when running mkfs.ext4 
/dev/pmem0 with guest kernel 7.1.3:

> [root@archlinux ~]# mkfs.ext4 /dev/pmem0
> mke2fs 1.47.4 (6-Mar-2025)
> Creating filesystem with 26214400 4k blocks and 6553600 inodes
> Filesystem UUID: 1a140446-43e6-4501-91db-cfaa250916e5
> Superblock backups stored on blocks: 
>     32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
>     4096000, 7962624, 11239424, 20480000, 23887872
> 
> Allocating group tables: done                            
> Writing inode tables: done                            
> Creating journal (131072 blocks): done
> Writing superblocks and filesystem accounting information: mkfs.ext4: Input/output error while writing out and closing file system

I figured it must've been a recent regression since it worked until 
7.0.13 (the latest that I tested in the VM). I investigated a bit and 
was able to track it down to b520c4eef83d where some kind of refactor 
was committed. It seems to create the filesystem fine until the flush at 
the end. I did another test:

No fsync dd:

> [root@archlinux ~]# dd if=/dev/zero of=/dev/pmem0 bs=1M count=100           
> 100+0 records in
> 100+0 records out
> 104857600 bytes (105 MB, 100 MiB) copied, 0.195327 s, 537 MB/s

fsync dd:

> [root@archlinux ~]# dd if=/dev/zero of=/dev/pmem0 bs=1M count=100 conv=fsync
> dd: fsync failed for '/dev/pmem0': Input/output error
> 100+0 records in
> 100+0 records out
> 104857600 bytes (105 MB, 100 MiB) copied, 0.442089 s, 237 MB/s

Now, I'm entirely unfamiliar with the block subsystem in Linux but I 
poked at it a little and was able to produce a tiny patch that fixes 
this for me and I'm attaching it to this email as a discussion point. 
However, I'm not submitting it as an official patch because frankly I 
can't explain it well enough and I haven't done C in a long time, I just 
looked at the old logic and the new and put a bunch of debug prints all 
over the place. Basically this is just me doing my best to try to report 
this issue.

While scanning around, I noticed that just yesterday, a suspiciously 
similar topic was sent to the ML [0]. That patch is a lot bigger than 
mine, though. Also just when I was about to send this mail, I noticed 
[1] which seems to be exactly my issue.

All of this makes me even less confident in my patch since all of these 
patches are so much bigger and at least on the surface seem to tackle 
the same problem but maybe my report can add something here. If not, 
sorry for the noise.

#regzbot introduced: b520c4eef83d

[0] 
https://lore.kernel.org/lkml/20260709124455.1547912-1-joseph.qi@linux.alibaba.com/
[1] https://lore.kernel.org/lkml/20260630092338.2094628-1-me@linux.beauty/

[-- Attachment #1.1.2: bio.patch --]
[-- Type: text/x-patch, Size: 392 bytes --]

diff --git a/block/bio.c b/block/bio.c
index 5f10900b3f42..9a94b45135b7 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -555,6 +555,8 @@ struct bio *bio_alloc_bioset(struct block_device *bdev, unsigned short nr_vecs,
 		bio = bio_alloc_percpu_cache(bs);
 	} else {
 		opf &= ~REQ_ALLOC_CACHE;
+	}
+	if (!bio) {
 		p = kmem_cache_alloc(bs->bio_slab, gfp);
 		if (p)
 			bio = p + bs->front_pad;

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply related

* Re: [REGRESSION] commit b520c4eef83d ("block: split bio_alloc_bioset more clearly into a fast and slowpath") causes fsync to fail with pmem
From: Keith Busch @ 2026-07-10 18:17 UTC (permalink / raw)
  To: Sven-Hendrik Haase
  Cc: Jens Axboe, Christoph Hellwig, regressions, linux-block, Li Chen,
	Joseph Qi
In-Reply-To: <8a2b1abf-3c8a-4242-82c5-fba9943cf8f4@archlinux.org>

On Fri, Jul 10, 2026 at 08:07:32PM +0200, Sven-Hendrik Haase wrote:
> I noticed that starting with Linux 7.1, my pmem volumes inside of QEMU
> stopped working. My use case is this:
> 
> qemu-system-x86_64 ... tons of QEMU flags ...
> -object memory-backend-file,id=pmem0,share=on,merge=on,discard-data=on,mem-path=/path/pmem0.pmem,size=100G
> -device virtio-pmem-pci,memdev=pmem0,id=nv0
> 
> This used to work but inside the VM I'd get this when running mkfs.ext4
> /dev/pmem0 with guest kernel 7.1.3:

This pending fix (which is the same as what you proposed here) should
take care of it:

https://lore.kernel.org/linux-block/20260709020145.4011533-1-joseph.qi@linux.alibaba.com/

^ permalink raw reply

* Re: [REGRESSION] commit b520c4eef83d ("block: split bio_alloc_bioset more clearly into a fast and slowpath") causes fsync to fail with pmem
From: Sven-Hendrik Haase @ 2026-07-10 18:26 UTC (permalink / raw)
  To: Keith Busch, Sven-Hendrik Haase
  Cc: Jens Axboe, Christoph Hellwig, regressions, linux-block, Li Chen,
	Joseph Qi
In-Reply-To: <alE3PqhMQ63lBcWe@kbusch-mbp>


[-- Attachment #1.1: Type: text/plain, Size: 872 bytes --]



On 10.07.26 20:17, Keith Busch wrote:
> On Fri, Jul 10, 2026 at 08:07:32PM +0200, Sven-Hendrik Haase wrote:
>> I noticed that starting with Linux 7.1, my pmem volumes inside of QEMU
>> stopped working. My use case is this:
>>
>> qemu-system-x86_64 ... tons of QEMU flags ...
>> -object memory-backend-file,id=pmem0,share=on,merge=on,discard-data=on,mem-path=/path/pmem0.pmem,size=100G
>> -device virtio-pmem-pci,memdev=pmem0,id=nv0
>>
>> This used to work but inside the VM I'd get this when running mkfs.ext4
>> /dev/pmem0 with guest kernel 7.1.3:
> 
> This pending fix (which is the same as what you proposed here) should
> take care of it:
> 
> https://lore.kernel.org/linux-block/20260709020145.4011533-1-joseph.qi@linux.alibaba.com/

Oh, indeed. That's the very same patch. Well, looks like it's in the 
queue, then.

Sorry for the noise. :)

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply

* [PATCHv2 3/5] xfs: report direct io attributes through file_getattr
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
In-Reply-To: <20260710210646.3576365-1-kbusch@meta.com>

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

* [PATCHv2 2/5] block: report direct io attributes through file_getattr
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
In-Reply-To: <20260710210646.3576365-1-kbusch@meta.com>

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

* Re: [PATCH] fs: report direct io constraints through file_getattr
From: Eric Biggers @ 2026-07-10 21:20 UTC (permalink / raw)
  To: Jan Kara
  Cc: Christoph Hellwig, Keith Busch, linux-block, linux-ext4,
	linux-f2fs-devel, linux-fsdevel, linux-xfs, axboe, brauner, cem,
	jaegeuk, aalbersh, tytso, Keith Busch
In-Reply-To: <neamg3phll7hjwd765ddtqebtxasdvkoskff75dqzmgzv2xy5i@mf4agr6yoizn>

On Thu, Jul 09, 2026 at 11:14:47AM +0200, Jan Kara wrote:
> On Thu 09-07-26 09:13:52, Christoph Hellwig wrote:
> > On Tue, Jul 07, 2026 at 06:18:43PM -0700, Keith Busch wrote:
> > > +		u32 dio_align = ext4_dio_alignment(inode);
> > > +
> > > +		if (dio_align != 0) {
> > 
> > 
> > > +			struct block_device *bdev = inode->i_sb->s_bdev;
> > > +
> > > +			if (dio_align == 1) {
> > > +				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);
> > > +			} else {
> > > +				fa->fsx_dio_mem_align = dio_align;
> > > +				fa->fsx_dio_offset_align = dio_align;
> > > +				fa->fsx_dio_read_offset_align = dio_align;
> > > +			}
> > 
> > Call bdev_fileattr and override the relevant field as needed?
> > 
> > Question to the ext4 maintainers: why does ext4_dio_alignment
> > affect the in-memory alignment?  If it does so, it should probably
> > also affect the virt boundry alignment..
> 
> I guess that is mostly a historical accident. ext4_dio_alignment() returns
> 1 (iomap alignment is used and that's different for memory and file offset
> alignment), 0 (dio not supported, memory and file offset alignment is
> indeed the same), and blocksize (a special case which can happen for
> fscrypt if it supports dio and where I believe memory alignment
> requirements may be in fact different). I'm adding Eric to CC to answer
> what actual requirements fscrypt has for memory buffers for direct IO. I'd
> expect with inline encryption we would have the same requirements as
> ordinary iomap direct IO and for other code paths I'm not sure... Eric?

Please see Documentation/filesystems/fscrypt.rst:

    The I/O request must be fully aligned to the filesystem block size.
    This means that the file position the I/O is targeting, the lengths
    of all I/O segments, and the memory addresses of all I/O buffers
    must be multiples of this value.  Note that the filesystem block
    size may be greater than the logical block size of the block device.

We go over this about once a year, whenever someone suggests that the
memory alignment requirement is not needed.  blk-crypto-fallback needs
it, the block layer itself needs it, and at least some storage drivers
need it.

To support less memory alignment, we'd need to:

   - Make some fairly complex updates to blk-crypto-fallback to support
     en/decrypting data units split across pages.  Note that there's no
     way to do this with zero overhead on other requests.

   - Update the block layer to not split crypto data units across bvecs,
     regardless of memory alignment.  This also would add more overhead
     to all requests.

   - Test the hardware support on each eMMC and UFS host controller
     individually and opt in the ones that actually correctly handle
     crypto data units split across DMA segments.  We already know it
     does *not* work on at least one.

   - And finally update the filesystems as the last step, not the first.

So far I haven't seen the point.  Yes, applications can benefit from the
lower alignment in theory.  But especially with encryption/decryption,
it isn't at all easy to support.  This has apparently been getting
learned the hard way, as (for example) alignment was initially relaxed
for dm-crypt without testing it, and it had to be reverted
(https://lore.kernel.org/dm-devel/20221103152559.1909328-1-kbusch@meta.com/).

- Eric

^ permalink raw reply

* [PATCHv2 4/5] ext4: report direct io attributes through file_getattr
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
In-Reply-To: <20260710210646.3576365-1-kbusch@meta.com>

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

* [PATCHv2 5/5] f2fs: report direct io attributes through file_getattr
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
In-Reply-To: <20260710210646.3576365-1-kbusch@meta.com>

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

* Re: [f2fs-dev] [PATCH] fs: report direct io constraints through file_getattr
From: Eric Biggers @ 2026-07-10 21:25 UTC (permalink / raw)
  To: Keith Busch
  Cc: linux-block, linux-ext4, linux-f2fs-devel, linux-fsdevel,
	linux-xfs, axboe, brauner, aalbersh, jack, Christoph Hellwig,
	tytso, Keith Busch, jaegeuk, cem
In-Reply-To: <20260708011843.1036846-1-kbusch@meta.com>

On Tue, Jul 07, 2026 at 06:18:43PM -0700, Keith Busch via Linux-f2fs-devel wrote:
> From: Keith Busch <kbusch@kernel.org>
> 
> Memory alignment constraints for direct io can vary depending on the
> backing storage hardware. Provide support through file_getattr to report
> the attributes necessary for applications to know how to construct valid
> read and write requests.
> 
> Suggested-by: Christoph Hellwig <hch@lst.de>
> Signed-off-by: Keith Busch <kbusch@kernel.org>

This seems to be reinventing STATX_DIOALIGN and STATX_DIO_READ_ALIGN.
Any reason for this?

- Eric

^ permalink raw reply

* [PATCHv2 1/5] fs: add direct io attributes to file_getattr
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
In-Reply-To: <20260710210646.3576365-1-kbusch@meta.com>

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

* [PATCHv2 0/5] direct-io file extended attributes
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>

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.

Keith Busch (5):
  fs: add direct io attributes to file_getattr
  block: report direct io attributes through file_getattr
  xfs: report direct io attributes through file_getattr
  ext4: report direct io attributes through file_getattr
  f2fs: report direct io attributes through file_getattr

 block/bdev.c             | 37 +++++++++++++++++++++++++++++++++++++
 fs/ext4/ioctl.c          | 23 +++++++++++++++++++++++
 fs/f2fs/file.c           | 20 ++++++++++++++++++++
 fs/file_attr.c           | 13 ++++++++++++-
 fs/xfs/xfs_ioctl.c       | 26 ++++++++++++++++++++++++++
 include/linux/blkdev.h   | 14 ++++++++++++++
 include/linux/fileattr.h | 10 ++++++++--
 include/uapi/linux/fs.h  | 10 +++++++++-
 8 files changed, 149 insertions(+), 4 deletions(-)

-- 
2.53.0-Meta


^ permalink raw reply

* Re: [f2fs-dev] [PATCH] fs: report direct io constraints through file_getattr
From: Eric Biggers @ 2026-07-10 21:28 UTC (permalink / raw)
  To: Andrey Albershteyn
  Cc: Christoph Hellwig, axboe, linux-xfs, brauner, jack, Keith Busch,
	cem, aalbersh, linux-f2fs-devel, linux-block, Keith Busch, tytso,
	linux-fsdevel, jaegeuk, linux-ext4
In-Reply-To: <ak9f0CXSegLq8l5w@aalbersh-thinkpadx1carbongen13.rmtcz.csb>

On Thu, Jul 09, 2026 at 10:51:39AM +0200, Andrey Albershteyn via Linux-f2fs-devel wrote:
> > Andrey, is there a man page or other official documentation for
> > file_setattr/file_getattr?
> 
> No, I had a draft in cover letter but haven't got to sending it to
> man-pages. I will prepare a man page.

Or just abandon this series, and read the statx(2) man page which
documents the already-existing UAPI for getting the DIO alignments?

- Eric

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox