AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/07/01 08:58 flow patch-triage
2m Args:
null

Results:
{
  "EnableConfigs": [
    "FS_IOMAP",
    "BLOCK"
  ],
  "FocusSymbols": [
    "iomap_dio_simple",
    "iomap_dio_simple_supported",
    "iomap_dio_simple_complete",
    "iomap_dio_simple_end_io",
    "iomap_dio_simple_complete_work"
  ],
  "Reasoning": "The patch introduces a new fast path for small, block-aligned direct I/Os in the iomap subsystem. This adds new core logic for direct I/O handling that is reachable via various filesystems (ext4, xfs, btrfs, etc.) and should be fuzzed.",
  "WorthFuzzing": true
}

1/1 2026/07/01 08:58 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 29ebb2ce766840676c05f54b6535a82778378b2c\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Wed Jul 1 08:58:49 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c\nindex b485e3b191dafa..ca790239e5eb32 100644\n--- a/fs/iomap/direct-io.c\n+++ b/fs/iomap/direct-io.c\n@@ -10,6 +10,7 @@\n #include \u003clinux/iomap.h\u003e\n #include \u003clinux/task_io_accounting_ops.h\u003e\n #include \u003clinux/fserror.h\u003e\n+#include \u003clinux/init.h\u003e\n #include \"internal.h\"\n #include \"trace.h\"\n \n@@ -88,9 +89,9 @@ static inline enum fserror_type iomap_dio_err_type(const struct iomap_dio *dio)\n \treturn FSERR_DIRECTIO_READ;\n }\n \n-static inline bool should_report_dio_fserror(const struct iomap_dio *dio)\n+static inline bool should_report_dio_fserror(int error)\n {\n-\tswitch (dio-\u003eerror) {\n+\tswitch (error) {\n \tcase 0:\n \tcase -EAGAIN:\n \tcase -ENOTBLK:\n@@ -110,7 +111,7 @@ ssize_t iomap_dio_complete(struct iomap_dio *dio)\n \n \tif (dops \u0026\u0026 dops-\u003eend_io)\n \t\tret = dops-\u003eend_io(iocb, dio-\u003esize, ret, dio-\u003eflags);\n-\tif (should_report_dio_fserror(dio))\n+\tif (should_report_dio_fserror(dio-\u003eerror))\n \t\tfserror_report_io(file_inode(iocb-\u003eki_filp),\n \t\t\t\t  iomap_dio_err_type(dio), offset, dio-\u003esize,\n \t\t\t\t  dio-\u003eerror, GFP_NOFS);\n@@ -398,6 +399,14 @@ static ssize_t iomap_dio_bio_iter_one(struct iomap_iter *iter,\n \treturn ret;\n }\n \n+static inline unsigned int iomap_dio_alignment(struct inode *inode,\n+\t\tstruct block_device *bdev, unsigned int dio_flags)\n+{\n+\tif (dio_flags \u0026 IOMAP_DIO_FSBLOCK_ALIGNED)\n+\t\treturn i_blocksize(inode);\n+\treturn bdev_logical_block_size(bdev);\n+}\n+\n static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio)\n {\n \tconst struct iomap *iomap = \u0026iter-\u003eiomap;\n@@ -416,10 +425,7 @@ static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio)\n \t * File systems that write out of place and always allocate new blocks\n \t * need each bio to be block aligned as that's the unit of allocation.\n \t */\n-\tif (dio-\u003eflags \u0026 IOMAP_DIO_FSBLOCK_ALIGNED)\n-\t\talignment = fs_block_size;\n-\telse\n-\t\talignment = bdev_logical_block_size(iomap-\u003ebdev);\n+\talignment = iomap_dio_alignment(inode, iomap-\u003ebdev, dio-\u003eflags);\n \n \tif ((pos | length) \u0026 (alignment - 1))\n \t\treturn -EINVAL;\n@@ -888,12 +894,277 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,\n }\n EXPORT_SYMBOL_GPL(__iomap_dio_rw);\n \n+struct iomap_dio_simple {\n+\tstruct kiocb\t\t*iocb;\n+\tsize_t\t\t\tsize;\n+\tunsigned int\t\tdio_flags;\n+\tstruct work_struct\twork;\n+\t/*\n+\t * Align @bio to a cacheline boundary so that, combined with the\n+\t * front_pad passed to bioset_init(), the bio sits at the start of\n+\t * a cacheline in memory returned by the (HWCACHE-aligned) bio\n+\t * slab.  This keeps the hot fields block layer touches on submit\n+\t * and completion (bi_iter, bi_status, ...) within a single line.\n+\t */\n+\tstruct bio\t\tbio ____cacheline_aligned_in_smp;\n+};\n+\n+static struct bio_set iomap_dio_simple_pool;\n+\n+static ssize_t iomap_dio_simple_complete(struct iomap_dio_simple *sr)\n+{\n+\tstruct bio *bio = \u0026sr-\u003ebio;\n+\tstruct kiocb *iocb = sr-\u003eiocb;\n+\tstruct inode *inode = file_inode(iocb-\u003eki_filp);\n+\tssize_t ret;\n+\n+\tif (unlikely(bio-\u003ebi_status)) {\n+\t\tret = blk_status_to_errno(bio-\u003ebi_status);\n+\t\tif (should_report_dio_fserror(ret))\n+\t\t\tfserror_report_io(inode, FSERR_DIRECTIO_READ,\n+\t\t\t\t\t  iocb-\u003eki_pos, sr-\u003esize, ret,\n+\t\t\t\t\t  GFP_NOFS);\n+\t} else {\n+\t\tret = sr-\u003esize;\n+\t\tiocb-\u003eki_pos += ret;\n+\t}\n+\n+\tif (sr-\u003edio_flags \u0026 IOMAP_DIO_USER_BACKED) {\n+\t\tbio_check_pages_dirty(bio);\n+\t} else {\n+\t\tbio_release_pages(bio, false);\n+\t\tbio_put(bio);\n+\t}\n+\tinode_dio_end(inode);\n+\ttrace_iomap_dio_complete(iocb, ret \u003c 0 ? ret : 0, ret);\n+\treturn ret;\n+}\n+\n+static void iomap_dio_simple_complete_work(struct work_struct *work)\n+{\n+\tstruct iomap_dio_simple *sr =\n+\t\tcontainer_of(work, struct iomap_dio_simple, work);\n+\tstruct kiocb *iocb = sr-\u003eiocb;\n+\n+\tWRITE_ONCE(iocb-\u003eprivate, NULL);\n+\tiocb-\u003eki_complete(iocb, iomap_dio_simple_complete(sr));\n+}\n+\n+static void iomap_dio_simple_end_io(struct bio *bio)\n+{\n+\tstruct iomap_dio_simple *sr =\n+\t\tcontainer_of(bio, struct iomap_dio_simple, bio);\n+\tstruct kiocb *iocb = sr-\u003eiocb;\n+\n+\tif (unlikely(sr-\u003ebio.bi_status)) {\n+\t\tstruct inode *inode = file_inode(iocb-\u003eki_filp);\n+\n+\t\tINIT_WORK(\u0026sr-\u003ework, iomap_dio_simple_complete_work);\n+\t\tqueue_work(inode-\u003ei_sb-\u003es_dio_done_wq, \u0026sr-\u003ework);\n+\t\treturn;\n+\t}\n+\n+\tWRITE_ONCE(iocb-\u003eprivate, NULL);\n+\tiocb-\u003eki_complete(iocb, iomap_dio_simple_complete(sr));\n+}\n+\n+static inline bool\n+iomap_dio_simple_supported(struct kiocb *iocb, struct iov_iter *iter,\n+\t\t\t   const struct iomap_dio_ops *dops,\n+\t\t\t   unsigned int dio_flags, size_t done_before)\n+{\n+\tstruct inode *inode = file_inode(iocb-\u003eki_filp);\n+\tsize_t count = iov_iter_count(iter);\n+\n+\tif (dops || done_before)\n+\t\treturn false;\n+\tif (iov_iter_rw(iter) != READ)\n+\t\treturn false;\n+\tif (!count)\n+\t\treturn false;\n+\t/*\n+\t * Simple dio is an optimization for small IO. Filter out large IO\n+\t * early as it's the most common case to fail for typical direct IO\n+\t * workloads.\n+\t */\n+\tif (count \u003e inode-\u003ei_sb-\u003es_blocksize)\n+\t\treturn false;\n+\tif (dio_flags \u0026 (IOMAP_DIO_FORCE_WAIT | IOMAP_DIO_PARTIAL |\n+\t\t\t IOMAP_DIO_BOUNCE))\n+\t\treturn false;\n+\tif (iocb-\u003eki_pos + count \u003e i_size_read(inode))\n+\t\treturn false;\n+\tif (IS_ENCRYPTED(inode))\n+\t\treturn false;\n+\n+\treturn true;\n+}\n+\n+/*\n+ * Fast path for small, block-aligned direct I/Os that map to a single\n+ * contiguous on-disk extent.\n+ *\n+ * iomap_dio_simple_supported() enforces the cheap up-front constraints before\n+ * entering this path.\n+ *\n+ * @dops must be NULL: a non-NULL @dops means the caller wants its\n+ * -\u003eend_io / -\u003esubmit_io hooks invoked, and in particular wants its bios to be\n+ * allocated from the filesystem-private @dops-\u003ebio_set (whose front_pad sizes a\n+ * filesystem-private wrapper around the bio).  The fast path instead allocates\n+ * from the shared iomap_dio_simple_pool, whose front_pad matches struct\n+ * iomap_dio_simple; the two wrappers are not interchangeable, so we must fall\n+ * back to __iomap_dio_rw() in that case.\n+ *\n+ * @done_before must be zero: a non-zero caller-accumulated residual cannot be\n+ * carried through a single-bio inline completion.\n+ *\n+ * @iter must describe a non-empty READ no larger than the inode block size:\n+ * writes, zero-length I/O, and larger requests need the generic iomap direct\n+ * I/O path.\n+ *\n+ * @dio_flags must not request IOMAP_DIO_FORCE_WAIT, IOMAP_DIO_PARTIAL, or\n+ * IOMAP_DIO_BOUNCE: this path does not support forced waiting, partial direct\n+ * I/O, or bouncing.  The range must also stay within i_size and encrypted\n+ * inodes must use the generic iomap direct I/O path.\n+ *\n+ * -ENOTBLK is the private sentinel returned by iomap_dio_simple() when it\n+ * decides the request does not fit the fast path.  In that case we proceed to\n+ * the generic __iomap_dio_rw() slow path.  Any other errno is a real result and\n+ * is propagated as-is, in particular -EAGAIN for IOCB_NOWAIT must reach the\n+ * caller.\n+ */\n+static ssize_t\n+iomap_dio_simple(struct kiocb *iocb, struct iov_iter *iter,\n+\t\t const struct iomap_ops *ops, void *private,\n+\t\t unsigned int dio_flags)\n+{\n+\tstruct inode *inode = file_inode(iocb-\u003eki_filp);\n+\tsize_t count = iov_iter_count(iter);\n+\tbool wait_for_completion = is_sync_kiocb(iocb);\n+\tstruct iomap_iter iomi = {\n+\t\t.inode\t\t= inode,\n+\t\t.pos\t\t= iocb-\u003eki_pos,\n+\t\t.len\t\t= count,\n+\t\t.flags\t\t= IOMAP_DIRECT,\n+\t\t.private\t= private,\n+\t};\n+\tstruct iomap_dio_simple *sr;\n+\tunsigned int alignment;\n+\tstruct bio *bio;\n+\tssize_t ret;\n+\n+\tif (iocb-\u003eki_flags \u0026 IOCB_NOWAIT)\n+\t\tiomi.flags |= IOMAP_NOWAIT;\n+\n+\tret = kiocb_write_and_wait(iocb, count);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tinode_dio_begin(inode);\n+\n+\tret = ops-\u003eiomap_begin(inode, iomi.pos, count, iomi.flags,\n+\t\t\t       \u0026iomi.iomap, \u0026iomi.srcmap);\n+\tif (ret) {\n+\t\tinode_dio_end(inode);\n+\t\treturn ret;\n+\t}\n+\n+\tif (iomi.iomap.type != IOMAP_MAPPED ||\n+\t    iomi.iomap.offset + iomi.iomap.length \u003c iomi.pos + count ||\n+\t    (iomi.iomap.flags \u0026 IOMAP_F_INTEGRITY)) {\n+\t\tret = -ENOTBLK;\n+\t\tgoto out_iomap_end;\n+\t}\n+\n+\talignment = iomap_dio_alignment(inode, iomi.iomap.bdev, dio_flags);\n+\tif ((iomi.pos | count) \u0026 (alignment - 1)) {\n+\t\tret = -EINVAL;\n+\t\tgoto out_iomap_end;\n+\t}\n+\n+\tif (!wait_for_completion \u0026\u0026 unlikely(!inode-\u003ei_sb-\u003es_dio_done_wq)) {\n+\t\tret = sb_init_dio_done_wq(inode-\u003ei_sb);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto out_iomap_end;\n+\t}\n+\n+\ttrace_iomap_dio_rw_begin(iocb, iter, dio_flags, 0);\n+\n+\tif (user_backed_iter(iter))\n+\t\tdio_flags |= IOMAP_DIO_USER_BACKED;\n+\n+\tbio = bio_alloc_bioset(iomi.iomap.bdev,\n+\t\t\t       bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS),\n+\t\t\t       REQ_OP_READ, GFP_KERNEL, \u0026iomap_dio_simple_pool);\n+\tsr = container_of(bio, struct iomap_dio_simple, bio);\n+\tsr-\u003eiocb = iocb;\n+\tsr-\u003edio_flags = dio_flags;\n+\n+\tbio-\u003ebi_iter.bi_sector = iomap_sector(\u0026iomi.iomap, iomi.pos);\n+\tbio-\u003ebi_ioprio = iocb-\u003eki_ioprio;\n+\n+\tret = bio_iov_iter_get_pages(bio, iter, alignment - 1);\n+\tif (unlikely(ret))\n+\t\tgoto out_bio_put;\n+\n+\tif (bio-\u003ebi_iter.bi_size != count) {\n+\t\tiov_iter_revert(iter, bio-\u003ebi_iter.bi_size);\n+\t\tret = -ENOTBLK;\n+\t\tgoto out_bio_release_pages;\n+\t}\n+\n+\tsr-\u003esize = bio-\u003ebi_iter.bi_size;\n+\n+\tif (dio_flags \u0026 IOMAP_DIO_USER_BACKED)\n+\t\tbio_set_pages_dirty(bio);\n+\n+\tif (iocb-\u003eki_flags \u0026 IOCB_NOWAIT)\n+\t\tbio-\u003ebi_opf |= REQ_NOWAIT;\n+\tif ((iocb-\u003eki_flags \u0026 IOCB_HIPRI) \u0026\u0026 !wait_for_completion) {\n+\t\tbio-\u003ebi_opf |= REQ_POLLED;\n+\t\tWRITE_ONCE(iocb-\u003eprivate, bio);\n+\t}\n+\n+\tif (ops-\u003eiomap_end)\n+\t\tops-\u003eiomap_end(inode, iomi.pos, count, count, iomi.flags,\n+\t\t\t       \u0026iomi.iomap);\n+\n+\tif (!wait_for_completion) {\n+\t\tbio-\u003ebi_end_io = iomap_dio_simple_end_io;\n+\t\tsubmit_bio(bio);\n+\t\ttrace_iomap_dio_rw_queued(inode, iomi.pos, count);\n+\t\treturn -EIOCBQUEUED;\n+\t}\n+\n+\tsubmit_bio_wait(bio);\n+\treturn iomap_dio_simple_complete(sr);\n+\n+out_bio_release_pages:\n+\tbio_release_pages(bio, false);\n+out_bio_put:\n+\tbio_put(bio);\n+out_iomap_end:\n+\tif (ops-\u003eiomap_end)\n+\t\tops-\u003eiomap_end(inode, iomi.pos, count, 0, iomi.flags,\n+\t\t\t       \u0026iomi.iomap);\n+\tinode_dio_end(inode);\n+\treturn ret;\n+}\n+\n ssize_t\n iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,\n \t\tconst struct iomap_ops *ops, const struct iomap_dio_ops *dops,\n \t\tunsigned int dio_flags, void *private, size_t done_before)\n {\n \tstruct iomap_dio *dio;\n+\tssize_t ret;\n+\n+\tif (iomap_dio_simple_supported(iocb, iter, dops, dio_flags,\n+\t\t\t\t       done_before)) {\n+\t\tret = iomap_dio_simple(iocb, iter, ops, private, dio_flags);\n+\t\tif (ret != -ENOTBLK)\n+\t\t\treturn ret;\n+\t}\n \n \tdio = __iomap_dio_rw(iocb, iter, ops, dops, dio_flags, private,\n \t\t\t     done_before);\n@@ -902,3 +1173,11 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,\n \treturn iomap_dio_complete(dio);\n }\n EXPORT_SYMBOL_GPL(iomap_dio_rw);\n+\n+static int __init iomap_dio_init(void)\n+{\n+\treturn bioset_init(\u0026iomap_dio_simple_pool, 4,\n+\t\t\t   offsetof(struct iomap_dio_simple, bio),\n+\t\t\t   BIOSET_NEED_BVECS | BIOSET_PERCPU_CACHE);\n+}\n+fs_initcall(iomap_dio_init);\n"
}

2/1 2026/07/01 08:58 agent patch-evaluator
1m Model:
gemini-3.1-pro-preview

Args:
null

Results:
{
  "EnableConfigs": [
    "FS_IOMAP",
    "BLOCK"
  ],
  "FocusSymbols": [
    "iomap_dio_simple",
    "iomap_dio_simple_supported",
    "iomap_dio_simple_complete",
    "iomap_dio_simple_end_io",
    "iomap_dio_simple_complete_work"
  ],
  "Reasoning": "The patch introduces a new fast path for small, block-aligned direct I/Os in the iomap subsystem. This adds new core logic for direct I/O handling that is reachable via various filesystems (ext4, xfs, btrfs, etc.) and should be fuzzed.",
  "WorthFuzzing": true
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Do not list too generic configs (we already have them enabled). Only list those that
   specifically cover the modified code. List them in the EnableConfigs output array,
   and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
For your convenience, here is the diff of the changes:
commit 29ebb2ce766840676c05f54b6535a82778378b2c
Author: syz-cluster <triage@syzkaller.com>
Date:   Wed Jul 1 08:58:49 2026 +0000

    syz-cluster: applied patch under review

diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
index b485e3b191dafa..ca790239e5eb32 100644
--- a/fs/iomap/direct-io.c
+++ b/fs/iomap/direct-io.c
@@ -10,6 +10,7 @@
 #include <linux/iomap.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/fserror.h>
+#include <linux/init.h>
 #include "internal.h"
 #include "trace.h"
 
@@ -88,9 +89,9 @@ static inline enum fserror_type iomap_dio_err_type(const struct iomap_dio *dio)
 	return FSERR_DIRECTIO_READ;
 }
 
-static inline bool should_report_dio_fserror(const struct iomap_dio *dio)
+static inline bool should_report_dio_fserror(int error)
 {
-	switch (dio->error) {
+	switch (error) {
 	case 0:
 	case -EAGAIN:
 	case -ENOTBLK:
@@ -110,7 +111,7 @@ ssize_t iomap_dio_complete(struct iomap_dio *dio)
 
 	if (dops && dops->end_io)
 		ret = dops->end_io(iocb, dio->size, ret, dio->flags);
-	if (should_report_dio_fserror(dio))
+	if (should_report_dio_fserror(dio->error))
 		fserror_report_io(file_inode(iocb->ki_filp),
 				  iomap_dio_err_type(dio), offset, dio->size,
 				  dio->error, GFP_NOFS);
@@ -398,6 +399,14 @@ static ssize_t iomap_dio_bio_iter_one(struct iomap_iter *iter,
 	return ret;
 }
 
+static inline unsigned int iomap_dio_alignment(struct inode *inode,
+		struct block_device *bdev, unsigned int dio_flags)
+{
+	if (dio_flags & IOMAP_DIO_FSBLOCK_ALIGNED)
+		return i_blocksize(inode);
+	return bdev_logical_block_size(bdev);
+}
+
 static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio)
 {
 	const struct iomap *iomap = &iter->iomap;
@@ -416,10 +425,7 @@ static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio)
 	 * File systems that write out of place and always allocate new blocks
 	 * need each bio to be block aligned as that's the unit of allocation.
 	 */
-	if (dio->flags & IOMAP_DIO_FSBLOCK_ALIGNED)
-		alignment = fs_block_size;
-	else
-		alignment = bdev_logical_block_size(iomap->bdev);
+	alignment = iomap_dio_alignment(inode, iomap->bdev, dio->flags);
 
 	if ((pos | length) & (alignment - 1))
 		return -EINVAL;
@@ -888,12 +894,277 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
 }
 EXPORT_SYMBOL_GPL(__iomap_dio_rw);
 
+struct iomap_dio_simple {
+	struct kiocb		*iocb;
+	size_t			size;
+	unsigned int		dio_flags;
+	struct work_struct	work;
+	/*
+	 * Align @bio to a cacheline boundary so that, combined with the
+	 * front_pad passed to bioset_init(), the bio sits at the start of
+	 * a cacheline in memory returned by the (HWCACHE-aligned) bio
+	 * slab.  This keeps the hot fields block layer touches on submit
+	 * and completion (bi_iter, bi_status, ...) within a single line.
+	 */
+	struct bio		bio ____cacheline_aligned_in_smp;
+};
+
+static struct bio_set iomap_dio_simple_pool;
+
+static ssize_t iomap_dio_simple_complete(struct iomap_dio_simple *sr)
+{
+	struct bio *bio = &sr->bio;
+	struct kiocb *iocb = sr->iocb;
+	struct inode *inode = file_inode(iocb->ki_filp);
+	ssize_t ret;
+
+	if (unlikely(bio->bi_status)) {
+		ret = blk_status_to_errno(bio->bi_status);
+		if (should_report_dio_fserror(ret))
+			fserror_report_io(inode, FSERR_DIRECTIO_READ,
+					  iocb->ki_pos, sr->size, ret,
+					  GFP_NOFS);
+	} else {
+		ret = sr->size;
+		iocb->ki_pos += ret;
+	}
+
+	if (sr->dio_flags & IOMAP_DIO_USER_BACKED) {
+		bio_check_pages_dirty(bio);
+	} else {
+		bio_release_pages(bio, false);
+		bio_put(bio);
+	}
+	inode_dio_end(inode);
+	trace_iomap_dio_complete(iocb, ret < 0 ? ret : 0, ret);
+	return ret;
+}
+
+static void iomap_dio_simple_complete_work(struct work_struct *work)
+{
+	struct iomap_dio_simple *sr =
+		container_of(work, struct iomap_dio_simple, work);
+	struct kiocb *iocb = sr->iocb;
+
+	WRITE_ONCE(iocb->private, NULL);
+	iocb->ki_complete(iocb, iomap_dio_simple_complete(sr));
+}
+
+static void iomap_dio_simple_end_io(struct bio *bio)
+{
+	struct iomap_dio_simple *sr =
+		container_of(bio, struct iomap_dio_simple, bio);
+	struct kiocb *iocb = sr->iocb;
+
+	if (unlikely(sr->bio.bi_status)) {
+		struct inode *inode = file_inode(iocb->ki_filp);
+
+		INIT_WORK(&sr->work, iomap_dio_simple_complete_work);
+		queue_work(inode->i_sb->s_dio_done_wq, &sr->work);
+		return;
+	}
+
+	WRITE_ONCE(iocb->private, NULL);
+	iocb->ki_complete(iocb, iomap_dio_simple_complete(sr));
+}
+
+static inline bool
+iomap_dio_simple_supported(struct kiocb *iocb, struct iov_iter *iter,
+			   const struct iomap_dio_ops *dops,
+			   unsigned int dio_flags, size_t done_before)
+{
+	struct inode *inode = file_inode(iocb->ki_filp);
+	size_t count = iov_iter_count(iter);
+
+	if (dops || done_before)
+		return false;
+	if (iov_iter_rw(iter) != READ)
+		return false;
+	if (!count)
+		return false;
+	/*
+	 * Simple dio is an optimization for small IO. Filter out large IO
+	 * early as it's the most common case to fail for typical direct IO
+	 * workloads.
+	 */
+	if (count > inode->i_sb->s_blocksize)
+		return false;
+	if (dio_flags & (IOMAP_DIO_FORCE_WAIT | IOMAP_DIO_PARTIAL |
+			 IOMAP_DIO_BOUNCE))
+		return false;
+	if (iocb->ki_pos + count > i_size_read(inode))
+		return false;
+	if (IS_ENCRYPTED(inode))
+		return false;
+
+	return true;
+}
+
+/*
+ * Fast path for small, block-aligned direct I/Os that map to a single
+ * contiguous on-disk extent.
+ *
+ * iomap_dio_simple_supported() enforces the cheap up-front constraints before
+ * entering this path.
+ *
+ * @dops must be NULL: a non-NULL @dops means the caller wants its
+ * ->end_io / ->submit_io hooks invoked, and in particular wants its bios to be
+ * allocated from the filesystem-private @dops->bio_set (whose front_pad sizes a
+ * filesystem-private wrapper around the bio).  The fast path instead allocates
+ * from the shared iomap_dio_simple_pool, whose front_pad matches struct
+ * iomap_dio_simple; the two wrappers are not interchangeable, so we must fall
+ * back to __iomap_dio_rw() in that case.
+ *
+ * @done_before must be zero: a non-zero caller-accumulated residual cannot be
+ * carried through a single-bio inline completion.
+ *
+ * @iter must describe a non-empty READ no larger than the inode block size:
+ * writes, zero-length I/O, and larger requests need the generic iomap direct
+ * I/O path.
+ *
+ * @dio_flags must not request IOMAP_DIO_FORCE_WAIT, IOMAP_DIO_PARTIAL, or
+ * IOMAP_DIO_BOUNCE: this path does not support forced waiting, partial direct
+ * I/O, or bouncing.  The range must also stay within i_size and encrypted
+ * inodes must use the generic iomap direct I/O path.
+ *
+ * -ENOTBLK is the private sentinel returned by iomap_dio_simple() when it
+ * decides the request does not fit the fast path.  In that case we proceed to
+ * the generic __iomap_dio_rw() slow path.  Any other errno is a real result and
+ * is propagated as-is, in particular -EAGAIN for IOCB_NOWAIT must reach the
+ * caller.
+ */
+static ssize_t
+iomap_dio_simple(struct kiocb *iocb, struct iov_iter *iter,
+		 const struct iomap_ops *ops, void *private,
+		 unsigned int dio_flags)
+{
+	struct inode *inode = file_inode(iocb->ki_filp);
+	size_t count = iov_iter_count(iter);
+	bool wait_for_completion = is_sync_kiocb(iocb);
+	struct iomap_iter iomi = {
+		.inode		= inode,
+		.pos		= iocb->ki_pos,
+		.len		= count,
+		.flags		= IOMAP_DIRECT,
+		.private	= private,
+	};
+	struct iomap_dio_simple *sr;
+	unsigned int alignment;
+	struct bio *bio;
+	ssize_t ret;
+
+	if (iocb->ki_flags & IOCB_NOWAIT)
+		iomi.flags |= IOMAP_NOWAIT;
+
+	ret = kiocb_write_and_wait(iocb, count);
+	if (ret)
+		return ret;
+
+	inode_dio_begin(inode);
+
+	ret = ops->iomap_begin(inode, iomi.pos, count, iomi.flags,
+			       &iomi.iomap, &iomi.srcmap);
+	if (ret) {
+		inode_dio_end(inode);
+		return ret;
+	}
+
+	if (iomi.iomap.type != IOMAP_MAPPED ||
+	    iomi.iomap.offset + iomi.iomap.length < iomi.pos + count ||
+	    (iomi.iomap.flags & IOMAP_F_INTEGRITY)) {
+		ret = -ENOTBLK;
+		goto out_iomap_end;
+	}
+
+	alignment = iomap_dio_alignment(inode, iomi.iomap.bdev, dio_flags);
+	if ((iomi.pos | count) & (alignment - 1)) {
+		ret = -EINVAL;
+		goto out_iomap_end;
+	}
+
+	if (!wait_for_completion && unlikely(!inode->i_sb->s_dio_done_wq)) {
+		ret = sb_init_dio_done_wq(inode->i_sb);
+		if (ret < 0)
+			goto out_iomap_end;
+	}
+
+	trace_iomap_dio_rw_begin(iocb, iter, dio_flags, 0);
+
+	if (user_backed_iter(iter))
+		dio_flags |= IOMAP_DIO_USER_BACKED;
+
+	bio = bio_alloc_bioset(iomi.iomap.bdev,
+			       bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS),
+			       REQ_OP_READ, GFP_KERNEL, &iomap_dio_simple_pool);
+	sr = container_of(bio, struct iomap_dio_simple, bio);
+	sr->iocb = iocb;
+	sr->dio_flags = dio_flags;
+
+	bio->bi_iter.bi_sector = iomap_sector(&iomi.iomap, iomi.pos);
+	bio->bi_ioprio = iocb->ki_ioprio;
+
+	ret = bio_iov_iter_get_pages(bio, iter, alignment - 1);
+	if (unlikely(ret))
+		goto out_bio_put;
+
+	if (bio->bi_iter.bi_size != count) {
+		iov_iter_revert(iter, bio->bi_iter.bi_size);
+		ret = -ENOTBLK;
+		goto out_bio_release_pages;
+	}
+
+	sr->size = bio->bi_iter.bi_size;
+
+	if (dio_flags & IOMAP_DIO_USER_BACKED)
+		bio_set_pages_dirty(bio);
+
+	if (iocb->ki_flags & IOCB_NOWAIT)
+		bio->bi_opf |= REQ_NOWAIT;
+	if ((iocb->ki_flags & IOCB_HIPRI) && !wait_for_completion) {
+		bio->bi_opf |= REQ_POLLED;
+		WRITE_ONCE(iocb->private, bio);
+	}
+
+	if (ops->iomap_end)
+		ops->iomap_end(inode, iomi.pos, count, count, iomi.flags,
+			       &iomi.iomap);
+
+	if (!wait_for_completion) {
+		bio->bi_end_io = iomap_dio_simple_end_io;
+		submit_bio(bio);
+		trace_iomap_dio_rw_queued(inode, iomi.pos, count);
+		return -EIOCBQUEUED;
+	}
+
+	submit_bio_wait(bio);
+	return iomap_dio_simple_complete(sr);
+
+out_bio_release_pages:
+	bio_release_pages(bio, false);
+out_bio_put:
+	bio_put(bio);
+out_iomap_end:
+	if (ops->iomap_end)
+		ops->iomap_end(inode, iomi.pos, count, 0, iomi.flags,
+			       &iomi.iomap);
+	inode_dio_end(inode);
+	return ret;
+}
+
 ssize_t
 iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
 		const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
 		unsigned int dio_flags, void *private, size_t done_before)
 {
 	struct iomap_dio *dio;
+	ssize_t ret;
+
+	if (iomap_dio_simple_supported(iocb, iter, dops, dio_flags,
+				       done_before)) {
+		ret = iomap_dio_simple(iocb, iter, ops, private, dio_flags);
+		if (ret != -ENOTBLK)
+			return ret;
+	}
 
 	dio = __iomap_dio_rw(iocb, iter, ops, dops, dio_flags, private,
 			     done_before);
@@ -902,3 +1173,11 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
 	return iomap_dio_complete(dio);
 }
 EXPORT_SYMBOL_GPL(iomap_dio_rw);
+
+static int __init iomap_dio_init(void)
+{
+	return bioset_init(&iomap_dio_simple_pool, 4,
+			   offsetof(struct iomap_dio_simple, bio),
+			   BIOSET_NEED_BVECS | BIOSET_PERCPU_CACHE);
+}
+fs_initcall(iomap_dio_init);

3/2 2026/07/01 08:58 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 6115
							output: 31
							thoughts: 246
						

Thoughts:
**My Assessment of the Proposed Direct I/O Optimization**

Okay, so we have a new patch touching `fs/iomap/direct-io.c`. It looks like they're implementing a fast path specifically for small, block-aligned direct I/Os that hit a single, contiguous extent on disk—that's `iomap_dio_simple`. They've added a whole suite of new functions to handle this optimization: `iomap_dio_simple_supported`, `iomap_dio_simple`, `iomap_dio_simple_complete`, `iomap_dio_simple_complete_work`, `iomap_dio_simple_end_io`, and `iomap_dio_init`. The critical piece is how `iomap_dio_rw` is being modified to leverage these new functions; it's calling `iomap_dio_simple_supported` and `iomap_dio_simple`.

Functionally, this is a core change to the kernel's direct I/O logic, which means it demands thorough scrutiny. Given the potential for subtle issues in such low-level code, fuzzing is an absolute must. We need to throw everything at it to ensure stability.

My next step is to nail down the relevant configurations. I need to figure out when `fs/iomap/direct-io.c` gets compiled. I'll check `fs/iomap/Makefile` or `fs/iomap/Kconfig` to see if `CONFIG_FS_IOMAP` is what enables this module, which will be critical to understand how this code gets built into the kernel, and the conditions for it to be active.



4/2 2026/07/01 08:58 tool grepper
0m Args:
{
  "Expression": "direct-io.o",
  "PathPrefix": "fs/iomap/"
}

Results:
{
  "Output": "fs/iomap/Makefile=11=iomap-y\t\t\t\t+= trace.o \\\n--\nfs/iomap/Makefile-13-\t\t\t\t   buffered-io.o\nfs/iomap/Makefile:14:iomap-$(CONFIG_BLOCK)\t\t+= direct-io.o \\\nfs/iomap/Makefile-15-\t\t\t\t   ioend.o \\\n"
}

5/2 2026/07/01 08:58 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 6617
							output: 35
							thoughts: 619
						

Thoughts:
**Analyzing the New Direct I/O Fast Path for iomap**

Okay, so this patch introduces a new, optimized path for simple direct I/O reads within `fs/iomap/direct-io.c`. It's creating several new functions: `iomap_dio_simple_supported`, `iomap_dio_simple`, `iomap_dio_simple_complete`, `iomap_dio_simple_complete_work`, and `iomap_dio_simple_end_io`. The core `iomap_dio_rw` function is being modified to leverage these new additions. This is a pretty significant functional change affecting the iomap direct I/O path, meaning it's reachable from userspace through direct I/O reads on iomap-using filesystems like XFS, ext4, and btrfs – all critical targets.

First, I need to understand the configuration dependencies. Looking at `fs/iomap/Makefile`, it's clear that `CONFIG_BLOCK` is a requirement. Also, we need a filesystem that actually *uses* iomap for direct I/O, such as those that enable `CONFIG_XFS_FS` or `CONFIG_EXT4_FS`. I'll also double-check the `Kconfig` for iomap, but `CONFIG_FS_IOMAP` is typically selected by the relevant filesystem itself.

Now, where's the best place to focus my fuzzing efforts? `iomap_dio_rw` is the main entry point, the hot path, but it's pretty generic. The real interesting parts, the new logic, are these `iomap_dio_simple*` functions.

Ah, right, these are static, so they're not directly exported symbols and may not be directly reachable by the fuzzer by name. However, syzkaller *can* fuzz static functions with kcov, and it focuses on code coverage. I should be able to provide the static function names. So, the key functions to focus on are:
-   `iomap_dio_simple`
-   `iomap_dio_simple_supported`
-   `iomap_dio_simple_complete`
-   `iomap_dio_simple_complete_work`
-   `iomap_dio_simple_end_io`

I should double-check the configs. Looks like we need `CONFIG_BLOCK` and a filesystem that uses iomap (and therefore selects `CONFIG_FS_IOMAP`). Better go check `fs/iomap/Kconfig` to be absolutely certain.



6/2 2026/07/01 08:59 tool read-file
0m Error:
the file does not exist

Args:
{
  "File": "fs/iomap/Kconfig",
  "FirstLine": 1,
  "LineCount": 100
}

Results:
{
  "error": "the file does not exist"
}

7/2 2026/07/01 08:59 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 7244
							output: 29
							thoughts: 258
						

Thoughts:
**Analyzing the New Direct I/O Fast Path**

Okay, so this patch is introducing a new, faster path for direct I/O reads within `fs/iomap/direct-io.c`. That's interesting, and potentially significant for overall performance, especially under heavy load. I see a suite of new functions being added: `iomap_dio_simple_supported`, `iomap_dio_simple`, `iomap_dio_simple_complete`, `iomap_dio_simple_end_io`, `iomap_dio_simple_complete_work`, and `iomap_dio_init`. Clearly, these are the building blocks of this new fast path, and the modification of `iomap_dio_rw` indicates they're being integrated directly into the core iomap logic.

This is a functional change, not just a bug fix, and it's touching the iomap subsystem, which, as we know, is fundamental to block device I/O and used by several major filesystems like XFS, ext4, and btrfs for direct I/O. Therefore, fuzzing is an absolute must to expose any edge cases or unexpected behavior.

Now, let's look at the configuration dependencies. `fs/iomap/Makefile` indicates that `direct-io.o` is built when `CONFIG_BLOCK` is enabled. That makes sense, as direct I/O is fundamentally tied to block devices. However, iomap itself is typically selected by the filesystems themselves. I need to trace the call graph to see how `iomap_dio_rw` is used. That will allow me to understand how these new functions will be called in practice. Time to fire up the tools and investigate how this all fits together!



8/2 2026/07/01 08:59 tool grepper
0m Args:
{
  "Expression": "iomap_dio_rw",
  "PathPrefix": "fs/"
}

Results:
{
  "Output": "fs/btrfs/direct-io.c=364=static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,\n--\nfs/btrfs/direct-io.c-404-\t/*\nfs/btrfs/direct-io.c:405:\t * iomap_dio_rw() only does filemap_write_and_wait_range(), which isn't\nfs/btrfs/direct-io.c-406-\t * enough if we've written compressed pages to this area, so we need to\n--\nfs/btrfs/direct-io.c-416-\t * dirty or under writeback (same as for the non-compression case).\nfs/btrfs/direct-io.c:417:\t * iomap_dio_rw() did the same check, but after that and before we got\nfs/btrfs/direct-io.c-418-\t * here, mmap'ed writes may have happened or buffered reads started\n--\nfs/btrfs/direct-io.c-515-\t * When doing a read, because we use IOMAP_DIO_PARTIAL when calling\nfs/btrfs/direct-io.c:516:\t * iomap_dio_rw(), we can end up returning less data then what the caller\nfs/btrfs/direct-io.c-517-\t * asked for, resulting in an unexpected, and incorrect, short read.\n--\nfs/btrfs/direct-io.c-520-\t * page fault error when trying to fault in pages for the buffer that is\nfs/btrfs/direct-io.c:521:\t * associated to the struct iov_iter passed to iomap_dio_rw(), and we\nfs/btrfs/direct-io.c-522-\t * have previously submitted bios for other extents in the range, in\nfs/btrfs/direct-io.c:523:\t * which case iomap_dio_rw() may return us EIOCBQUEUED if not all of\nfs/btrfs/direct-io.c-524-\t * those bios have completed by the time we get the page fault error,\n--\nfs/btrfs/direct-io.c=811=static ssize_t btrfs_dio_read(struct kiocb *iocb, struct iov_iter *iter,\n--\nfs/btrfs/direct-io.c-815-\nfs/btrfs/direct-io.c:816:\treturn iomap_dio_rw(iocb, iter, \u0026btrfs_dio_iomap_ops, \u0026btrfs_dio_ops,\nfs/btrfs/direct-io.c-817-\t\t\t    IOMAP_DIO_PARTIAL | IOMAP_DIO_FSBLOCK_ALIGNED, \u0026data, done_before);\n--\nfs/btrfs/direct-io.c=820=static struct iomap_dio *btrfs_dio_write(struct kiocb *iocb, struct iov_iter *iter,\n--\nfs/btrfs/direct-io.c-824-\nfs/btrfs/direct-io.c:825:\treturn __iomap_dio_rw(iocb, iter, \u0026btrfs_dio_iomap_ops, \u0026btrfs_dio_ops,\nfs/btrfs/direct-io.c-826-\t\t\t    IOMAP_DIO_PARTIAL | IOMAP_DIO_FSBLOCK_ALIGNED, \u0026data, done_before);\n--\nfs/erofs/data.c=445=static ssize_t erofs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)\n--\nfs/erofs/data.c-460-\nfs/erofs/data.c:461:\t\treturn iomap_dio_rw(iocb, to, \u0026erofs_iomap_ops,\nfs/erofs/data.c-462-\t\t\t\t    NULL, 0, \u0026iter_ctx, 0);\n--\nfs/exfat/file.c=708=static ssize_t exfat_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)\n--\nfs/exfat/file.c-711-\nfs/exfat/file.c:712:\tret = iomap_dio_rw(iocb, from, \u0026exfat_write_iomap_ops,\nfs/exfat/file.c-713-\t\t\t\u0026exfat_write_dio_ops, 0, NULL, 0);\n--\nfs/exfat/file.c=800=static ssize_t exfat_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)\n--\nfs/exfat/file.c-811-\t\tfile_accessed(iocb-\u003eki_filp);\nfs/exfat/file.c:812:\t\tret = iomap_dio_rw(iocb, iter, \u0026exfat_iomap_ops, NULL, 0,\nfs/exfat/file.c-813-\t\t\t\tNULL, 0);\n--\nfs/ext2/file.c=65=static ssize_t ext2_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)\n--\nfs/ext2/file.c-72-\tinode_lock_shared(inode);\nfs/ext2/file.c:73:\tret = iomap_dio_rw(iocb, to, \u0026ext2_iomap_ops, NULL, 0, NULL, 0);\nfs/ext2/file.c-74-\tinode_unlock_shared(inode);\n--\nfs/ext2/file.c=80=static int ext2_dio_write_end_io(struct kiocb *iocb, ssize_t size,\n--\nfs/ext2/file.c-90-\t * If we are extending the file, we have to update i_size here before\nfs/ext2/file.c:91:\t * page cache gets invalidated in iomap_dio_rw(). This prevents racing\nfs/ext2/file.c-92-\t * buffered reads from zeroing out too much from page cache pages.\n--\nfs/ext2/file.c=111=static ssize_t ext2_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)\n--\nfs/ext2/file.c-136-\nfs/ext2/file.c:137:\tret = iomap_dio_rw(iocb, from, \u0026ext2_iomap_ops, \u0026ext2_dio_write_ops,\nfs/ext2/file.c-138-\t\t\t   flags, NULL, 0);\n--\nfs/ext4/file.c-46- * any special features like encryption or verity, ext4 has traditionally\nfs/ext4/file.c:47: * returned EINVAL for misaligned DIO.  iomap_dio_rw() uses this convention too.\nfs/ext4/file.c-48- * In this case, we should attempt the DIO, *not* fall back to buffered I/O.\n--\nfs/ext4/file.c=69=static ssize_t ext4_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)\n--\nfs/ext4/file.c-93-\nfs/ext4/file.c:94:\tret = iomap_dio_rw(iocb, to, \u0026ext4_iomap_ops, NULL, 0, NULL, 0);\nfs/ext4/file.c-95-\tinode_unlock_shared(inode);\n--\nfs/ext4/file.c=519=static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)\n--\nfs/ext4/file.c-591-\nfs/ext4/file.c:592:\tret = iomap_dio_rw(iocb, from, \u0026ext4_iomap_ops, \u0026ext4_dio_write_ops,\nfs/ext4/file.c-593-\t\t\t   dio_flags, NULL, 0);\n--\nfs/f2fs/file.c=4849=static ssize_t f2fs_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)\n--\nfs/f2fs/file.c-4881-\t/*\nfs/f2fs/file.c:4882:\t * We have to use __iomap_dio_rw() and iomap_dio_complete() instead of\nfs/f2fs/file.c:4883:\t * the higher-level function iomap_dio_rw() in order to ensure that the\nfs/f2fs/file.c-4884-\t * F2FS_DIO_READ counter will be decremented correctly in all cases.\n--\nfs/f2fs/file.c-4886-\tinc_page_count(sbi, F2FS_DIO_READ);\nfs/f2fs/file.c:4887:\tdio = __iomap_dio_rw(iocb, to, \u0026f2fs_iomap_ops,\nfs/f2fs/file.c-4888-\t\t\t     \u0026f2fs_iomap_dio_read_ops, 0, NULL, 0);\n--\nfs/f2fs/file.c=5166=static ssize_t f2fs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from,\n--\nfs/f2fs/file.c-5214-\t/*\nfs/f2fs/file.c:5215:\t * We have to use __iomap_dio_rw() and iomap_dio_complete() instead of\nfs/f2fs/file.c:5216:\t * the higher-level function iomap_dio_rw() in order to ensure that the\nfs/f2fs/file.c-5217-\t * F2FS_DIO_WRITE counter will be decremented correctly in all cases.\n--\nfs/f2fs/file.c-5222-\t\tdio_flags |= IOMAP_DIO_FORCE_WAIT;\nfs/f2fs/file.c:5223:\tdio = __iomap_dio_rw(iocb, from, \u0026f2fs_iomap_ops,\nfs/f2fs/file.c-5224-\t\t\t     \u0026f2fs_iomap_dio_write_ops, dio_flags, iocb, 0);\n--\nfs/f2fs/file.c-5274-\t} else {\nfs/f2fs/file.c:5275:\t\t/* iomap_dio_rw() already handled the generic_write_sync(). */\nfs/f2fs/file.c-5276-\t\t*may_need_sync = false;\n--\nfs/gfs2/file.c=811=static ssize_t gfs2_file_direct_read(struct kiocb *iocb, struct iov_iter *to,\n--\nfs/gfs2/file.c-825-\t *\nfs/gfs2/file.c:826:\t * Unlike generic_file_read_iter, for reads, iomap_dio_rw can trigger\nfs/gfs2/file.c-827-\t * physical as well as manual page faults, and we need to disable both\n--\nfs/gfs2/file.c-846-\tto-\u003enofault = true;\nfs/gfs2/file.c:847:\tret = iomap_dio_rw(iocb, to, \u0026gfs2_iomap_ops, NULL,\nfs/gfs2/file.c-848-\t\t\t   IOMAP_DIO_PARTIAL, NULL, read);\n--\nfs/gfs2/file.c-852-\t\tgoto out_unlock;\nfs/gfs2/file.c:853:\t/* No increment (+=) because iomap_dio_rw returns a cumulative value. */\nfs/gfs2/file.c-854-\tif (ret \u003e 0)\n--\nfs/gfs2/file.c=874=static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from,\n--\nfs/gfs2/file.c-890-\t *\nfs/gfs2/file.c:891:\t * For writes, iomap_dio_rw only triggers manual page faults, so we\nfs/gfs2/file.c-892-\t * don't need to disable physical ones.\n--\nfs/gfs2/file.c-912-\tfrom-\u003enofault = true;\nfs/gfs2/file.c:913:\tret = iomap_dio_rw(iocb, from, \u0026gfs2_iomap_ops, NULL,\nfs/gfs2/file.c-914-\t\t\t   IOMAP_DIO_PARTIAL, NULL, written);\n--\nfs/gfs2/file.c-921-\t}\nfs/gfs2/file.c:922:\t/* No increment (+=) because iomap_dio_rw returns a cumulative value. */\nfs/gfs2/file.c-923-\tif (ret \u003e 0)\n--\nfs/iomap/direct-io.c=410=static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio)\n--\nfs/iomap/direct-io.c-505-\t\t * Writes that extend i_size are also not supported, but this is\nfs/iomap/direct-io.c:506:\t\t * handled in __iomap_dio_rw().\nfs/iomap/direct-io.c-507-\t\t */\n--\nfs/iomap/direct-io.c=632=static int iomap_dio_iter(struct iomap_iter *iter, struct iomap_dio *dio)\n--\nfs/iomap/direct-io.c-663-/*\nfs/iomap/direct-io.c:664: * iomap_dio_rw() always completes O_[D]SYNC writes regardless of whether the IO\nfs/iomap/direct-io.c-665- * is being issued as AIO or not.  This allows us to optimise pure data writes\n--\nfs/iomap/direct-io.c-672- * When page faults are disabled and @dio_flags includes IOMAP_DIO_PARTIAL,\nfs/iomap/direct-io.c:673: * __iomap_dio_rw can return a partial result if it encounters a non-resident\nfs/iomap/direct-io.c-674- * page in @iter after preparing a transfer.  In that case, the non-resident\n--\nfs/iomap/direct-io.c=683=struct iomap_dio *\nfs/iomap/direct-io.c:684:__iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,\nfs/iomap/direct-io.c-685-\t\tconst struct iomap_ops *ops, const struct iomap_dio_ops *dops,\n--\nfs/iomap/direct-io.c-701-\nfs/iomap/direct-io.c:702:\ttrace_iomap_dio_rw_begin(iocb, iter, dio_flags, done_before);\nfs/iomap/direct-io.c-703-\n--\nfs/iomap/direct-io.c-872-\t\tif (!wait_for_completion) {\nfs/iomap/direct-io.c:873:\t\t\ttrace_iomap_dio_rw_queued(inode, iomi.pos, iomi.len);\nfs/iomap/direct-io.c-874-\t\t\treturn ERR_PTR(-EIOCBQUEUED);\n--\nfs/iomap/direct-io.c-894-}\nfs/iomap/direct-io.c:895:EXPORT_SYMBOL_GPL(__iomap_dio_rw);\nfs/iomap/direct-io.c-896-\n--\nfs/iomap/direct-io.c=972=iomap_dio_simple_supported(struct kiocb *iocb, struct iov_iter *iter,\n--\nfs/iomap/direct-io.c-1015- * iomap_dio_simple; the two wrappers are not interchangeable, so we must fall\nfs/iomap/direct-io.c:1016: * back to __iomap_dio_rw() in that case.\nfs/iomap/direct-io.c-1017- *\n--\nfs/iomap/direct-io.c-1031- * decides the request does not fit the fast path.  In that case we proceed to\nfs/iomap/direct-io.c:1032: * the generic __iomap_dio_rw() slow path.  Any other errno is a real result and\nfs/iomap/direct-io.c-1033- * is propagated as-is, in particular -EAGAIN for IOCB_NOWAIT must reach the\n--\nfs/iomap/direct-io.c=1037=iomap_dio_simple(struct kiocb *iocb, struct iov_iter *iter,\n--\nfs/iomap/direct-io.c-1090-\nfs/iomap/direct-io.c:1091:\ttrace_iomap_dio_rw_begin(iocb, iter, dio_flags, 0);\nfs/iomap/direct-io.c-1092-\n--\nfs/iomap/direct-io.c-1134-\t\tsubmit_bio(bio);\nfs/iomap/direct-io.c:1135:\t\ttrace_iomap_dio_rw_queued(inode, iomi.pos, count);\nfs/iomap/direct-io.c-1136-\t\treturn -EIOCBQUEUED;\n--\nfs/iomap/direct-io.c=1154=ssize_t\nfs/iomap/direct-io.c:1155:iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,\nfs/iomap/direct-io.c-1156-\t\tconst struct iomap_ops *ops, const struct iomap_dio_ops *dops,\n--\nfs/iomap/direct-io.c-1168-\nfs/iomap/direct-io.c:1169:\tdio = __iomap_dio_rw(iocb, iter, ops, dops, dio_flags, private,\nfs/iomap/direct-io.c-1170-\t\t\t     done_before);\n--\nfs/iomap/direct-io.c-1174-}\nfs/iomap/direct-io.c:1175:EXPORT_SYMBOL_GPL(iomap_dio_rw);\nfs/iomap/direct-io.c-1176-\n--\nfs/iomap/trace.h=85=DEFINE_RANGE_EVENT(iomap_dio_invalidate_fail);\nfs/iomap/trace.h:86:DEFINE_RANGE_EVENT(iomap_dio_rw_queued);\nfs/iomap/trace.h-87-DEFINE_RANGE_EVENT(iomap_zero_iter);\n--\nfs/iomap/trace.h=220=TRACE_EVENT(iomap_iter,\n--\nfs/iomap/trace.h-255-\nfs/iomap/trace.h:256:TRACE_EVENT(iomap_dio_rw_begin,\nfs/iomap/trace.h-257-\tTP_PROTO(struct kiocb *iocb, struct iov_iter *iter,\n--\nfs/ntfs/file.c=438=static ssize_t ntfs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)\n--\nfs/ntfs/file.c-460-\t\tfile_accessed(iocb-\u003eki_filp);\nfs/ntfs/file.c:461:\t\tret = iomap_dio_rw(iocb, to, \u0026ntfs_read_iomap_ops, NULL, 0,\nfs/ntfs/file.c-462-\t\t\t\tNULL, 0);\n--\nfs/ntfs/file.c=495=static ssize_t ntfs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)\n--\nfs/ntfs/file.c-498-\nfs/ntfs/file.c:499:\tret = iomap_dio_rw(iocb, from, \u0026ntfs_dio_iomap_ops,\nfs/ntfs/file.c-500-\t\t\t\u0026ntfs_write_dio_ops, 0, NULL, 0);\n--\nfs/ntfs3/file.c=815=static ssize_t ntfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)\n--\nfs/ntfs3/file.c-874-\nfs/ntfs3/file.c:875:\t\terr = iomap_dio_rw(iocb, iter, \u0026ntfs_iomap_ops, NULL, dio_flags,\nfs/ntfs3/file.c-876-\t\t\t\t   NULL, 0);\n--\nfs/ntfs3/file.c=1220=static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)\n--\nfs/ntfs3/file.c-1305-\nfs/ntfs3/file.c:1306:\tret = iomap_dio_rw(iocb, from, \u0026ntfs_iomap_ops, NULL,\nfs/ntfs3/file.c-1307-\t\t\t   IOMAP_DIO_FORCE_WAIT, NULL, 0);\n--\nfs/ntfs3/inode.c=679=int ntfs_set_size(struct inode *inode, u64 new_size)\n--\nfs/ntfs3/inode.c-721- * - iomap_truncate_page\nfs/ntfs3/inode.c:722: * - iomap_dio_rw\nfs/ntfs3/inode.c-723- * - iomap_file_buffered_write\n--\nfs/xfs/xfs_file.c=249=xfs_file_dio_read(\n--\nfs/xfs/xfs_file.c-271-\t}\nfs/xfs/xfs_file.c:272:\tret = iomap_dio_rw(iocb, to, \u0026xfs_read_iomap_ops, dio_ops, dio_flags,\nfs/xfs/xfs_file.c-273-\t\t\tNULL, 0);\n--\nfs/xfs/xfs_file.c=741=xfs_file_dio_write_aligned(\n--\nfs/xfs/xfs_file.c-779-\ttrace_xfs_file_direct_write(iocb, from);\nfs/xfs/xfs_file.c:780:\tret = iomap_dio_rw(iocb, from, ops, dops, dio_flags, ac, 0);\nfs/xfs/xfs_file.c-781-out_unlock:\n--\nfs/xfs/xfs_file.c=819=xfs_file_dio_write_atomic(\n--\nfs/xfs/xfs_file.c-855-\t\tdio_flags |= IOMAP_DIO_BOUNCE;\nfs/xfs/xfs_file.c:856:\tret = iomap_dio_rw(iocb, from, dops, \u0026xfs_dio_write_ops, dio_flags,\nfs/xfs/xfs_file.c-857-\t\t\tNULL, 0);\n--\nfs/xfs/xfs_file.c=895=xfs_file_dio_write_unaligned(\n--\nfs/xfs/xfs_file.c-949-\ttrace_xfs_file_direct_write(iocb, from);\nfs/xfs/xfs_file.c:950:\tret = iomap_dio_rw(iocb, from, \u0026xfs_direct_write_iomap_ops,\nfs/xfs/xfs_file.c-951-\t\t\t   \u0026xfs_dio_write_ops, flags, NULL, 0);\n--\nfs/zonefs/file.c=469=static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)\n--\nfs/zonefs/file.c-523-\t/*\nfs/zonefs/file.c:524:\t * iomap_dio_rw() may return ENOTBLK if there was an issue with\nfs/zonefs/file.c-525-\t * page invalidation. Overwrite that error code with EBUSY so that\n--\nfs/zonefs/file.c-527-\t */\nfs/zonefs/file.c:528:\tret = iomap_dio_rw(iocb, from, \u0026zonefs_write_iomap_ops,\nfs/zonefs/file.c-529-\t\t\t   \u0026zonefs_write_dio_ops, 0, NULL, 0);\n--\nfs/zonefs/file.c=631=static ssize_t zonefs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)\n--\nfs/zonefs/file.c-672-\t\tfile_accessed(iocb-\u003eki_filp);\nfs/zonefs/file.c:673:\t\tret = iomap_dio_rw(iocb, to, \u0026zonefs_read_iomap_ops,\nfs/zonefs/file.c-674-\t\t\t\t   \u0026zonefs_read_dio_ops, 0, NULL, 0);\n"
}

9/2 2026/07/01 08:59 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 14307
							output: 29
							thoughts: 0
						

10/2 2026/07/01 09:00 tool grepper
0m Args:
{
  "Expression": "iomap_dio_simple",
  "PathPrefix": "fs/"
}

Results:
{
  "Output": "fs/iomap/direct-io.c=895=EXPORT_SYMBOL_GPL(__iomap_dio_rw);\nfs/iomap/direct-io.c-896-\nfs/iomap/direct-io.c:897:struct iomap_dio_simple {\nfs/iomap/direct-io.c-898-\tstruct kiocb\t\t*iocb;\n--\nfs/iomap/direct-io.c-911-\nfs/iomap/direct-io.c:912:static struct bio_set iomap_dio_simple_pool;\nfs/iomap/direct-io.c-913-\nfs/iomap/direct-io.c:914:static ssize_t iomap_dio_simple_complete(struct iomap_dio_simple *sr)\nfs/iomap/direct-io.c-915-{\n--\nfs/iomap/direct-io.c-942-\nfs/iomap/direct-io.c:943:static void iomap_dio_simple_complete_work(struct work_struct *work)\nfs/iomap/direct-io.c-944-{\nfs/iomap/direct-io.c:945:\tstruct iomap_dio_simple *sr =\nfs/iomap/direct-io.c:946:\t\tcontainer_of(work, struct iomap_dio_simple, work);\nfs/iomap/direct-io.c-947-\tstruct kiocb *iocb = sr-\u003eiocb;\n--\nfs/iomap/direct-io.c-949-\tWRITE_ONCE(iocb-\u003eprivate, NULL);\nfs/iomap/direct-io.c:950:\tiocb-\u003eki_complete(iocb, iomap_dio_simple_complete(sr));\nfs/iomap/direct-io.c-951-}\nfs/iomap/direct-io.c-952-\nfs/iomap/direct-io.c:953:static void iomap_dio_simple_end_io(struct bio *bio)\nfs/iomap/direct-io.c-954-{\nfs/iomap/direct-io.c:955:\tstruct iomap_dio_simple *sr =\nfs/iomap/direct-io.c:956:\t\tcontainer_of(bio, struct iomap_dio_simple, bio);\nfs/iomap/direct-io.c-957-\tstruct kiocb *iocb = sr-\u003eiocb;\n--\nfs/iomap/direct-io.c-961-\nfs/iomap/direct-io.c:962:\t\tINIT_WORK(\u0026sr-\u003ework, iomap_dio_simple_complete_work);\nfs/iomap/direct-io.c-963-\t\tqueue_work(inode-\u003ei_sb-\u003es_dio_done_wq, \u0026sr-\u003ework);\n--\nfs/iomap/direct-io.c-967-\tWRITE_ONCE(iocb-\u003eprivate, NULL);\nfs/iomap/direct-io.c:968:\tiocb-\u003eki_complete(iocb, iomap_dio_simple_complete(sr));\nfs/iomap/direct-io.c-969-}\n--\nfs/iomap/direct-io.c=971=static inline bool\nfs/iomap/direct-io.c:972:iomap_dio_simple_supported(struct kiocb *iocb, struct iov_iter *iter,\nfs/iomap/direct-io.c-973-\t\t\t   const struct iomap_dio_ops *dops,\n--\nfs/iomap/direct-io.c-1006- *\nfs/iomap/direct-io.c:1007: * iomap_dio_simple_supported() enforces the cheap up-front constraints before\nfs/iomap/direct-io.c-1008- * entering this path.\n--\nfs/iomap/direct-io.c-1013- * filesystem-private wrapper around the bio).  The fast path instead allocates\nfs/iomap/direct-io.c:1014: * from the shared iomap_dio_simple_pool, whose front_pad matches struct\nfs/iomap/direct-io.c:1015: * iomap_dio_simple; the two wrappers are not interchangeable, so we must fall\nfs/iomap/direct-io.c-1016- * back to __iomap_dio_rw() in that case.\n--\nfs/iomap/direct-io.c-1029- *\nfs/iomap/direct-io.c:1030: * -ENOTBLK is the private sentinel returned by iomap_dio_simple() when it\nfs/iomap/direct-io.c-1031- * decides the request does not fit the fast path.  In that case we proceed to\n--\nfs/iomap/direct-io.c=1036=static ssize_t\nfs/iomap/direct-io.c:1037:iomap_dio_simple(struct kiocb *iocb, struct iov_iter *iter,\nfs/iomap/direct-io.c-1038-\t\t const struct iomap_ops *ops, void *private,\n--\nfs/iomap/direct-io.c-1050-\t};\nfs/iomap/direct-io.c:1051:\tstruct iomap_dio_simple *sr;\nfs/iomap/direct-io.c-1052-\tunsigned int alignment;\n--\nfs/iomap/direct-io.c-1097-\t\t\t       bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS),\nfs/iomap/direct-io.c:1098:\t\t\t       REQ_OP_READ, GFP_KERNEL, \u0026iomap_dio_simple_pool);\nfs/iomap/direct-io.c:1099:\tsr = container_of(bio, struct iomap_dio_simple, bio);\nfs/iomap/direct-io.c-1100-\tsr-\u003eiocb = iocb;\n--\nfs/iomap/direct-io.c-1132-\tif (!wait_for_completion) {\nfs/iomap/direct-io.c:1133:\t\tbio-\u003ebi_end_io = iomap_dio_simple_end_io;\nfs/iomap/direct-io.c-1134-\t\tsubmit_bio(bio);\n--\nfs/iomap/direct-io.c-1139-\tsubmit_bio_wait(bio);\nfs/iomap/direct-io.c:1140:\treturn iomap_dio_simple_complete(sr);\nfs/iomap/direct-io.c-1141-\n--\nfs/iomap/direct-io.c=1155=iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,\n--\nfs/iomap/direct-io.c-1161-\nfs/iomap/direct-io.c:1162:\tif (iomap_dio_simple_supported(iocb, iter, dops, dio_flags,\nfs/iomap/direct-io.c-1163-\t\t\t\t       done_before)) {\nfs/iomap/direct-io.c:1164:\t\tret = iomap_dio_simple(iocb, iter, ops, private, dio_flags);\nfs/iomap/direct-io.c-1165-\t\tif (ret != -ENOTBLK)\n--\nfs/iomap/direct-io.c=1177=static int __init iomap_dio_init(void)\nfs/iomap/direct-io.c-1178-{\nfs/iomap/direct-io.c:1179:\treturn bioset_init(\u0026iomap_dio_simple_pool, 4,\nfs/iomap/direct-io.c:1180:\t\t\t   offsetof(struct iomap_dio_simple, bio),\nfs/iomap/direct-io.c-1181-\t\t\t   BIOSET_NEED_BVECS | BIOSET_PERCPU_CACHE);\n"
}

11/2 2026/07/01 09:00 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 16463
							output: 27
							thoughts: 278
						

Thoughts:
**My Analysis of the Direct I/O Fast Path Patch**

Okay, so this patch is implementing a fast path for direct I/O operations. Specifically, it targets small, block-aligned I/Os that hit a single contiguous extent on disk within the `fs/iomap/direct-io.c` file. The core of this optimization involves two new functions, `iomap_dio_simple()` and `iomap_dio_simple_supported()`, and modifications to `iomap_dio_rw()`. The implication is a performance improvement to the kernel's direct I/O path, which users access through standard file operations like `read()` and `write()` with the `O_DIRECT` flag.

Given that this touches core VFS and iomap logic, fuzzing is an absolute must. We need to expose this to as many stress tests as we can to shake out any edge cases.

Now, let's look at the build configuration dependencies. Starting with the file location itself, `fs/iomap/direct-io.c`. Diving into the `fs/iomap/Makefile`, I see that `iomap-$(CONFIG_BLOCK) += direct-io.o`. So `CONFIG_BLOCK` is the primary requirement. That is a *very* general config, so I'm not overly concerned about that. The more relevant requirement is `CONFIG_FS_IOMAP`. This is the core iomap configuration, and it is selected by numerous file systems like ext4, xfs, and btrfs, which means its pretty broadly used. Now, wait a minute... where is the Kconfig for the iomap subsystem itself? It doesn't appear to exist in `fs/iomap/`. I'll have to check `fs/Kconfig` for the iomap config.



12/2 2026/07/01 09:00 tool grepper
0m Args:
{
  "Expression": "FS_IOMAP",
  "PathPrefix": "fs/"
}

Results:
{
  "Output": "fs/Kconfig=12=config VALIDATE_FS_PARSER\n--\nfs/Kconfig-17-\nfs/Kconfig:18:config FS_IOMAP\nfs/Kconfig-19-\tbool\n--\nfs/Kconfig=58=config FS_DAX\n--\nfs/Kconfig-61-\tdepends on ZONE_DEVICE\nfs/Kconfig:62:\tselect FS_IOMAP\nfs/Kconfig-63-\tselect DAX\n--\nfs/btrfs/Kconfig=3=config BTRFS_FS\n--\nfs/btrfs/Kconfig-14-\tselect ZSTD_DECOMPRESS\nfs/btrfs/Kconfig:15:\tselect FS_IOMAP\nfs/btrfs/Kconfig-16-\tselect RAID6_PQ\n--\nfs/erofs/Kconfig=3=config EROFS_FS\n--\nfs/erofs/Kconfig-8-\tselect CRYPTO_DEFLATE if EROFS_FS_ZIP_ACCEL\nfs/erofs/Kconfig:9:\tselect FS_IOMAP\nfs/erofs/Kconfig-10-\tselect LZ4_DECOMPRESS if EROFS_FS_ZIP\n--\nfs/exfat/Kconfig=3=config EXFAT_FS\n--\nfs/exfat/Kconfig-6-\tselect NLS\nfs/exfat/Kconfig:7:\tselect FS_IOMAP\nfs/exfat/Kconfig-8-\thelp\n--\nfs/ext2/Kconfig=2=config EXT2_FS\n--\nfs/ext2/Kconfig-4-\tselect BUFFER_HEAD\nfs/ext2/Kconfig:5:\tselect FS_IOMAP\nfs/ext2/Kconfig-6-\thelp\n--\nfs/ext4/Kconfig=2=config EXT4_FS\n--\nfs/ext4/Kconfig-7-\tselect CRC32\nfs/ext4/Kconfig:8:\tselect FS_IOMAP\nfs/ext4/Kconfig-9-\tselect FS_ENCRYPTION_ALGS if FS_ENCRYPTION\n--\nfs/f2fs/Kconfig=2=config F2FS_FS\n--\nfs/f2fs/Kconfig-9-\tselect FS_ENCRYPTION_ALGS if FS_ENCRYPTION\nfs/f2fs/Kconfig:10:\tselect FS_IOMAP\nfs/f2fs/Kconfig-11-\tselect LZ4_COMPRESS if F2FS_FS_LZ4\n--\nfs/fuse/Kconfig=2=config FUSE_FS\n--\nfs/fuse/Kconfig-4-\tselect FS_POSIX_ACL\nfs/fuse/Kconfig:5:\tselect FS_IOMAP\nfs/fuse/Kconfig-6-\thelp\n--\nfs/gfs2/Kconfig=2=config GFS2_FS\n--\nfs/gfs2/Kconfig-7-\tselect QUOTACTL\nfs/gfs2/Kconfig:8:\tselect FS_IOMAP\nfs/gfs2/Kconfig-9-\thelp\n--\nfs/hpfs/Kconfig=2=config HPFS_FS\n--\nfs/hpfs/Kconfig-5-\tselect BUFFER_HEAD\nfs/hpfs/Kconfig:6:\tselect FS_IOMAP\nfs/hpfs/Kconfig-7-\thelp\n--\nfs/iomap/Makefile=7=ccflags-y += -I $(src)\t\t# needed for trace events\nfs/iomap/Makefile-8-\nfs/iomap/Makefile:9:obj-$(CONFIG_FS_IOMAP)\t\t+= iomap.o\nfs/iomap/Makefile-10-\n--\nfs/ntfs/Kconfig=2=config NTFS_FS\n--\nfs/ntfs/Kconfig-4-\tselect NLS\nfs/ntfs/Kconfig:5:\tselect FS_IOMAP\nfs/ntfs/Kconfig-6-\thelp\n--\nfs/ntfs/iomap.c=363=static int ntfs_write_simple_iomap_begin_non_resident(struct inode *inode, loff_t offset,\n--\nfs/ntfs/iomap.c-540-\nfs/ntfs/iomap.c:541:#define NTFS_IOMAP_FLAGS_BEGIN\t\tBIT(1)\nfs/ntfs/iomap.c:542:#define NTFS_IOMAP_FLAGS_DIO\t\tBIT(2)\nfs/ntfs/iomap.c:543:#define\tNTFS_IOMAP_FLAGS_MKWRITE\tBIT(3)\nfs/ntfs/iomap.c:544:#define\tNTFS_IOMAP_FLAGS_WRITEBACK\tBIT(4)\nfs/ntfs/iomap.c-545-\nfs/ntfs/iomap.c=546=static int ntfs_write_da_iomap_begin_non_resident(struct inode *inode,\n--\nfs/ntfs/iomap.c-561-\nfs/ntfs/iomap.c:562:\tupdate_mp = ntfs_iomap_flags \u0026 (NTFS_IOMAP_FLAGS_DIO | NTFS_IOMAP_FLAGS_MKWRITE) ||\nfs/ntfs/iomap.c-563-\t\t\tNInoAttr(ni) || ni-\u003emft_no \u003c FILE_first_user;\n--\nfs/ntfs/iomap.c-566-\t\t\tmax_clu_count, \u0026balloc, update_mp,\nfs/ntfs/iomap.c:567:\t\t\tntfs_iomap_flags \u0026 NTFS_IOMAP_FLAGS_WRITEBACK);\nfs/ntfs/iomap.c-568-\tup_write(\u0026ni-\u003erunlist.lock);\n--\nfs/ntfs/iomap.c-594-\t\tif (flags \u0026 IOMAP_DIRECT ||\nfs/ntfs/iomap.c:595:\t\t    ntfs_iomap_flags \u0026 NTFS_IOMAP_FLAGS_MKWRITE) {\nfs/ntfs/iomap.c-596-\t\t\tloff_t end = offset + length;\n--\nfs/ntfs/iomap.c-620-\nfs/ntfs/iomap.c:621:\tif (ntfs_iomap_flags \u0026 NTFS_IOMAP_FLAGS_MKWRITE \u0026\u0026\nfs/ntfs/iomap.c-622-\t    iomap-\u003eoffset + iomap-\u003elength \u003e ni-\u003einitialized_size) {\n--\nfs/ntfs/iomap.c=674=static int ntfs_write_iomap_begin_non_resident(struct inode *inode, loff_t offset,\n--\nfs/ntfs/iomap.c-679-\nfs/ntfs/iomap.c:680:\tif (ntfs_iomap_flags \u0026 (NTFS_IOMAP_FLAGS_BEGIN | NTFS_IOMAP_FLAGS_DIO) \u0026\u0026\nfs/ntfs/iomap.c-681-\t    offset + length \u003e ni-\u003einitialized_size) {\n--\nfs/ntfs/iomap.c-686-\t\t\t\t\t\t   ntfs_iomap_flags \u0026\nfs/ntfs/iomap.c:687:\t\t\t\t\t\t   NTFS_IOMAP_FLAGS_DIO);\nfs/ntfs/iomap.c-688-\t\tif (ret \u003c 0)\n--\nfs/ntfs/iomap.c-692-\tmutex_lock(\u0026ni-\u003emrec_lock);\nfs/ntfs/iomap.c:693:\tif (ntfs_iomap_flags \u0026 NTFS_IOMAP_FLAGS_BEGIN)\nfs/ntfs/iomap.c-694-\t\treturn  ntfs_write_simple_iomap_begin_non_resident(inode, offset,\n--\nfs/ntfs/iomap.c=703=static int __ntfs_write_iomap_begin(struct inode *inode, loff_t offset,\n--\nfs/ntfs/iomap.c-712-\nfs/ntfs/iomap.c:713:\tif (ntfs_iomap_flags \u0026 (NTFS_IOMAP_FLAGS_BEGIN | NTFS_IOMAP_FLAGS_DIO) \u0026\u0026\nfs/ntfs/iomap.c-714-\t    end \u003e ni-\u003edata_size) {\n--\nfs/ntfs/iomap.c=738=static int ntfs_write_iomap_begin(struct inode *inode, loff_t offset,\n--\nfs/ntfs/iomap.c-742-\treturn __ntfs_write_iomap_begin(inode, offset, length, flags, iomap,\nfs/ntfs/iomap.c:743:\t\t\tNTFS_IOMAP_FLAGS_BEGIN);\nfs/ntfs/iomap.c-744-}\n--\nfs/ntfs/iomap.c=772=static int ntfs_page_mkwrite_iomap_begin(struct inode *inode, loff_t offset,\n--\nfs/ntfs/iomap.c-776-\treturn __ntfs_write_iomap_begin(inode, offset, length, flags, iomap,\nfs/ntfs/iomap.c:777:\t\t\tNTFS_IOMAP_FLAGS_MKWRITE);\nfs/ntfs/iomap.c-778-}\n--\nfs/ntfs/iomap.c=785=static int ntfs_dio_iomap_begin(struct inode *inode, loff_t offset,\n--\nfs/ntfs/iomap.c-789-\treturn __ntfs_write_iomap_begin(inode, offset, length, flags, iomap,\nfs/ntfs/iomap.c:790:\t\t\tNTFS_IOMAP_FLAGS_DIO);\nfs/ntfs/iomap.c-791-}\n--\nfs/ntfs/iomap.c=798=static ssize_t ntfs_writeback_range(struct iomap_writepage_ctx *wpc,\n--\nfs/ntfs/iomap.c-807-\t\t\t\tIOMAP_WRITE, \u0026wpc-\u003eiomap,\nfs/ntfs/iomap.c:808:\t\t\t\tNTFS_IOMAP_FLAGS_WRITEBACK);\nfs/ntfs/iomap.c-809-\t\tif (error)\n--\nfs/ntfs/iomap.h-5-\nfs/ntfs/iomap.h:6:#ifndef _LINUX_NTFS_IOMAP_H\nfs/ntfs/iomap.h:7:#define _LINUX_NTFS_IOMAP_H\nfs/ntfs/iomap.h-8-\n--\nfs/ntfs/iomap.h=22=extern int ntfs_dio_zero_range(struct inode *inode, loff_t offset, loff_t length);\nfs/ntfs/iomap.h:23:#endif /* _LINUX_NTFS_IOMAP_H */\n--\nfs/xfs/Kconfig=2=config XFS_FS\n--\nfs/xfs/Kconfig-6-\tselect CRC32\nfs/xfs/Kconfig:7:\tselect FS_IOMAP\nfs/xfs/Kconfig-8-\thelp\n--\nfs/xfs/xfs_iomap.h-5- */\nfs/xfs/xfs_iomap.h:6:#ifndef __XFS_IOMAP_H__\nfs/xfs/xfs_iomap.h:7:#define __XFS_IOMAP_H__\nfs/xfs/xfs_iomap.h-8-\n--\nfs/xfs/xfs_iomap.h=60=extern const struct iomap_write_ops xfs_iomap_write_ops;\nfs/xfs/xfs_iomap.h-61-\nfs/xfs/xfs_iomap.h:62:#endif /* __XFS_IOMAP_H__*/\n--\nfs/zonefs/Kconfig=1=config ZONEFS_FS\n--\nfs/zonefs/Kconfig-4-\tdepends on BLK_DEV_ZONED\nfs/zonefs/Kconfig:5:\tselect FS_IOMAP\nfs/zonefs/Kconfig-6-\tselect CRC32\n"
}

13/2 2026/07/01 09:00 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 19981
							output: 33
							thoughts: 0
						

14/2 2026/07/01 09:00 tool grepper
0m Args:
{
  "Expression": "iomap_dio_simple",
  "PathPrefix": "fs/iomap/"
}

Results:
{
  "Output": "fs/iomap/direct-io.c=895=EXPORT_SYMBOL_GPL(__iomap_dio_rw);\nfs/iomap/direct-io.c-896-\nfs/iomap/direct-io.c:897:struct iomap_dio_simple {\nfs/iomap/direct-io.c-898-\tstruct kiocb\t\t*iocb;\n--\nfs/iomap/direct-io.c-911-\nfs/iomap/direct-io.c:912:static struct bio_set iomap_dio_simple_pool;\nfs/iomap/direct-io.c-913-\nfs/iomap/direct-io.c:914:static ssize_t iomap_dio_simple_complete(struct iomap_dio_simple *sr)\nfs/iomap/direct-io.c-915-{\n--\nfs/iomap/direct-io.c-942-\nfs/iomap/direct-io.c:943:static void iomap_dio_simple_complete_work(struct work_struct *work)\nfs/iomap/direct-io.c-944-{\nfs/iomap/direct-io.c:945:\tstruct iomap_dio_simple *sr =\nfs/iomap/direct-io.c:946:\t\tcontainer_of(work, struct iomap_dio_simple, work);\nfs/iomap/direct-io.c-947-\tstruct kiocb *iocb = sr-\u003eiocb;\n--\nfs/iomap/direct-io.c-949-\tWRITE_ONCE(iocb-\u003eprivate, NULL);\nfs/iomap/direct-io.c:950:\tiocb-\u003eki_complete(iocb, iomap_dio_simple_complete(sr));\nfs/iomap/direct-io.c-951-}\nfs/iomap/direct-io.c-952-\nfs/iomap/direct-io.c:953:static void iomap_dio_simple_end_io(struct bio *bio)\nfs/iomap/direct-io.c-954-{\nfs/iomap/direct-io.c:955:\tstruct iomap_dio_simple *sr =\nfs/iomap/direct-io.c:956:\t\tcontainer_of(bio, struct iomap_dio_simple, bio);\nfs/iomap/direct-io.c-957-\tstruct kiocb *iocb = sr-\u003eiocb;\n--\nfs/iomap/direct-io.c-961-\nfs/iomap/direct-io.c:962:\t\tINIT_WORK(\u0026sr-\u003ework, iomap_dio_simple_complete_work);\nfs/iomap/direct-io.c-963-\t\tqueue_work(inode-\u003ei_sb-\u003es_dio_done_wq, \u0026sr-\u003ework);\n--\nfs/iomap/direct-io.c-967-\tWRITE_ONCE(iocb-\u003eprivate, NULL);\nfs/iomap/direct-io.c:968:\tiocb-\u003eki_complete(iocb, iomap_dio_simple_complete(sr));\nfs/iomap/direct-io.c-969-}\n--\nfs/iomap/direct-io.c=971=static inline bool\nfs/iomap/direct-io.c:972:iomap_dio_simple_supported(struct kiocb *iocb, struct iov_iter *iter,\nfs/iomap/direct-io.c-973-\t\t\t   const struct iomap_dio_ops *dops,\n--\nfs/iomap/direct-io.c-1006- *\nfs/iomap/direct-io.c:1007: * iomap_dio_simple_supported() enforces the cheap up-front constraints before\nfs/iomap/direct-io.c-1008- * entering this path.\n--\nfs/iomap/direct-io.c-1013- * filesystem-private wrapper around the bio).  The fast path instead allocates\nfs/iomap/direct-io.c:1014: * from the shared iomap_dio_simple_pool, whose front_pad matches struct\nfs/iomap/direct-io.c:1015: * iomap_dio_simple; the two wrappers are not interchangeable, so we must fall\nfs/iomap/direct-io.c-1016- * back to __iomap_dio_rw() in that case.\n--\nfs/iomap/direct-io.c-1029- *\nfs/iomap/direct-io.c:1030: * -ENOTBLK is the private sentinel returned by iomap_dio_simple() when it\nfs/iomap/direct-io.c-1031- * decides the request does not fit the fast path.  In that case we proceed to\n--\nfs/iomap/direct-io.c=1036=static ssize_t\nfs/iomap/direct-io.c:1037:iomap_dio_simple(struct kiocb *iocb, struct iov_iter *iter,\nfs/iomap/direct-io.c-1038-\t\t const struct iomap_ops *ops, void *private,\n--\nfs/iomap/direct-io.c-1050-\t};\nfs/iomap/direct-io.c:1051:\tstruct iomap_dio_simple *sr;\nfs/iomap/direct-io.c-1052-\tunsigned int alignment;\n--\nfs/iomap/direct-io.c-1097-\t\t\t       bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS),\nfs/iomap/direct-io.c:1098:\t\t\t       REQ_OP_READ, GFP_KERNEL, \u0026iomap_dio_simple_pool);\nfs/iomap/direct-io.c:1099:\tsr = container_of(bio, struct iomap_dio_simple, bio);\nfs/iomap/direct-io.c-1100-\tsr-\u003eiocb = iocb;\n--\nfs/iomap/direct-io.c-1132-\tif (!wait_for_completion) {\nfs/iomap/direct-io.c:1133:\t\tbio-\u003ebi_end_io = iomap_dio_simple_end_io;\nfs/iomap/direct-io.c-1134-\t\tsubmit_bio(bio);\n--\nfs/iomap/direct-io.c-1139-\tsubmit_bio_wait(bio);\nfs/iomap/direct-io.c:1140:\treturn iomap_dio_simple_complete(sr);\nfs/iomap/direct-io.c-1141-\n--\nfs/iomap/direct-io.c=1155=iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,\n--\nfs/iomap/direct-io.c-1161-\nfs/iomap/direct-io.c:1162:\tif (iomap_dio_simple_supported(iocb, iter, dops, dio_flags,\nfs/iomap/direct-io.c-1163-\t\t\t\t       done_before)) {\nfs/iomap/direct-io.c:1164:\t\tret = iomap_dio_simple(iocb, iter, ops, private, dio_flags);\nfs/iomap/direct-io.c-1165-\t\tif (ret != -ENOTBLK)\n--\nfs/iomap/direct-io.c=1177=static int __init iomap_dio_init(void)\nfs/iomap/direct-io.c-1178-{\nfs/iomap/direct-io.c:1179:\treturn bioset_init(\u0026iomap_dio_simple_pool, 4,\nfs/iomap/direct-io.c:1180:\t\t\t   offsetof(struct iomap_dio_simple, bio),\nfs/iomap/direct-io.c-1181-\t\t\t   BIOSET_NEED_BVECS | BIOSET_PERCPU_CACHE);\n"
}

15/2 2026/07/01 09:00 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 22141
							output: 165
							thoughts: 710
						

Thoughts:
**My Assessment of the New Direct I/O Path**

Okay, here's what I'm thinking about this patch. It introduces a "simple" direct I/O path, specifically `iomap_dio_simple`, within the `fs/iomap/direct-io.c` file. This new path is designed for handling fast path, small, block-aligned direct I/Os that map to a single contiguous extent on disk. My initial thought? This is definitely functional and ripe for fuzzing. It's a prime target.

The `iomap_dio_simple` function is called from `iomap_dio_rw`, which is, as we know, a function used by numerous filesystems, including btrfs, ext4, xfs, f2fs, and gfs2. That immediately expands the potential impact and attack surface, and means it should be very well tested, and thus fuzzed.

The configuration option to enable all this is `FS_IOMAP`. This option is selected by many filesystems, which is good, but in my experience, it might also be worth keeping an eye on the selected filesystems. Since `FS_IOMAP` is a bool config, listing it is fine. It would also be useful to keep `EXT4_FS`, `XFS_FS`, `BTRFS_FS` in mind.

So, let's get down to brass tacks. I need to focus on these functions: `iomap_dio_simple`, `iomap_dio_simple_supported`, `iomap_dio_simple_complete`, `iomap_dio_simple_end_io`, and `iomap_dio_simple_complete_work`. These are the core elements of this new path, and where the vulnerabilities are likely to be.

The patch includes `iomap_dio_simple` and `iomap_dio_simple_supported`, so this is a solid addition.

Therefore, for my fuzzing assessment:

*   **WorthFuzzing**: `true`
*   **FocusSymbols**: `iomap_dio_simple`, `iomap_dio_simple_supported`, `iomap_dio_simple_complete`, `iomap_dio_simple_end_io`, `iomap_dio_simple_complete_work`
*   **EnableConfigs**: `FS_IOMAP` and, wait, since the `direct-io.o` file also requires `CONFIG_BLOCK`, I should add that too. `BLOCK`

**Reasoning**: This patch introduces a new, faster path for handling specific types of direct I/Os within the iomap subsystem. Because this path adds new core logic, and because it is reachable via several widely used filesystems (ext4, xfs, btrfs, etc.) it should be fuzzed as part of a proper security assessment.



16/2 2026/07/01 09:00 tool set-results
0m Args:
{
  "EnableConfigs": [
    "FS_IOMAP",
    "BLOCK"
  ],
  "FocusSymbols": [
    "iomap_dio_simple",
    "iomap_dio_simple_supported",
    "iomap_dio_simple_complete",
    "iomap_dio_simple_end_io",
    "iomap_dio_simple_complete_work"
  ],
  "Reasoning": "The patch introduces a new fast path for small, block-aligned direct I/Os in the iomap subsystem. This adds new core logic for direct I/O handling that is reachable via various filesystems (ext4, xfs, btrfs, etc.) and should be fuzzed.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "FS_IOMAP",
    "BLOCK"
  ],
  "FocusSymbols": [
    "iomap_dio_simple",
    "iomap_dio_simple_supported",
    "iomap_dio_simple_complete",
    "iomap_dio_simple_end_io",
    "iomap_dio_simple_complete_work"
  ],
  "Reasoning": "The patch introduces a new fast path for small, block-aligned direct I/Os in the iomap subsystem. This adds new core logic for direct I/O handling that is reachable via various filesystems (ext4, xfs, btrfs, etc.) and should be fuzzed.",
  "WorthFuzzing": true
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)