Linux XFS filesystem development
 help / color / mirror / Atom feed
* [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model
@ 2026-07-01  0:09 Joanne Koong
  2026-07-01  0:09 ` [PATCH v2 01/18] iomap: add ->iomap_next() and iomap_process() helper Joanne Koong
                   ` (18 more replies)
  0 siblings, 19 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch; +Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs

This series implements a suggestion by Christoph for finishing the conversion
of iomap to an iterator model. This revives Matthew's previous RFC [1], which
had the same intention.

This series has no functional changes intended. Patch 1 introduces the new
->iomap_next() interface, and the rest is a mechanical conversion to the new
api. The patches are broken down as:

1) Patch 1: adds ->iomap_next() and an iomap_process() inline helper that
filesystems can use by passing in their direct begin/end helper functions

2) Patches 2 to 15: converts each filesystem to ->iomap_next()

3) Patch 16: Removes the legacy ->iomap_begin()/->iomap_end() path

4) Patch 17: Passes iomap_next_fn directly instead of struct iomap_ops

5) Patch 18: Updates the iomap documentation to match.

If needed, performance-critical callers can later inline the iteration into
the caller and avoid the indirect iomap_next_fn call on hot paths.

This series is submitted against Christian's vfs iomap tree, and is based
on top of the current head of his tree (commit f2727952b21d1).

Thanks,
Joanne

[1] https://lore.kernel.org/linux-fsdevel/20200728173216.7184-1-willy@infradead.org/T/#u

Changelog
---------
v1: https://lore.kernel.org/linux-fsdevel/20260625024723.1611000-1-joannelkoong@gmail.com/
v1 -> v2:
* Implement conversion for all callers

Joanne Koong (18):
  iomap: add ->iomap_next() and iomap_process() helper
  xfs: convert iomap ops to ->iomap_next()
  btrfs: convert iomap ops to ->iomap_next()
  ntfs3: convert iomap ops to ->iomap_next()
  ntfs: convert iomap ops to ->iomap_next()
  ext4: convert iomap ops to ->iomap_next()
  erofs: convert iomap ops to ->iomap_next()
  zonefs: convert iomap ops to ->iomap_next()
  ext2: convert iomap ops to ->iomap_next()
  block: convert iomap ops to ->iomap_next()
  f2fs: convert iomap ops to ->iomap_next()
  gfs2: convert iomap ops to ->iomap_next()
  hpfs: convert iomap ops to ->iomap_next()
  fuse: convert iomap ops to ->iomap_next()
  exfat: convert iomap ops to ->iomap_next()
  iomap: remove ->iomap_begin()/->iomap_end() legacy path
  iomap: pass iomap_next_fn directly instead of struct iomap_ops
  Documentation: iomap: update docs to reflect iomap_next model

 Documentation/filesystems/iomap/design.rst    | 115 ++++++++++-----
 .../filesystems/iomap/operations.rst          |  60 ++++----
 Documentation/filesystems/iomap/porting.rst   |  22 ++-
 block/fops.c                                  |  14 +-
 fs/btrfs/direct-io.c                          |  14 +-
 fs/dax.c                                      |  47 ++++---
 fs/erofs/data.c                               |  30 ++--
 fs/erofs/internal.h                           |   3 +-
 fs/erofs/zmap.c                               |   9 +-
 fs/exfat/file.c                               |  18 +--
 fs/exfat/inode.c                              |   6 +-
 fs/exfat/iomap.c                              |  20 +--
 fs/exfat/iomap.h                              |   6 +-
 fs/ext2/ext2.h                                |   3 +-
 fs/ext2/file.c                                |   4 +-
 fs/ext2/inode.c                               |  12 +-
 fs/ext4/ext4.h                                |   6 +-
 fs/ext4/extents.c                             |  12 +-
 fs/ext4/file.c                                |  14 +-
 fs/ext4/inode.c                               |  23 +--
 fs/f2fs/data.c                                |   9 +-
 fs/f2fs/f2fs.h                                |   3 +-
 fs/f2fs/file.c                                |   4 +-
 fs/fuse/dax.c                                 |  16 ++-
 fs/fuse/file.c                                |  14 +-
 fs/fuse/virtio_fs.c                           |   2 +-
 fs/gfs2/aops.c                                |   6 +-
 fs/gfs2/bmap.c                                |  12 +-
 fs/gfs2/bmap.h                                |   3 +-
 fs/gfs2/file.c                                |   6 +-
 fs/gfs2/inode.c                               |   6 +-
 fs/hpfs/file.c                                |  10 +-
 fs/internal.h                                 |   1 -
 fs/iomap/buffered-io.c                        |  38 ++---
 fs/iomap/direct-io.c                          |   8 +-
 fs/iomap/fiemap.c                             |   8 +-
 fs/iomap/iter.c                               |  88 +++++++-----
 fs/iomap/seek.c                               |   8 +-
 fs/iomap/swapfile.c                           |   4 +-
 fs/ntfs/aops.c                                |   6 +-
 fs/ntfs/file.c                                |  24 ++--
 fs/ntfs/inode.c                               |   2 +-
 fs/ntfs/iomap.c                               |  58 +++++---
 fs/ntfs/iomap.h                               |  15 +-
 fs/ntfs3/file.c                               |  16 +--
 fs/ntfs3/inode.c                              |  16 ++-
 fs/ntfs3/ntfs_fs.h                            |   3 +-
 fs/remap_range.c                              |   6 +-
 fs/xfs/xfs_aops.c                             |   8 +-
 fs/xfs/xfs_file.c                             |  44 +++---
 fs/xfs/xfs_iomap.c                            | 105 ++++++++++----
 fs/xfs/xfs_iomap.h                            |  24 ++--
 fs/xfs/xfs_iops.c                             |   4 +-
 fs/xfs/xfs_reflink.c                          |   6 +-
 fs/zonefs/file.c                              |  32 +++--
 include/linux/dax.h                           |  18 ++-
 include/linux/fs.h                            |   7 +-
 include/linux/iomap.h                         | 131 ++++++++++++------
 58 files changed, 730 insertions(+), 479 deletions(-)

-- 
2.52.0


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 01/18] iomap: add ->iomap_next() and iomap_process() helper
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-02 14:00   ` Christoph Hellwig
  2026-07-02 16:23   ` Darrick J. Wong
  2026-07-01  0:09 ` [PATCH v2 02/18] xfs: convert iomap ops to ->iomap_next() Joanne Koong
                   ` (17 subsequent siblings)
  18 siblings, 2 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs, open list

Have one ->iomap_next() callback instead of ->iomap_begin() and
->iomap_end(). ->iomap_next() finishes the previous mapping if needed,
and produces the next mapping. This lets performance-critical callers
inline the iteration with a fixed callback, which the compiler is able
to call directly instead of indirectly.

iomap_iter() uses ->iomap_next() when the filesystem provides that
callback and otherwise falls back to the ->iomap_begin()/->iomap_end()
path, so filesystems can be converted one at a time.

Add a iomap_process() inline helper that does most of the logic needed
in an ->iomap_next() implementation.

Suggested-by: Christoph Hellwig <hch@lst.de>
Suggested-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/iomap/iter.c       | 113 ++++++++++++++++++++++++++++++++++++------
 include/linux/iomap.h |  91 +++++++++++++++++++++++++++-------
 2 files changed, 171 insertions(+), 33 deletions(-)

diff --git a/fs/iomap/iter.c b/fs/iomap/iter.c
index e4a29829591a..1062e4e34c38 100644
--- a/fs/iomap/iter.c
+++ b/fs/iomap/iter.c
@@ -39,22 +39,7 @@ static inline void iomap_iter_done(struct iomap_iter *iter)
 		trace_iomap_iter_srcmap(iter->inode, &iter->srcmap);
 }
 
-/**
- * iomap_iter - iterate over a ranges in a file
- * @iter: iteration structue
- * @ops: iomap ops provided by the file system
- *
- * Iterate over filesystem-provided space mappings for the provided file range.
- *
- * This function handles cleanup of resources acquired for iteration when the
- * filesystem indicates there are no more space mappings, which means that this
- * function must be called in a loop that continues as long it returns a
- * positive value.  If 0 or a negative value is returned, the caller must not
- * return to the loop body.  Within a loop body, there are two ways to break out
- * of the loop body:  leave @iter.status unchanged, or set it to a negative
- * errno.
- */
-int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
+static int iomap_iter_legacy(struct iomap_iter *iter, const struct iomap_ops *ops)
 {
 	bool stale = iter->iomap.flags & IOMAP_F_STALE;
 	ssize_t advanced;
@@ -114,3 +99,99 @@ int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
 	iomap_iter_done(iter);
 	return 1;
 }
+
+static int iomap_iter_next(struct iomap_iter *iter, const struct iomap_ops *ops)
+{
+	int ret;
+
+	trace_iomap_iter(iter, ops, _RET_IP_);
+
+	ret = ops->iomap_next(iter, &iter->iomap, &iter->srcmap);
+	iter->status = 0;
+	if (ret > 0)
+		iomap_iter_done(iter);
+
+	return ret;
+}
+
+/**
+ * iomap_iter - iterate over a ranges in a file
+ * @iter: iteration structue
+ * @ops: iomap ops provided by the file system
+ *
+ * Iterate over filesystem-provided space mappings for the provided file range.
+ *
+ * This function handles cleanup of resources acquired for iteration when the
+ * filesystem indicates there are no more space mappings, which means that this
+ * function must be called in a loop that continues as long it returns a
+ * positive value.  If 0 or a negative value is returned, the caller must not
+ * return to the loop body.  Within a loop body, there are two ways to break out
+ * of the loop body:  leave @iter.status unchanged, or set it to a negative
+ * errno.
+ */
+int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
+{
+	if (ops->iomap_next)
+		return iomap_iter_next(iter, ops);
+
+	return iomap_iter_legacy(iter, ops);
+}
+
+/**
+ * iomap_iter_continue - decide whether iteration should continue
+ * @iter: iteration structure
+ * @iomap: the mapping that was just processed
+ * @srcmap: the source mapping that was just processed
+ *
+ * Helper for ->iomap_next() implementations, normally called via
+ * iomap_process().  Called after the previous mapping has been finished to
+ * determine whether there is more of the file range left to process.
+ *
+ * Returns 1 if there is more work to do, in which case @iomap and @srcmap are
+ * cleared so the caller can produce the next mapping; zero if the range is
+ * fully consumed; or a negative errno on error.  Any folio batch attached to
+ * the mapping is released before returning.
+ */
+int iomap_iter_continue(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap, int ret)
+{
+	bool stale = iomap->flags & IOMAP_F_STALE;
+	ssize_t advanced = iter->pos - iter->iter_start_pos;
+
+	if (!iomap->length)
+		return 1;
+
+	/*
+	 * Use iter->len to determine whether to continue onto the next mapping.
+	 * Explicitly terminate on error status or if the current iter has not
+	 * advanced at all (i.e. no work was done for some reason) unless the
+	 * mapping has been marked stale and needs to be reprocessed.
+	 */
+	if (ret < 0 && !advanced)
+		return ret;
+
+	/* detect old return semantics where this would advance */
+	if (WARN_ON_ONCE(iter->status > 0))
+		ret = -EIO;
+	else if (iter->status < 0)
+		ret = iter->status;
+	else if (iter->len == 0 || (!advanced && !stale))
+		ret = 0;
+	else
+		ret = 1;
+
+	if (iomap->flags & IOMAP_F_FOLIO_BATCH) {
+		folio_batch_release(iter->fbatch);
+		folio_batch_reinit(iter->fbatch);
+		iomap->flags &= ~IOMAP_F_FOLIO_BATCH;
+	}
+
+	if (ret <= 0)
+		return ret;
+
+	memset(iomap, 0, sizeof(*iomap));
+	memset(srcmap, 0, sizeof(*srcmap));
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iomap_iter_continue);
diff --git a/include/linux/iomap.h b/include/linux/iomap.h
index 3582ed1fe236..8a78f47c557b 100644
--- a/include/linux/iomap.h
+++ b/include/linux/iomap.h
@@ -212,24 +212,35 @@ struct iomap_write_ops {
 #define IOMAP_ATOMIC		(1 << 9) /* torn-write protection */
 #define IOMAP_DONTCACHE		(1 << 10)
 
-struct iomap_ops {
-	/*
-	 * Return the existing mapping at pos, or reserve space starting at
-	 * pos for up to length, as long as we can do it as a single mapping.
-	 * The actual length is returned in iomap->length.
-	 */
-	int (*iomap_begin)(struct inode *inode, loff_t pos, loff_t length,
-			unsigned flags, struct iomap *iomap,
-			struct iomap *srcmap);
+/*
+ * Return the existing mapping at pos, or reserve space starting at pos for up
+ * to length, as long as we can do it as a single mapping.
+ * The actual length is returned in iomap->length.
+ */
+typedef int (*iomap_begin_fn)(struct inode *inode, loff_t pos, loff_t length,
+		unsigned flags, struct iomap *iomap, struct iomap *srcmap);
 
-	/*
-	 * Commit and/or unreserve space previous allocated using iomap_begin.
-	 * Written indicates the length of the successful write operation which
-	 * needs to be commited, while the rest needs to be unreserved.
-	 * Written might be zero if no data was written.
-	 */
-	int (*iomap_end)(struct inode *inode, loff_t pos, loff_t length,
-			ssize_t written, unsigned flags, struct iomap *iomap);
+/*
+ * Commit and/or unreserve space previous allocated using iomap_begin.
+ * Written indicates the length of the successful write operation which needs
+ * to be commited, while the rest needs to be unreserved.
+ * Written might be zero if no data was written.
+ */
+typedef int (*iomap_end_fn)(struct inode *inode, loff_t pos, loff_t length,
+		ssize_t written, unsigned flags, struct iomap *iomap);
+
+/*
+ * Produce the next mapping (finishing the previous one if needed).
+ * Return 1 to continue iterating, 0 if the range is fully consumed, or a
+ * negative error on failure.
+ */
+typedef int (*iomap_next_fn)(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap);
+
+struct iomap_ops {
+	iomap_begin_fn iomap_begin;
+	iomap_end_fn iomap_end;
+	iomap_next_fn iomap_next;
 };
 
 /**
@@ -317,6 +328,9 @@ static inline const struct iomap *iomap_iter_srcmap(const struct iomap_iter *i)
 	return &i->iomap;
 }
 
+int iomap_iter_continue(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap, int ret);
+
 /*
  * Return the file offset for the first unchanged block after a short write.
  *
@@ -648,4 +662,47 @@ static inline void iomap_bio_readahead(struct readahead_control *rac,
 }
 #endif /* CONFIG_BLOCK */
 
+/**
+ * iomap_process - finish the previous mapping and produce the next one
+ * @iter: iteration structure
+ * @iomap: mapping to finish and then repopulate
+ * @srcmap: source mapping to finish and then repopulate
+ * @begin: callback that produces a mapping for the current position
+ * @end: optional callback that finishes the previous mapping, or NULL
+ *
+ * Inline helper that implements the common body of an ->iomap_next()
+ * callback: it finishes the previous mapping via @end (if present), decides
+ * via iomap_iter_continue() whether to keep going, and obtains the next
+ * mapping via @begin.
+ *
+ * Returns 1 to continue iterating, 0 once the range is fully consumed, or a
+ * negative errno on error.
+ */
+static __always_inline int iomap_process(const struct iomap_iter *iter,
+		struct iomap *iomap, struct iomap *srcmap, iomap_begin_fn begin,
+		iomap_end_fn end)
+{
+	int ret = 0;
+
+	if (iomap->length && end) {
+		ssize_t advanced = iter->pos - iter->iter_start_pos;
+		loff_t len;
+
+		len = iomap_length_trim(iter, iter->iter_start_pos,
+				iter->len + advanced);
+
+		ret = end(iter->inode, iter->iter_start_pos, len, advanced,
+				iter->flags, iomap);
+	}
+
+	ret = iomap_iter_continue(iter, iomap, srcmap, ret);
+	if (ret <= 0)
+		return ret;
+
+	ret = begin(iter->inode, iter->pos, iter->len, iter->flags, iomap,
+			srcmap);
+
+	return ret < 0 ? ret : 1;
+}
+
 #endif /* LINUX_IOMAP_H */
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 02/18] xfs: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
  2026-07-01  0:09 ` [PATCH v2 01/18] iomap: add ->iomap_next() and iomap_process() helper Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-02 14:03   ` Christoph Hellwig
  2026-07-02 16:43   ` Darrick J. Wong
  2026-07-01  0:09 ` [PATCH v2 03/18] btrfs: " Joanne Koong
                   ` (16 subsequent siblings)
  18 siblings, 2 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Carlos Maiolino, open list

Convert xfs iomap_ops to the new ->iomap_next() callback. This uses the
iomap_process() helper, which finishes the previous mapping if needed
and produces the next one. No functional changes are intended.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/xfs/xfs_file.c  |  4 +-
 fs/xfs/xfs_iomap.c | 96 +++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 88 insertions(+), 12 deletions(-)

diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 845a97c9b063..7f8bef1a9954 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -857,9 +857,9 @@ xfs_file_dio_write_atomic(
 			NULL, 0);
 
 	/*
-	 * The retry mechanism is based on the ->iomap_begin method returning
+	 * The retry mechanism is based on the ->iomap_next method returning
 	 * -ENOPROTOOPT, which would be when the REQ_ATOMIC-based write is not
-	 * possible. The REQ_ATOMIC-based method typically not be possible if
+	 * possible. The REQ_ATOMIC-based method is typically not possible if
 	 * the write spans multiple extents or the disk blocks are misaligned.
 	 */
 	if (ret == -ENOPROTOOPT && dops == &xfs_direct_write_iomap_ops) {
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 225c3de88d03..4fa1a5c985db 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -1037,8 +1037,18 @@ xfs_direct_write_iomap_begin(
 	return error;
 }
 
+static int
+xfs_direct_write_iomap_next(
+	const struct iomap_iter *iter,
+	struct iomap		*iomap,
+	struct iomap		*srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, xfs_direct_write_iomap_begin,
+			NULL);
+}
+
 const struct iomap_ops xfs_direct_write_iomap_ops = {
-	.iomap_begin		= xfs_direct_write_iomap_begin,
+	.iomap_next		= xfs_direct_write_iomap_next,
 };
 
 #ifdef CONFIG_XFS_RT
@@ -1089,8 +1099,18 @@ xfs_zoned_direct_write_iomap_begin(
 	return 0;
 }
 
+static int
+xfs_zoned_direct_write_iomap_next(
+	const struct iomap_iter *iter,
+	struct iomap		*iomap,
+	struct iomap		*srcmap)
+{
+	return iomap_process(iter, iomap, srcmap,
+			xfs_zoned_direct_write_iomap_begin, NULL);
+}
+
 const struct iomap_ops xfs_zoned_direct_write_iomap_ops = {
-	.iomap_begin		= xfs_zoned_direct_write_iomap_begin,
+	.iomap_next		= xfs_zoned_direct_write_iomap_next,
 };
 #endif /* CONFIG_XFS_RT */
 
@@ -1274,8 +1294,18 @@ xfs_atomic_write_cow_iomap_begin(
 	return error;
 }
 
+static int
+xfs_atomic_write_cow_iomap_next(
+	const struct iomap_iter *iter,
+	struct iomap		*iomap,
+	struct iomap		*srcmap)
+{
+	return iomap_process(iter, iomap, srcmap,
+			xfs_atomic_write_cow_iomap_begin, NULL);
+}
+
 const struct iomap_ops xfs_atomic_write_cow_iomap_ops = {
-	.iomap_begin		= xfs_atomic_write_cow_iomap_begin,
+	.iomap_next		= xfs_atomic_write_cow_iomap_next,
 };
 
 static int
@@ -1298,9 +1328,18 @@ xfs_dax_write_iomap_end(
 	return xfs_reflink_end_cow(ip, pos, written);
 }
 
+static int
+xfs_dax_write_iomap_next(
+	const struct iomap_iter *iter,
+	struct iomap		*iomap,
+	struct iomap		*srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, xfs_direct_write_iomap_begin,
+			xfs_dax_write_iomap_end);
+}
+
 const struct iomap_ops xfs_dax_write_iomap_ops = {
-	.iomap_begin	= xfs_direct_write_iomap_begin,
-	.iomap_end	= xfs_dax_write_iomap_end,
+	.iomap_next	= xfs_dax_write_iomap_next,
 };
 
 /*
@@ -2168,9 +2207,19 @@ xfs_buffered_write_iomap_end(
 	return 0;
 }
 
+static int
+xfs_buffered_write_iomap_next(
+	const struct iomap_iter *iter,
+	struct iomap		*iomap,
+	struct iomap		*srcmap)
+{
+	return iomap_process(iter, iomap, srcmap,
+			xfs_buffered_write_iomap_begin,
+			xfs_buffered_write_iomap_end);
+}
+
 const struct iomap_ops xfs_buffered_write_iomap_ops = {
-	.iomap_begin		= xfs_buffered_write_iomap_begin,
-	.iomap_end		= xfs_buffered_write_iomap_end,
+	.iomap_next		= xfs_buffered_write_iomap_next,
 };
 
 static int
@@ -2214,8 +2263,17 @@ xfs_read_iomap_begin(
 				 shared ? IOMAP_F_SHARED : 0, seq);
 }
 
+static int
+xfs_read_iomap_next(
+	const struct iomap_iter *iter,
+	struct iomap		*iomap,
+	struct iomap		*srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, xfs_read_iomap_begin, NULL);
+}
+
 const struct iomap_ops xfs_read_iomap_ops = {
-	.iomap_begin		= xfs_read_iomap_begin,
+	.iomap_next		= xfs_read_iomap_next,
 };
 
 static int
@@ -2302,8 +2360,17 @@ xfs_seek_iomap_begin(
 	return error;
 }
 
+static int
+xfs_seek_iomap_next(
+	const struct iomap_iter *iter,
+	struct iomap		*iomap,
+	struct iomap		*srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, xfs_seek_iomap_begin, NULL);
+}
+
 const struct iomap_ops xfs_seek_iomap_ops = {
-	.iomap_begin		= xfs_seek_iomap_begin,
+	.iomap_next		= xfs_seek_iomap_next,
 };
 
 static int
@@ -2349,8 +2416,17 @@ xfs_xattr_iomap_begin(
 	return xfs_bmbt_to_iomap(ip, iomap, &imap, flags, IOMAP_F_XATTR, seq);
 }
 
+static int
+xfs_xattr_iomap_next(
+	const struct iomap_iter *iter,
+	struct iomap		*iomap,
+	struct iomap		*srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, xfs_xattr_iomap_begin, NULL);
+}
+
 const struct iomap_ops xfs_xattr_iomap_ops = {
-	.iomap_begin		= xfs_xattr_iomap_begin,
+	.iomap_next		= xfs_xattr_iomap_next,
 };
 
 int
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 03/18] btrfs: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
  2026-07-01  0:09 ` [PATCH v2 01/18] iomap: add ->iomap_next() and iomap_process() helper Joanne Koong
  2026-07-01  0:09 ` [PATCH v2 02/18] xfs: convert iomap ops to ->iomap_next() Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-01  0:09 ` [PATCH v2 04/18] ntfs3: " Joanne Koong
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs, Chris Mason,
	David Sterba, open list:BTRFS FILE SYSTEM, open list

Convert btrfs iomap_ops to the new ->iomap_next() callback. This uses the
iomap_process() helper, which finishes the previous mapping if needed
and produces the next one. No functional changes are intended.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/btrfs/direct-io.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/fs/btrfs/direct-io.c b/fs/btrfs/direct-io.c
index 460326d34143..46dd72982fba 100644
--- a/fs/btrfs/direct-io.c
+++ b/fs/btrfs/direct-io.c
@@ -798,9 +798,15 @@ static void btrfs_dio_submit_io(const struct iomap_iter *iter, struct bio *bio,
 	btrfs_submit_bbio(bbio, 0);
 }
 
+static int btrfs_dio_iomap_next(const struct iomap_iter *iter,
+				struct iomap *iomap, struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, btrfs_dio_iomap_begin,
+			     btrfs_dio_iomap_end);
+}
+
 static const struct iomap_ops btrfs_dio_iomap_ops = {
-	.iomap_begin            = btrfs_dio_iomap_begin,
-	.iomap_end              = btrfs_dio_iomap_end,
+	.iomap_next             = btrfs_dio_iomap_next,
 };
 
 static const struct iomap_dio_ops btrfs_dio_ops = {
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 04/18] ntfs3: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (2 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 03/18] btrfs: " Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-01  0:09 ` [PATCH v2 05/18] ntfs: " Joanne Koong
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Konstantin Komarov, open list:NTFS3 FILESYSTEM, open list

Convert ntfs3 iomap_ops to the new ->iomap_next() callback. This uses the
iomap_process() helper, which finishes the previous mapping if needed
and produces the next one. No functional changes are intended.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/ntfs3/inode.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c
index c43101cc064d..c5676c51a3a4 100644
--- a/fs/ntfs3/inode.c
+++ b/fs/ntfs3/inode.c
@@ -2101,9 +2101,15 @@ const struct address_space_operations ntfs_aops_cmpr = {
 	.invalidate_folio = iomap_invalidate_folio,
 };
 
+static int ntfs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+			   struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, ntfs_iomap_begin,
+			     ntfs_iomap_end);
+}
+
 const struct iomap_ops ntfs_iomap_ops = {
-	.iomap_begin	= ntfs_iomap_begin,
-	.iomap_end	= ntfs_iomap_end,
+	.iomap_next	= ntfs_iomap_next,
 };
 
 const struct iomap_write_ops ntfs_iomap_folio_ops = {
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 05/18] ntfs: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (3 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 04/18] ntfs3: " Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-01  0:09 ` [PATCH v2 06/18] ext4: " Joanne Koong
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs, Namjae Jeon,
	Hyunchul Lee, open list

Convert ntfs iomap_ops to the new ->iomap_next() callback. This uses the
iomap_process() helper, which finishes the previous mapping if needed
and produces the next one. No functional changes are intended.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/ntfs/iomap.c | 56 ++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 46 insertions(+), 10 deletions(-)

diff --git a/fs/ntfs/iomap.c b/fs/ntfs/iomap.c
index 52eecf5cb256..0f9f02e1593e 100644
--- a/fs/ntfs/iomap.c
+++ b/fs/ntfs/iomap.c
@@ -277,8 +277,14 @@ static int ntfs_read_iomap_begin(struct inode *inode, loff_t offset, loff_t leng
 			srcmap, true);
 }
 
+static int ntfs_read_iomap_next(const struct iomap_iter *iter,
+		struct iomap *iomap, struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, ntfs_read_iomap_begin, NULL);
+}
+
 const struct iomap_ops ntfs_read_iomap_ops = {
-	.iomap_begin = ntfs_read_iomap_begin,
+	.iomap_next = ntfs_read_iomap_next,
 };
 
 /*
@@ -329,13 +335,25 @@ static int ntfs_zero_read_iomap_end(struct inode *inode, loff_t pos, loff_t leng
 	return written;
 }
 
+static int ntfs_zero_read_iomap_next(const struct iomap_iter *iter,
+		struct iomap *iomap, struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, ntfs_seek_iomap_begin,
+			ntfs_zero_read_iomap_end);
+}
+
 static const struct iomap_ops ntfs_zero_read_iomap_ops = {
-	.iomap_begin = ntfs_seek_iomap_begin,
-	.iomap_end = ntfs_zero_read_iomap_end,
+	.iomap_next = ntfs_zero_read_iomap_next,
 };
 
+static int ntfs_seek_iomap_next(const struct iomap_iter *iter,
+		struct iomap *iomap, struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, ntfs_seek_iomap_begin, NULL);
+}
+
 const struct iomap_ops ntfs_seek_iomap_ops = {
-	.iomap_begin = ntfs_seek_iomap_begin,
+	.iomap_next = ntfs_seek_iomap_next,
 };
 
 int ntfs_dio_zero_range(struct inode *inode, loff_t offset, loff_t length)
@@ -764,9 +782,15 @@ static int ntfs_write_iomap_end(struct inode *inode, loff_t pos, loff_t length,
 	return written;
 }
 
+static int ntfs_write_iomap_next(const struct iomap_iter *iter,
+		struct iomap *iomap, struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, ntfs_write_iomap_begin,
+			ntfs_write_iomap_end);
+}
+
 const struct iomap_ops ntfs_write_iomap_ops = {
-	.iomap_begin		= ntfs_write_iomap_begin,
-	.iomap_end		= ntfs_write_iomap_end,
+	.iomap_next		= ntfs_write_iomap_next,
 };
 
 static int ntfs_page_mkwrite_iomap_begin(struct inode *inode, loff_t offset,
@@ -777,9 +801,15 @@ static int ntfs_page_mkwrite_iomap_begin(struct inode *inode, loff_t offset,
 			NTFS_IOMAP_FLAGS_MKWRITE);
 }
 
+static int ntfs_page_mkwrite_iomap_next(const struct iomap_iter *iter,
+		struct iomap *iomap, struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, ntfs_page_mkwrite_iomap_begin,
+			ntfs_write_iomap_end);
+}
+
 const struct iomap_ops ntfs_page_mkwrite_iomap_ops = {
-	.iomap_begin		= ntfs_page_mkwrite_iomap_begin,
-	.iomap_end		= ntfs_write_iomap_end,
+	.iomap_next		= ntfs_page_mkwrite_iomap_next,
 };
 
 static int ntfs_dio_iomap_begin(struct inode *inode, loff_t offset,
@@ -790,9 +820,15 @@ static int ntfs_dio_iomap_begin(struct inode *inode, loff_t offset,
 			NTFS_IOMAP_FLAGS_DIO);
 }
 
+static int ntfs_dio_iomap_next(const struct iomap_iter *iter,
+		struct iomap *iomap, struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, ntfs_dio_iomap_begin,
+			ntfs_write_iomap_end);
+}
+
 const struct iomap_ops ntfs_dio_iomap_ops = {
-	.iomap_begin		= ntfs_dio_iomap_begin,
-	.iomap_end		= ntfs_write_iomap_end,
+	.iomap_next		= ntfs_dio_iomap_next,
 };
 
 static ssize_t ntfs_writeback_range(struct iomap_writepage_ctx *wpc,
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 06/18] ext4: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (4 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 05/18] ntfs: " Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-01 10:01   ` Jan Kara
  2026-07-01  0:09 ` [PATCH v2 07/18] erofs: " Joanne Koong
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Theodore Ts'o, Andreas Dilger, Baokun Li, Jan Kara,
	Ojaswin Mujoo, Ritesh Harjani (IBM), Zhang Yi,
	open list:EXT4 FILE SYSTEM, open list

Convert ext4 iomap_ops to the new ->iomap_next() callback. This uses the
iomap_process() helper, which finishes the previous mapping if needed
and produces the next one. No functional changes are intended.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/ext4/extents.c |  8 +++++++-
 fs/ext4/inode.c   | 17 +++++++++++++++--
 2 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 91c97af64b31..431298eca7e8 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -5171,8 +5171,14 @@ static int ext4_iomap_xattr_begin(struct inode *inode, loff_t offset,
 	return error;
 }
 
+static int ext4_iomap_xattr_next(const struct iomap_iter *iter,
+				 struct iomap *iomap, struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, ext4_iomap_xattr_begin, NULL);
+}
+
 static const struct iomap_ops ext4_iomap_xattr_ops = {
-	.iomap_begin		= ext4_iomap_xattr_begin,
+	.iomap_next		= ext4_iomap_xattr_next,
 };
 
 static int ext4_fiemap_check_ranges(struct inode *inode, u64 start, u64 *len)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index ce99807c5f5b..cf7aa8275651 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3850,8 +3850,14 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
 	return 0;
 }
 
+static int ext4_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+			   struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, ext4_iomap_begin, NULL);
+}
+
 const struct iomap_ops ext4_iomap_ops = {
-	.iomap_begin		= ext4_iomap_begin,
+	.iomap_next		= ext4_iomap_next,
 };
 
 static int ext4_iomap_begin_report(struct inode *inode, loff_t offset,
@@ -3905,8 +3911,15 @@ static int ext4_iomap_begin_report(struct inode *inode, loff_t offset,
 	return 0;
 }
 
+static int ext4_iomap_next_report(const struct iomap_iter *iter,
+				  struct iomap *iomap, struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, ext4_iomap_begin_report,
+			     NULL);
+}
+
 const struct iomap_ops ext4_iomap_report_ops = {
-	.iomap_begin = ext4_iomap_begin_report,
+	.iomap_next = ext4_iomap_next_report,
 };
 
 /*
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 07/18] erofs: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (5 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 06/18] ext4: " Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-01  0:41   ` Gao Xiang
  2026-07-01  0:09 ` [PATCH v2 08/18] zonefs: " Joanne Koong
                   ` (11 subsequent siblings)
  18 siblings, 1 reply; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs, Gao Xiang,
	Chao Yu, Yue Hu, Jeffle Xu, Sandeep Dhavale, Hongbo Li,
	Chunhai Guo, open list:EROFS FILE SYSTEM, open list

Convert erofs iomap_ops to the new ->iomap_next() callback. This uses the
iomap_process() helper, which finishes the previous mapping if needed
and produces the next one. No functional changes are intended.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/erofs/data.c | 10 ++++++++--
 fs/erofs/zmap.c |  9 ++++++++-
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index 9aa48c8d67d1..47dba61ec576 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -380,9 +380,15 @@ static int erofs_iomap_end(struct inode *inode, loff_t pos, loff_t length,
 	return written;
 }
 
+static int erofs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+			    struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, erofs_iomap_begin,
+			     erofs_iomap_end);
+}
+
 static const struct iomap_ops erofs_iomap_ops = {
-	.iomap_begin = erofs_iomap_begin,
-	.iomap_end = erofs_iomap_end,
+	.iomap_next = erofs_iomap_next,
 };
 
 int erofs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
index bab521613552..dd058413a0b6 100644
--- a/fs/erofs/zmap.c
+++ b/fs/erofs/zmap.c
@@ -821,6 +821,13 @@ static int z_erofs_iomap_begin_report(struct inode *inode, loff_t offset,
 	return 0;
 }
 
+static int z_erofs_iomap_next_report(const struct iomap_iter *iter,
+				     struct iomap *iomap, struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, z_erofs_iomap_begin_report,
+			     NULL);
+}
+
 const struct iomap_ops z_erofs_iomap_report_ops = {
-	.iomap_begin = z_erofs_iomap_begin_report,
+	.iomap_next = z_erofs_iomap_next_report,
 };
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 08/18] zonefs: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (6 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 07/18] erofs: " Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-01  0:09 ` [PATCH v2 09/18] ext2: " Joanne Koong
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Damien Le Moal, Naohiro Aota, Johannes Thumshirn, open list

Convert zonefs iomap_ops to the new ->iomap_next() callback. This uses the
iomap_process() helper, which finishes the previous mapping if needed
and produces the next one. No functional changes are intended.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/zonefs/file.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/fs/zonefs/file.c b/fs/zonefs/file.c
index 5ada33f70bb4..a29a8756d660 100644
--- a/fs/zonefs/file.c
+++ b/fs/zonefs/file.c
@@ -57,8 +57,15 @@ static int zonefs_read_iomap_begin(struct inode *inode, loff_t offset,
 	return 0;
 }
 
+static int zonefs_read_iomap_next(const struct iomap_iter *iter,
+				  struct iomap *iomap, struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, zonefs_read_iomap_begin,
+			     NULL);
+}
+
 static const struct iomap_ops zonefs_read_iomap_ops = {
-	.iomap_begin	= zonefs_read_iomap_begin,
+	.iomap_next	= zonefs_read_iomap_next,
 };
 
 static int zonefs_write_iomap_begin(struct inode *inode, loff_t offset,
@@ -106,8 +113,15 @@ static int zonefs_write_iomap_begin(struct inode *inode, loff_t offset,
 	return 0;
 }
 
+static int zonefs_write_iomap_next(const struct iomap_iter *iter,
+				   struct iomap *iomap, struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, zonefs_write_iomap_begin,
+			     NULL);
+}
+
 static const struct iomap_ops zonefs_write_iomap_ops = {
-	.iomap_begin	= zonefs_write_iomap_begin,
+	.iomap_next	= zonefs_write_iomap_next,
 };
 
 static int zonefs_read_folio(struct file *unused, struct folio *folio)
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 09/18] ext2: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (7 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 08/18] zonefs: " Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-01 10:02   ` Jan Kara
  2026-07-01  0:09 ` [PATCH v2 10/18] block: " Joanne Koong
                   ` (9 subsequent siblings)
  18 siblings, 1 reply; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs, Jan Kara,
	open list:EXT2 FILE SYSTEM, open list

Convert ext2 iomap_ops to the new ->iomap_next() callback. This uses the
iomap_process() helper, which finishes the previous mapping if needed
and produces the next one. No functional changes are intended.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/ext2/inode.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 29808629cce5..0693059caa35 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -860,9 +860,15 @@ ext2_iomap_end(struct inode *inode, loff_t offset, loff_t length,
 	return 0;
 }
 
+static int ext2_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+			   struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, ext2_iomap_begin,
+			     ext2_iomap_end);
+}
+
 const struct iomap_ops ext2_iomap_ops = {
-	.iomap_begin		= ext2_iomap_begin,
-	.iomap_end		= ext2_iomap_end,
+	.iomap_next		= ext2_iomap_next,
 };
 
 int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 10/18] block: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (8 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 09/18] ext2: " Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-01  0:55   ` Keith Busch
  2026-07-01  0:09 ` [PATCH v2 11/18] f2fs: " Joanne Koong
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs, Jens Axboe,
	open list:BLOCK LAYER, open list

Convert block iomap_ops to the new ->iomap_next() callback. This uses the
iomap_process() helper, which finishes the previous mapping if needed
and produces the next one. No functional changes are intended.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 block/fops.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/block/fops.c b/block/fops.c
index 15783a6180de..c2721e2c659b 100644
--- a/block/fops.c
+++ b/block/fops.c
@@ -453,8 +453,14 @@ static int blkdev_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
 	return 0;
 }
 
+static int blkdev_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, blkdev_iomap_begin, NULL);
+}
+
 static const struct iomap_ops blkdev_iomap_ops = {
-	.iomap_begin		= blkdev_iomap_begin,
+	.iomap_next		= blkdev_iomap_next,
 };
 
 #ifdef CONFIG_BUFFER_HEAD
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 11/18] f2fs: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (9 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 10/18] block: " Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-01  0:09 ` [PATCH v2 12/18] gfs2: " Joanne Koong
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs, Jaegeuk Kim,
	Chao Yu, open list:F2FS FILE SYSTEM, open list

Convert f2fs iomap_ops to the new ->iomap_next() callback. This uses the
iomap_process() helper, which finishes the previous mapping if needed
and produces the next one. No functional changes are intended.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/f2fs/data.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index a765fda71536..afc9b2adaa98 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -4653,6 +4653,12 @@ static int f2fs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
 	return 0;
 }
 
+static int f2fs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+			   struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, f2fs_iomap_begin, NULL);
+}
+
 const struct iomap_ops f2fs_iomap_ops = {
-	.iomap_begin	= f2fs_iomap_begin,
+	.iomap_next	= f2fs_iomap_next,
 };
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 12/18] gfs2: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (10 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 11/18] f2fs: " Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-01  0:09 ` [PATCH v2 13/18] hpfs: " Joanne Koong
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Andreas Gruenbacher, open list:GFS2 FILE SYSTEM, open list

Convert gfs2 iomap_ops to the new ->iomap_next() callback. This uses the
iomap_process() helper, which finishes the previous mapping if needed
and produces the next one. No functional changes are intended.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/gfs2/bmap.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 51ac1fd44f78..6cb1d4513882 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -1200,9 +1200,15 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length,
 	return 0;
 }
 
+static int gfs2_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+			   struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, gfs2_iomap_begin,
+			     gfs2_iomap_end);
+}
+
 const struct iomap_ops gfs2_iomap_ops = {
-	.iomap_begin = gfs2_iomap_begin,
-	.iomap_end = gfs2_iomap_end,
+	.iomap_next = gfs2_iomap_next,
 };
 
 /**
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 13/18] hpfs: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (11 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 12/18] gfs2: " Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-01  0:09 ` [PATCH v2 14/18] fuse: " Joanne Koong
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Mikulas Patocka, open list

Convert hpfs iomap_ops to the new ->iomap_next() callback. This uses the
iomap_process() helper, which finishes the previous mapping if needed
and produces the next one. No functional changes are intended.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/hpfs/file.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index 29e876705369..1df9f28fb40b 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -156,8 +156,14 @@ static int hpfs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
 	return 0;
 }
 
+static int hpfs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+			   struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, hpfs_iomap_begin, NULL);
+}
+
 static const struct iomap_ops hpfs_iomap_ops = {
-	.iomap_begin		= hpfs_iomap_begin,
+	.iomap_next		= hpfs_iomap_next,
 };
 
 static int hpfs_read_folio(struct file *file, struct folio *folio)
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 14/18] fuse: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (12 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 13/18] hpfs: " Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-01  0:09 ` [PATCH v2 15/18] exfat: " Joanne Koong
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Miklos Szeredi, German Maglione, Vivek Goyal, Stefan Hajnoczi,
	Eugenio Pérez, open list:FUSE FILESYSTEM [CORE], open list,
	open list:VIRTIO FILE SYSTEM

Convert fuse iomap_ops to the new ->iomap_next() callback. This uses the
iomap_process() helper, which finishes the previous mapping if needed
and produces the next one. No functional changes are intended.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/dax.c       | 10 ++++++++--
 fs/fuse/file.c      |  8 +++++++-
 fs/fuse/virtio_fs.c |  2 +-
 3 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/fs/fuse/dax.c b/fs/fuse/dax.c
index 8b53625ac7ab..e8d8c9f5d728 100644
--- a/fs/fuse/dax.c
+++ b/fs/fuse/dax.c
@@ -653,9 +653,15 @@ static int fuse_iomap_end(struct inode *inode, loff_t pos, loff_t length,
 	return 0;
 }
 
+static int fuse_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+			   struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, fuse_iomap_begin,
+			     fuse_iomap_end);
+}
+
 static const struct iomap_ops fuse_iomap_ops = {
-	.iomap_begin = fuse_iomap_begin,
-	.iomap_end = fuse_iomap_end,
+	.iomap_next = fuse_iomap_next,
 };
 
 static void fuse_wait_dax_page(struct inode *inode)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index e052a0d44dee..5c0d400629cc 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -890,8 +890,14 @@ static int fuse_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
 	return 0;
 }
 
+static int fuse_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+			   struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, fuse_iomap_begin, NULL);
+}
+
 static const struct iomap_ops fuse_iomap_ops = {
-	.iomap_begin	= fuse_iomap_begin,
+	.iomap_next	= fuse_iomap_next,
 };
 
 struct fuse_fill_read_data {
diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c
index df25d4faca41..84e699f88574 100644
--- a/fs/fuse/virtio_fs.c
+++ b/fs/fuse/virtio_fs.c
@@ -1024,7 +1024,7 @@ static void virtio_fs_cleanup_vqs(struct virtio_device *vdev)
 }
 
 /* Map a window offset to a page frame number.  The window offset will have
- * been produced by .iomap_begin(), which maps a file offset to a window
+ * been produced by .iomap_next(), which maps a file offset to a window
  * offset.
  */
 static long virtio_fs_direct_access(struct dax_device *dax_dev, pgoff_t pgoff,
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 15/18] exfat: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (13 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 14/18] fuse: " Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-03  1:41   ` Joanne Koong
  2026-07-01  0:09 ` [PATCH v2 16/18] iomap: remove ->iomap_begin()/->iomap_end() legacy path Joanne Koong
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs, Namjae Jeon,
	Sungjong Seo, Yuezhang Mo, open list

Convert fuse iomap_ops to the new ->iomap_next() callback. This uses the
iomap_process() helper, which finishes the previous mapping if needed
and produces the next one. No functional changes are intended.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/exfat/iomap.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/fs/exfat/iomap.c b/fs/exfat/iomap.c
index 1aac38e63fe6..8d33690a562d 100644
--- a/fs/exfat/iomap.c
+++ b/fs/exfat/iomap.c
@@ -151,8 +151,14 @@ static int exfat_write_iomap_begin(struct inode *inode, loff_t offset, loff_t le
 	return __exfat_iomap_begin(inode, offset, length, flags, iomap, true);
 }
 
+static int exfat_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap, exfat_iomap_begin, NULL);
+}
+
 const struct iomap_ops exfat_iomap_ops = {
-	.iomap_begin = exfat_iomap_begin,
+	.iomap_next = exfat_iomap_next,
 };
 
 /*
@@ -186,9 +192,15 @@ static int exfat_write_iomap_end(struct inode *inode, loff_t pos, loff_t length,
 	return written;
 }
 
+static int exfat_write_iomap_next(const struct iomap_iter *iter,
+		struct iomap *iomap, struct iomap *srcmap)
+{
+	return iomap_process(iter, iomap, srcmap,
+			exfat_write_iomap_begin, exfat_write_iomap_end);
+}
+
 const struct iomap_ops exfat_write_iomap_ops = {
-	.iomap_begin	= exfat_write_iomap_begin,
-	.iomap_end	= exfat_write_iomap_end,
+	.iomap_next	= exfat_write_iomap_next,
 };
 
 /*
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 16/18] iomap: remove ->iomap_begin()/->iomap_end() legacy path
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (14 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 15/18] exfat: " Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-02 14:04   ` Christoph Hellwig
  2026-07-02 16:51   ` Darrick J. Wong
  2026-07-01  0:09 ` [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops Joanne Koong
                   ` (2 subsequent siblings)
  18 siblings, 2 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs, open list

With all in-tree filesystems implementing ->iomap_next(), drop the
->iomap_begin()/->iomap_end() path.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/iomap/iter.c       | 87 +++++--------------------------------------
 include/linux/iomap.h |  4 +-
 2 files changed, 11 insertions(+), 80 deletions(-)

diff --git a/fs/iomap/iter.c b/fs/iomap/iter.c
index 1062e4e34c38..466c491bdef6 100644
--- a/fs/iomap/iter.c
+++ b/fs/iomap/iter.c
@@ -39,81 +39,6 @@ static inline void iomap_iter_done(struct iomap_iter *iter)
 		trace_iomap_iter_srcmap(iter->inode, &iter->srcmap);
 }
 
-static int iomap_iter_legacy(struct iomap_iter *iter, const struct iomap_ops *ops)
-{
-	bool stale = iter->iomap.flags & IOMAP_F_STALE;
-	ssize_t advanced;
-	u64 olen;
-	int ret;
-
-	trace_iomap_iter(iter, ops, _RET_IP_);
-
-	if (!iter->iomap.length)
-		goto begin;
-
-	/*
-	 * Calculate how far the iter was advanced and the original length bytes
-	 * for ->iomap_end().
-	 */
-	advanced = iter->pos - iter->iter_start_pos;
-	olen = iter->len + advanced;
-
-	if (ops->iomap_end) {
-		ret = ops->iomap_end(iter->inode, iter->iter_start_pos,
-				iomap_length_trim(iter, iter->iter_start_pos,
-						  olen),
-				advanced, iter->flags, &iter->iomap);
-		if (ret < 0 && !advanced)
-			return ret;
-	}
-
-	/* detect old return semantics where this would advance */
-	if (WARN_ON_ONCE(iter->status > 0))
-		iter->status = -EIO;
-
-	/*
-	 * Use iter->len to determine whether to continue onto the next mapping.
-	 * Explicitly terminate on error status or if the current iter has not
-	 * advanced at all (i.e. no work was done for some reason) unless the
-	 * mapping has been marked stale and needs to be reprocessed.
-	 */
-	if (iter->status < 0)
-		ret = iter->status;
-	else if (iter->len == 0 || (!advanced && !stale))
-		ret = 0;
-	else
-		ret = 1;
-	iomap_iter_clean_fbatch(iter);
-	iter->status = 0;
-	if (ret <= 0)
-		return ret;
-
-	memset(&iter->iomap, 0, sizeof(iter->iomap));
-	memset(&iter->srcmap, 0, sizeof(iter->srcmap));
-
-begin:
-	ret = ops->iomap_begin(iter->inode, iter->pos, iter->len, iter->flags,
-			       &iter->iomap, &iter->srcmap);
-	if (ret < 0)
-		return ret;
-	iomap_iter_done(iter);
-	return 1;
-}
-
-static int iomap_iter_next(struct iomap_iter *iter, const struct iomap_ops *ops)
-{
-	int ret;
-
-	trace_iomap_iter(iter, ops, _RET_IP_);
-
-	ret = ops->iomap_next(iter, &iter->iomap, &iter->srcmap);
-	iter->status = 0;
-	if (ret > 0)
-		iomap_iter_done(iter);
-
-	return ret;
-}
-
 /**
  * iomap_iter - iterate over a ranges in a file
  * @iter: iteration structue
@@ -131,10 +56,16 @@ static int iomap_iter_next(struct iomap_iter *iter, const struct iomap_ops *ops)
  */
 int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
 {
-	if (ops->iomap_next)
-		return iomap_iter_next(iter, ops);
+	int ret;
+
+	trace_iomap_iter(iter, ops, _RET_IP_);
 
-	return iomap_iter_legacy(iter, ops);
+	ret = ops->iomap_next(iter, &iter->iomap, &iter->srcmap);
+	iter->status = 0;
+	if (ret > 0)
+		iomap_iter_done(iter);
+
+	return ret;
 }
 
 /**
diff --git a/include/linux/iomap.h b/include/linux/iomap.h
index 8a78f47c557b..52d6f585b941 100644
--- a/include/linux/iomap.h
+++ b/include/linux/iomap.h
@@ -194,7 +194,7 @@ struct iomap_write_ops {
 };
 
 /*
- * Flags for iomap_begin / iomap_end.  No flag implies a read.
+ * Flags for iomap_next.  No flag implies a read.
  */
 #define IOMAP_WRITE		(1 << 0) /* writing, must allocate blocks */
 #define IOMAP_ZERO		(1 << 1) /* zeroing operation, may skip holes */
@@ -254,7 +254,7 @@ struct iomap_ops {
  *	incremental iter advance.
  * @status: Status of the most recent iteration. Zero on success or a negative
  *	errno on error.
- * @flags: Zero or more of the iomap_begin flags above.
+ * @flags: Zero or more of the iomap_next flags above.
  * @iomap: Map describing the I/O iteration
  * @srcmap: Source map for COW operations
  */
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (15 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 16/18] iomap: remove ->iomap_begin()/->iomap_end() legacy path Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-01 10:04   ` Jan Kara
                     ` (2 more replies)
  2026-07-01  0:09 ` [PATCH v2 18/18] Documentation: iomap: update docs to reflect iomap_next model Joanne Koong
  2026-07-02 13:49 ` [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Christoph Hellwig
  18 siblings, 3 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs, Jens Axboe,
	Chris Mason, David Sterba, Alexander Viro, Jan Kara, Dan Williams,
	Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu, Sandeep Dhavale, Hongbo Li,
	Chunhai Guo, Namjae Jeon, Sungjong Seo, Yuezhang Mo,
	Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
	Ritesh Harjani (IBM), Zhang Yi, Jaegeuk Kim, Miklos Szeredi,
	Andreas Gruenbacher, Mikulas Patocka, Hyunchul Lee,
	Konstantin Komarov, Carlos Maiolino, Damien Le Moal, Naohiro Aota,
	Johannes Thumshirn, open list:BLOCK LAYER, open list,
	open list:BTRFS FILE SYSTEM,
	open list:FILESYSTEM DIRECT ACCESS (DAX),
	open list:EROFS FILE SYSTEM, open list:EXT2 FILE SYSTEM,
	open list:F2FS FILE SYSTEM, open list:FUSE FILESYSTEM [CORE],
	open list:GFS2 FILE SYSTEM, open list:NTFS3 FILESYSTEM

Now that all filesystems implement ->iomap_next() and the legacy
->iomap_begin()/->iomap_end() fallback is gone, struct iomap_ops only
wraps a single iomap_next function pointer. Drop the struct entirely and
pass the iomap_next_fn directly to iomap_iter() and all the iomap/dax
entry points; filesystems pass their ->iomap_next function instead of an
ops struct.

No functional change intended.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 block/fops.c           | 10 +++-----
 fs/btrfs/direct-io.c   |  8 ++----
 fs/dax.c               | 47 ++++++++++++++++++------------------
 fs/erofs/data.c        | 24 ++++++++----------
 fs/erofs/internal.h    |  3 ++-
 fs/erofs/zmap.c        |  8 ++----
 fs/exfat/file.c        | 18 +++++++-------
 fs/exfat/inode.c       |  6 ++---
 fs/exfat/iomap.c       | 16 +++---------
 fs/exfat/iomap.h       |  6 +++--
 fs/ext2/ext2.h         |  3 ++-
 fs/ext2/file.c         |  4 +--
 fs/ext2/inode.c        |  8 ++----
 fs/ext4/ext4.h         |  6 +++--
 fs/ext4/extents.c      |  8 ++----
 fs/ext4/file.c         | 14 +++++------
 fs/ext4/inode.c        | 20 +++++----------
 fs/f2fs/data.c         |  9 +++----
 fs/f2fs/f2fs.h         |  3 ++-
 fs/f2fs/file.c         |  4 +--
 fs/fuse/dax.c          | 10 +++-----
 fs/fuse/file.c         | 10 +++-----
 fs/gfs2/aops.c         |  6 ++---
 fs/gfs2/bmap.c         | 10 +++-----
 fs/gfs2/bmap.h         |  3 ++-
 fs/gfs2/file.c         |  6 ++---
 fs/gfs2/inode.c        |  6 ++---
 fs/hpfs/file.c         |  6 +----
 fs/internal.h          |  1 -
 fs/iomap/buffered-io.c | 38 ++++++++++++++---------------
 fs/iomap/direct-io.c   |  8 +++---
 fs/iomap/fiemap.c      |  8 +++---
 fs/iomap/iter.c        |  8 +++---
 fs/iomap/seek.c        |  8 +++---
 fs/iomap/swapfile.c    |  4 +--
 fs/ntfs/aops.c         |  6 ++---
 fs/ntfs/file.c         | 24 +++++++++---------
 fs/ntfs/inode.c        |  2 +-
 fs/ntfs/iomap.c        | 42 +++++++-------------------------
 fs/ntfs/iomap.h        | 15 ++++++++----
 fs/ntfs3/file.c        | 16 ++++++------
 fs/ntfs3/inode.c       | 12 +++------
 fs/ntfs3/ntfs_fs.h     |  3 ++-
 fs/remap_range.c       |  6 ++---
 fs/xfs/xfs_aops.c      |  8 +++---
 fs/xfs/xfs_file.c      | 40 +++++++++++++++---------------
 fs/xfs/xfs_iomap.c     | 55 +++++++++---------------------------------
 fs/xfs/xfs_iomap.h     | 24 ++++++++++++------
 fs/xfs/xfs_iops.c      |  4 +--
 fs/xfs/xfs_reflink.c   |  6 ++---
 fs/zonefs/file.c       | 22 ++++++-----------
 include/linux/dax.h    | 18 ++++++--------
 include/linux/fs.h     |  7 ++++--
 include/linux/iomap.h  | 46 +++++++++++++++--------------------
 54 files changed, 302 insertions(+), 411 deletions(-)

diff --git a/block/fops.c b/block/fops.c
index c2721e2c659b..9ccec477f90d 100644
--- a/block/fops.c
+++ b/block/fops.c
@@ -459,10 +459,6 @@ static int blkdev_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
 	return iomap_process(iter, iomap, srcmap, blkdev_iomap_begin, NULL);
 }
 
-static const struct iomap_ops blkdev_iomap_ops = {
-	.iomap_next		= blkdev_iomap_next,
-};
-
 #ifdef CONFIG_BUFFER_HEAD
 static int blkdev_get_block(struct inode *inode, sector_t iblock,
 		struct buffer_head *bh, int create)
@@ -516,13 +512,13 @@ const struct address_space_operations def_blk_aops = {
 #else /* CONFIG_BUFFER_HEAD */
 static int blkdev_read_folio(struct file *file, struct folio *folio)
 {
-	iomap_bio_read_folio(folio, &blkdev_iomap_ops);
+	iomap_bio_read_folio(folio, blkdev_iomap_next);
 	return 0;
 }
 
 static void blkdev_readahead(struct readahead_control *rac)
 {
-	iomap_bio_readahead(rac, &blkdev_iomap_ops);
+	iomap_bio_readahead(rac, blkdev_iomap_next);
 }
 
 static ssize_t blkdev_writeback_range(struct iomap_writepage_ctx *wpc,
@@ -713,7 +709,7 @@ blkdev_direct_write(struct kiocb *iocb, struct iov_iter *from)
 
 static ssize_t blkdev_buffered_write(struct kiocb *iocb, struct iov_iter *from)
 {
-	return iomap_file_buffered_write(iocb, from, &blkdev_iomap_ops, NULL,
+	return iomap_file_buffered_write(iocb, from, blkdev_iomap_next, NULL,
 			NULL);
 }
 
diff --git a/fs/btrfs/direct-io.c b/fs/btrfs/direct-io.c
index 46dd72982fba..f1feeb68642d 100644
--- a/fs/btrfs/direct-io.c
+++ b/fs/btrfs/direct-io.c
@@ -805,10 +805,6 @@ static int btrfs_dio_iomap_next(const struct iomap_iter *iter,
 			     btrfs_dio_iomap_end);
 }
 
-static const struct iomap_ops btrfs_dio_iomap_ops = {
-	.iomap_next             = btrfs_dio_iomap_next,
-};
-
 static const struct iomap_dio_ops btrfs_dio_ops = {
 	.submit_io		= btrfs_dio_submit_io,
 	.bio_set		= &btrfs_dio_bioset,
@@ -819,7 +815,7 @@ static ssize_t btrfs_dio_read(struct kiocb *iocb, struct iov_iter *iter,
 {
 	struct btrfs_dio_data data = { 0 };
 
-	return iomap_dio_rw(iocb, iter, &btrfs_dio_iomap_ops, &btrfs_dio_ops,
+	return iomap_dio_rw(iocb, iter, btrfs_dio_iomap_next, &btrfs_dio_ops,
 			    IOMAP_DIO_PARTIAL | IOMAP_DIO_FSBLOCK_ALIGNED, &data, done_before);
 }
 
@@ -828,7 +824,7 @@ static struct iomap_dio *btrfs_dio_write(struct kiocb *iocb, struct iov_iter *it
 {
 	struct btrfs_dio_data data = { 0 };
 
-	return __iomap_dio_rw(iocb, iter, &btrfs_dio_iomap_ops, &btrfs_dio_ops,
+	return __iomap_dio_rw(iocb, iter, btrfs_dio_iomap_next, &btrfs_dio_ops,
 			    IOMAP_DIO_PARTIAL | IOMAP_DIO_FSBLOCK_ALIGNED, &data, done_before);
 }
 
diff --git a/fs/dax.c b/fs/dax.c
index 6d175cd47a99..c0a6b87dc052 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -1492,7 +1492,7 @@ static int dax_unshare_iter(struct iomap_iter *iter)
 }
 
 int dax_file_unshare(struct inode *inode, loff_t pos, loff_t len,
-		const struct iomap_ops *ops)
+		iomap_next_fn iomap_next)
 {
 	struct iomap_iter iter = {
 		.inode		= inode,
@@ -1506,7 +1506,7 @@ int dax_file_unshare(struct inode *inode, loff_t pos, loff_t len,
 		return 0;
 
 	iter.len = min(len, size - pos);
-	while ((ret = iomap_iter(&iter, ops)) > 0)
+	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
 		iter.status = dax_unshare_iter(&iter);
 	return ret;
 }
@@ -1584,7 +1584,7 @@ static int dax_zero_iter(struct iomap_iter *iter, bool *did_zero)
 }
 
 int dax_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
-		const struct iomap_ops *ops)
+		iomap_next_fn iomap_next)
 {
 	struct iomap_iter iter = {
 		.inode		= inode,
@@ -1594,14 +1594,14 @@ int dax_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
 	};
 	int ret;
 
-	while ((ret = iomap_iter(&iter, ops)) > 0)
+	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
 		iter.status = dax_zero_iter(&iter, did_zero);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(dax_zero_range);
 
 int dax_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
-		const struct iomap_ops *ops)
+		iomap_next_fn iomap_next)
 {
 	unsigned int blocksize = i_blocksize(inode);
 	unsigned int off = pos & (blocksize - 1);
@@ -1609,7 +1609,7 @@ int dax_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
 	/* Block boundary? Nothing to do */
 	if (!off)
 		return 0;
-	return dax_zero_range(inode, pos, blocksize - off, did_zero, ops);
+	return dax_zero_range(inode, pos, blocksize - off, did_zero, iomap_next);
 }
 EXPORT_SYMBOL_GPL(dax_truncate_page);
 
@@ -1734,7 +1734,7 @@ static int dax_iomap_iter(struct iomap_iter *iomi, struct iov_iter *iter)
  * dax_iomap_rw - Perform I/O to a DAX file
  * @iocb:	The control block for this I/O
  * @iter:	The addresses to do I/O from or to
- * @ops:	iomap ops passed from the file system
+ * @iomap_next: iomap_next callback passed from the file system
  *
  * This function performs read and write operations to directly mapped
  * persistent memory.  The callers needs to take care of read/write exclusion
@@ -1742,7 +1742,7 @@ static int dax_iomap_iter(struct iomap_iter *iomi, struct iov_iter *iter)
  */
 ssize_t
 dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
-		const struct iomap_ops *ops)
+		iomap_next_fn iomap_next)
 {
 	struct iomap_iter iomi = {
 		.inode		= iocb->ki_filp->f_mapping->host,
@@ -1769,7 +1769,7 @@ dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
 	if (iocb->ki_flags & IOCB_NOWAIT)
 		iomi.flags |= IOMAP_NOWAIT;
 
-	while ((ret = iomap_iter(&iomi, ops)) > 0)
+	while ((ret = iomap_iter(&iomi, iomap_next)) > 0)
 		iomi.status = dax_iomap_iter(&iomi, iter);
 
 	done = iomi.pos - iocb->ki_pos;
@@ -1897,7 +1897,7 @@ static vm_fault_t dax_fault_iter(struct vm_fault *vmf,
 }
 
 static vm_fault_t dax_iomap_pte_fault(struct vm_fault *vmf, unsigned long *pfnp,
-			       int *iomap_errp, const struct iomap_ops *ops)
+			       int *iomap_errp, iomap_next_fn iomap_next)
 {
 	struct address_space *mapping = vmf->vma->vm_file->f_mapping;
 	XA_STATE(xas, &mapping->i_pages, vmf->pgoff);
@@ -1942,7 +1942,7 @@ static vm_fault_t dax_iomap_pte_fault(struct vm_fault *vmf, unsigned long *pfnp,
 		goto unlock_entry;
 	}
 
-	while ((error = iomap_iter(&iter, ops)) > 0) {
+	while ((error = iomap_iter(&iter, iomap_next)) > 0) {
 		if (WARN_ON_ONCE(iomap_length(&iter) < PAGE_SIZE)) {
 			iter.status = -EIO;	/* fs corruption? */
 			continue;
@@ -2007,7 +2007,7 @@ static bool dax_fault_check_fallback(struct vm_fault *vmf, struct xa_state *xas,
 }
 
 static vm_fault_t dax_iomap_pmd_fault(struct vm_fault *vmf, unsigned long *pfnp,
-			       const struct iomap_ops *ops)
+			       iomap_next_fn iomap_next)
 {
 	struct address_space *mapping = vmf->vma->vm_file->f_mapping;
 	XA_STATE_ORDER(xas, &mapping->i_pages, vmf->pgoff, PMD_ORDER);
@@ -2064,7 +2064,7 @@ static vm_fault_t dax_iomap_pmd_fault(struct vm_fault *vmf, unsigned long *pfnp,
 	}
 
 	iter.pos = (loff_t)xas.xa_index << PAGE_SHIFT;
-	while (iomap_iter(&iter, ops) > 0) {
+	while (iomap_iter(&iter, iomap_next) > 0) {
 		if (iomap_length(&iter) < PMD_SIZE)
 			continue; /* actually breaks out of the loop */
 
@@ -2086,7 +2086,7 @@ static vm_fault_t dax_iomap_pmd_fault(struct vm_fault *vmf, unsigned long *pfnp,
 }
 #else
 static vm_fault_t dax_iomap_pmd_fault(struct vm_fault *vmf, unsigned long *pfnp,
-			       const struct iomap_ops *ops)
+			       iomap_next_fn iomap_next)
 {
 	return VM_FAULT_FALLBACK;
 }
@@ -2098,7 +2098,7 @@ static vm_fault_t dax_iomap_pmd_fault(struct vm_fault *vmf, unsigned long *pfnp,
  * @order: Order of the page to fault in
  * @pfnp: PFN to insert for synchronous faults if fsync is required
  * @iomap_errp: Storage for detailed error code in case of error
- * @ops: Iomap ops passed from the file system
+ * @iomap_next: iomap_next callback passed from the file system
  *
  * When a page fault occurs, filesystems may call this helper in
  * their fault handler for DAX files. dax_iomap_fault() assumes the caller
@@ -2107,12 +2107,12 @@ static vm_fault_t dax_iomap_pmd_fault(struct vm_fault *vmf, unsigned long *pfnp,
  */
 vm_fault_t dax_iomap_fault(struct vm_fault *vmf, unsigned int order,
 			unsigned long *pfnp, int *iomap_errp,
-			const struct iomap_ops *ops)
+			iomap_next_fn iomap_next)
 {
 	if (order == 0)
-		return dax_iomap_pte_fault(vmf, pfnp, iomap_errp, ops);
+		return dax_iomap_pte_fault(vmf, pfnp, iomap_errp, iomap_next);
 	else if (order == PMD_ORDER)
-		return dax_iomap_pmd_fault(vmf, pfnp, ops);
+		return dax_iomap_pmd_fault(vmf, pfnp, iomap_next);
 	else
 		return VM_FAULT_FALLBACK;
 }
@@ -2240,7 +2240,7 @@ static int dax_range_compare_iter(struct iomap_iter *it_src,
 
 int dax_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
 		struct inode *dst, loff_t dstoff, loff_t len, bool *same,
-		const struct iomap_ops *ops)
+		iomap_next_fn iomap_next)
 {
 	struct iomap_iter src_iter = {
 		.inode		= src,
@@ -2256,8 +2256,8 @@ int dax_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
 	};
 	int ret, status;
 
-	while ((ret = iomap_iter(&src_iter, ops)) > 0 &&
-	       (ret = iomap_iter(&dst_iter, ops)) > 0) {
+	while ((ret = iomap_iter(&src_iter, iomap_next)) > 0 &&
+	       (ret = iomap_iter(&dst_iter, iomap_next)) > 0) {
 		status = dax_range_compare_iter(&src_iter, &dst_iter,
 				min(src_iter.len, dst_iter.len), same);
 		if (status < 0)
@@ -2270,9 +2270,10 @@ int dax_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
 int dax_remap_file_range_prep(struct file *file_in, loff_t pos_in,
 			      struct file *file_out, loff_t pos_out,
 			      loff_t *len, unsigned int remap_flags,
-			      const struct iomap_ops *ops)
+			      iomap_next_fn iomap_next)
 {
 	return __generic_remap_file_range_prep(file_in, pos_in, file_out,
-					       pos_out, len, remap_flags, ops);
+					       pos_out, len, remap_flags,
+					       iomap_next);
 }
 EXPORT_SYMBOL_GPL(dax_remap_file_range_prep);
diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index 47dba61ec576..f6fe8c7eaf6d 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -387,10 +387,6 @@ static int erofs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
 			     erofs_iomap_end);
 }
 
-static const struct iomap_ops erofs_iomap_ops = {
-	.iomap_next = erofs_iomap_next,
-};
-
 int erofs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 		 u64 start, u64 len)
 {
@@ -398,9 +394,9 @@ int erofs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 		if (!IS_ENABLED(CONFIG_EROFS_FS_ZIP))
 			return -EOPNOTSUPP;
 		return iomap_fiemap(inode, fieinfo, start, len,
-				    &z_erofs_iomap_report_ops);
+				    z_erofs_iomap_next_report);
 	}
-	return iomap_fiemap(inode, fieinfo, start, len, &erofs_iomap_ops);
+	return iomap_fiemap(inode, fieinfo, start, len, erofs_iomap_next);
 }
 
 /*
@@ -419,7 +415,7 @@ static int erofs_read_folio(struct file *file, struct folio *folio)
 	};
 
 	trace_erofs_read_folio(iter_ctx.realinode, folio, true);
-	iomap_read_folio(&erofs_iomap_ops, &read_ctx, &iter_ctx);
+	iomap_read_folio(erofs_iomap_next, &read_ctx, &iter_ctx);
 	if (need_iput)
 		iput(iter_ctx.realinode);
 	return 0;
@@ -438,14 +434,14 @@ static void erofs_readahead(struct readahead_control *rac)
 
 	trace_erofs_readahead(iter_ctx.realinode, readahead_index(rac),
 			      readahead_count(rac), true);
-	iomap_readahead(&erofs_iomap_ops, &read_ctx, &iter_ctx);
+	iomap_readahead(erofs_iomap_next, &read_ctx, &iter_ctx);
 	if (need_iput)
 		iput(iter_ctx.realinode);
 }
 
 static sector_t erofs_bmap(struct address_space *mapping, sector_t block)
 {
-	return iomap_bmap(mapping, block, &erofs_iomap_ops);
+	return iomap_bmap(mapping, block, erofs_iomap_next);
 }
 
 static ssize_t erofs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
@@ -457,14 +453,14 @@ static ssize_t erofs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 		return 0;
 
 	if (IS_ENABLED(CONFIG_FS_DAX) && IS_DAX(inode))
-		return dax_iomap_rw(iocb, to, &erofs_iomap_ops);
+		return dax_iomap_rw(iocb, to, erofs_iomap_next);
 
 	if ((iocb->ki_flags & IOCB_DIRECT) && inode->i_sb->s_bdev) {
 		struct erofs_iomap_iter_ctx iter_ctx = {
 			.realinode = inode,
 		};
 
-		return iomap_dio_rw(iocb, to, &erofs_iomap_ops,
+		return iomap_dio_rw(iocb, to, erofs_iomap_next,
 				    NULL, 0, &iter_ctx, 0);
 	}
 	return filemap_read(iocb, to, 0);
@@ -484,7 +480,7 @@ const struct address_space_operations erofs_aops = {
 static vm_fault_t erofs_dax_huge_fault(struct vm_fault *vmf,
 		unsigned int order)
 {
-	return dax_iomap_fault(vmf, order, NULL, NULL, &erofs_iomap_ops);
+	return dax_iomap_fault(vmf, order, NULL, NULL, erofs_iomap_next);
 }
 
 static vm_fault_t erofs_dax_fault(struct vm_fault *vmf)
@@ -516,12 +512,12 @@ static int erofs_file_mmap_prepare(struct vm_area_desc *desc)
 static loff_t erofs_file_llseek(struct file *file, loff_t offset, int whence)
 {
 	struct inode *inode = file->f_mapping->host;
-	const struct iomap_ops *ops = &erofs_iomap_ops;
+	iomap_next_fn ops = erofs_iomap_next;
 
 	if (erofs_inode_is_data_compressed(EROFS_I(inode)->datalayout)) {
 		if (!IS_ENABLED(CONFIG_EROFS_FS_ZIP))
 			return generic_file_llseek(file, offset, whence);
-		ops = &z_erofs_iomap_report_ops;
+		ops = z_erofs_iomap_next_report;
 	}
 
 	if (whence == SEEK_HOLE)
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index 580f8d9f14e7..72ccd6f335b8 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -397,7 +397,8 @@ extern const struct file_operations erofs_file_fops;
 extern const struct file_operations erofs_dir_fops;
 extern const struct file_operations erofs_ishare_fops;
 
-extern const struct iomap_ops z_erofs_iomap_report_ops;
+int z_erofs_iomap_next_report(const struct iomap_iter *iter,
+		struct iomap *iomap, struct iomap *srcmap);
 
 void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf,
 			  erofs_off_t *offset, int *lengthp);
diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
index dd058413a0b6..59054eecd69e 100644
--- a/fs/erofs/zmap.c
+++ b/fs/erofs/zmap.c
@@ -821,13 +821,9 @@ static int z_erofs_iomap_begin_report(struct inode *inode, loff_t offset,
 	return 0;
 }
 
-static int z_erofs_iomap_next_report(const struct iomap_iter *iter,
-				     struct iomap *iomap, struct iomap *srcmap)
+int z_erofs_iomap_next_report(const struct iomap_iter *iter,
+			      struct iomap *iomap, struct iomap *srcmap)
 {
 	return iomap_process(iter, iomap, srcmap, z_erofs_iomap_begin_report,
 			     NULL);
 }
-
-const struct iomap_ops z_erofs_iomap_report_ops = {
-	.iomap_next = z_erofs_iomap_next_report,
-};
diff --git a/fs/exfat/file.c b/fs/exfat/file.c
index 5fc13378d35f..c05849d305ae 100644
--- a/fs/exfat/file.c
+++ b/fs/exfat/file.c
@@ -668,7 +668,7 @@ static int exfat_extend_valid_size(struct inode *inode, loff_t new_valid_size)
 
 		ret = iomap_zero_range(inode, old_valid_size,
 				new_valid_size - old_valid_size, NULL,
-				&exfat_write_iomap_ops, NULL, NULL);
+				exfat_write_iomap_next, NULL, NULL);
 		if (ret) {
 			truncate_setsize(inode, old_valid_size);
 			exfat_truncate(inode);
@@ -687,7 +687,7 @@ static ssize_t exfat_fallback_buffered_write(struct kiocb *iocb,
 
 	iocb->ki_flags &= ~IOCB_DIRECT;
 
-	written = iomap_file_buffered_write(iocb, from, &exfat_write_iomap_ops,
+	written = iomap_file_buffered_write(iocb, from, exfat_write_iomap_next,
 			NULL, NULL);
 	if (written < 0)
 		return written;
@@ -709,7 +709,7 @@ static ssize_t exfat_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
 	ssize_t ret;
 
-	ret = iomap_dio_rw(iocb, from, &exfat_write_iomap_ops,
+	ret = iomap_dio_rw(iocb, from, exfat_write_iomap_next,
 			&exfat_write_dio_ops, 0, NULL, 0);
 	if (ret == -ENOTBLK)
 		ret = 0;
@@ -773,7 +773,7 @@ static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter)
 		ret = exfat_dio_write_iter(iocb, iter);
 	else
 		ret = iomap_file_buffered_write(iocb, iter,
-				&exfat_write_iomap_ops, NULL, NULL);
+				exfat_write_iomap_next, NULL, NULL);
 	if (ret < 0)
 		goto unlock;
 
@@ -809,7 +809,7 @@ static ssize_t exfat_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
 
 	if (iocb->ki_flags & IOCB_DIRECT) {
 		file_accessed(iocb->ki_filp);
-		ret = iomap_dio_rw(iocb, iter, &exfat_iomap_ops, NULL, 0,
+		ret = iomap_dio_rw(iocb, iter, exfat_iomap_next, NULL, 0,
 				NULL, 0);
 	} else {
 		ret = generic_file_read_iter(iocb, iter);
@@ -850,7 +850,7 @@ static vm_fault_t exfat_page_mkwrite(struct vm_fault *vmf)
 			 */
 			err = iomap_zero_range(inode, ei->zeroed_size,
 					mmap_valid_size - ei->zeroed_size, NULL,
-					&exfat_iomap_ops, NULL, NULL);
+					exfat_iomap_next, NULL, NULL);
 			if (err < 0) {
 				inode_unlock(inode);
 				return vmf_fs_error(err);
@@ -866,7 +866,7 @@ static vm_fault_t exfat_page_mkwrite(struct vm_fault *vmf)
 	file_update_time(vmf->vma->vm_file);
 
 	filemap_invalidate_lock_shared(inode->i_mapping);
-	ret = iomap_page_mkwrite(vmf, &exfat_write_iomap_ops, NULL);
+	ret = iomap_page_mkwrite(vmf, exfat_write_iomap_next, NULL);
 	filemap_invalidate_unlock_shared(inode->i_mapping);
 	sb_end_pagefault(inode->i_sb);
 	inode_unlock(inode);
@@ -939,12 +939,12 @@ static loff_t exfat_file_llseek(struct file *file, loff_t offset, int whence)
 	switch (whence) {
 	case SEEK_HOLE:
 		inode_lock_shared(inode);
-		offset = iomap_seek_hole(inode, offset, &exfat_iomap_ops);
+		offset = iomap_seek_hole(inode, offset, exfat_iomap_next);
 		inode_unlock_shared(inode);
 		break;
 	case SEEK_DATA:
 		inode_lock_shared(inode);
-		offset = iomap_seek_data(inode, offset, &exfat_iomap_ops);
+		offset = iomap_seek_data(inode, offset, exfat_iomap_next);
 		inode_unlock_shared(inode);
 		break;
 	default:
diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
index 89826aea5e1e..a6b9aa2ad792 100644
--- a/fs/exfat/inode.c
+++ b/fs/exfat/inode.c
@@ -248,7 +248,7 @@ static int exfat_read_folio(struct file *file, struct folio *folio)
 		.ops = &exfat_iomap_bio_read_ops,
 	};
 
-	iomap_read_folio(&exfat_iomap_ops, &ctx, NULL);
+	iomap_read_folio(exfat_iomap_next, &ctx, NULL);
 	return 0;
 }
 
@@ -269,7 +269,7 @@ static void exfat_readahead(struct readahead_control *rac)
 	    ei->valid_size < pos + readahead_length(rac))
 		return;
 
-	iomap_readahead(&exfat_iomap_ops, &ctx, NULL);
+	iomap_readahead(exfat_iomap_next, &ctx, NULL);
 }
 
 static int exfat_writepages(struct address_space *mapping,
@@ -293,7 +293,7 @@ static sector_t exfat_aop_bmap(struct address_space *mapping, sector_t block)
 
 	/* exfat_get_cluster() assumes the requested blocknr isn't truncated. */
 	down_read(&EXFAT_I(mapping->host)->truncate_lock);
-	blocknr = iomap_bmap(mapping, block, &exfat_iomap_ops);
+	blocknr = iomap_bmap(mapping, block, exfat_iomap_next);
 	up_read(&EXFAT_I(mapping->host)->truncate_lock);
 	return blocknr;
 }
diff --git a/fs/exfat/iomap.c b/fs/exfat/iomap.c
index 8d33690a562d..6120e0758f7b 100644
--- a/fs/exfat/iomap.c
+++ b/fs/exfat/iomap.c
@@ -151,16 +151,12 @@ static int exfat_write_iomap_begin(struct inode *inode, loff_t offset, loff_t le
 	return __exfat_iomap_begin(inode, offset, length, flags, iomap, true);
 }
 
-static int exfat_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+int exfat_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
 		struct iomap *srcmap)
 {
 	return iomap_process(iter, iomap, srcmap, exfat_iomap_begin, NULL);
 }
 
-const struct iomap_ops exfat_iomap_ops = {
-	.iomap_next = exfat_iomap_next,
-};
-
 /*
  * exfat_write_iomap_end - Update the state after write
  *
@@ -192,17 +188,13 @@ static int exfat_write_iomap_end(struct inode *inode, loff_t pos, loff_t length,
 	return written;
 }
 
-static int exfat_write_iomap_next(const struct iomap_iter *iter,
-		struct iomap *iomap, struct iomap *srcmap)
+int exfat_write_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap)
 {
 	return iomap_process(iter, iomap, srcmap,
 			exfat_write_iomap_begin, exfat_write_iomap_end);
 }
 
-const struct iomap_ops exfat_write_iomap_ops = {
-	.iomap_next	= exfat_write_iomap_next,
-};
-
 /*
  * exfat_writeback_range - Map folio during writeback
  *
@@ -279,5 +271,5 @@ const struct iomap_read_ops exfat_iomap_bio_read_ops = {
 int exfat_iomap_swap_activate(struct swap_info_struct *sis,
 			       struct file *file, sector_t *span)
 {
-	return iomap_swapfile_activate(sis, file, span, &exfat_iomap_ops);
+	return iomap_swapfile_activate(sis, file, span, exfat_iomap_next);
 }
diff --git a/fs/exfat/iomap.h b/fs/exfat/iomap.h
index fd8a913f7794..47d7b753735e 100644
--- a/fs/exfat/iomap.h
+++ b/fs/exfat/iomap.h
@@ -7,8 +7,10 @@
 #define _LINUX_EXFAT_IOMAP_H
 
 extern const struct iomap_dio_ops exfat_write_dio_ops;
-extern const struct iomap_ops exfat_iomap_ops;
-extern const struct iomap_ops exfat_write_iomap_ops;
+int exfat_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap);
+int exfat_write_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap);
 extern const struct iomap_writeback_ops exfat_writeback_ops;
 extern const struct iomap_read_ops exfat_iomap_bio_read_ops;
 
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 79f7b395258c..59ef8b898940 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -780,7 +780,8 @@ extern const struct file_operations ext2_file_operations;
 /* inode.c */
 extern void ext2_set_file_ops(struct inode *inode);
 extern const struct address_space_operations ext2_aops;
-extern const struct iomap_ops ext2_iomap_ops;
+int ext2_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap);
 
 /* namei.c */
 extern const struct inode_operations ext2_dir_inode_operations;
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 8dca9ec4cacd..1fc00ad77517 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -70,7 +70,7 @@ static ssize_t ext2_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
 
 	trace_ext2_dio_read_begin(iocb, to, 0);
 	inode_lock_shared(inode);
-	ret = iomap_dio_rw(iocb, to, &ext2_iomap_ops, NULL, 0, NULL, 0);
+	ret = iomap_dio_rw(iocb, to, ext2_iomap_next, NULL, 0, NULL, 0);
 	inode_unlock_shared(inode);
 	trace_ext2_dio_read_end(iocb, to, ret);
 
@@ -134,7 +134,7 @@ static ssize_t ext2_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
 	   (!IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(from), blocksize)))
 		flags |= IOMAP_DIO_FORCE_WAIT;
 
-	ret = iomap_dio_rw(iocb, from, &ext2_iomap_ops, &ext2_dio_write_ops,
+	ret = iomap_dio_rw(iocb, from, ext2_iomap_next, &ext2_dio_write_ops,
 			   flags, NULL, 0);
 
 	/* ENOTBLK is magic return value for fallback to buffered-io */
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 0693059caa35..74d5be85341d 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -860,17 +860,13 @@ ext2_iomap_end(struct inode *inode, loff_t offset, loff_t length,
 	return 0;
 }
 
-static int ext2_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+int ext2_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
 			   struct iomap *srcmap)
 {
 	return iomap_process(iter, iomap, srcmap, ext2_iomap_begin,
 			     ext2_iomap_end);
 }
 
-const struct iomap_ops ext2_iomap_ops = {
-	.iomap_next		= ext2_iomap_next,
-};
-
 int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 		u64 start, u64 len)
 {
@@ -888,7 +884,7 @@ int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 	if (i_size == 0)
 		i_size = 1;
 	len = min_t(u64, len, i_size);
-	ret = iomap_fiemap(inode, fieinfo, start, len, &ext2_iomap_ops);
+	ret = iomap_fiemap(inode, fieinfo, start, len, ext2_iomap_next);
 	inode_unlock(inode);
 
 	return ret;
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index b37c136ea3ab..755fde1baf03 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -4004,8 +4004,10 @@ static inline void ext4_clear_io_unwritten_flag(ext4_io_end_t *io_end)
 		io_end->flag &= ~EXT4_IO_END_UNWRITTEN;
 }
 
-extern const struct iomap_ops ext4_iomap_ops;
-extern const struct iomap_ops ext4_iomap_report_ops;
+int ext4_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap);
+int ext4_iomap_next_report(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap);
 
 static inline int ext4_buffer_uptodate(struct buffer_head *bh)
 {
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 431298eca7e8..aa3c5c0915c0 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -5177,10 +5177,6 @@ static int ext4_iomap_xattr_next(const struct iomap_iter *iter,
 	return iomap_process(iter, iomap, srcmap, ext4_iomap_xattr_begin, NULL);
 }
 
-static const struct iomap_ops ext4_iomap_xattr_ops = {
-	.iomap_next		= ext4_iomap_xattr_next,
-};
-
 static int ext4_fiemap_check_ranges(struct inode *inode, u64 start, u64 *len)
 {
 	u64 maxbytes = ext4_get_maxbytes(inode);
@@ -5223,10 +5219,10 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 	if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) {
 		fieinfo->fi_flags &= ~FIEMAP_FLAG_XATTR;
 		error = iomap_fiemap(inode, fieinfo, start, len,
-				     &ext4_iomap_xattr_ops);
+				     ext4_iomap_xattr_next);
 	} else {
 		error = iomap_fiemap(inode, fieinfo, start, len,
-				     &ext4_iomap_report_ops);
+				     ext4_iomap_next_report);
 	}
 unlock:
 	inode_unlock_shared(inode);
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index eb1a323962b1..dbe073e181a7 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -91,7 +91,7 @@ static ssize_t ext4_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
 		return generic_file_read_iter(iocb, to);
 	}
 
-	ret = iomap_dio_rw(iocb, to, &ext4_iomap_ops, NULL, 0, NULL, 0);
+	ret = iomap_dio_rw(iocb, to, ext4_iomap_next, NULL, 0, NULL, 0);
 	inode_unlock_shared(inode);
 
 	file_accessed(iocb->ki_filp);
@@ -119,7 +119,7 @@ static ssize_t ext4_dax_read_iter(struct kiocb *iocb, struct iov_iter *to)
 		/* Fallback to buffered IO in case we cannot support DAX */
 		return generic_file_read_iter(iocb, to);
 	}
-	ret = dax_iomap_rw(iocb, to, &ext4_iomap_ops);
+	ret = dax_iomap_rw(iocb, to, ext4_iomap_next);
 	inode_unlock_shared(inode);
 
 	file_accessed(iocb->ki_filp);
@@ -589,7 +589,7 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
 			goto out;
 	}
 
-	ret = iomap_dio_rw(iocb, from, &ext4_iomap_ops, &ext4_dio_write_ops,
+	ret = iomap_dio_rw(iocb, from, ext4_iomap_next, &ext4_dio_write_ops,
 			   dio_flags, NULL, 0);
 	if (ret == -ENOTBLK)
 		ret = 0;
@@ -688,7 +688,7 @@ ext4_dax_write_iter(struct kiocb *iocb, struct iov_iter *from)
 		ext4_journal_stop(handle);
 	}
 
-	ret = dax_iomap_rw(iocb, from, &ext4_iomap_ops);
+	ret = dax_iomap_rw(iocb, from, ext4_iomap_next);
 
 	if (extend) {
 		ret = ext4_handle_inode_extension(inode, offset, ret, count);
@@ -776,7 +776,7 @@ static vm_fault_t ext4_dax_huge_fault(struct vm_fault *vmf, unsigned int order)
 	} else {
 		filemap_invalidate_lock_shared(mapping);
 	}
-	result = dax_iomap_fault(vmf, order, &pfn, &error, &ext4_iomap_ops);
+	result = dax_iomap_fault(vmf, order, &pfn, &error, ext4_iomap_next);
 	if (write) {
 		ext4_journal_stop(handle);
 
@@ -955,13 +955,13 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int whence)
 	case SEEK_HOLE:
 		inode_lock_shared(inode);
 		offset = iomap_seek_hole(inode, offset,
-					 &ext4_iomap_report_ops);
+					 ext4_iomap_next_report);
 		inode_unlock_shared(inode);
 		break;
 	case SEEK_DATA:
 		inode_lock_shared(inode);
 		offset = iomap_seek_data(inode, offset,
-					 &ext4_iomap_report_ops);
+					 ext4_iomap_next_report);
 		inode_unlock_shared(inode);
 		break;
 	}
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index cf7aa8275651..4c30dd8dbec7 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3391,7 +3391,7 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block)
 		filemap_write_and_wait(mapping);
 	}
 
-	ret = iomap_bmap(mapping, block, &ext4_iomap_ops);
+	ret = iomap_bmap(mapping, block, ext4_iomap_next);
 
 out:
 	inode_unlock_shared(inode);
@@ -3850,16 +3850,12 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
 	return 0;
 }
 
-static int ext4_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+int ext4_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
 			   struct iomap *srcmap)
 {
 	return iomap_process(iter, iomap, srcmap, ext4_iomap_begin, NULL);
 }
 
-const struct iomap_ops ext4_iomap_ops = {
-	.iomap_next		= ext4_iomap_next,
-};
-
 static int ext4_iomap_begin_report(struct inode *inode, loff_t offset,
 				   loff_t length, unsigned int flags,
 				   struct iomap *iomap, struct iomap *srcmap)
@@ -3911,17 +3907,13 @@ static int ext4_iomap_begin_report(struct inode *inode, loff_t offset,
 	return 0;
 }
 
-static int ext4_iomap_next_report(const struct iomap_iter *iter,
-				  struct iomap *iomap, struct iomap *srcmap)
+int ext4_iomap_next_report(const struct iomap_iter *iter, struct iomap *iomap,
+			   struct iomap *srcmap)
 {
 	return iomap_process(iter, iomap, srcmap, ext4_iomap_begin_report,
 			     NULL);
 }
 
-const struct iomap_ops ext4_iomap_report_ops = {
-	.iomap_next = ext4_iomap_next_report,
-};
-
 /*
  * For data=journal mode, folio should be marked dirty only when it was
  * writeably mapped. When that happens, it was already attached to the
@@ -3957,7 +3949,7 @@ static int ext4_iomap_swap_activate(struct swap_info_struct *sis,
 				    struct file *file, sector_t *span)
 {
 	return iomap_swapfile_activate(sis, file, span,
-				       &ext4_iomap_report_ops);
+				       ext4_iomap_next_report);
 }
 
 static const struct address_space_operations ext4_aops = {
@@ -4204,7 +4196,7 @@ static int ext4_block_zero_range(struct inode *inode,
 
 	if (IS_DAX(inode)) {
 		return dax_zero_range(inode, from, length, did_zero,
-				      &ext4_iomap_ops);
+				      ext4_iomap_next);
 	} else if (ext4_should_journal_data(inode)) {
 		return ext4_block_journalled_zero_range(inode, from, length,
 							did_zero);
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index afc9b2adaa98..9c281336c9b3 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -4171,6 +4171,7 @@ static bool f2fs_dirty_data_folio(struct address_space *mapping,
 }
 
 
+
 static sector_t f2fs_bmap_compress(struct inode *inode, sector_t block)
 {
 #ifdef CONFIG_F2FS_FS_COMPRESSION
@@ -4653,12 +4654,8 @@ static int f2fs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
 	return 0;
 }
 
-static int f2fs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
-			   struct iomap *srcmap)
+int f2fs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		    struct iomap *srcmap)
 {
 	return iomap_process(iter, iomap, srcmap, f2fs_iomap_begin, NULL);
 }
-
-const struct iomap_ops f2fs_iomap_ops = {
-	.iomap_next	= f2fs_iomap_next,
-};
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 8f3e632f315c..946a91834aec 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -4216,7 +4216,8 @@ int f2fs_init_post_read_processing(void);
 void f2fs_destroy_post_read_processing(void);
 int f2fs_init_wq(struct f2fs_sb_info *sbi);
 void f2fs_destroy_wq(struct f2fs_sb_info *sbi);
-extern const struct iomap_ops f2fs_iomap_ops;
+int f2fs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		    struct iomap *srcmap);
 
 /*
  * gc.c
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 4b52c56d71f0..74514b117257 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -4884,7 +4884,7 @@ static ssize_t f2fs_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
 	 * F2FS_DIO_READ counter will be decremented correctly in all cases.
 	 */
 	inc_page_count(sbi, F2FS_DIO_READ);
-	dio = __iomap_dio_rw(iocb, to, &f2fs_iomap_ops,
+	dio = __iomap_dio_rw(iocb, to, f2fs_iomap_next,
 			     &f2fs_iomap_dio_read_ops, 0, NULL, 0);
 	if (IS_ERR_OR_NULL(dio)) {
 		ret = PTR_ERR_OR_ZERO(dio);
@@ -5220,7 +5220,7 @@ static ssize_t f2fs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from,
 	dio_flags = 0;
 	if (pos + count > inode->i_size)
 		dio_flags |= IOMAP_DIO_FORCE_WAIT;
-	dio = __iomap_dio_rw(iocb, from, &f2fs_iomap_ops,
+	dio = __iomap_dio_rw(iocb, from, f2fs_iomap_next,
 			     &f2fs_iomap_dio_write_ops, dio_flags, iocb, 0);
 	if (IS_ERR_OR_NULL(dio)) {
 		ret = PTR_ERR_OR_ZERO(dio);
diff --git a/fs/fuse/dax.c b/fs/fuse/dax.c
index e8d8c9f5d728..a6e9721552ba 100644
--- a/fs/fuse/dax.c
+++ b/fs/fuse/dax.c
@@ -660,10 +660,6 @@ static int fuse_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
 			     fuse_iomap_end);
 }
 
-static const struct iomap_ops fuse_iomap_ops = {
-	.iomap_next = fuse_iomap_next,
-};
-
 static void fuse_wait_dax_page(struct inode *inode)
 {
 	filemap_invalidate_unlock(inode->i_mapping);
@@ -691,7 +687,7 @@ ssize_t fuse_dax_read_iter(struct kiocb *iocb, struct iov_iter *to)
 		inode_lock_shared(inode);
 	}
 
-	ret = dax_iomap_rw(iocb, to, &fuse_iomap_ops);
+	ret = dax_iomap_rw(iocb, to, fuse_iomap_next);
 	inode_unlock_shared(inode);
 
 	/* TODO file_accessed(iocb->f_filp) */
@@ -746,7 +742,7 @@ ssize_t fuse_dax_write_iter(struct kiocb *iocb, struct iov_iter *from)
 	if (file_extending_write(iocb, from))
 		ret = fuse_dax_direct_write(iocb, from);
 	else
-		ret = dax_iomap_rw(iocb, from, &fuse_iomap_ops);
+		ret = dax_iomap_rw(iocb, from, fuse_iomap_next);
 
 out:
 	inode_unlock(inode);
@@ -781,7 +777,7 @@ static vm_fault_t __fuse_dax_fault(struct vm_fault *vmf, unsigned int order,
 	 * to populate page cache or access memory we are trying to free.
 	 */
 	filemap_invalidate_lock_shared(inode->i_mapping);
-	ret = dax_iomap_fault(vmf, order, &pfn, &error, &fuse_iomap_ops);
+	ret = dax_iomap_fault(vmf, order, &pfn, &error, fuse_iomap_next);
 	if ((ret & VM_FAULT_ERROR) && error == -EAGAIN) {
 		error = 0;
 		retry = true;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 5c0d400629cc..b3e95a28623d 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -896,10 +896,6 @@ static int fuse_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
 	return iomap_process(iter, iomap, srcmap, fuse_iomap_begin, NULL);
 }
 
-static const struct iomap_ops fuse_iomap_ops = {
-	.iomap_next	= fuse_iomap_next,
-};
-
 struct fuse_fill_read_data {
 	struct file *file;
 
@@ -1020,7 +1016,7 @@ static int fuse_read_folio(struct file *file, struct folio *folio)
 		return -EIO;
 	}
 
-	iomap_read_folio(&fuse_iomap_ops, &ctx, NULL);
+	iomap_read_folio(fuse_iomap_next, &ctx, NULL);
 	fuse_invalidate_atime(inode);
 	return 0;
 }
@@ -1121,7 +1117,7 @@ static void fuse_readahead(struct readahead_control *rac)
 	if (fuse_is_bad(inode))
 		return;
 
-	iomap_readahead(&fuse_iomap_ops, &ctx, NULL);
+	iomap_readahead(fuse_iomap_next, &ctx, NULL);
 }
 
 static ssize_t fuse_cache_read_iter(struct kiocb *iocb, struct iov_iter *to)
@@ -1553,7 +1549,7 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
 		 * and granular dirty tracking for large folios.
 		 */
 		written = iomap_file_buffered_write(iocb, from,
-						    &fuse_iomap_ops,
+						    fuse_iomap_next,
 						    &fuse_iomap_write_ops,
 						    file);
 	} else {
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 0a7b8076af3a..66bc19c011cc 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -425,7 +425,7 @@ static int gfs2_read_folio(struct file *file, struct folio *folio)
 
 	if (!gfs2_is_jdata(ip) ||
 	    (i_blocksize(inode) == PAGE_SIZE && !folio_buffers(folio))) {
-		iomap_bio_read_folio(folio, &gfs2_iomap_ops);
+		iomap_bio_read_folio(folio, gfs2_iomap_next);
 	} else if (gfs2_is_stuffed(ip)) {
 		error = stuffed_read_folio(ip, folio);
 	} else {
@@ -500,7 +500,7 @@ static void gfs2_readahead(struct readahead_control *rac)
 	else if (gfs2_is_jdata(ip))
 		mpage_readahead(rac, gfs2_block_map);
 	else
-		iomap_bio_readahead(rac, &gfs2_iomap_ops);
+		iomap_bio_readahead(rac, gfs2_iomap_next);
 }
 
 /**
@@ -571,7 +571,7 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock)
 		return 0;
 
 	if (!gfs2_is_stuffed(ip))
-		dblock = iomap_bmap(mapping, lblock, &gfs2_iomap_ops);
+		dblock = iomap_bmap(mapping, lblock, gfs2_iomap_next);
 
 	gfs2_glock_dq_uninit(&i_gh);
 
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 6cb1d4513882..1b96f5622be6 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -1200,17 +1200,13 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length,
 	return 0;
 }
 
-static int gfs2_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
-			   struct iomap *srcmap)
+int gfs2_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		    struct iomap *srcmap)
 {
 	return iomap_process(iter, iomap, srcmap, gfs2_iomap_begin,
 			     gfs2_iomap_end);
 }
 
-const struct iomap_ops gfs2_iomap_ops = {
-	.iomap_next = gfs2_iomap_next,
-};
-
 /**
  * gfs2_block_map - Map one or more blocks of an inode to a disk block
  * @inode: The inode
@@ -1324,7 +1320,7 @@ static int gfs2_block_zero_range(struct inode *inode, loff_t from, loff_t length
 	if (from >= inode->i_size)
 		return 0;
 	length = min(length, inode->i_size - from);
-	return iomap_zero_range(inode, from, length, NULL, &gfs2_iomap_ops,
+	return iomap_zero_range(inode, from, length, NULL, gfs2_iomap_next,
 			&gfs2_iomap_write_ops, NULL);
 }
 
diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h
index e3d6efdfd890..2c2b7ab39259 100644
--- a/fs/gfs2/bmap.h
+++ b/fs/gfs2/bmap.h
@@ -43,7 +43,8 @@ static inline void gfs2_write_calc_reserv(const struct gfs2_inode *ip,
 	}
 }
 
-extern const struct iomap_ops gfs2_iomap_ops;
+int gfs2_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap);
 extern const struct iomap_write_ops gfs2_iomap_write_ops;
 extern const struct iomap_writeback_ops gfs2_writeback_ops;
 
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index b8c10de113ba..ef5f521a46c0 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -844,7 +844,7 @@ static ssize_t gfs2_file_direct_read(struct kiocb *iocb, struct iov_iter *to,
 		goto out_uninit;
 	pagefault_disable();
 	to->nofault = true;
-	ret = iomap_dio_rw(iocb, to, &gfs2_iomap_ops, NULL,
+	ret = iomap_dio_rw(iocb, to, gfs2_iomap_next, NULL,
 			   IOMAP_DIO_PARTIAL, NULL, read);
 	to->nofault = false;
 	pagefault_enable();
@@ -910,7 +910,7 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from,
 		goto out_unlock;
 
 	from->nofault = true;
-	ret = iomap_dio_rw(iocb, from, &gfs2_iomap_ops, NULL,
+	ret = iomap_dio_rw(iocb, from, gfs2_iomap_next, NULL,
 			   IOMAP_DIO_PARTIAL, NULL, written);
 	from->nofault = false;
 	if (ret <= 0) {
@@ -1062,7 +1062,7 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
 		goto out_unlock;
 
 	pagefault_disable();
-	ret = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops,
+	ret = iomap_file_buffered_write(iocb, from, gfs2_iomap_next,
 			&gfs2_iomap_write_ops, NULL);
 	pagefault_enable();
 	if (ret > 0)
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 8a77794bbd4a..737a3b6c5268 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -2217,7 +2217,7 @@ static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 		goto out;
 
 	pagefault_disable();
-	ret = iomap_fiemap(inode, fieinfo, start, len, &gfs2_iomap_ops);
+	ret = iomap_fiemap(inode, fieinfo, start, len, gfs2_iomap_next);
 	pagefault_enable();
 
 	gfs2_glock_dq_uninit(&gh);
@@ -2242,7 +2242,7 @@ loff_t gfs2_seek_data(struct file *file, loff_t offset)
 	inode_lock_shared(inode);
 	ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
 	if (!ret)
-		ret = iomap_seek_data(inode, offset, &gfs2_iomap_ops);
+		ret = iomap_seek_data(inode, offset, gfs2_iomap_next);
 	gfs2_glock_dq_uninit(&gh);
 	inode_unlock_shared(inode);
 
@@ -2261,7 +2261,7 @@ loff_t gfs2_seek_hole(struct file *file, loff_t offset)
 	inode_lock_shared(inode);
 	ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
 	if (!ret)
-		ret = iomap_seek_hole(inode, offset, &gfs2_iomap_ops);
+		ret = iomap_seek_hole(inode, offset, gfs2_iomap_next);
 	gfs2_glock_dq_uninit(&gh);
 	inode_unlock_shared(inode);
 
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index 1df9f28fb40b..08d5df5fb3cf 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -162,10 +162,6 @@ static int hpfs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
 	return iomap_process(iter, iomap, srcmap, hpfs_iomap_begin, NULL);
 }
 
-static const struct iomap_ops hpfs_iomap_ops = {
-	.iomap_next		= hpfs_iomap_next,
-};
-
 static int hpfs_read_folio(struct file *file, struct folio *folio)
 {
 	return mpage_read_folio(folio, hpfs_get_block);
@@ -242,7 +238,7 @@ static int hpfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 
 	inode_lock(inode);
 	len = min_t(u64, len, i_size_read(inode));
-	ret = iomap_fiemap(inode, fieinfo, start, len, &hpfs_iomap_ops);
+	ret = iomap_fiemap(inode, fieinfo, start, len, hpfs_iomap_next);
 	inode_unlock(inode);
 
 	return ret;
diff --git a/fs/internal.h b/fs/internal.h
index 355d93f92208..19601f8406dc 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -8,7 +8,6 @@
 struct super_block;
 struct file_system_type;
 struct iomap;
-struct iomap_ops;
 struct linux_binprm;
 struct path;
 struct mount;
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index 3f0932e46fd6..0aa8abc438c1 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -626,7 +626,7 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
 	return 0;
 }
 
-void iomap_read_folio(const struct iomap_ops *ops,
+void iomap_read_folio(iomap_next_fn iomap_next,
 		struct iomap_read_folio_ctx *ctx, void *private)
 {
 	struct folio *folio = ctx->cur_folio;
@@ -650,7 +650,7 @@ void iomap_read_folio(const struct iomap_ops *ops,
 		fsverity_readahead(ctx->vi, folio->index,
 				   folio_nr_pages(folio));
 
-	while ((ret = iomap_iter(&iter, ops)) > 0) {
+	while ((ret = iomap_iter(&iter, iomap_next)) > 0) {
 		iter.status = iomap_read_folio_iter(&iter, ctx,
 				&bytes_submitted);
 		iomap_read_submit(&iter, ctx);
@@ -688,22 +688,22 @@ static int iomap_readahead_iter(struct iomap_iter *iter,
 
 /**
  * iomap_readahead - Attempt to read pages from a file.
- * @ops: The operations vector for the filesystem.
+ * @iomap_next: The iomap_next callback for the filesystem.
  * @ctx: The ctx used for issuing readahead.
  * @private: The filesystem-specific information for issuing iomap_iter.
  *
  * This function is for filesystems to call to implement their readahead
  * address_space operation.
  *
- * Context: The @ops callbacks may submit I/O (eg to read the addresses of
+ * Context: The @iomap_next callback may submit I/O (eg to read the addresses of
  * blocks from disc), and may wait for it.  The caller may be trying to
  * access a different page, and so sleeping excessively should be avoided.
  * It may allocate memory, but should avoid costly allocations.  This
  * function is called with memalloc_nofs set, so allocations will not cause
  * the filesystem to be reentered.
  */
-void iomap_readahead(const struct iomap_ops *ops,
-		struct iomap_read_folio_ctx *ctx, void *private)
+void iomap_readahead(iomap_next_fn iomap_next, struct iomap_read_folio_ctx *ctx,
+		void *private)
 {
 	struct readahead_control *rac = ctx->rac;
 	struct iomap_iter iter = {
@@ -725,7 +725,7 @@ void iomap_readahead(const struct iomap_ops *ops,
 		fsverity_readahead(ctx->vi, readahead_index(rac),
 				readahead_count(rac));
 
-	while (iomap_iter(&iter, ops) > 0) {
+	while (iomap_iter(&iter, iomap_next) > 0) {
 		iter.status = iomap_readahead_iter(&iter, ctx,
 					&cur_bytes_submitted);
 		iomap_read_submit(&iter, ctx);
@@ -1268,7 +1268,7 @@ static int iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i,
 
 ssize_t
 iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *i,
-		const struct iomap_ops *ops,
+		iomap_next_fn iomap_next,
 		const struct iomap_write_ops *write_ops, void *private)
 {
 	struct iomap_iter iter = {
@@ -1285,7 +1285,7 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *i,
 	if (iocb->ki_flags & IOCB_DONTCACHE)
 		iter.flags |= IOMAP_DONTCACHE;
 
-	while ((ret = iomap_iter(&iter, ops)) > 0)
+	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
 		iter.status = iomap_write_iter(&iter, i, write_ops);
 
 	if (unlikely(iter.pos == iocb->ki_pos))
@@ -1297,7 +1297,7 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *i,
 EXPORT_SYMBOL_GPL(iomap_file_buffered_write);
 
 int iomap_fsverity_write(struct file *file, loff_t pos, size_t length,
-		const void *buf, const struct iomap_ops *ops,
+		const void *buf, iomap_next_fn iomap_next,
 		const struct iomap_write_ops *write_ops)
 {
 	int			ret;
@@ -1314,7 +1314,7 @@ int iomap_fsverity_write(struct file *file, loff_t pos, size_t length,
 
 	iov_iter_kvec(&iiter, WRITE, &kvec, 1, length);
 
-	ret = iomap_file_buffered_write(&iocb, &iiter, ops, write_ops, NULL);
+	ret = iomap_file_buffered_write(&iocb, &iiter, iomap_next, write_ops, NULL);
 	if (ret < 0)
 		return ret;
 	return ret == length ? 0 : -EIO;
@@ -1586,7 +1586,7 @@ static int iomap_unshare_iter(struct iomap_iter *iter,
 
 int
 iomap_file_unshare(struct inode *inode, loff_t pos, loff_t len,
-		const struct iomap_ops *ops,
+		iomap_next_fn iomap_next,
 		const struct iomap_write_ops *write_ops)
 {
 	struct iomap_iter iter = {
@@ -1601,7 +1601,7 @@ iomap_file_unshare(struct inode *inode, loff_t pos, loff_t len,
 		return 0;
 
 	iter.len = min(len, size - pos);
-	while ((ret = iomap_iter(&iter, ops)) > 0)
+	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
 		iter.status = iomap_unshare_iter(&iter, write_ops);
 	return ret;
 }
@@ -1710,7 +1710,7 @@ EXPORT_SYMBOL_GPL(iomap_fill_dirty_folios);
 
 int
 iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
-		const struct iomap_ops *ops,
+		iomap_next_fn iomap_next,
 		const struct iomap_write_ops *write_ops, void *private)
 {
 	struct folio_batch fbatch;
@@ -1735,7 +1735,7 @@ iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
 	 */
 	range_dirty = filemap_range_needs_writeback(mapping, iter.pos,
 					iter.pos + iter.len - 1);
-	while ((ret = iomap_iter(&iter, ops)) > 0) {
+	while ((ret = iomap_iter(&iter, iomap_next)) > 0) {
 		const struct iomap *srcmap = iomap_iter_srcmap(&iter);
 
 		if (!(iter.iomap.flags & IOMAP_F_FOLIO_BATCH) &&
@@ -1761,7 +1761,7 @@ EXPORT_SYMBOL_GPL(iomap_zero_range);
 
 int
 iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
-		const struct iomap_ops *ops,
+		iomap_next_fn iomap_next,
 		const struct iomap_write_ops *write_ops, void *private)
 {
 	unsigned int blocksize = i_blocksize(inode);
@@ -1770,7 +1770,7 @@ iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
 	/* Block boundary? Nothing to do */
 	if (!off)
 		return 0;
-	return iomap_zero_range(inode, pos, blocksize - off, did_zero, ops,
+	return iomap_zero_range(inode, pos, blocksize - off, did_zero, iomap_next,
 			write_ops, private);
 }
 EXPORT_SYMBOL_GPL(iomap_truncate_page);
@@ -1795,7 +1795,7 @@ static int iomap_folio_mkwrite_iter(struct iomap_iter *iter,
 	return iomap_iter_advance(iter, length);
 }
 
-vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, const struct iomap_ops *ops,
+vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, iomap_next_fn iomap_next,
 		void *private)
 {
 	struct iomap_iter iter = {
@@ -1812,7 +1812,7 @@ vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, const struct iomap_ops *ops,
 		goto out_unlock;
 	iter.pos = folio_pos(folio);
 	iter.len = ret;
-	while ((ret = iomap_iter(&iter, ops)) > 0)
+	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
 		iter.status = iomap_folio_mkwrite_iter(&iter, folio);
 
 	if (ret < 0)
diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
index b485e3b191da..e299d186f743 100644
--- a/fs/iomap/direct-io.c
+++ b/fs/iomap/direct-io.c
@@ -676,7 +676,7 @@ static int iomap_dio_iter(struct iomap_iter *iter, struct iomap_dio *dio)
  */
 struct iomap_dio *
 __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
-		const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
+		iomap_next_fn iomap_next, const struct iomap_dio_ops *dops,
 		unsigned int dio_flags, void *private, size_t done_before)
 {
 	struct inode *inode = file_inode(iocb->ki_filp);
@@ -800,7 +800,7 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
 	inode_dio_begin(inode);
 
 	blk_start_plug(&plug);
-	while ((ret = iomap_iter(&iomi, ops)) > 0) {
+	while ((ret = iomap_iter(&iomi, iomap_next)) > 0) {
 		iomi.status = iomap_dio_iter(&iomi, dio);
 
 		/*
@@ -890,12 +890,12 @@ EXPORT_SYMBOL_GPL(__iomap_dio_rw);
 
 ssize_t
 iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
-		const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
+		iomap_next_fn iomap_next, const struct iomap_dio_ops *dops,
 		unsigned int dio_flags, void *private, size_t done_before)
 {
 	struct iomap_dio *dio;
 
-	dio = __iomap_dio_rw(iocb, iter, ops, dops, dio_flags, private,
+	dio = __iomap_dio_rw(iocb, iter, iomap_next, dops, dio_flags, private,
 			     done_before);
 	if (IS_ERR_OR_NULL(dio))
 		return PTR_ERR_OR_ZERO(dio);
diff --git a/fs/iomap/fiemap.c b/fs/iomap/fiemap.c
index d11dadff8286..fc488f05d8ce 100644
--- a/fs/iomap/fiemap.c
+++ b/fs/iomap/fiemap.c
@@ -56,7 +56,7 @@ static int iomap_fiemap_iter(struct iomap_iter *iter,
 }
 
 int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
-		u64 start, u64 len, const struct iomap_ops *ops)
+		u64 start, u64 len, iomap_next_fn iomap_next)
 {
 	struct iomap_iter iter = {
 		.inode		= inode,
@@ -73,7 +73,7 @@ int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
 	if (ret)
 		return ret;
 
-	while ((ret = iomap_iter(&iter, ops)) > 0)
+	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
 		iter.status = iomap_fiemap_iter(&iter, fi, &prev);
 
 	if (prev.type != IOMAP_HOLE) {
@@ -92,7 +92,7 @@ EXPORT_SYMBOL_GPL(iomap_fiemap);
 /* legacy ->bmap interface.  0 is the error return (!) */
 sector_t
 iomap_bmap(struct address_space *mapping, sector_t bno,
-		const struct iomap_ops *ops)
+		iomap_next_fn iomap_next)
 {
 	struct iomap_iter iter = {
 		.inode	= mapping->host,
@@ -107,7 +107,7 @@ iomap_bmap(struct address_space *mapping, sector_t bno,
 		return 0;
 
 	bno = 0;
-	while ((ret = iomap_iter(&iter, ops)) > 0) {
+	while ((ret = iomap_iter(&iter, iomap_next)) > 0) {
 		if (iter.iomap.type == IOMAP_MAPPED)
 			bno = iomap_sector(&iter.iomap, iter.pos) >> blkshift;
 		/* leave iter.status unset to abort loop */
diff --git a/fs/iomap/iter.c b/fs/iomap/iter.c
index 466c491bdef6..984045af310a 100644
--- a/fs/iomap/iter.c
+++ b/fs/iomap/iter.c
@@ -42,7 +42,7 @@ static inline void iomap_iter_done(struct iomap_iter *iter)
 /**
  * iomap_iter - iterate over a ranges in a file
  * @iter: iteration structue
- * @ops: iomap ops provided by the file system
+ * @iomap_next: iomap_next callback provided by the file system
  *
  * Iterate over filesystem-provided space mappings for the provided file range.
  *
@@ -54,13 +54,13 @@ static inline void iomap_iter_done(struct iomap_iter *iter)
  * of the loop body:  leave @iter.status unchanged, or set it to a negative
  * errno.
  */
-int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
+int iomap_iter(struct iomap_iter *iter, iomap_next_fn iomap_next)
 {
 	int ret;
 
-	trace_iomap_iter(iter, ops, _RET_IP_);
+	trace_iomap_iter(iter, iomap_next, _RET_IP_);
 
-	ret = ops->iomap_next(iter, &iter->iomap, &iter->srcmap);
+	ret = iomap_next(iter, &iter->iomap, &iter->srcmap);
 	iter->status = 0;
 	if (ret > 0)
 		iomap_iter_done(iter);
diff --git a/fs/iomap/seek.c b/fs/iomap/seek.c
index 6cbc587c93da..1bc5053d3fc1 100644
--- a/fs/iomap/seek.c
+++ b/fs/iomap/seek.c
@@ -27,7 +27,7 @@ static int iomap_seek_hole_iter(struct iomap_iter *iter,
 }
 
 loff_t
-iomap_seek_hole(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
+iomap_seek_hole(struct inode *inode, loff_t pos, iomap_next_fn iomap_next)
 {
 	loff_t size = i_size_read(inode);
 	struct iomap_iter iter = {
@@ -42,7 +42,7 @@ iomap_seek_hole(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
 		return -ENXIO;
 
 	iter.len = size - pos;
-	while ((ret = iomap_iter(&iter, ops)) > 0)
+	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
 		iter.status = iomap_seek_hole_iter(&iter, &pos);
 	if (ret < 0)
 		return ret;
@@ -73,7 +73,7 @@ static int iomap_seek_data_iter(struct iomap_iter *iter,
 }
 
 loff_t
-iomap_seek_data(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
+iomap_seek_data(struct inode *inode, loff_t pos, iomap_next_fn iomap_next)
 {
 	loff_t size = i_size_read(inode);
 	struct iomap_iter iter = {
@@ -88,7 +88,7 @@ iomap_seek_data(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
 		return -ENXIO;
 
 	iter.len = size - pos;
-	while ((ret = iomap_iter(&iter, ops)) > 0)
+	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
 		iter.status = iomap_seek_data_iter(&iter, &pos);
 	if (ret < 0)
 		return ret;
diff --git a/fs/iomap/swapfile.c b/fs/iomap/swapfile.c
index 0db77c449467..b8bb34deddfc 100644
--- a/fs/iomap/swapfile.c
+++ b/fs/iomap/swapfile.c
@@ -139,7 +139,7 @@ static int iomap_swapfile_iter(struct iomap_iter *iter,
  */
 int iomap_swapfile_activate(struct swap_info_struct *sis,
 		struct file *swap_file, sector_t *pagespan,
-		const struct iomap_ops *ops)
+		iomap_next_fn iomap_next)
 {
 	struct inode *inode = swap_file->f_mapping->host;
 	struct iomap_iter iter = {
@@ -163,7 +163,7 @@ int iomap_swapfile_activate(struct swap_info_struct *sis,
 	if (ret)
 		return ret;
 
-	while ((ret = iomap_iter(&iter, ops)) > 0)
+	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
 		iter.status = iomap_swapfile_iter(&iter, &iter.iomap, &isi);
 	if (ret < 0)
 		return ret;
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
index 1fbf832ad165..43ad597ed491 100644
--- a/fs/ntfs/aops.c
+++ b/fs/ntfs/aops.c
@@ -97,7 +97,7 @@ static int ntfs_read_folio(struct file *file, struct folio *folio)
 			return ntfs_read_compressed_block(folio);
 	}
 
-	iomap_read_folio(&ntfs_read_iomap_ops, &ctx, NULL);
+	iomap_read_folio(ntfs_read_iomap_next, &ctx, NULL);
 	return 0;
 }
 
@@ -238,7 +238,7 @@ static void ntfs_readahead(struct readahead_control *rac)
 	 */
 	if (!NInoNonResident(ni) || NInoCompressed(ni))
 		return;
-	iomap_readahead(&ntfs_read_iomap_ops, &ctx, NULL);
+	iomap_readahead(ntfs_read_iomap_next, &ctx, NULL);
 }
 
 static int ntfs_writepages(struct address_space *mapping,
@@ -274,7 +274,7 @@ static int ntfs_swap_activate(struct swap_info_struct *sis,
 		struct file *swap_file, sector_t *span)
 {
 	return iomap_swapfile_activate(sis, swap_file, span,
-			&ntfs_read_iomap_ops);
+			ntfs_read_iomap_next);
 }
 
 const struct address_space_operations ntfs_aops = {
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index 6a7b638e523d..a4f99128b46c 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -281,7 +281,7 @@ static int ntfs_setattr_size(struct inode *vi, struct iattr *attr)
 				round_up(old_size, PAGE_SIZE) - old_size,
 				attr->ia_size - old_size);
 		err = iomap_zero_range(vi, old_size, len,
-				NULL, &ntfs_seek_iomap_ops,
+				NULL, ntfs_seek_iomap_next,
 				&ntfs_iomap_folio_ops, NULL);
 	}
 
@@ -417,12 +417,12 @@ static loff_t ntfs_file_llseek(struct file *file, loff_t offset, int whence)
 	switch (whence) {
 	case SEEK_HOLE:
 		inode_lock_shared(inode);
-		offset = iomap_seek_hole(inode, offset, &ntfs_seek_iomap_ops);
+		offset = iomap_seek_hole(inode, offset, ntfs_seek_iomap_next);
 		inode_unlock_shared(inode);
 		break;
 	case SEEK_DATA:
 		inode_lock_shared(inode);
-		offset = iomap_seek_data(inode, offset, &ntfs_seek_iomap_ops);
+		offset = iomap_seek_data(inode, offset, ntfs_seek_iomap_next);
 		inode_unlock_shared(inode);
 		break;
 	default:
@@ -458,7 +458,7 @@ static ssize_t ntfs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 		}
 
 		file_accessed(iocb->ki_filp);
-		ret = iomap_dio_rw(iocb, to, &ntfs_read_iomap_ops, NULL, 0,
+		ret = iomap_dio_rw(iocb, to, ntfs_read_iomap_next, NULL, 0,
 				NULL, 0);
 	} else {
 		ret = generic_file_read_iter(iocb, to);
@@ -496,7 +496,7 @@ static ssize_t ntfs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
 	ssize_t ret;
 
-	ret = iomap_dio_rw(iocb, from, &ntfs_dio_iomap_ops,
+	ret = iomap_dio_rw(iocb, from, ntfs_dio_iomap_next,
 			&ntfs_write_dio_ops, 0, NULL, 0);
 	if (ret == -ENOTBLK)
 		ret = 0;
@@ -511,7 +511,7 @@ static ssize_t ntfs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
 		offset = iocb->ki_pos;
 		iocb->ki_flags &= ~IOCB_DIRECT;
 		written = iomap_file_buffered_write(iocb, from,
-				&ntfs_write_iomap_ops, &ntfs_iomap_folio_ops,
+				ntfs_write_iomap_next, &ntfs_iomap_folio_ops,
 				NULL);
 		if (written < 0) {
 			ret = written;
@@ -594,7 +594,7 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 	if (NInoNonResident(ni) && iocb->ki_flags & IOCB_DIRECT)
 		ret = ntfs_dio_write_iter(iocb, from);
 	else
-		ret = iomap_file_buffered_write(iocb, from, &ntfs_write_iomap_ops,
+		ret = iomap_file_buffered_write(iocb, from, ntfs_write_iomap_next,
 				&ntfs_iomap_folio_ops, NULL);
 out:
 	if (ret < 0 && ret != -EIOCBQUEUED) {
@@ -623,7 +623,7 @@ static vm_fault_t ntfs_filemap_page_mkwrite(struct vm_fault *vmf)
 	sb_start_pagefault(inode->i_sb);
 	file_update_time(vmf->vma->vm_file);
 
-	ret = iomap_page_mkwrite(vmf, &ntfs_page_mkwrite_iomap_ops, NULL);
+	ret = iomap_page_mkwrite(vmf, ntfs_page_mkwrite_iomap_next, NULL);
 	sb_end_pagefault(inode->i_sb);
 	return ret;
 }
@@ -670,7 +670,7 @@ static int ntfs_file_mmap_prepare(struct vm_area_desc *desc)
 static int ntfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 		u64 start, u64 len)
 {
-	return iomap_fiemap(inode, fieinfo, start, len, &ntfs_read_iomap_ops);
+	return iomap_fiemap(inode, fieinfo, start, len, ntfs_read_iomap_next);
 }
 
 static const char *ntfs_get_link(struct dentry *dentry, struct inode *inode,
@@ -911,7 +911,7 @@ static int ntfs_punch_hole(struct ntfs_inode *ni, int mode, loff_t offset,
 				   ntfs_cluster_to_bytes(vol, start_vcn + 1),
 				   end_offset);
 			err = iomap_zero_range(vi, offset, to - offset,
-					       NULL, &ntfs_seek_iomap_ops,
+					       NULL, ntfs_seek_iomap_next,
 					       &ntfs_iomap_folio_ops, NULL);
 			if (err < 0)
 				goto out;
@@ -927,7 +927,7 @@ static int ntfs_punch_hole(struct ntfs_inode *ni, int mode, loff_t offset,
 		from = ntfs_cluster_to_bytes(vol, end_vcn - 1);
 		if (from < ni->initialized_size) {
 			err = iomap_zero_range(vi, from, end_offset - from,
-					       NULL, &ntfs_seek_iomap_ops,
+					       NULL, ntfs_seek_iomap_next,
 					       &ntfs_iomap_folio_ops, NULL);
 			if (err < 0)
 				goto out;
@@ -1131,7 +1131,7 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t offset, loff_t le
 					   round_up(old_size, PAGE_SIZE) - old_size,
 					   offset - old_size);
 			err = iomap_zero_range(vi, old_size, len, NULL,
-					       &ntfs_seek_iomap_ops,
+					       ntfs_seek_iomap_next,
 					       &ntfs_iomap_folio_ops, NULL);
 		}
 		NInoSetFileNameDirty(ni);
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index c2715521e562..05132d92e87b 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -2415,7 +2415,7 @@ int ntfs_extend_initialized_size(struct inode *vi, const loff_t offset,
 	if (!NInoCompressed(ni) && old_init_size < offset) {
 		err = iomap_zero_range(vi, old_init_size,
 				       offset - old_init_size,
-				       NULL, &ntfs_seek_iomap_ops,
+				       NULL, ntfs_seek_iomap_next,
 				       &ntfs_iomap_folio_ops, NULL);
 		if (err)
 			return err;
diff --git a/fs/ntfs/iomap.c b/fs/ntfs/iomap.c
index 0f9f02e1593e..502f08f01354 100644
--- a/fs/ntfs/iomap.c
+++ b/fs/ntfs/iomap.c
@@ -277,16 +277,12 @@ static int ntfs_read_iomap_begin(struct inode *inode, loff_t offset, loff_t leng
 			srcmap, true);
 }
 
-static int ntfs_read_iomap_next(const struct iomap_iter *iter,
-		struct iomap *iomap, struct iomap *srcmap)
+int ntfs_read_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap)
 {
 	return iomap_process(iter, iomap, srcmap, ntfs_read_iomap_begin, NULL);
 }
 
-const struct iomap_ops ntfs_read_iomap_ops = {
-	.iomap_next = ntfs_read_iomap_next,
-};
-
 /*
  * Check that the cached iomap still matches the NTFS runlist before
  * iomap_zero_range() is called. if the runlist changes while iomap is
@@ -342,20 +338,12 @@ static int ntfs_zero_read_iomap_next(const struct iomap_iter *iter,
 			ntfs_zero_read_iomap_end);
 }
 
-static const struct iomap_ops ntfs_zero_read_iomap_ops = {
-	.iomap_next = ntfs_zero_read_iomap_next,
-};
-
-static int ntfs_seek_iomap_next(const struct iomap_iter *iter,
+int ntfs_seek_iomap_next(const struct iomap_iter *iter,
 		struct iomap *iomap, struct iomap *srcmap)
 {
 	return iomap_process(iter, iomap, srcmap, ntfs_seek_iomap_begin, NULL);
 }
 
-const struct iomap_ops ntfs_seek_iomap_ops = {
-	.iomap_next = ntfs_seek_iomap_next,
-};
-
 int ntfs_dio_zero_range(struct inode *inode, loff_t offset, loff_t length)
 {
 	if ((offset | length) & (SECTOR_SIZE - 1))
@@ -373,7 +361,7 @@ static int ntfs_zero_range(struct inode *inode, loff_t offset, loff_t length)
 	return iomap_zero_range(inode,
 				offset, length,
 				NULL,
-				&ntfs_zero_read_iomap_ops,
+				ntfs_zero_read_iomap_next,
 				&ntfs_zero_iomap_folio_ops,
 				NULL);
 }
@@ -782,17 +770,13 @@ static int ntfs_write_iomap_end(struct inode *inode, loff_t pos, loff_t length,
 	return written;
 }
 
-static int ntfs_write_iomap_next(const struct iomap_iter *iter,
-		struct iomap *iomap, struct iomap *srcmap)
+int ntfs_write_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap)
 {
 	return iomap_process(iter, iomap, srcmap, ntfs_write_iomap_begin,
 			ntfs_write_iomap_end);
 }
 
-const struct iomap_ops ntfs_write_iomap_ops = {
-	.iomap_next		= ntfs_write_iomap_next,
-};
-
 static int ntfs_page_mkwrite_iomap_begin(struct inode *inode, loff_t offset,
 				  loff_t length, unsigned int flags,
 				  struct iomap *iomap, struct iomap *srcmap)
@@ -801,17 +785,13 @@ static int ntfs_page_mkwrite_iomap_begin(struct inode *inode, loff_t offset,
 			NTFS_IOMAP_FLAGS_MKWRITE);
 }
 
-static int ntfs_page_mkwrite_iomap_next(const struct iomap_iter *iter,
+int ntfs_page_mkwrite_iomap_next(const struct iomap_iter *iter,
 		struct iomap *iomap, struct iomap *srcmap)
 {
 	return iomap_process(iter, iomap, srcmap, ntfs_page_mkwrite_iomap_begin,
 			ntfs_write_iomap_end);
 }
 
-const struct iomap_ops ntfs_page_mkwrite_iomap_ops = {
-	.iomap_next		= ntfs_page_mkwrite_iomap_next,
-};
-
 static int ntfs_dio_iomap_begin(struct inode *inode, loff_t offset,
 				  loff_t length, unsigned int flags,
 				  struct iomap *iomap, struct iomap *srcmap)
@@ -820,17 +800,13 @@ static int ntfs_dio_iomap_begin(struct inode *inode, loff_t offset,
 			NTFS_IOMAP_FLAGS_DIO);
 }
 
-static int ntfs_dio_iomap_next(const struct iomap_iter *iter,
-		struct iomap *iomap, struct iomap *srcmap)
+int ntfs_dio_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap)
 {
 	return iomap_process(iter, iomap, srcmap, ntfs_dio_iomap_begin,
 			ntfs_write_iomap_end);
 }
 
-const struct iomap_ops ntfs_dio_iomap_ops = {
-	.iomap_next		= ntfs_dio_iomap_next,
-};
-
 static ssize_t ntfs_writeback_range(struct iomap_writepage_ctx *wpc,
 		struct folio *folio, u64 offset, unsigned int len, u64 end_pos)
 {
diff --git a/fs/ntfs/iomap.h b/fs/ntfs/iomap.h
index 3abc1d493e91..69443de1fefd 100644
--- a/fs/ntfs/iomap.h
+++ b/fs/ntfs/iomap.h
@@ -12,11 +12,16 @@
 #include "volume.h"
 #include "inode.h"
 
-extern const struct iomap_ops ntfs_write_iomap_ops;
-extern const struct iomap_ops ntfs_read_iomap_ops;
-extern const struct iomap_ops ntfs_seek_iomap_ops;
-extern const struct iomap_ops ntfs_page_mkwrite_iomap_ops;
-extern const struct iomap_ops ntfs_dio_iomap_ops;
+int ntfs_write_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap);
+int ntfs_read_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap);
+int ntfs_seek_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap);
+int ntfs_page_mkwrite_iomap_next(const struct iomap_iter *iter,
+		struct iomap *iomap, struct iomap *srcmap);
+int ntfs_dio_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap);
 extern const struct iomap_writeback_ops ntfs_writeback_ops;
 extern const struct iomap_write_ops ntfs_iomap_folio_ops;
 extern int ntfs_dio_zero_range(struct inode *inode, loff_t offset, loff_t length);
diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
index d601f088618c..55844b42920a 100644
--- a/fs/ntfs3/file.c
+++ b/fs/ntfs3/file.c
@@ -315,7 +315,7 @@ static int ntfs_extend_initialized_size(struct file *file,
 	}
 
 	err = iomap_zero_range(inode, valid, new_valid - valid, NULL,
-			       &ntfs_iomap_ops, &ntfs_iomap_folio_ops, NULL);
+			       ntfs_iomap_next, &ntfs_iomap_folio_ops, NULL);
 	if (err) {
 		ni->i_valid = valid;
 		ntfs_inode_warn(inode,
@@ -554,7 +554,7 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
 		/* Zero head of punch. */
 		if (tmp > from) {
 			err = iomap_zero_range(inode, from, tmp - from, NULL,
-					       &ntfs_iomap_ops,
+					       ntfs_iomap_next,
 					       &ntfs_iomap_folio_ops, NULL);
 			if (err)
 				goto out;
@@ -572,7 +572,7 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
 		/* Zero tail of punch. */
 		if (vbo < end_a && end_a < end) {
 			err = iomap_zero_range(inode, end_a, end - end_a, NULL,
-					       &ntfs_iomap_ops,
+					       ntfs_iomap_next,
 					       &ntfs_iomap_folio_ops, NULL);
 			if (err)
 				goto out;
@@ -872,7 +872,7 @@ static ssize_t ntfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
 				goto out;
 		}
 
-		err = iomap_dio_rw(iocb, iter, &ntfs_iomap_ops, NULL, dio_flags,
+		err = iomap_dio_rw(iocb, iter, ntfs_iomap_next, NULL, dio_flags,
 				   NULL, 0);
 
 		if (err <= 0)
@@ -1286,7 +1286,7 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 	    !ntfs_should_use_dio(iocb, from)) {
 		iocb->ki_flags &= ~IOCB_DIRECT;
 
-		ret = iomap_file_buffered_write(iocb, from, &ntfs_iomap_ops,
+		ret = iomap_file_buffered_write(iocb, from, ntfs_iomap_next,
 						&ntfs_iomap_folio_ops, NULL);
 		inode_unlock(inode);
 
@@ -1303,7 +1303,7 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 			goto out;
 	}
 
-	ret = iomap_dio_rw(iocb, from, &ntfs_iomap_ops, NULL,
+	ret = iomap_dio_rw(iocb, from, ntfs_iomap_next, NULL,
 			   IOMAP_DIO_FORCE_WAIT, NULL, 0);
 
 	if (ret == -ENOTBLK) {
@@ -1316,7 +1316,7 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 		vbo = iocb->ki_pos;
 
 		iocb->ki_flags &= ~IOCB_DIRECT;
-		err = iomap_file_buffered_write(iocb, from, &ntfs_iomap_ops,
+		err = iomap_file_buffered_write(iocb, from, ntfs_iomap_next,
 						&ntfs_iomap_folio_ops, NULL);
 		if (err < 0) {
 			ret = err;
@@ -1465,7 +1465,7 @@ int ntfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 
 	inode_lock_shared(inode);
 
-	err = iomap_fiemap(inode, fieinfo, start, len, &ntfs_iomap_ops);
+	err = iomap_fiemap(inode, fieinfo, start, len, ntfs_iomap_next);
 
 	inode_unlock_shared(inode);
 	return err;
diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c
index c5676c51a3a4..8a454ab6ee2a 100644
--- a/fs/ntfs3/inode.c
+++ b/fs/ntfs3/inode.c
@@ -576,7 +576,7 @@ static sector_t ntfs_bmap(struct address_space *mapping, sector_t block)
 		ni_allocate_da_blocks(ni);
 	}
 
-	return iomap_bmap(mapping, block, &ntfs_iomap_ops);
+	return iomap_bmap(mapping, block, ntfs_iomap_next);
 }
 
 static void ntfs_iomap_read_end_io(struct bio *bio)
@@ -649,7 +649,7 @@ static int ntfs_read_folio(struct file *file, struct folio *folio)
 		return err;
 	}
 
-	iomap_read_folio(&ntfs_iomap_ops, &ctx, NULL);
+	iomap_read_folio(ntfs_iomap_next, &ctx, NULL);
 	return 0;
 }
 
@@ -673,7 +673,7 @@ static void ntfs_readahead(struct readahead_control *rac)
 		return;
 	}
 
-	iomap_readahead(&ntfs_iomap_ops, &ctx, NULL);
+	iomap_readahead(ntfs_iomap_next, &ctx, NULL);
 }
 
 int ntfs_set_size(struct inode *inode, u64 new_size)
@@ -2101,17 +2101,13 @@ const struct address_space_operations ntfs_aops_cmpr = {
 	.invalidate_folio = iomap_invalidate_folio,
 };
 
-static int ntfs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+int ntfs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
 			   struct iomap *srcmap)
 {
 	return iomap_process(iter, iomap, srcmap, ntfs_iomap_begin,
 			     ntfs_iomap_end);
 }
 
-const struct iomap_ops ntfs_iomap_ops = {
-	.iomap_next	= ntfs_iomap_next,
-};
-
 const struct iomap_write_ops ntfs_iomap_folio_ops = {
 	.put_folio = ntfs_iomap_put_folio,
 };
diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h
index d98d7e474476..e00dae3ce700 100644
--- a/fs/ntfs3/ntfs_fs.h
+++ b/fs/ntfs3/ntfs_fs.h
@@ -785,7 +785,8 @@ int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
 int ntfs_link_inode(struct inode *inode, struct dentry *dentry);
 int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry);
 void ntfs_evict_inode(struct inode *inode);
-extern const struct iomap_ops ntfs_iomap_ops;
+int ntfs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		    struct iomap *srcmap);
 extern const struct iomap_write_ops ntfs_iomap_folio_ops;
 extern const struct inode_operations ntfs_link_inode_operations;
 extern const struct address_space_operations ntfs_aops;
diff --git a/fs/remap_range.c b/fs/remap_range.c
index 26afbbbfb10c..3d0a355dc90e 100644
--- a/fs/remap_range.c
+++ b/fs/remap_range.c
@@ -277,7 +277,7 @@ int
 __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
 				struct file *file_out, loff_t pos_out,
 				loff_t *len, unsigned int remap_flags,
-				const struct iomap_ops *dax_read_ops)
+				iomap_next_fn dax_read_next)
 {
 	struct inode *inode_in = file_inode(file_in);
 	struct inode *inode_out = file_inode(file_out);
@@ -340,10 +340,10 @@ __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
 		if (!IS_DAX(inode_in))
 			ret = vfs_dedupe_file_range_compare(file_in, pos_in,
 					file_out, pos_out, *len, &is_same);
-		else if (dax_read_ops)
+		else if (dax_read_next)
 			ret = dax_dedupe_file_range_compare(inode_in, pos_in,
 					inode_out, pos_out, *len, &is_same,
-					dax_read_ops);
+					dax_read_next);
 		else
 			return -EINVAL;
 		if (ret)
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 2a0c54256e93..91480cb6a4d8 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -752,7 +752,7 @@ xfs_vm_bmap(
 	 */
 	if (xfs_is_cow_inode(ip) || XFS_IS_REALTIME_INODE(ip))
 		return 0;
-	return iomap_bmap(mapping, block, &xfs_read_iomap_ops);
+	return iomap_bmap(mapping, block, xfs_read_iomap_next);
 }
 
 static void
@@ -793,7 +793,7 @@ xfs_vm_read_folio(
 	struct iomap_read_folio_ctx	ctx = { .cur_folio = folio };
 
 	ctx.ops = xfs_get_iomap_read_ops(folio->mapping);
-	iomap_read_folio(&xfs_read_iomap_ops, &ctx, NULL);
+	iomap_read_folio(xfs_read_iomap_next, &ctx, NULL);
 	return 0;
 }
 
@@ -804,7 +804,7 @@ xfs_vm_readahead(
 	struct iomap_read_folio_ctx	ctx = { .rac = rac };
 
 	ctx.ops = xfs_get_iomap_read_ops(rac->mapping),
-	iomap_readahead(&xfs_read_iomap_ops, &ctx, NULL);
+	iomap_readahead(xfs_read_iomap_next, &ctx, NULL);
 }
 
 static int
@@ -850,7 +850,7 @@ xfs_vm_swap_activate(
 	sis->bdev = xfs_inode_buftarg(ip)->bt_bdev;
 
 	return iomap_swapfile_activate(sis, swap_file, span,
-			&xfs_read_iomap_ops);
+			xfs_read_iomap_next);
 }
 
 const struct address_space_operations xfs_address_space_operations = {
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 7f8bef1a9954..a987ffbf3c02 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -269,7 +269,7 @@ xfs_file_dio_read(
 		dio_ops = &xfs_dio_read_bounce_ops;
 		dio_flags |= IOMAP_DIO_BOUNCE;
 	}
-	ret = iomap_dio_rw(iocb, to, &xfs_read_iomap_ops, dio_ops, dio_flags,
+	ret = iomap_dio_rw(iocb, to, xfs_read_iomap_next, dio_ops, dio_flags,
 			NULL, 0);
 	xfs_iunlock(ip, XFS_IOLOCK_SHARED);
 
@@ -292,7 +292,7 @@ xfs_file_dax_read(
 	ret = xfs_ilock_iocb(iocb, XFS_IOLOCK_SHARED);
 	if (ret)
 		return ret;
-	ret = dax_iomap_rw(iocb, to, &xfs_read_iomap_ops);
+	ret = dax_iomap_rw(iocb, to, xfs_read_iomap_next);
 	xfs_iunlock(ip, XFS_IOLOCK_SHARED);
 
 	file_accessed(iocb->ki_filp);
@@ -742,7 +742,7 @@ xfs_file_dio_write_aligned(
 	struct xfs_inode	*ip,
 	struct kiocb		*iocb,
 	struct iov_iter		*from,
-	const struct iomap_ops	*ops,
+	iomap_next_fn		iomap_next,
 	const struct iomap_dio_ops *dops,
 	struct xfs_zone_alloc_ctx *ac)
 {
@@ -777,7 +777,7 @@ xfs_file_dio_write_aligned(
 	if (mapping_stable_writes(iocb->ki_filp->f_mapping))
 		dio_flags |= IOMAP_DIO_BOUNCE;
 	trace_xfs_file_direct_write(iocb, from);
-	ret = iomap_dio_rw(iocb, from, ops, dops, dio_flags, ac, 0);
+	ret = iomap_dio_rw(iocb, from, iomap_next, dops, dio_flags, ac, 0);
 out_unlock:
 	xfs_iunlock(ip, iolock);
 	return ret;
@@ -799,7 +799,7 @@ xfs_file_dio_write_zoned(
 	if (ret < 0)
 		return ret;
 	ret = xfs_file_dio_write_aligned(ip, iocb, from,
-			&xfs_zoned_direct_write_iomap_ops,
+			xfs_zoned_direct_write_iomap_next,
 			&xfs_dio_zoned_write_ops, &ac);
 	xfs_zoned_space_unreserve(ip->i_mount, &ac);
 	return ret;
@@ -824,16 +824,16 @@ xfs_file_dio_write_atomic(
 	unsigned int		iolock = XFS_IOLOCK_SHARED;
 	ssize_t			ret, ocount = iov_iter_count(from);
 	unsigned int		dio_flags = 0;
-	const struct iomap_ops	*dops;
+	iomap_next_fn		dops;
 
 	/*
 	 * HW offload should be faster, so try that first if it is already
 	 * known that the write length is not too large.
 	 */
 	if (ocount > xfs_inode_buftarg(ip)->bt_awu_max)
-		dops = &xfs_atomic_write_cow_iomap_ops;
+		dops = xfs_atomic_write_cow_iomap_next;
 	else
-		dops = &xfs_direct_write_iomap_ops;
+		dops = xfs_direct_write_iomap_next;
 
 retry:
 	ret = xfs_ilock_iocb_for_write(iocb, &iolock);
@@ -862,9 +862,9 @@ xfs_file_dio_write_atomic(
 	 * possible. The REQ_ATOMIC-based method is typically not possible if
 	 * the write spans multiple extents or the disk blocks are misaligned.
 	 */
-	if (ret == -ENOPROTOOPT && dops == &xfs_direct_write_iomap_ops) {
+	if (ret == -ENOPROTOOPT && dops == xfs_direct_write_iomap_next) {
 		xfs_iunlock(ip, iolock);
-		dops = &xfs_atomic_write_cow_iomap_ops;
+		dops = xfs_atomic_write_cow_iomap_next;
 		goto retry;
 	}
 
@@ -947,7 +947,7 @@ xfs_file_dio_write_unaligned(
 		flags |= IOMAP_DIO_BOUNCE;
 
 	trace_xfs_file_direct_write(iocb, from);
-	ret = iomap_dio_rw(iocb, from, &xfs_direct_write_iomap_ops,
+	ret = iomap_dio_rw(iocb, from, xfs_direct_write_iomap_next,
 			   &xfs_dio_write_ops, flags, NULL, 0);
 
 	/*
@@ -987,7 +987,7 @@ xfs_file_dio_write(
 	if (iocb->ki_flags & IOCB_ATOMIC)
 		return xfs_file_dio_write_atomic(ip, iocb, from);
 	return xfs_file_dio_write_aligned(ip, iocb, from,
-			&xfs_direct_write_iomap_ops, &xfs_dio_write_ops, NULL);
+			xfs_direct_write_iomap_next, &xfs_dio_write_ops, NULL);
 }
 
 static noinline ssize_t
@@ -1011,7 +1011,7 @@ xfs_file_dax_write(
 	pos = iocb->ki_pos;
 
 	trace_xfs_file_dax_write(iocb, from);
-	ret = dax_iomap_rw(iocb, from, &xfs_dax_write_iomap_ops);
+	ret = dax_iomap_rw(iocb, from, xfs_dax_write_iomap_next);
 	if (ret > 0 && iocb->ki_pos > i_size_read(inode)) {
 		i_size_write(inode, iocb->ki_pos);
 		error = xfs_setfilesize(ip, pos, ret);
@@ -1054,7 +1054,7 @@ xfs_file_buffered_write(
 
 	trace_xfs_file_buffered_write(iocb, from);
 	ret = iomap_file_buffered_write(iocb, from,
-			&xfs_buffered_write_iomap_ops, &xfs_iomap_write_ops,
+			xfs_buffered_write_iomap_next, &xfs_iomap_write_ops,
 			NULL);
 
 	/*
@@ -1135,7 +1135,7 @@ xfs_file_buffered_write_zoned(
 retry:
 	trace_xfs_file_buffered_write(iocb, from);
 	ret = iomap_file_buffered_write(iocb, from,
-			&xfs_buffered_write_iomap_ops, &xfs_iomap_write_ops,
+			xfs_buffered_write_iomap_next, &xfs_iomap_write_ops,
 			&ac);
 	if (ret == -ENOSPC && !cleared_space) {
 		/*
@@ -1856,10 +1856,10 @@ xfs_file_llseek(
 	default:
 		return generic_file_llseek(file, offset, whence);
 	case SEEK_HOLE:
-		offset = iomap_seek_hole(inode, offset, &xfs_seek_iomap_ops);
+		offset = iomap_seek_hole(inode, offset, xfs_seek_iomap_next);
 		break;
 	case SEEK_DATA:
-		offset = iomap_seek_data(inode, offset, &xfs_seek_iomap_ops);
+		offset = iomap_seek_data(inode, offset, xfs_seek_iomap_next);
 		break;
 	}
 
@@ -1883,8 +1883,8 @@ xfs_dax_fault_locked(
 	}
 	ret = dax_iomap_fault(vmf, order, &pfn, NULL,
 			(write_fault && !vmf->cow_page) ?
-				&xfs_dax_write_iomap_ops :
-				&xfs_read_iomap_ops);
+				xfs_dax_write_iomap_next :
+				xfs_read_iomap_next);
 	if (ret & VM_FAULT_NEEDDSYNC)
 		ret = dax_finish_sync_fault(vmf, order, pfn);
 	return ret;
@@ -1948,7 +1948,7 @@ __xfs_write_fault(
 	if (IS_DAX(inode))
 		ret = xfs_dax_fault_locked(vmf, order, true);
 	else
-		ret = iomap_page_mkwrite(vmf, &xfs_buffered_write_iomap_ops,
+		ret = iomap_page_mkwrite(vmf, xfs_buffered_write_iomap_next,
 				ac);
 	xfs_iunlock(ip, lock_mode);
 
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 4fa1a5c985db..71c4bb024f04 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -1037,7 +1037,7 @@ xfs_direct_write_iomap_begin(
 	return error;
 }
 
-static int
+int
 xfs_direct_write_iomap_next(
 	const struct iomap_iter *iter,
 	struct iomap		*iomap,
@@ -1047,10 +1047,6 @@ xfs_direct_write_iomap_next(
 			NULL);
 }
 
-const struct iomap_ops xfs_direct_write_iomap_ops = {
-	.iomap_next		= xfs_direct_write_iomap_next,
-};
-
 #ifdef CONFIG_XFS_RT
 /*
  * This is really simple.  The space has already been reserved before taking the
@@ -1099,7 +1095,7 @@ xfs_zoned_direct_write_iomap_begin(
 	return 0;
 }
 
-static int
+int
 xfs_zoned_direct_write_iomap_next(
 	const struct iomap_iter *iter,
 	struct iomap		*iomap,
@@ -1109,9 +1105,6 @@ xfs_zoned_direct_write_iomap_next(
 			xfs_zoned_direct_write_iomap_begin, NULL);
 }
 
-const struct iomap_ops xfs_zoned_direct_write_iomap_ops = {
-	.iomap_next		= xfs_zoned_direct_write_iomap_next,
-};
 #endif /* CONFIG_XFS_RT */
 
 #ifdef DEBUG
@@ -1294,7 +1287,7 @@ xfs_atomic_write_cow_iomap_begin(
 	return error;
 }
 
-static int
+int
 xfs_atomic_write_cow_iomap_next(
 	const struct iomap_iter *iter,
 	struct iomap		*iomap,
@@ -1304,10 +1297,6 @@ xfs_atomic_write_cow_iomap_next(
 			xfs_atomic_write_cow_iomap_begin, NULL);
 }
 
-const struct iomap_ops xfs_atomic_write_cow_iomap_ops = {
-	.iomap_next		= xfs_atomic_write_cow_iomap_next,
-};
-
 static int
 xfs_dax_write_iomap_end(
 	struct inode		*inode,
@@ -1328,7 +1317,7 @@ xfs_dax_write_iomap_end(
 	return xfs_reflink_end_cow(ip, pos, written);
 }
 
-static int
+int
 xfs_dax_write_iomap_next(
 	const struct iomap_iter *iter,
 	struct iomap		*iomap,
@@ -1338,10 +1327,6 @@ xfs_dax_write_iomap_next(
 			xfs_dax_write_iomap_end);
 }
 
-const struct iomap_ops xfs_dax_write_iomap_ops = {
-	.iomap_next	= xfs_dax_write_iomap_next,
-};
-
 /*
  * Convert a hole to a delayed allocation.
  */
@@ -2207,7 +2192,7 @@ xfs_buffered_write_iomap_end(
 	return 0;
 }
 
-static int
+int
 xfs_buffered_write_iomap_next(
 	const struct iomap_iter *iter,
 	struct iomap		*iomap,
@@ -2218,10 +2203,6 @@ xfs_buffered_write_iomap_next(
 			xfs_buffered_write_iomap_end);
 }
 
-const struct iomap_ops xfs_buffered_write_iomap_ops = {
-	.iomap_next		= xfs_buffered_write_iomap_next,
-};
-
 static int
 xfs_read_iomap_begin(
 	struct inode		*inode,
@@ -2263,7 +2244,7 @@ xfs_read_iomap_begin(
 				 shared ? IOMAP_F_SHARED : 0, seq);
 }
 
-static int
+int
 xfs_read_iomap_next(
 	const struct iomap_iter *iter,
 	struct iomap		*iomap,
@@ -2272,10 +2253,6 @@ xfs_read_iomap_next(
 	return iomap_process(iter, iomap, srcmap, xfs_read_iomap_begin, NULL);
 }
 
-const struct iomap_ops xfs_read_iomap_ops = {
-	.iomap_next		= xfs_read_iomap_next,
-};
-
 static int
 xfs_seek_iomap_begin(
 	struct inode		*inode,
@@ -2360,7 +2337,7 @@ xfs_seek_iomap_begin(
 	return error;
 }
 
-static int
+int
 xfs_seek_iomap_next(
 	const struct iomap_iter *iter,
 	struct iomap		*iomap,
@@ -2369,10 +2346,6 @@ xfs_seek_iomap_next(
 	return iomap_process(iter, iomap, srcmap, xfs_seek_iomap_begin, NULL);
 }
 
-const struct iomap_ops xfs_seek_iomap_ops = {
-	.iomap_next		= xfs_seek_iomap_next,
-};
-
 static int
 xfs_xattr_iomap_begin(
 	struct inode		*inode,
@@ -2416,7 +2389,7 @@ xfs_xattr_iomap_begin(
 	return xfs_bmbt_to_iomap(ip, iomap, &imap, flags, IOMAP_F_XATTR, seq);
 }
 
-static int
+int
 xfs_xattr_iomap_next(
 	const struct iomap_iter *iter,
 	struct iomap		*iomap,
@@ -2425,10 +2398,6 @@ xfs_xattr_iomap_next(
 	return iomap_process(iter, iomap, srcmap, xfs_xattr_iomap_begin, NULL);
 }
 
-const struct iomap_ops xfs_xattr_iomap_ops = {
-	.iomap_next		= xfs_xattr_iomap_next,
-};
-
 int
 xfs_zero_range(
 	struct xfs_inode	*ip,
@@ -2443,9 +2412,9 @@ xfs_zero_range(
 
 	if (IS_DAX(inode))
 		return dax_zero_range(inode, pos, len, did_zero,
-				      &xfs_dax_write_iomap_ops);
+				      xfs_dax_write_iomap_next);
 	return iomap_zero_range(inode, pos, len, did_zero,
-			&xfs_buffered_write_iomap_ops, &xfs_iomap_write_ops,
+			xfs_buffered_write_iomap_next, &xfs_iomap_write_ops,
 			ac);
 }
 
@@ -2460,8 +2429,8 @@ xfs_truncate_page(
 
 	if (IS_DAX(inode))
 		return dax_truncate_page(inode, pos, did_zero,
-					&xfs_dax_write_iomap_ops);
+					xfs_dax_write_iomap_next);
 	return iomap_truncate_page(inode, pos, did_zero,
-			&xfs_buffered_write_iomap_ops, &xfs_iomap_write_ops,
+			xfs_buffered_write_iomap_next, &xfs_iomap_write_ops,
 			ac);
 }
diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h
index ebcce7d49446..01875d20fb66 100644
--- a/fs/xfs/xfs_iomap.h
+++ b/fs/xfs/xfs_iomap.h
@@ -49,14 +49,22 @@ xfs_aligned_fsb_count(
 	return count_fsb;
 }
 
-extern const struct iomap_ops xfs_buffered_write_iomap_ops;
-extern const struct iomap_ops xfs_direct_write_iomap_ops;
-extern const struct iomap_ops xfs_zoned_direct_write_iomap_ops;
-extern const struct iomap_ops xfs_read_iomap_ops;
-extern const struct iomap_ops xfs_seek_iomap_ops;
-extern const struct iomap_ops xfs_xattr_iomap_ops;
-extern const struct iomap_ops xfs_dax_write_iomap_ops;
-extern const struct iomap_ops xfs_atomic_write_cow_iomap_ops;
+int xfs_buffered_write_iomap_next(const struct iomap_iter *iter,
+		struct iomap *iomap, struct iomap *srcmap);
+int xfs_direct_write_iomap_next(const struct iomap_iter *iter,
+		struct iomap *iomap, struct iomap *srcmap);
+int xfs_zoned_direct_write_iomap_next(const struct iomap_iter *iter,
+		struct iomap *iomap, struct iomap *srcmap);
+int xfs_read_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap);
+int xfs_seek_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap);
+int xfs_xattr_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap);
+int xfs_dax_write_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
+		struct iomap *srcmap);
+int xfs_atomic_write_cow_iomap_next(const struct iomap_iter *iter,
+		struct iomap *iomap, struct iomap *srcmap);
 extern const struct iomap_write_ops xfs_iomap_write_ops;
 
 #endif /* __XFS_IOMAP_H__*/
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 6339f4956ecb..5c3d9a365f93 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -1239,10 +1239,10 @@ xfs_vn_fiemap(
 	if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) {
 		fieinfo->fi_flags &= ~FIEMAP_FLAG_XATTR;
 		error = iomap_fiemap(inode, fieinfo, start, length,
-				&xfs_xattr_iomap_ops);
+				xfs_xattr_iomap_next);
 	} else {
 		error = iomap_fiemap(inode, fieinfo, start, length,
-				&xfs_read_iomap_ops);
+				xfs_read_iomap_next);
 	}
 	xfs_iunlock(XFS_I(inode), XFS_IOLOCK_SHARED);
 
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index a5c188b78138..2b9792626bab 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -1683,7 +1683,7 @@ xfs_reflink_remap_prep(
 				pos_out, len, remap_flags);
 	else
 		ret = dax_remap_file_range_prep(file_in, pos_in, file_out,
-				pos_out, len, remap_flags, &xfs_read_iomap_ops);
+				pos_out, len, remap_flags, xfs_read_iomap_next);
 	if (ret || *len == 0)
 		goto out_unlock;
 
@@ -1878,10 +1878,10 @@ xfs_reflink_unshare(
 
 	if (IS_DAX(inode))
 		error = dax_file_unshare(inode, offset, len,
-				&xfs_dax_write_iomap_ops);
+				xfs_dax_write_iomap_next);
 	else
 		error = iomap_file_unshare(inode, offset, len,
-				&xfs_buffered_write_iomap_ops,
+				xfs_buffered_write_iomap_next,
 				&xfs_iomap_write_ops);
 	if (error)
 		goto out;
diff --git a/fs/zonefs/file.c b/fs/zonefs/file.c
index a29a8756d660..3ef1a655dbfe 100644
--- a/fs/zonefs/file.c
+++ b/fs/zonefs/file.c
@@ -64,10 +64,6 @@ static int zonefs_read_iomap_next(const struct iomap_iter *iter,
 			     NULL);
 }
 
-static const struct iomap_ops zonefs_read_iomap_ops = {
-	.iomap_next	= zonefs_read_iomap_next,
-};
-
 static int zonefs_write_iomap_begin(struct inode *inode, loff_t offset,
 				    loff_t length, unsigned int flags,
 				    struct iomap *iomap, struct iomap *srcmap)
@@ -120,19 +116,15 @@ static int zonefs_write_iomap_next(const struct iomap_iter *iter,
 			     NULL);
 }
 
-static const struct iomap_ops zonefs_write_iomap_ops = {
-	.iomap_next	= zonefs_write_iomap_next,
-};
-
 static int zonefs_read_folio(struct file *unused, struct folio *folio)
 {
-	iomap_bio_read_folio(folio, &zonefs_read_iomap_ops);
+	iomap_bio_read_folio(folio, zonefs_read_iomap_next);
 	return 0;
 }
 
 static void zonefs_readahead(struct readahead_control *rac)
 {
-	iomap_bio_readahead(rac, &zonefs_read_iomap_ops);
+	iomap_bio_readahead(rac, zonefs_read_iomap_next);
 }
 
 /*
@@ -193,7 +185,7 @@ static int zonefs_swap_activate(struct swap_info_struct *sis,
 	}
 
 	return iomap_swapfile_activate(sis, swap_file, span,
-				       &zonefs_read_iomap_ops);
+				       zonefs_read_iomap_next);
 }
 
 const struct address_space_operations zonefs_file_aops = {
@@ -323,7 +315,7 @@ static vm_fault_t zonefs_filemap_page_mkwrite(struct vm_fault *vmf)
 
 	/* Serialize against truncates */
 	filemap_invalidate_lock_shared(inode->i_mapping);
-	ret = iomap_page_mkwrite(vmf, &zonefs_write_iomap_ops, NULL);
+	ret = iomap_page_mkwrite(vmf, zonefs_write_iomap_next, NULL);
 	filemap_invalidate_unlock_shared(inode->i_mapping);
 
 	sb_end_pagefault(inode->i_sb);
@@ -539,7 +531,7 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
 	 * page invalidation. Overwrite that error code with EBUSY so that
 	 * the user can make sense of the error.
 	 */
-	ret = iomap_dio_rw(iocb, from, &zonefs_write_iomap_ops,
+	ret = iomap_dio_rw(iocb, from, zonefs_write_iomap_next,
 			   &zonefs_write_dio_ops, 0, NULL, 0);
 	if (ret == -ENOTBLK)
 		ret = -EBUSY;
@@ -589,7 +581,7 @@ static ssize_t zonefs_file_buffered_write(struct kiocb *iocb,
 	if (ret <= 0)
 		goto inode_unlock;
 
-	ret = iomap_file_buffered_write(iocb, from, &zonefs_write_iomap_ops,
+	ret = iomap_file_buffered_write(iocb, from, zonefs_write_iomap_next,
 			NULL, NULL);
 	if (ret == -EIO)
 		zonefs_io_error(inode, true);
@@ -684,7 +676,7 @@ static ssize_t zonefs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 			goto inode_unlock;
 		}
 		file_accessed(iocb->ki_filp);
-		ret = iomap_dio_rw(iocb, to, &zonefs_read_iomap_ops,
+		ret = iomap_dio_rw(iocb, to, zonefs_read_iomap_next,
 				   &zonefs_read_dio_ops, 0, NULL, 0);
 	} else {
 		ret = generic_file_read_iter(iocb, to);
diff --git a/include/linux/dax.h b/include/linux/dax.h
index fe6c3ded1b50..a5a88f5186bf 100644
--- a/include/linux/dax.h
+++ b/include/linux/dax.h
@@ -3,6 +3,7 @@
 #define _LINUX_DAX_H
 
 #include <linux/fs.h>
+#include <linux/iomap.h>
 #include <linux/mm.h>
 #include <linux/radix-tree.h>
 
@@ -10,9 +11,6 @@ typedef unsigned long dax_entry_t;
 
 struct dax_device;
 struct gendisk;
-struct iomap_ops;
-struct iomap_iter;
-struct iomap;
 
 enum dax_access_mode {
 	DAX_ACCESS,
@@ -213,11 +211,11 @@ static inline void dax_unlock_mapping_entry(struct address_space *mapping,
 #endif
 
 int dax_file_unshare(struct inode *inode, loff_t pos, loff_t len,
-		const struct iomap_ops *ops);
+		iomap_next_fn iomap_next);
 int dax_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
-		const struct iomap_ops *ops);
+		iomap_next_fn iomap_next);
 int dax_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
-		const struct iomap_ops *ops);
+		iomap_next_fn iomap_next);
 
 static inline bool dax_page_is_idle(struct page *page)
 {
@@ -266,10 +264,10 @@ int dax_holder_notify_failure(struct dax_device *dax_dev, u64 off, u64 len,
 void dax_flush(struct dax_device *dax_dev, void *addr, size_t size);
 
 ssize_t dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
-		const struct iomap_ops *ops);
+		iomap_next_fn iomap_next);
 vm_fault_t dax_iomap_fault(struct vm_fault *vmf, unsigned int order,
 			unsigned long *pfnp, int *errp,
-			const struct iomap_ops *ops);
+			iomap_next_fn iomap_next);
 vm_fault_t dax_finish_sync_fault(struct vm_fault *vmf,
 		unsigned int order, unsigned long pfn);
 int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index);
@@ -288,11 +286,11 @@ void dax_break_layout_final(struct inode *inode);
 int dax_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
 				  struct inode *dest, loff_t destoff,
 				  loff_t len, bool *is_same,
-				  const struct iomap_ops *ops);
+				  iomap_next_fn iomap_next);
 int dax_remap_file_range_prep(struct file *file_in, loff_t pos_in,
 			      struct file *file_out, loff_t pos_out,
 			      loff_t *len, unsigned int remap_flags,
-			      const struct iomap_ops *ops);
+			      iomap_next_fn iomap_next);
 static inline bool dax_mapping(struct address_space *mapping)
 {
 	return mapping->host && IS_DAX(mapping->host);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index d10897b3a1e3..2eb063438a3b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -70,7 +70,8 @@ struct fsnotify_mark_connector;
 struct fs_context;
 struct fs_parameter_spec;
 struct file_kattr;
-struct iomap_ops;
+struct iomap_iter;
+struct iomap;
 struct delegated_inode;
 
 extern void __init inode_init(void);
@@ -2079,7 +2080,9 @@ int remap_verify_area(struct file *file, loff_t pos, loff_t len, bool write);
 int __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
 				    struct file *file_out, loff_t pos_out,
 				    loff_t *len, unsigned int remap_flags,
-				    const struct iomap_ops *dax_read_ops);
+				    int (*dax_read_next)(const struct iomap_iter *iter,
+							 struct iomap *iomap,
+							 struct iomap *srcmap));
 int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
 				  struct file *file_out, loff_t pos_out,
 				  loff_t *count, unsigned int remap_flags);
diff --git a/include/linux/iomap.h b/include/linux/iomap.h
index 52d6f585b941..3b41f123a92d 100644
--- a/include/linux/iomap.h
+++ b/include/linux/iomap.h
@@ -237,12 +237,6 @@ typedef int (*iomap_end_fn)(struct inode *inode, loff_t pos, loff_t length,
 typedef int (*iomap_next_fn)(const struct iomap_iter *iter, struct iomap *iomap,
 		struct iomap *srcmap);
 
-struct iomap_ops {
-	iomap_begin_fn iomap_begin;
-	iomap_end_fn iomap_end;
-	iomap_next_fn iomap_next;
-};
-
 /**
  * struct iomap_iter - Iterate through a range of a file
  * @inode: Set at the start of the iteration and should not change.
@@ -271,7 +265,7 @@ struct iomap_iter {
 	void *private;
 };
 
-int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops);
+int iomap_iter(struct iomap_iter *iter, iomap_next_fn iomap_next);
 int iomap_iter_advance(struct iomap_iter *iter, u64 count);
 
 /**
@@ -365,14 +359,14 @@ static inline bool iomap_want_unshare_iter(const struct iomap_iter *iter)
 }
 
 ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from,
-		const struct iomap_ops *ops,
+		iomap_next_fn iomap_next,
 		const struct iomap_write_ops *write_ops, void *private);
 int iomap_fsverity_write(struct file *file, loff_t pos, size_t length,
-		const void *buf, const struct iomap_ops *ops,
+		const void *buf, iomap_next_fn iomap_next,
 		const struct iomap_write_ops *write_ops);
-void iomap_read_folio(const struct iomap_ops *ops,
+void iomap_read_folio(iomap_next_fn iomap_next,
 		struct iomap_read_folio_ctx *ctx, void *private);
-void iomap_readahead(const struct iomap_ops *ops,
+void iomap_readahead(iomap_next_fn iomap_next,
 		struct iomap_read_folio_ctx *ctx, void *private);
 bool iomap_is_partially_uptodate(struct folio *, size_t from, size_t count);
 struct folio *iomap_get_folio(struct iomap_iter *iter, loff_t pos, size_t len);
@@ -380,17 +374,17 @@ bool iomap_release_folio(struct folio *folio, gfp_t gfp_flags);
 void iomap_invalidate_folio(struct folio *folio, size_t offset, size_t len);
 bool iomap_dirty_folio(struct address_space *mapping, struct folio *folio);
 int iomap_file_unshare(struct inode *inode, loff_t pos, loff_t len,
-		const struct iomap_ops *ops,
+		iomap_next_fn iomap_next,
 		const struct iomap_write_ops *write_ops);
 unsigned int iomap_fill_dirty_folios(struct iomap_iter *iter, loff_t *start,
 		loff_t end, unsigned int *iomap_flags);
 int iomap_zero_range(struct inode *inode, loff_t pos, loff_t len,
-		bool *did_zero, const struct iomap_ops *ops,
+		bool *did_zero, iomap_next_fn iomap_next,
 		const struct iomap_write_ops *write_ops, void *private);
 int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
-		const struct iomap_ops *ops,
+		iomap_next_fn iomap_next,
 		const struct iomap_write_ops *write_ops, void *private);
-vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, const struct iomap_ops *ops,
+vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, iomap_next_fn iomap_next,
 		void *private);
 typedef void (*iomap_punch_t)(struct inode *inode, loff_t offset, loff_t length,
 		struct iomap *iomap);
@@ -399,13 +393,13 @@ void iomap_write_delalloc_release(struct inode *inode, loff_t start_byte,
 		iomap_punch_t punch);
 
 int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
-		u64 start, u64 len, const struct iomap_ops *ops);
+		u64 start, u64 len, iomap_next_fn iomap_next);
 loff_t iomap_seek_hole(struct inode *inode, loff_t offset,
-		const struct iomap_ops *ops);
+		iomap_next_fn iomap_next);
 loff_t iomap_seek_data(struct inode *inode, loff_t offset,
-		const struct iomap_ops *ops);
+		iomap_next_fn iomap_next);
 sector_t iomap_bmap(struct address_space *mapping, sector_t bno,
-		const struct iomap_ops *ops);
+		iomap_next_fn iomap_next);
 
 /*
  * Flags for iomap_ioend->io_flags.
@@ -612,10 +606,10 @@ struct iomap_dio_ops {
 #define IOMAP_DIO_BOUNCE		(1 << 4)
 
 ssize_t iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
-		const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
+		iomap_next_fn iomap_next, const struct iomap_dio_ops *dops,
 		unsigned int dio_flags, void *private, size_t done_before);
 struct iomap_dio *__iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
-		const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
+		iomap_next_fn iomap_next, const struct iomap_dio_ops *dops,
 		unsigned int dio_flags, void *private, size_t done_before);
 ssize_t iomap_dio_complete(struct iomap_dio *dio);
 void iomap_dio_bio_end_io(struct bio *bio);
@@ -626,7 +620,7 @@ struct swap_info_struct;
 
 int iomap_swapfile_activate(struct swap_info_struct *sis,
 		struct file *swap_file, sector_t *pagespan,
-		const struct iomap_ops *ops);
+		iomap_next_fn iomap_next);
 #else
 # define iomap_swapfile_activate(sis, swapfile, pagespan, ops)	(-EIO)
 #endif /* CONFIG_SWAP */
@@ -640,25 +634,25 @@ int iomap_bio_read_folio_range(const struct iomap_iter *iter,
 extern const struct iomap_read_ops iomap_bio_read_ops;
 
 static inline void iomap_bio_read_folio(struct folio *folio,
-		const struct iomap_ops *ops)
+		iomap_next_fn iomap_next)
 {
 	struct iomap_read_folio_ctx ctx = {
 		.ops		= &iomap_bio_read_ops,
 		.cur_folio	= folio,
 	};
 
-	iomap_read_folio(ops, &ctx, NULL);
+	iomap_read_folio(iomap_next, &ctx, NULL);
 }
 
 static inline void iomap_bio_readahead(struct readahead_control *rac,
-		const struct iomap_ops *ops)
+		iomap_next_fn iomap_next)
 {
 	struct iomap_read_folio_ctx ctx = {
 		.ops		= &iomap_bio_read_ops,
 		.rac		= rac,
 	};
 
-	iomap_readahead(ops, &ctx, NULL);
+	iomap_readahead(iomap_next, &ctx, NULL);
 }
 #endif /* CONFIG_BLOCK */
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 18/18] Documentation: iomap: update docs to reflect iomap_next model
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (16 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops Joanne Koong
@ 2026-07-01  0:09 ` Joanne Koong
  2026-07-02 14:07   ` Christoph Hellwig
  2026-07-02 19:26   ` Darrick J. Wong
  2026-07-02 13:49 ` [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Christoph Hellwig
  18 siblings, 2 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-01  0:09 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Jonathan Corbet, Shuah Khan, open list:DOCUMENTATION, open list

Filesystems no longer pass a struct iomap_ops with separate
->iomap_begin() and ->iomap_end() callbacks.  Instead, every iomap
operation takes a single iomap_next() callback directly. iomap_next()
finishes the previous mapping (if any) and produces the next one. Most
filesystems build it from begin and end helpers via the iomap_process()
helper.

Update the iomap documentation to match this change.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 Documentation/filesystems/iomap/design.rst    | 115 +++++++++++++-----
 .../filesystems/iomap/operations.rst          |  60 +++++----
 Documentation/filesystems/iomap/porting.rst   |  22 +++-
 3 files changed, 132 insertions(+), 65 deletions(-)

diff --git a/Documentation/filesystems/iomap/design.rst b/Documentation/filesystems/iomap/design.rst
index 0f7672676c0b..7a37e303eea8 100644
--- a/Documentation/filesystems/iomap/design.rst
+++ b/Documentation/filesystems/iomap/design.rst
@@ -75,7 +75,10 @@ At a high level, an iomap operation `looks like this
 
 1. For each byte in the operation range...
 
-   1. Obtain a space mapping via ``->iomap_begin``
+   1. Obtain the next space mapping via the ``iomap_next`` callback.
+      From the second iteration onwards this same callback first finishes
+      the previous mapping (committing or unreserving space as needed)
+      and then produces the next one.
 
    2. For each sub-unit of work...
 
@@ -86,7 +89,13 @@ At a high level, an iomap operation `looks like this
 
    3. Increment operation cursor
 
-   4. Release the mapping via ``->iomap_end``, if necessary
+iomap repeats this until the range is fully consumed.  The ``iomap_next``
+callback returns ``1`` while there is more of the range left to process,
+``0`` once it is fully consumed, and a negative errno on error.
+Filesystems rarely implement ``->iomap_next`` by hand. The ``iomap_process``
+helper implements the finish-then-produce sequence in +terms of two smaller
+callbacks, ``begin`` and ``end``. See `The Mapping Callback`_ below for more
+info.
 
 Each iomap operation will be covered in more detail below.
 This library was covered previously by an `LWN article
@@ -189,7 +198,7 @@ The fields are as follows:
    * **IOMAP_DELALLOC**: A promise to allocate space at a later time
      ("delayed allocation").
      If the filesystem returns IOMAP_F_NEW here and the write fails, the
-     ``->iomap_end`` function must delete the reservation.
+     ``end`` function must delete the reservation.
      The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
 
    * **IOMAP_MAPPED**: The file range maps to specific space on the
@@ -208,12 +217,12 @@ The fields are as follows:
 
    * **IOMAP_INLINE**: The file range maps to the memory buffer
      specified by ``inline_data``.
-     For write operation, the ``->iomap_end`` function presumably
-     handles persisting the data.
+     For write operation, the ``end`` function presumably handles
+     persisting the data.
      The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
 
  * ``flags`` describe the status of the space mapping.
-   These flags should be set by the filesystem in ``->iomap_begin``:
+   These flags should be set by the filesystem in ``begin``:
 
    * **IOMAP_F_NEW**: The space under the mapping is newly allocated.
      Areas that will not be written to must be zeroed.
@@ -262,15 +271,15 @@ The fields are as follows:
      update.
 
    These flags can be set by iomap itself during file operations.
-   The filesystem should supply an ``->iomap_end`` function if it needs
+   The filesystem should supply an ``end`` function if it needs
    to observe these flags:
 
    * **IOMAP_F_SIZE_CHANGED**: The file size has changed as a result of
      using this mapping.
 
    * **IOMAP_F_STALE**: The mapping was found to be stale.
-     iomap will call ``->iomap_end`` on this mapping and then
-     ``->iomap_begin`` to obtain a new mapping.
+     iomap will call ``end`` on this mapping and then
+     ``begin`` to obtain a new mapping.
 
    Currently, these flags are only set by pagecache operations.
 
@@ -289,41 +298,80 @@ The fields are as follows:
 
  * ``private`` is a pointer to `filesystem-private information
    <https://lore.kernel.org/all/20180619164137.13720-7-hch@lst.de/>`_.
-   This value will be passed unchanged to ``->iomap_end``.
+   This value will be passed unchanged to ``end``.
 
  * ``validity_cookie`` is a magic freshness value set by the filesystem
    that should be used to detect stale mappings.
    For pagecache operations this is critical for correct operation
    because page faults can occur, which implies that filesystem locks
-   should not be held between ``->iomap_begin`` and ``->iomap_end``.
+   should not be held between ``begin`` and ``end``.
    Filesystems with completely static mappings need not set this value.
    Only pagecache operations revalidate mappings; see the section about
    ``iomap_valid`` for details.
 
-``struct iomap_ops``
+The Mapping Callback
 --------------------
 
-Every iomap function requires the filesystem to pass an operations
-structure to obtain a mapping and (optionally) to release the mapping:
+Every iomap operation takes an ``iomap_next_fn`` callback from the
+filesystem. iomap calls it once per iteration of the file range:
 
 .. code-block:: c
 
- struct iomap_ops {
-     int (*iomap_begin)(struct inode *inode, loff_t pos, loff_t length,
-                        unsigned flags, struct iomap *iomap,
-                        struct iomap *srcmap);
+ typedef int (*iomap_next_fn)(const struct iomap_iter *iter,
+                              struct iomap *iomap, struct iomap *srcmap);
 
-     int (*iomap_end)(struct inode *inode, loff_t pos, loff_t length,
-                      ssize_t written, unsigned flags,
-                      struct iomap *iomap);
- };
+``->iomap_next``
+~~~~~~~~~~~~~~~~
+
+Each call must finish the previous mapping, if any, and then produce the
+next mapping for the current iteration position described by ``iter``.
+The mapping is returned through ``iomap`` (and through ``srcmap`` for
+operations that read from one mapping while writing to another; see
+``begin`` below).
 
-``->iomap_begin``
+The callback returns ``1`` to continue iterating, ``0`` once the file
+range has been fully consumed, and a negative errno on error.
+
+``iomap_process``
 ~~~~~~~~~~~~~~~~~
 
-iomap operations call ``->iomap_begin`` to obtain one file mapping for
-the range of bytes specified by ``pos`` and ``length`` for the file
-``inode``.
+Filesystems rarely need a hand-written ``iomap_next`` callback.  The
+``iomap_process`` helper implements the finish-then-produce sequence in
+terms of two smaller callbacks, ``begin`` and ``end``, so most
+``->iomap_next`` implementations are simply:
+
+.. code-block:: c
+
+ static int my_iomap_next(const struct iomap_iter *iter,
+                          struct iomap *iomap, struct iomap *srcmap)
+ {
+         return iomap_process(iter, iomap, srcmap,
+                              my_iomap_begin, my_iomap_end);
+ }
+
+``end`` may be ``NULL`` when the filesystem has nothing to finish.
+The two callbacks have these prototypes:
+
+.. code-block:: c
+
+ typedef int (*iomap_begin_fn)(struct inode *inode, loff_t pos,
+                               loff_t length, unsigned flags,
+                               struct iomap *iomap, struct iomap *srcmap);
+
+ typedef int (*iomap_end_fn)(struct inode *inode, loff_t pos,
+                             loff_t length, ssize_t written,
+                             unsigned flags, struct iomap *iomap);
+
+``iomap_process`` is an inline helper, so when it is called with fixed
+``begin`` and ``end`` functions the compiler can inline both into the
+filesystem's ``->iomap_next``, keeping indirect calls out of the
+iteration hot path.  The two callbacks are described next.
+
+``begin``
+~~~~~~~~~
+
+The ``begin`` callback obtains one file mapping for the range of bytes
+specified by ``pos`` and ``length`` for the file ``inode``.
 This mapping should be returned through the ``iomap`` pointer.
 The mapping must cover at least the first byte of the supplied file
 range, but it does not need to cover the entire requested range.
@@ -377,18 +425,19 @@ information via ``srcmap``.
 Only pagecache and fsdax operations support reading from one mapping and
 writing to another.
 
-``->iomap_end``
-~~~~~~~~~~~~~~~
+``end``
+~~~~~~~
 
-After the operation completes, the ``->iomap_end`` function, if present,
-is called to signal that iomap is finished with a mapping.
+The ``end`` callback, if present, is called when iomap is
+finished with a mapping: before each subsequent mapping is produced, and
+once more after the final mapping when the operation completes.
 Typically, implementations will use this function to tear down any
-context that were set up in ``->iomap_begin``.
+context that was set up in ``begin``.
 For example, a write might wish to commit the reservations for the bytes
 that were operated upon and unreserve any space that was not operated
 upon.
 ``written`` might be zero if no bytes were touched.
-``flags`` will contain the same value passed to ``->iomap_begin``.
+``flags`` will contain the same value passed to ``begin``.
 iomap ops for reads are not likely to need to supply this function.
 
 Both functions should return a negative errno code on error, or zero on
@@ -421,7 +470,7 @@ iomap is concerned:
    accessing the folio until writeback is underway.
 
    * The **lower** level primitive is taken by the filesystem in the
-     ``->iomap_begin`` and ``->iomap_end`` functions to coordinate
+     ``begin`` and ``end`` functions to coordinate
      access to the file space mapping information.
      The fields of the iomap object should be filled out while holding
      this primitive.
diff --git a/Documentation/filesystems/iomap/operations.rst b/Documentation/filesystems/iomap/operations.rst
index da982ca7e413..e065398dad95 100644
--- a/Documentation/filesystems/iomap/operations.rst
+++ b/Documentation/filesystems/iomap/operations.rst
@@ -17,6 +17,12 @@ Supported File Operations
 Below are a discussion of the high level file operations that iomap
 implements.
 
+Each operation takes an ``iomap_next_fn`` callback that supplies the file
+mappings, as described in the iomap design document.  The per-operation
+``flags`` documented below are passed to that callback; references to
+``begin`` and ``end`` name the two steps a typical callback is built from
+via ``iomap_process``.
+
 Buffered I/O
 ============
 
@@ -91,9 +97,9 @@ iomap calls these functions:
     that was set up by ``->get_folio``.
 
   - ``iomap_valid``: The filesystem may not hold locks between
-    ``->iomap_begin`` and ``->iomap_end`` because pagecache operations
-    can take folio locks, fault on userspace pages, initiate writeback
-    for memory reclamation, or engage in other time-consuming actions.
+    ``begin`` and ``end`` because pagecache operations can take folio locks,
+    fault on userspace pages, initiate writeback for memory reclamation, or
+    engage in other time-consuming actions.
     If a file's space mapping data are mutable, it is possible that the
     mapping for a particular pagecache folio can `change in the time it
     takes
@@ -114,12 +120,12 @@ iomap calls these functions:
     If the mapping is not valid, the mapping will be sampled again.
 
     To support making the validity decision, the filesystem's
-    ``->iomap_begin`` function may set ``struct iomap::validity_cookie``
+    ``begin`` function may set ``struct iomap::validity_cookie``
     at the same time that it populates the other iomap fields.
     A simple validation cookie implementation is a sequence counter.
     If the filesystem bumps the sequence counter every time it modifies
     the inode's extent map, it can be placed in the ``struct
-    iomap::validity_cookie`` during ``->iomap_begin``.
+    iomap::validity_cookie`` during ``begin``.
     If the value in the cookie is found to be different to the value
     the filesystem holds when the mapping is passed back to
     ``->iomap_valid``, then the iomap should considered stale and the
@@ -199,7 +205,7 @@ Buffered Readahead and Reads
 The ``iomap_readahead`` function initiates readahead to the pagecache.
 The ``iomap_read_folio`` function reads one folio's worth of data into
 the pagecache.
-The ``flags`` argument to ``->iomap_begin`` will be set to zero.
+The ``flags`` argument to ``begin`` will be set to zero.
 The pagecache takes whatever locks it needs before calling the
 filesystem.
 
@@ -231,7 +237,7 @@ Buffered Writes
 The ``iomap_file_buffered_write`` function writes an ``iocb`` to the
 pagecache.
 ``IOMAP_WRITE`` or ``IOMAP_WRITE`` | ``IOMAP_NOWAIT`` will be passed as
-the ``flags`` argument to ``->iomap_begin``.
+the ``flags`` argument to ``begin``.
 Callers commonly take ``i_rwsem`` in either shared or exclusive mode
 before calling this function.
 
@@ -241,7 +247,7 @@ mmap Write Faults
 The ``iomap_page_mkwrite`` function handles a write fault to a folio in
 the pagecache.
 ``IOMAP_WRITE | IOMAP_FAULT`` will be passed as the ``flags`` argument
-to ``->iomap_begin``.
+to ``begin``.
 Callers commonly take the mmap ``invalidate_lock`` in shared or
 exclusive mode before calling this function.
 
@@ -256,7 +262,7 @@ such `reservations
 <https://lore.kernel.org/linux-xfs/20220817093627.GZ3600936@dread.disaster.area/>`_
 because writeback will not consume the reservation.
 The ``iomap_write_delalloc_release`` can be called from a
-``->iomap_end`` function to find all the clean areas of the folios
+``end`` function to find all the clean areas of the folios
 caching a fresh (``IOMAP_F_NEW``) delalloc mapping.
 It takes the ``invalidate_lock``.
 
@@ -274,7 +280,7 @@ Filesystems can call ``iomap_zero_range`` to perform zeroing of the
 pagecache for non-truncation file operations that are not aligned to
 the fsblock size.
 ``IOMAP_ZERO`` will be passed as the ``flags`` argument to
-``->iomap_begin``.
+``begin``.
 Callers typically hold ``i_rwsem`` and ``invalidate_lock`` in exclusive
 mode before calling this function.
 
@@ -285,7 +291,7 @@ Filesystems can call ``iomap_file_unshare`` to force a file sharing
 storage with another file to preemptively copy the shared data to newly
 allocate storage.
 ``IOMAP_WRITE | IOMAP_UNSHARE`` will be passed as the ``flags`` argument
-to ``->iomap_begin``.
+to ``begin``.
 Callers typically hold ``i_rwsem`` and ``invalidate_lock`` in exclusive
 mode before calling this function.
 
@@ -298,7 +304,7 @@ operation.
 ``truncate_setsize`` or ``truncate_pagecache`` will take care of
 everything after the EOF block.
 ``IOMAP_ZERO`` will be passed as the ``flags`` argument to
-``->iomap_begin``.
+``begin``.
 Callers typically hold ``i_rwsem`` and ``invalidate_lock`` in exclusive
 mode before calling this function.
 
@@ -341,8 +347,8 @@ The fields are as follows:
     though it will `reuse mappings
     <https://lore.kernel.org/all/20231207072710.176093-15-hch@lst.de/>`_
     for runs of contiguous dirty fsblocks within a folio.
-    Do not return ``IOMAP_INLINE`` mappings here; the ``->iomap_end``
-    function must deal with persisting written data.
+    Do not return ``IOMAP_INLINE`` mappings here; the ``end`` function must
+    deal with persisting written data.
     Do not return ``IOMAP_DELALLOC`` mappings here; iomap currently
     requires mapping to allocated space.
     Filesystems can skip a potentially expensive mapping lookup if the
@@ -428,7 +434,7 @@ writes for files.
 .. code-block:: c
 
  ssize_t iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
-                      const struct iomap_ops *ops,
+                      iomap_next_fn iomap_next,
                       const struct iomap_dio_ops *dops,
                       unsigned int dio_flags, void *private,
                       size_t done_before);
@@ -511,7 +517,7 @@ Return Values
  * ``-ENOTBLK``: Fall back to buffered I/O.
    iomap itself will return this value if it cannot invalidate the page
    cache before issuing the I/O to storage.
-   The ``->iomap_begin`` or ``->iomap_end`` functions may also return
+   The ``begin`` or ``end`` functions may also return
    this value.
 
  * ``-EIOCBQUEUED``: The asynchronous direct I/O request has been
@@ -526,7 +532,7 @@ A direct I/O read initiates a read I/O from the storage device to the
 caller's buffer.
 Dirty parts of the pagecache are flushed to storage before initiating
 the read io.
-The ``flags`` value for ``->iomap_begin`` will be ``IOMAP_DIRECT`` with
+The ``flags`` value for ``begin`` will be ``IOMAP_DIRECT`` with
 any combination of the following enhancements:
 
  * ``IOMAP_NOWAIT``, as defined previously.
@@ -542,7 +548,7 @@ caller's buffer.
 Dirty parts of the pagecache are flushed to storage before initiating
 the write io.
 The pagecache is invalidated both before and after the write io.
-The ``flags`` value for ``->iomap_begin`` will be ``IOMAP_DIRECT |
+The ``flags`` value for ``begin`` will be ``IOMAP_DIRECT |
 IOMAP_WRITE`` with any combination of the following enhancements:
 
  * ``IOMAP_NOWAIT``, as defined previously.
@@ -644,7 +650,7 @@ fsdax Reads
 
 A fsdax read performs a memcpy from storage device to the caller's
 buffer.
-The ``flags`` value for ``->iomap_begin`` will be ``IOMAP_DAX`` with any
+The ``flags`` value for ``begin`` will be ``IOMAP_DAX`` with any
 combination of the following enhancements:
 
  * ``IOMAP_NOWAIT``, as defined previously.
@@ -657,7 +663,7 @@ fsdax Writes
 
 A fsdax write initiates a memcpy to the storage device from the caller's
 buffer.
-The ``flags`` value for ``->iomap_begin`` will be ``IOMAP_DAX |
+The ``flags`` value for ``begin`` will be ``IOMAP_DAX |
 IOMAP_WRITE`` with any combination of the following enhancements:
 
  * ``IOMAP_NOWAIT``, as defined previously.
@@ -680,9 +686,9 @@ fsdax mmap Faults
 The ``dax_iomap_fault`` function handles read and write faults to fsdax
 storage.
 For a read fault, ``IOMAP_DAX | IOMAP_FAULT`` will be passed as the
-``flags`` argument to ``->iomap_begin``.
+``flags`` argument to ``begin``.
 For a write fault, ``IOMAP_DAX | IOMAP_FAULT | IOMAP_WRITE`` will be
-passed as the ``flags`` argument to ``->iomap_begin``.
+passed as the ``flags`` argument to ``begin``.
 
 Callers commonly hold the same locks as they do to call their iomap
 pagecache counterparts.
@@ -692,7 +698,7 @@ fsdax Truncation, fallocate, and Unsharing
 
 For fsdax files, the following functions are provided to replace their
 iomap pagecache I/O counterparts.
-The ``flags`` argument to ``->iomap_begin`` are the same as the
+The ``flags`` argument to ``begin`` are the same as the
 pagecache counterparts, with ``IOMAP_DAX`` added.
 
  * ``dax_file_unshare``
@@ -720,7 +726,7 @@ SEEK_DATA
 The ``iomap_seek_data`` function implements the SEEK_DATA "whence" value
 for llseek.
 ``IOMAP_REPORT`` will be passed as the ``flags`` argument to
-``->iomap_begin``.
+``begin``.
 
 For unwritten mappings, the pagecache will be searched.
 Regions of the pagecache with a folio mapped and uptodate fsblocks
@@ -735,7 +741,7 @@ SEEK_HOLE
 The ``iomap_seek_hole`` function implements the SEEK_HOLE "whence" value
 for llseek.
 ``IOMAP_REPORT`` will be passed as the ``flags`` argument to
-``->iomap_begin``.
+``begin``.
 
 For unwritten mappings, the pagecache will be searched.
 Regions of the pagecache with no folio mapped, or a !uptodate fsblock
@@ -751,7 +757,7 @@ The ``iomap_swapfile_activate`` function finds all the base-page aligned
 regions in a file and sets them up as swap space.
 The file will be ``fsync()``'d before activation.
 ``IOMAP_REPORT`` will be passed as the ``flags`` argument to
-``->iomap_begin``.
+``begin``.
 All mappings must be mapped or unwritten; cannot be dirty or shared, and
 cannot span multiple block devices.
 Callers must hold ``i_rwsem`` in exclusive mode; this is already
@@ -768,7 +774,7 @@ FS_IOC_FIEMAP
 The ``iomap_fiemap`` function exports file extent mappings to userspace
 in the format specified by the ``FS_IOC_FIEMAP`` ioctl.
 ``IOMAP_REPORT`` will be passed as the ``flags`` argument to
-``->iomap_begin``.
+``begin``.
 Callers commonly hold ``i_rwsem`` in shared mode before calling this
 function.
 
diff --git a/Documentation/filesystems/iomap/porting.rst b/Documentation/filesystems/iomap/porting.rst
index 3d49a32c0fff..3591b5f28021 100644
--- a/Documentation/filesystems/iomap/porting.rst
+++ b/Documentation/filesystems/iomap/porting.rst
@@ -50,8 +50,20 @@ Build the kernel, run fstests with the ``-g all`` option across a wide
 variety of your filesystem's supported configurations to build a
 baseline of which tests pass and which ones fail.
 
-The recommended approach is first to implement ``->iomap_begin`` (and
-``->iomap_end`` if necessary) to allow iomap to obtain a read-only
+Every iomap operation is driven by an ``iomap_next`` callback.
+Filesystems normally do not write one by hand: implement ``begin``
+(and ``end`` if necessary) and wire them up through
+``iomap_process``::
+
+ static int my_iomap_next(const struct iomap_iter *iter,
+                          struct iomap *iomap, struct iomap *srcmap)
+ {
+         return iomap_process(iter, iomap, srcmap,
+                              my_iomap_begin, my_iomap_end);
+ }
+
+The recommended approach is first to implement ``begin`` (and
+``end`` if necessary) to allow iomap to obtain a read-only
 mapping of a file range.
 In most cases, this is a relatively trivial conversion of the existing
 ``get_block()`` function for read-only mappings.
@@ -62,7 +74,7 @@ If FIEMAP is returning the correct information, it's a good sign that
 other read-only mapping operations will do the right thing.
 
 Next, modify the filesystem's ``get_block(create = false)``
-implementation to use the new ``->iomap_begin`` implementation to map
+implementation to use the new ``begin`` implementation to map
 file space for selected read operations.
 Hide behind a debugging knob the ability to switch on the iomap mapping
 functions for selected call paths.
@@ -82,14 +94,14 @@ I/O path because of bufferheads.
 The buffered read I/O paths doesn't need to be converted yet, though the
 direct I/O read path should be converted in this phase.
 
-At this point, you should look over your ``->iomap_begin`` function.
+At this point, you should look over your ``begin`` function.
 If it switches between large blocks of code based on dispatching of the
 ``flags`` argument, you should consider breaking it up into
 per-operation iomap ops with smaller, more cohesive functions.
 XFS is a good example of this.
 
 The next thing to do is implement ``get_blocks(create == true)``
-functionality in the ``->iomap_begin``/``->iomap_end`` methods.
+functionality in the ``begin``/``end`` methods.
 It is strongly recommended to create separate mapping functions and
 iomap ops for write operations.
 Then convert the direct I/O write path to iomap, and start running fsx
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 07/18] erofs: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 ` [PATCH v2 07/18] erofs: " Joanne Koong
@ 2026-07-01  0:41   ` Gao Xiang
  0 siblings, 0 replies; 53+ messages in thread
From: Gao Xiang @ 2026-07-01  0:41 UTC (permalink / raw)
  To: Joanne Koong, brauner, hch
  Cc: djwong, willy, linux-fsdevel, linux-xfs, Gao Xiang, Chao Yu,
	Yue Hu, Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
	open list:EROFS FILE SYSTEM, open list



On 2026/7/1 08:09, Joanne Koong wrote:
> Convert erofs iomap_ops to the new ->iomap_next() callback. This uses the
> iomap_process() helper, which finishes the previous mapping if needed
> and produces the next one. No functional changes are intended.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>

Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>

Thanks,
Gao Xiang

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 10/18] block: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 ` [PATCH v2 10/18] block: " Joanne Koong
@ 2026-07-01  0:55   ` Keith Busch
  2026-07-02 14:03     ` Christoph Hellwig
  2026-07-03  0:06     ` Joanne Koong
  0 siblings, 2 replies; 53+ messages in thread
From: Keith Busch @ 2026-07-01  0:55 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Jens Axboe, open list:BLOCK LAYER, open list

On Tue, Jun 30, 2026 at 05:09:25PM -0700, Joanne Koong wrote:
>  static const struct iomap_ops blkdev_iomap_ops = {
> -	.iomap_begin		= blkdev_iomap_begin,
> +	.iomap_next		= blkdev_iomap_next,
>  };

I think it's generally safe to use the same mailing list for the entire
series. There's no context here on what "iomap_next" is because I'm
subscribed only to linux-block. I found the rest here:

  https://lore.kernel.org/linux-fsdevel/20260701000949.1666714-1-joannelkoong@gmail.com/

FWIW, everything looks good to me.

Reviewed-by: Keith Busch <kbusch@kernel.org>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 06/18] ext4: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 ` [PATCH v2 06/18] ext4: " Joanne Koong
@ 2026-07-01 10:01   ` Jan Kara
  0 siblings, 0 replies; 53+ messages in thread
From: Jan Kara @ 2026-07-01 10:01 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Theodore Ts'o, Andreas Dilger, Baokun Li, Jan Kara,
	Ojaswin Mujoo, Ritesh Harjani (IBM), Zhang Yi,
	open list:EXT4 FILE SYSTEM, open list

On Tue 30-06-26 17:09:21, Joanne Koong wrote:
> Convert ext4 iomap_ops to the new ->iomap_next() callback. This uses the
> iomap_process() helper, which finishes the previous mapping if needed
> and produces the next one. No functional changes are intended.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>

Looks good. Feel free to add:

Reviewed-by: Jan Kara <jack@suse.cz>

								Honza

> ---
>  fs/ext4/extents.c |  8 +++++++-
>  fs/ext4/inode.c   | 17 +++++++++++++++--
>  2 files changed, 22 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
> index 91c97af64b31..431298eca7e8 100644
> --- a/fs/ext4/extents.c
> +++ b/fs/ext4/extents.c
> @@ -5171,8 +5171,14 @@ static int ext4_iomap_xattr_begin(struct inode *inode, loff_t offset,
>  	return error;
>  }
>  
> +static int ext4_iomap_xattr_next(const struct iomap_iter *iter,
> +				 struct iomap *iomap, struct iomap *srcmap)
> +{
> +	return iomap_process(iter, iomap, srcmap, ext4_iomap_xattr_begin, NULL);
> +}
> +
>  static const struct iomap_ops ext4_iomap_xattr_ops = {
> -	.iomap_begin		= ext4_iomap_xattr_begin,
> +	.iomap_next		= ext4_iomap_xattr_next,
>  };
>  
>  static int ext4_fiemap_check_ranges(struct inode *inode, u64 start, u64 *len)
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index ce99807c5f5b..cf7aa8275651 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -3850,8 +3850,14 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
>  	return 0;
>  }
>  
> +static int ext4_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +			   struct iomap *srcmap)
> +{
> +	return iomap_process(iter, iomap, srcmap, ext4_iomap_begin, NULL);
> +}
> +
>  const struct iomap_ops ext4_iomap_ops = {
> -	.iomap_begin		= ext4_iomap_begin,
> +	.iomap_next		= ext4_iomap_next,
>  };
>  
>  static int ext4_iomap_begin_report(struct inode *inode, loff_t offset,
> @@ -3905,8 +3911,15 @@ static int ext4_iomap_begin_report(struct inode *inode, loff_t offset,
>  	return 0;
>  }
>  
> +static int ext4_iomap_next_report(const struct iomap_iter *iter,
> +				  struct iomap *iomap, struct iomap *srcmap)
> +{
> +	return iomap_process(iter, iomap, srcmap, ext4_iomap_begin_report,
> +			     NULL);
> +}
> +
>  const struct iomap_ops ext4_iomap_report_ops = {
> -	.iomap_begin = ext4_iomap_begin_report,
> +	.iomap_next = ext4_iomap_next_report,
>  };
>  
>  /*
> -- 
> 2.52.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 09/18] ext2: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 ` [PATCH v2 09/18] ext2: " Joanne Koong
@ 2026-07-01 10:02   ` Jan Kara
  0 siblings, 0 replies; 53+ messages in thread
From: Jan Kara @ 2026-07-01 10:02 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Jan Kara, open list:EXT2 FILE SYSTEM, open list

On Tue 30-06-26 17:09:24, Joanne Koong wrote:
> Convert ext2 iomap_ops to the new ->iomap_next() callback. This uses the
> iomap_process() helper, which finishes the previous mapping if needed
> and produces the next one. No functional changes are intended.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>

Looks good. Feel free to add:

Reviewed-by: Jan Kara <jack@suse.cz>

								Honza

> ---
>  fs/ext2/inode.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
> index 29808629cce5..0693059caa35 100644
> --- a/fs/ext2/inode.c
> +++ b/fs/ext2/inode.c
> @@ -860,9 +860,15 @@ ext2_iomap_end(struct inode *inode, loff_t offset, loff_t length,
>  	return 0;
>  }
>  
> +static int ext2_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +			   struct iomap *srcmap)
> +{
> +	return iomap_process(iter, iomap, srcmap, ext2_iomap_begin,
> +			     ext2_iomap_end);
> +}
> +
>  const struct iomap_ops ext2_iomap_ops = {
> -	.iomap_begin		= ext2_iomap_begin,
> -	.iomap_end		= ext2_iomap_end,
> +	.iomap_next		= ext2_iomap_next,
>  };
>  
>  int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
> -- 
> 2.52.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops
  2026-07-01  0:09 ` [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops Joanne Koong
@ 2026-07-01 10:04   ` Jan Kara
  2026-07-02 14:07   ` Christoph Hellwig
  2026-07-02 16:58   ` Darrick J. Wong
  2 siblings, 0 replies; 53+ messages in thread
From: Jan Kara @ 2026-07-01 10:04 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Jens Axboe, Chris Mason, David Sterba, Alexander Viro, Jan Kara,
	Dan Williams, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Sandeep Dhavale, Hongbo Li, Chunhai Guo, Namjae Jeon,
	Sungjong Seo, Yuezhang Mo, Theodore Ts'o, Andreas Dilger,
	Baokun Li, Ojaswin Mujoo, Ritesh Harjani (IBM), Zhang Yi,
	Jaegeuk Kim, Miklos Szeredi, Andreas Gruenbacher, Mikulas Patocka,
	Hyunchul Lee, Konstantin Komarov, Carlos Maiolino, Damien Le Moal,
	Naohiro Aota, Johannes Thumshirn, open list:BLOCK LAYER,
	open list, open list:BTRFS FILE SYSTEM,
	open list:FILESYSTEM DIRECT ACCESS (DAX),
	open list:EROFS FILE SYSTEM, open list:EXT2 FILE SYSTEM,
	open list:F2FS FILE SYSTEM, open list:FUSE FILESYSTEM [CORE],
	open list:GFS2 FILE SYSTEM, open list:NTFS3 FILESYSTEM

On Tue 30-06-26 17:09:32, Joanne Koong wrote:
> Now that all filesystems implement ->iomap_next() and the legacy
> ->iomap_begin()/->iomap_end() fallback is gone, struct iomap_ops only
> wraps a single iomap_next function pointer. Drop the struct entirely and
> pass the iomap_next_fn directly to iomap_iter() and all the iomap/dax
> entry points; filesystems pass their ->iomap_next function instead of an
> ops struct.
> 
> No functional change intended.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>

Feel free to add:

Acked-by: Jan Kara <jack@suse.cz>

for ext2 & ext4 changes.

								Honza

> ---
>  block/fops.c           | 10 +++-----
>  fs/btrfs/direct-io.c   |  8 ++----
>  fs/dax.c               | 47 ++++++++++++++++++------------------
>  fs/erofs/data.c        | 24 ++++++++----------
>  fs/erofs/internal.h    |  3 ++-
>  fs/erofs/zmap.c        |  8 ++----
>  fs/exfat/file.c        | 18 +++++++-------
>  fs/exfat/inode.c       |  6 ++---
>  fs/exfat/iomap.c       | 16 +++---------
>  fs/exfat/iomap.h       |  6 +++--
>  fs/ext2/ext2.h         |  3 ++-
>  fs/ext2/file.c         |  4 +--
>  fs/ext2/inode.c        |  8 ++----
>  fs/ext4/ext4.h         |  6 +++--
>  fs/ext4/extents.c      |  8 ++----
>  fs/ext4/file.c         | 14 +++++------
>  fs/ext4/inode.c        | 20 +++++----------
>  fs/f2fs/data.c         |  9 +++----
>  fs/f2fs/f2fs.h         |  3 ++-
>  fs/f2fs/file.c         |  4 +--
>  fs/fuse/dax.c          | 10 +++-----
>  fs/fuse/file.c         | 10 +++-----
>  fs/gfs2/aops.c         |  6 ++---
>  fs/gfs2/bmap.c         | 10 +++-----
>  fs/gfs2/bmap.h         |  3 ++-
>  fs/gfs2/file.c         |  6 ++---
>  fs/gfs2/inode.c        |  6 ++---
>  fs/hpfs/file.c         |  6 +----
>  fs/internal.h          |  1 -
>  fs/iomap/buffered-io.c | 38 ++++++++++++++---------------
>  fs/iomap/direct-io.c   |  8 +++---
>  fs/iomap/fiemap.c      |  8 +++---
>  fs/iomap/iter.c        |  8 +++---
>  fs/iomap/seek.c        |  8 +++---
>  fs/iomap/swapfile.c    |  4 +--
>  fs/ntfs/aops.c         |  6 ++---
>  fs/ntfs/file.c         | 24 +++++++++---------
>  fs/ntfs/inode.c        |  2 +-
>  fs/ntfs/iomap.c        | 42 +++++++-------------------------
>  fs/ntfs/iomap.h        | 15 ++++++++----
>  fs/ntfs3/file.c        | 16 ++++++------
>  fs/ntfs3/inode.c       | 12 +++------
>  fs/ntfs3/ntfs_fs.h     |  3 ++-
>  fs/remap_range.c       |  6 ++---
>  fs/xfs/xfs_aops.c      |  8 +++---
>  fs/xfs/xfs_file.c      | 40 +++++++++++++++---------------
>  fs/xfs/xfs_iomap.c     | 55 +++++++++---------------------------------
>  fs/xfs/xfs_iomap.h     | 24 ++++++++++++------
>  fs/xfs/xfs_iops.c      |  4 +--
>  fs/xfs/xfs_reflink.c   |  6 ++---
>  fs/zonefs/file.c       | 22 ++++++-----------
>  include/linux/dax.h    | 18 ++++++--------
>  include/linux/fs.h     |  7 ++++--
>  include/linux/iomap.h  | 46 +++++++++++++++--------------------
>  54 files changed, 302 insertions(+), 411 deletions(-)
> 
> diff --git a/block/fops.c b/block/fops.c
> index c2721e2c659b..9ccec477f90d 100644
> --- a/block/fops.c
> +++ b/block/fops.c
> @@ -459,10 +459,6 @@ static int blkdev_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
>  	return iomap_process(iter, iomap, srcmap, blkdev_iomap_begin, NULL);
>  }
>  
> -static const struct iomap_ops blkdev_iomap_ops = {
> -	.iomap_next		= blkdev_iomap_next,
> -};
> -
>  #ifdef CONFIG_BUFFER_HEAD
>  static int blkdev_get_block(struct inode *inode, sector_t iblock,
>  		struct buffer_head *bh, int create)
> @@ -516,13 +512,13 @@ const struct address_space_operations def_blk_aops = {
>  #else /* CONFIG_BUFFER_HEAD */
>  static int blkdev_read_folio(struct file *file, struct folio *folio)
>  {
> -	iomap_bio_read_folio(folio, &blkdev_iomap_ops);
> +	iomap_bio_read_folio(folio, blkdev_iomap_next);
>  	return 0;
>  }
>  
>  static void blkdev_readahead(struct readahead_control *rac)
>  {
> -	iomap_bio_readahead(rac, &blkdev_iomap_ops);
> +	iomap_bio_readahead(rac, blkdev_iomap_next);
>  }
>  
>  static ssize_t blkdev_writeback_range(struct iomap_writepage_ctx *wpc,
> @@ -713,7 +709,7 @@ blkdev_direct_write(struct kiocb *iocb, struct iov_iter *from)
>  
>  static ssize_t blkdev_buffered_write(struct kiocb *iocb, struct iov_iter *from)
>  {
> -	return iomap_file_buffered_write(iocb, from, &blkdev_iomap_ops, NULL,
> +	return iomap_file_buffered_write(iocb, from, blkdev_iomap_next, NULL,
>  			NULL);
>  }
>  
> diff --git a/fs/btrfs/direct-io.c b/fs/btrfs/direct-io.c
> index 46dd72982fba..f1feeb68642d 100644
> --- a/fs/btrfs/direct-io.c
> +++ b/fs/btrfs/direct-io.c
> @@ -805,10 +805,6 @@ static int btrfs_dio_iomap_next(const struct iomap_iter *iter,
>  			     btrfs_dio_iomap_end);
>  }
>  
> -static const struct iomap_ops btrfs_dio_iomap_ops = {
> -	.iomap_next             = btrfs_dio_iomap_next,
> -};
> -
>  static const struct iomap_dio_ops btrfs_dio_ops = {
>  	.submit_io		= btrfs_dio_submit_io,
>  	.bio_set		= &btrfs_dio_bioset,
> @@ -819,7 +815,7 @@ static ssize_t btrfs_dio_read(struct kiocb *iocb, struct iov_iter *iter,
>  {
>  	struct btrfs_dio_data data = { 0 };
>  
> -	return iomap_dio_rw(iocb, iter, &btrfs_dio_iomap_ops, &btrfs_dio_ops,
> +	return iomap_dio_rw(iocb, iter, btrfs_dio_iomap_next, &btrfs_dio_ops,
>  			    IOMAP_DIO_PARTIAL | IOMAP_DIO_FSBLOCK_ALIGNED, &data, done_before);
>  }
>  
> @@ -828,7 +824,7 @@ static struct iomap_dio *btrfs_dio_write(struct kiocb *iocb, struct iov_iter *it
>  {
>  	struct btrfs_dio_data data = { 0 };
>  
> -	return __iomap_dio_rw(iocb, iter, &btrfs_dio_iomap_ops, &btrfs_dio_ops,
> +	return __iomap_dio_rw(iocb, iter, btrfs_dio_iomap_next, &btrfs_dio_ops,
>  			    IOMAP_DIO_PARTIAL | IOMAP_DIO_FSBLOCK_ALIGNED, &data, done_before);
>  }
>  
> diff --git a/fs/dax.c b/fs/dax.c
> index 6d175cd47a99..c0a6b87dc052 100644
> --- a/fs/dax.c
> +++ b/fs/dax.c
> @@ -1492,7 +1492,7 @@ static int dax_unshare_iter(struct iomap_iter *iter)
>  }
>  
>  int dax_file_unshare(struct inode *inode, loff_t pos, loff_t len,
> -		const struct iomap_ops *ops)
> +		iomap_next_fn iomap_next)
>  {
>  	struct iomap_iter iter = {
>  		.inode		= inode,
> @@ -1506,7 +1506,7 @@ int dax_file_unshare(struct inode *inode, loff_t pos, loff_t len,
>  		return 0;
>  
>  	iter.len = min(len, size - pos);
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = dax_unshare_iter(&iter);
>  	return ret;
>  }
> @@ -1584,7 +1584,7 @@ static int dax_zero_iter(struct iomap_iter *iter, bool *did_zero)
>  }
>  
>  int dax_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
> -		const struct iomap_ops *ops)
> +		iomap_next_fn iomap_next)
>  {
>  	struct iomap_iter iter = {
>  		.inode		= inode,
> @@ -1594,14 +1594,14 @@ int dax_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
>  	};
>  	int ret;
>  
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = dax_zero_iter(&iter, did_zero);
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(dax_zero_range);
>  
>  int dax_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
> -		const struct iomap_ops *ops)
> +		iomap_next_fn iomap_next)
>  {
>  	unsigned int blocksize = i_blocksize(inode);
>  	unsigned int off = pos & (blocksize - 1);
> @@ -1609,7 +1609,7 @@ int dax_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
>  	/* Block boundary? Nothing to do */
>  	if (!off)
>  		return 0;
> -	return dax_zero_range(inode, pos, blocksize - off, did_zero, ops);
> +	return dax_zero_range(inode, pos, blocksize - off, did_zero, iomap_next);
>  }
>  EXPORT_SYMBOL_GPL(dax_truncate_page);
>  
> @@ -1734,7 +1734,7 @@ static int dax_iomap_iter(struct iomap_iter *iomi, struct iov_iter *iter)
>   * dax_iomap_rw - Perform I/O to a DAX file
>   * @iocb:	The control block for this I/O
>   * @iter:	The addresses to do I/O from or to
> - * @ops:	iomap ops passed from the file system
> + * @iomap_next: iomap_next callback passed from the file system
>   *
>   * This function performs read and write operations to directly mapped
>   * persistent memory.  The callers needs to take care of read/write exclusion
> @@ -1742,7 +1742,7 @@ static int dax_iomap_iter(struct iomap_iter *iomi, struct iov_iter *iter)
>   */
>  ssize_t
>  dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
> -		const struct iomap_ops *ops)
> +		iomap_next_fn iomap_next)
>  {
>  	struct iomap_iter iomi = {
>  		.inode		= iocb->ki_filp->f_mapping->host,
> @@ -1769,7 +1769,7 @@ dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
>  	if (iocb->ki_flags & IOCB_NOWAIT)
>  		iomi.flags |= IOMAP_NOWAIT;
>  
> -	while ((ret = iomap_iter(&iomi, ops)) > 0)
> +	while ((ret = iomap_iter(&iomi, iomap_next)) > 0)
>  		iomi.status = dax_iomap_iter(&iomi, iter);
>  
>  	done = iomi.pos - iocb->ki_pos;
> @@ -1897,7 +1897,7 @@ static vm_fault_t dax_fault_iter(struct vm_fault *vmf,
>  }
>  
>  static vm_fault_t dax_iomap_pte_fault(struct vm_fault *vmf, unsigned long *pfnp,
> -			       int *iomap_errp, const struct iomap_ops *ops)
> +			       int *iomap_errp, iomap_next_fn iomap_next)
>  {
>  	struct address_space *mapping = vmf->vma->vm_file->f_mapping;
>  	XA_STATE(xas, &mapping->i_pages, vmf->pgoff);
> @@ -1942,7 +1942,7 @@ static vm_fault_t dax_iomap_pte_fault(struct vm_fault *vmf, unsigned long *pfnp,
>  		goto unlock_entry;
>  	}
>  
> -	while ((error = iomap_iter(&iter, ops)) > 0) {
> +	while ((error = iomap_iter(&iter, iomap_next)) > 0) {
>  		if (WARN_ON_ONCE(iomap_length(&iter) < PAGE_SIZE)) {
>  			iter.status = -EIO;	/* fs corruption? */
>  			continue;
> @@ -2007,7 +2007,7 @@ static bool dax_fault_check_fallback(struct vm_fault *vmf, struct xa_state *xas,
>  }
>  
>  static vm_fault_t dax_iomap_pmd_fault(struct vm_fault *vmf, unsigned long *pfnp,
> -			       const struct iomap_ops *ops)
> +			       iomap_next_fn iomap_next)
>  {
>  	struct address_space *mapping = vmf->vma->vm_file->f_mapping;
>  	XA_STATE_ORDER(xas, &mapping->i_pages, vmf->pgoff, PMD_ORDER);
> @@ -2064,7 +2064,7 @@ static vm_fault_t dax_iomap_pmd_fault(struct vm_fault *vmf, unsigned long *pfnp,
>  	}
>  
>  	iter.pos = (loff_t)xas.xa_index << PAGE_SHIFT;
> -	while (iomap_iter(&iter, ops) > 0) {
> +	while (iomap_iter(&iter, iomap_next) > 0) {
>  		if (iomap_length(&iter) < PMD_SIZE)
>  			continue; /* actually breaks out of the loop */
>  
> @@ -2086,7 +2086,7 @@ static vm_fault_t dax_iomap_pmd_fault(struct vm_fault *vmf, unsigned long *pfnp,
>  }
>  #else
>  static vm_fault_t dax_iomap_pmd_fault(struct vm_fault *vmf, unsigned long *pfnp,
> -			       const struct iomap_ops *ops)
> +			       iomap_next_fn iomap_next)
>  {
>  	return VM_FAULT_FALLBACK;
>  }
> @@ -2098,7 +2098,7 @@ static vm_fault_t dax_iomap_pmd_fault(struct vm_fault *vmf, unsigned long *pfnp,
>   * @order: Order of the page to fault in
>   * @pfnp: PFN to insert for synchronous faults if fsync is required
>   * @iomap_errp: Storage for detailed error code in case of error
> - * @ops: Iomap ops passed from the file system
> + * @iomap_next: iomap_next callback passed from the file system
>   *
>   * When a page fault occurs, filesystems may call this helper in
>   * their fault handler for DAX files. dax_iomap_fault() assumes the caller
> @@ -2107,12 +2107,12 @@ static vm_fault_t dax_iomap_pmd_fault(struct vm_fault *vmf, unsigned long *pfnp,
>   */
>  vm_fault_t dax_iomap_fault(struct vm_fault *vmf, unsigned int order,
>  			unsigned long *pfnp, int *iomap_errp,
> -			const struct iomap_ops *ops)
> +			iomap_next_fn iomap_next)
>  {
>  	if (order == 0)
> -		return dax_iomap_pte_fault(vmf, pfnp, iomap_errp, ops);
> +		return dax_iomap_pte_fault(vmf, pfnp, iomap_errp, iomap_next);
>  	else if (order == PMD_ORDER)
> -		return dax_iomap_pmd_fault(vmf, pfnp, ops);
> +		return dax_iomap_pmd_fault(vmf, pfnp, iomap_next);
>  	else
>  		return VM_FAULT_FALLBACK;
>  }
> @@ -2240,7 +2240,7 @@ static int dax_range_compare_iter(struct iomap_iter *it_src,
>  
>  int dax_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
>  		struct inode *dst, loff_t dstoff, loff_t len, bool *same,
> -		const struct iomap_ops *ops)
> +		iomap_next_fn iomap_next)
>  {
>  	struct iomap_iter src_iter = {
>  		.inode		= src,
> @@ -2256,8 +2256,8 @@ int dax_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
>  	};
>  	int ret, status;
>  
> -	while ((ret = iomap_iter(&src_iter, ops)) > 0 &&
> -	       (ret = iomap_iter(&dst_iter, ops)) > 0) {
> +	while ((ret = iomap_iter(&src_iter, iomap_next)) > 0 &&
> +	       (ret = iomap_iter(&dst_iter, iomap_next)) > 0) {
>  		status = dax_range_compare_iter(&src_iter, &dst_iter,
>  				min(src_iter.len, dst_iter.len), same);
>  		if (status < 0)
> @@ -2270,9 +2270,10 @@ int dax_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
>  int dax_remap_file_range_prep(struct file *file_in, loff_t pos_in,
>  			      struct file *file_out, loff_t pos_out,
>  			      loff_t *len, unsigned int remap_flags,
> -			      const struct iomap_ops *ops)
> +			      iomap_next_fn iomap_next)
>  {
>  	return __generic_remap_file_range_prep(file_in, pos_in, file_out,
> -					       pos_out, len, remap_flags, ops);
> +					       pos_out, len, remap_flags,
> +					       iomap_next);
>  }
>  EXPORT_SYMBOL_GPL(dax_remap_file_range_prep);
> diff --git a/fs/erofs/data.c b/fs/erofs/data.c
> index 47dba61ec576..f6fe8c7eaf6d 100644
> --- a/fs/erofs/data.c
> +++ b/fs/erofs/data.c
> @@ -387,10 +387,6 @@ static int erofs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
>  			     erofs_iomap_end);
>  }
>  
> -static const struct iomap_ops erofs_iomap_ops = {
> -	.iomap_next = erofs_iomap_next,
> -};
> -
>  int erofs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
>  		 u64 start, u64 len)
>  {
> @@ -398,9 +394,9 @@ int erofs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
>  		if (!IS_ENABLED(CONFIG_EROFS_FS_ZIP))
>  			return -EOPNOTSUPP;
>  		return iomap_fiemap(inode, fieinfo, start, len,
> -				    &z_erofs_iomap_report_ops);
> +				    z_erofs_iomap_next_report);
>  	}
> -	return iomap_fiemap(inode, fieinfo, start, len, &erofs_iomap_ops);
> +	return iomap_fiemap(inode, fieinfo, start, len, erofs_iomap_next);
>  }
>  
>  /*
> @@ -419,7 +415,7 @@ static int erofs_read_folio(struct file *file, struct folio *folio)
>  	};
>  
>  	trace_erofs_read_folio(iter_ctx.realinode, folio, true);
> -	iomap_read_folio(&erofs_iomap_ops, &read_ctx, &iter_ctx);
> +	iomap_read_folio(erofs_iomap_next, &read_ctx, &iter_ctx);
>  	if (need_iput)
>  		iput(iter_ctx.realinode);
>  	return 0;
> @@ -438,14 +434,14 @@ static void erofs_readahead(struct readahead_control *rac)
>  
>  	trace_erofs_readahead(iter_ctx.realinode, readahead_index(rac),
>  			      readahead_count(rac), true);
> -	iomap_readahead(&erofs_iomap_ops, &read_ctx, &iter_ctx);
> +	iomap_readahead(erofs_iomap_next, &read_ctx, &iter_ctx);
>  	if (need_iput)
>  		iput(iter_ctx.realinode);
>  }
>  
>  static sector_t erofs_bmap(struct address_space *mapping, sector_t block)
>  {
> -	return iomap_bmap(mapping, block, &erofs_iomap_ops);
> +	return iomap_bmap(mapping, block, erofs_iomap_next);
>  }
>  
>  static ssize_t erofs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> @@ -457,14 +453,14 @@ static ssize_t erofs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
>  		return 0;
>  
>  	if (IS_ENABLED(CONFIG_FS_DAX) && IS_DAX(inode))
> -		return dax_iomap_rw(iocb, to, &erofs_iomap_ops);
> +		return dax_iomap_rw(iocb, to, erofs_iomap_next);
>  
>  	if ((iocb->ki_flags & IOCB_DIRECT) && inode->i_sb->s_bdev) {
>  		struct erofs_iomap_iter_ctx iter_ctx = {
>  			.realinode = inode,
>  		};
>  
> -		return iomap_dio_rw(iocb, to, &erofs_iomap_ops,
> +		return iomap_dio_rw(iocb, to, erofs_iomap_next,
>  				    NULL, 0, &iter_ctx, 0);
>  	}
>  	return filemap_read(iocb, to, 0);
> @@ -484,7 +480,7 @@ const struct address_space_operations erofs_aops = {
>  static vm_fault_t erofs_dax_huge_fault(struct vm_fault *vmf,
>  		unsigned int order)
>  {
> -	return dax_iomap_fault(vmf, order, NULL, NULL, &erofs_iomap_ops);
> +	return dax_iomap_fault(vmf, order, NULL, NULL, erofs_iomap_next);
>  }
>  
>  static vm_fault_t erofs_dax_fault(struct vm_fault *vmf)
> @@ -516,12 +512,12 @@ static int erofs_file_mmap_prepare(struct vm_area_desc *desc)
>  static loff_t erofs_file_llseek(struct file *file, loff_t offset, int whence)
>  {
>  	struct inode *inode = file->f_mapping->host;
> -	const struct iomap_ops *ops = &erofs_iomap_ops;
> +	iomap_next_fn ops = erofs_iomap_next;
>  
>  	if (erofs_inode_is_data_compressed(EROFS_I(inode)->datalayout)) {
>  		if (!IS_ENABLED(CONFIG_EROFS_FS_ZIP))
>  			return generic_file_llseek(file, offset, whence);
> -		ops = &z_erofs_iomap_report_ops;
> +		ops = z_erofs_iomap_next_report;
>  	}
>  
>  	if (whence == SEEK_HOLE)
> diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
> index 580f8d9f14e7..72ccd6f335b8 100644
> --- a/fs/erofs/internal.h
> +++ b/fs/erofs/internal.h
> @@ -397,7 +397,8 @@ extern const struct file_operations erofs_file_fops;
>  extern const struct file_operations erofs_dir_fops;
>  extern const struct file_operations erofs_ishare_fops;
>  
> -extern const struct iomap_ops z_erofs_iomap_report_ops;
> +int z_erofs_iomap_next_report(const struct iomap_iter *iter,
> +		struct iomap *iomap, struct iomap *srcmap);
>  
>  void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf,
>  			  erofs_off_t *offset, int *lengthp);
> diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
> index dd058413a0b6..59054eecd69e 100644
> --- a/fs/erofs/zmap.c
> +++ b/fs/erofs/zmap.c
> @@ -821,13 +821,9 @@ static int z_erofs_iomap_begin_report(struct inode *inode, loff_t offset,
>  	return 0;
>  }
>  
> -static int z_erofs_iomap_next_report(const struct iomap_iter *iter,
> -				     struct iomap *iomap, struct iomap *srcmap)
> +int z_erofs_iomap_next_report(const struct iomap_iter *iter,
> +			      struct iomap *iomap, struct iomap *srcmap)
>  {
>  	return iomap_process(iter, iomap, srcmap, z_erofs_iomap_begin_report,
>  			     NULL);
>  }
> -
> -const struct iomap_ops z_erofs_iomap_report_ops = {
> -	.iomap_next = z_erofs_iomap_next_report,
> -};
> diff --git a/fs/exfat/file.c b/fs/exfat/file.c
> index 5fc13378d35f..c05849d305ae 100644
> --- a/fs/exfat/file.c
> +++ b/fs/exfat/file.c
> @@ -668,7 +668,7 @@ static int exfat_extend_valid_size(struct inode *inode, loff_t new_valid_size)
>  
>  		ret = iomap_zero_range(inode, old_valid_size,
>  				new_valid_size - old_valid_size, NULL,
> -				&exfat_write_iomap_ops, NULL, NULL);
> +				exfat_write_iomap_next, NULL, NULL);
>  		if (ret) {
>  			truncate_setsize(inode, old_valid_size);
>  			exfat_truncate(inode);
> @@ -687,7 +687,7 @@ static ssize_t exfat_fallback_buffered_write(struct kiocb *iocb,
>  
>  	iocb->ki_flags &= ~IOCB_DIRECT;
>  
> -	written = iomap_file_buffered_write(iocb, from, &exfat_write_iomap_ops,
> +	written = iomap_file_buffered_write(iocb, from, exfat_write_iomap_next,
>  			NULL, NULL);
>  	if (written < 0)
>  		return written;
> @@ -709,7 +709,7 @@ static ssize_t exfat_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  {
>  	ssize_t ret;
>  
> -	ret = iomap_dio_rw(iocb, from, &exfat_write_iomap_ops,
> +	ret = iomap_dio_rw(iocb, from, exfat_write_iomap_next,
>  			&exfat_write_dio_ops, 0, NULL, 0);
>  	if (ret == -ENOTBLK)
>  		ret = 0;
> @@ -773,7 +773,7 @@ static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter)
>  		ret = exfat_dio_write_iter(iocb, iter);
>  	else
>  		ret = iomap_file_buffered_write(iocb, iter,
> -				&exfat_write_iomap_ops, NULL, NULL);
> +				exfat_write_iomap_next, NULL, NULL);
>  	if (ret < 0)
>  		goto unlock;
>  
> @@ -809,7 +809,7 @@ static ssize_t exfat_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
>  
>  	if (iocb->ki_flags & IOCB_DIRECT) {
>  		file_accessed(iocb->ki_filp);
> -		ret = iomap_dio_rw(iocb, iter, &exfat_iomap_ops, NULL, 0,
> +		ret = iomap_dio_rw(iocb, iter, exfat_iomap_next, NULL, 0,
>  				NULL, 0);
>  	} else {
>  		ret = generic_file_read_iter(iocb, iter);
> @@ -850,7 +850,7 @@ static vm_fault_t exfat_page_mkwrite(struct vm_fault *vmf)
>  			 */
>  			err = iomap_zero_range(inode, ei->zeroed_size,
>  					mmap_valid_size - ei->zeroed_size, NULL,
> -					&exfat_iomap_ops, NULL, NULL);
> +					exfat_iomap_next, NULL, NULL);
>  			if (err < 0) {
>  				inode_unlock(inode);
>  				return vmf_fs_error(err);
> @@ -866,7 +866,7 @@ static vm_fault_t exfat_page_mkwrite(struct vm_fault *vmf)
>  	file_update_time(vmf->vma->vm_file);
>  
>  	filemap_invalidate_lock_shared(inode->i_mapping);
> -	ret = iomap_page_mkwrite(vmf, &exfat_write_iomap_ops, NULL);
> +	ret = iomap_page_mkwrite(vmf, exfat_write_iomap_next, NULL);
>  	filemap_invalidate_unlock_shared(inode->i_mapping);
>  	sb_end_pagefault(inode->i_sb);
>  	inode_unlock(inode);
> @@ -939,12 +939,12 @@ static loff_t exfat_file_llseek(struct file *file, loff_t offset, int whence)
>  	switch (whence) {
>  	case SEEK_HOLE:
>  		inode_lock_shared(inode);
> -		offset = iomap_seek_hole(inode, offset, &exfat_iomap_ops);
> +		offset = iomap_seek_hole(inode, offset, exfat_iomap_next);
>  		inode_unlock_shared(inode);
>  		break;
>  	case SEEK_DATA:
>  		inode_lock_shared(inode);
> -		offset = iomap_seek_data(inode, offset, &exfat_iomap_ops);
> +		offset = iomap_seek_data(inode, offset, exfat_iomap_next);
>  		inode_unlock_shared(inode);
>  		break;
>  	default:
> diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
> index 89826aea5e1e..a6b9aa2ad792 100644
> --- a/fs/exfat/inode.c
> +++ b/fs/exfat/inode.c
> @@ -248,7 +248,7 @@ static int exfat_read_folio(struct file *file, struct folio *folio)
>  		.ops = &exfat_iomap_bio_read_ops,
>  	};
>  
> -	iomap_read_folio(&exfat_iomap_ops, &ctx, NULL);
> +	iomap_read_folio(exfat_iomap_next, &ctx, NULL);
>  	return 0;
>  }
>  
> @@ -269,7 +269,7 @@ static void exfat_readahead(struct readahead_control *rac)
>  	    ei->valid_size < pos + readahead_length(rac))
>  		return;
>  
> -	iomap_readahead(&exfat_iomap_ops, &ctx, NULL);
> +	iomap_readahead(exfat_iomap_next, &ctx, NULL);
>  }
>  
>  static int exfat_writepages(struct address_space *mapping,
> @@ -293,7 +293,7 @@ static sector_t exfat_aop_bmap(struct address_space *mapping, sector_t block)
>  
>  	/* exfat_get_cluster() assumes the requested blocknr isn't truncated. */
>  	down_read(&EXFAT_I(mapping->host)->truncate_lock);
> -	blocknr = iomap_bmap(mapping, block, &exfat_iomap_ops);
> +	blocknr = iomap_bmap(mapping, block, exfat_iomap_next);
>  	up_read(&EXFAT_I(mapping->host)->truncate_lock);
>  	return blocknr;
>  }
> diff --git a/fs/exfat/iomap.c b/fs/exfat/iomap.c
> index 8d33690a562d..6120e0758f7b 100644
> --- a/fs/exfat/iomap.c
> +++ b/fs/exfat/iomap.c
> @@ -151,16 +151,12 @@ static int exfat_write_iomap_begin(struct inode *inode, loff_t offset, loff_t le
>  	return __exfat_iomap_begin(inode, offset, length, flags, iomap, true);
>  }
>  
> -static int exfat_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +int exfat_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
>  		struct iomap *srcmap)
>  {
>  	return iomap_process(iter, iomap, srcmap, exfat_iomap_begin, NULL);
>  }
>  
> -const struct iomap_ops exfat_iomap_ops = {
> -	.iomap_next = exfat_iomap_next,
> -};
> -
>  /*
>   * exfat_write_iomap_end - Update the state after write
>   *
> @@ -192,17 +188,13 @@ static int exfat_write_iomap_end(struct inode *inode, loff_t pos, loff_t length,
>  	return written;
>  }
>  
> -static int exfat_write_iomap_next(const struct iomap_iter *iter,
> -		struct iomap *iomap, struct iomap *srcmap)
> +int exfat_write_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap)
>  {
>  	return iomap_process(iter, iomap, srcmap,
>  			exfat_write_iomap_begin, exfat_write_iomap_end);
>  }
>  
> -const struct iomap_ops exfat_write_iomap_ops = {
> -	.iomap_next	= exfat_write_iomap_next,
> -};
> -
>  /*
>   * exfat_writeback_range - Map folio during writeback
>   *
> @@ -279,5 +271,5 @@ const struct iomap_read_ops exfat_iomap_bio_read_ops = {
>  int exfat_iomap_swap_activate(struct swap_info_struct *sis,
>  			       struct file *file, sector_t *span)
>  {
> -	return iomap_swapfile_activate(sis, file, span, &exfat_iomap_ops);
> +	return iomap_swapfile_activate(sis, file, span, exfat_iomap_next);
>  }
> diff --git a/fs/exfat/iomap.h b/fs/exfat/iomap.h
> index fd8a913f7794..47d7b753735e 100644
> --- a/fs/exfat/iomap.h
> +++ b/fs/exfat/iomap.h
> @@ -7,8 +7,10 @@
>  #define _LINUX_EXFAT_IOMAP_H
>  
>  extern const struct iomap_dio_ops exfat_write_dio_ops;
> -extern const struct iomap_ops exfat_iomap_ops;
> -extern const struct iomap_ops exfat_write_iomap_ops;
> +int exfat_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
> +int exfat_write_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
>  extern const struct iomap_writeback_ops exfat_writeback_ops;
>  extern const struct iomap_read_ops exfat_iomap_bio_read_ops;
>  
> diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
> index 79f7b395258c..59ef8b898940 100644
> --- a/fs/ext2/ext2.h
> +++ b/fs/ext2/ext2.h
> @@ -780,7 +780,8 @@ extern const struct file_operations ext2_file_operations;
>  /* inode.c */
>  extern void ext2_set_file_ops(struct inode *inode);
>  extern const struct address_space_operations ext2_aops;
> -extern const struct iomap_ops ext2_iomap_ops;
> +int ext2_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
>  
>  /* namei.c */
>  extern const struct inode_operations ext2_dir_inode_operations;
> diff --git a/fs/ext2/file.c b/fs/ext2/file.c
> index 8dca9ec4cacd..1fc00ad77517 100644
> --- a/fs/ext2/file.c
> +++ b/fs/ext2/file.c
> @@ -70,7 +70,7 @@ static ssize_t ext2_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
>  
>  	trace_ext2_dio_read_begin(iocb, to, 0);
>  	inode_lock_shared(inode);
> -	ret = iomap_dio_rw(iocb, to, &ext2_iomap_ops, NULL, 0, NULL, 0);
> +	ret = iomap_dio_rw(iocb, to, ext2_iomap_next, NULL, 0, NULL, 0);
>  	inode_unlock_shared(inode);
>  	trace_ext2_dio_read_end(iocb, to, ret);
>  
> @@ -134,7 +134,7 @@ static ssize_t ext2_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  	   (!IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(from), blocksize)))
>  		flags |= IOMAP_DIO_FORCE_WAIT;
>  
> -	ret = iomap_dio_rw(iocb, from, &ext2_iomap_ops, &ext2_dio_write_ops,
> +	ret = iomap_dio_rw(iocb, from, ext2_iomap_next, &ext2_dio_write_ops,
>  			   flags, NULL, 0);
>  
>  	/* ENOTBLK is magic return value for fallback to buffered-io */
> diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
> index 0693059caa35..74d5be85341d 100644
> --- a/fs/ext2/inode.c
> +++ b/fs/ext2/inode.c
> @@ -860,17 +860,13 @@ ext2_iomap_end(struct inode *inode, loff_t offset, loff_t length,
>  	return 0;
>  }
>  
> -static int ext2_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +int ext2_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
>  			   struct iomap *srcmap)
>  {
>  	return iomap_process(iter, iomap, srcmap, ext2_iomap_begin,
>  			     ext2_iomap_end);
>  }
>  
> -const struct iomap_ops ext2_iomap_ops = {
> -	.iomap_next		= ext2_iomap_next,
> -};
> -
>  int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
>  		u64 start, u64 len)
>  {
> @@ -888,7 +884,7 @@ int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
>  	if (i_size == 0)
>  		i_size = 1;
>  	len = min_t(u64, len, i_size);
> -	ret = iomap_fiemap(inode, fieinfo, start, len, &ext2_iomap_ops);
> +	ret = iomap_fiemap(inode, fieinfo, start, len, ext2_iomap_next);
>  	inode_unlock(inode);
>  
>  	return ret;
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index b37c136ea3ab..755fde1baf03 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -4004,8 +4004,10 @@ static inline void ext4_clear_io_unwritten_flag(ext4_io_end_t *io_end)
>  		io_end->flag &= ~EXT4_IO_END_UNWRITTEN;
>  }
>  
> -extern const struct iomap_ops ext4_iomap_ops;
> -extern const struct iomap_ops ext4_iomap_report_ops;
> +int ext4_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
> +int ext4_iomap_next_report(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
>  
>  static inline int ext4_buffer_uptodate(struct buffer_head *bh)
>  {
> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
> index 431298eca7e8..aa3c5c0915c0 100644
> --- a/fs/ext4/extents.c
> +++ b/fs/ext4/extents.c
> @@ -5177,10 +5177,6 @@ static int ext4_iomap_xattr_next(const struct iomap_iter *iter,
>  	return iomap_process(iter, iomap, srcmap, ext4_iomap_xattr_begin, NULL);
>  }
>  
> -static const struct iomap_ops ext4_iomap_xattr_ops = {
> -	.iomap_next		= ext4_iomap_xattr_next,
> -};
> -
>  static int ext4_fiemap_check_ranges(struct inode *inode, u64 start, u64 *len)
>  {
>  	u64 maxbytes = ext4_get_maxbytes(inode);
> @@ -5223,10 +5219,10 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
>  	if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) {
>  		fieinfo->fi_flags &= ~FIEMAP_FLAG_XATTR;
>  		error = iomap_fiemap(inode, fieinfo, start, len,
> -				     &ext4_iomap_xattr_ops);
> +				     ext4_iomap_xattr_next);
>  	} else {
>  		error = iomap_fiemap(inode, fieinfo, start, len,
> -				     &ext4_iomap_report_ops);
> +				     ext4_iomap_next_report);
>  	}
>  unlock:
>  	inode_unlock_shared(inode);
> diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> index eb1a323962b1..dbe073e181a7 100644
> --- a/fs/ext4/file.c
> +++ b/fs/ext4/file.c
> @@ -91,7 +91,7 @@ static ssize_t ext4_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
>  		return generic_file_read_iter(iocb, to);
>  	}
>  
> -	ret = iomap_dio_rw(iocb, to, &ext4_iomap_ops, NULL, 0, NULL, 0);
> +	ret = iomap_dio_rw(iocb, to, ext4_iomap_next, NULL, 0, NULL, 0);
>  	inode_unlock_shared(inode);
>  
>  	file_accessed(iocb->ki_filp);
> @@ -119,7 +119,7 @@ static ssize_t ext4_dax_read_iter(struct kiocb *iocb, struct iov_iter *to)
>  		/* Fallback to buffered IO in case we cannot support DAX */
>  		return generic_file_read_iter(iocb, to);
>  	}
> -	ret = dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> +	ret = dax_iomap_rw(iocb, to, ext4_iomap_next);
>  	inode_unlock_shared(inode);
>  
>  	file_accessed(iocb->ki_filp);
> @@ -589,7 +589,7 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  			goto out;
>  	}
>  
> -	ret = iomap_dio_rw(iocb, from, &ext4_iomap_ops, &ext4_dio_write_ops,
> +	ret = iomap_dio_rw(iocb, from, ext4_iomap_next, &ext4_dio_write_ops,
>  			   dio_flags, NULL, 0);
>  	if (ret == -ENOTBLK)
>  		ret = 0;
> @@ -688,7 +688,7 @@ ext4_dax_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  		ext4_journal_stop(handle);
>  	}
>  
> -	ret = dax_iomap_rw(iocb, from, &ext4_iomap_ops);
> +	ret = dax_iomap_rw(iocb, from, ext4_iomap_next);
>  
>  	if (extend) {
>  		ret = ext4_handle_inode_extension(inode, offset, ret, count);
> @@ -776,7 +776,7 @@ static vm_fault_t ext4_dax_huge_fault(struct vm_fault *vmf, unsigned int order)
>  	} else {
>  		filemap_invalidate_lock_shared(mapping);
>  	}
> -	result = dax_iomap_fault(vmf, order, &pfn, &error, &ext4_iomap_ops);
> +	result = dax_iomap_fault(vmf, order, &pfn, &error, ext4_iomap_next);
>  	if (write) {
>  		ext4_journal_stop(handle);
>  
> @@ -955,13 +955,13 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int whence)
>  	case SEEK_HOLE:
>  		inode_lock_shared(inode);
>  		offset = iomap_seek_hole(inode, offset,
> -					 &ext4_iomap_report_ops);
> +					 ext4_iomap_next_report);
>  		inode_unlock_shared(inode);
>  		break;
>  	case SEEK_DATA:
>  		inode_lock_shared(inode);
>  		offset = iomap_seek_data(inode, offset,
> -					 &ext4_iomap_report_ops);
> +					 ext4_iomap_next_report);
>  		inode_unlock_shared(inode);
>  		break;
>  	}
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index cf7aa8275651..4c30dd8dbec7 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -3391,7 +3391,7 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block)
>  		filemap_write_and_wait(mapping);
>  	}
>  
> -	ret = iomap_bmap(mapping, block, &ext4_iomap_ops);
> +	ret = iomap_bmap(mapping, block, ext4_iomap_next);
>  
>  out:
>  	inode_unlock_shared(inode);
> @@ -3850,16 +3850,12 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
>  	return 0;
>  }
>  
> -static int ext4_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +int ext4_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
>  			   struct iomap *srcmap)
>  {
>  	return iomap_process(iter, iomap, srcmap, ext4_iomap_begin, NULL);
>  }
>  
> -const struct iomap_ops ext4_iomap_ops = {
> -	.iomap_next		= ext4_iomap_next,
> -};
> -
>  static int ext4_iomap_begin_report(struct inode *inode, loff_t offset,
>  				   loff_t length, unsigned int flags,
>  				   struct iomap *iomap, struct iomap *srcmap)
> @@ -3911,17 +3907,13 @@ static int ext4_iomap_begin_report(struct inode *inode, loff_t offset,
>  	return 0;
>  }
>  
> -static int ext4_iomap_next_report(const struct iomap_iter *iter,
> -				  struct iomap *iomap, struct iomap *srcmap)
> +int ext4_iomap_next_report(const struct iomap_iter *iter, struct iomap *iomap,
> +			   struct iomap *srcmap)
>  {
>  	return iomap_process(iter, iomap, srcmap, ext4_iomap_begin_report,
>  			     NULL);
>  }
>  
> -const struct iomap_ops ext4_iomap_report_ops = {
> -	.iomap_next = ext4_iomap_next_report,
> -};
> -
>  /*
>   * For data=journal mode, folio should be marked dirty only when it was
>   * writeably mapped. When that happens, it was already attached to the
> @@ -3957,7 +3949,7 @@ static int ext4_iomap_swap_activate(struct swap_info_struct *sis,
>  				    struct file *file, sector_t *span)
>  {
>  	return iomap_swapfile_activate(sis, file, span,
> -				       &ext4_iomap_report_ops);
> +				       ext4_iomap_next_report);
>  }
>  
>  static const struct address_space_operations ext4_aops = {
> @@ -4204,7 +4196,7 @@ static int ext4_block_zero_range(struct inode *inode,
>  
>  	if (IS_DAX(inode)) {
>  		return dax_zero_range(inode, from, length, did_zero,
> -				      &ext4_iomap_ops);
> +				      ext4_iomap_next);
>  	} else if (ext4_should_journal_data(inode)) {
>  		return ext4_block_journalled_zero_range(inode, from, length,
>  							did_zero);
> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> index afc9b2adaa98..9c281336c9b3 100644
> --- a/fs/f2fs/data.c
> +++ b/fs/f2fs/data.c
> @@ -4171,6 +4171,7 @@ static bool f2fs_dirty_data_folio(struct address_space *mapping,
>  }
>  
>  
> +
>  static sector_t f2fs_bmap_compress(struct inode *inode, sector_t block)
>  {
>  #ifdef CONFIG_F2FS_FS_COMPRESSION
> @@ -4653,12 +4654,8 @@ static int f2fs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
>  	return 0;
>  }
>  
> -static int f2fs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> -			   struct iomap *srcmap)
> +int f2fs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		    struct iomap *srcmap)
>  {
>  	return iomap_process(iter, iomap, srcmap, f2fs_iomap_begin, NULL);
>  }
> -
> -const struct iomap_ops f2fs_iomap_ops = {
> -	.iomap_next	= f2fs_iomap_next,
> -};
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 8f3e632f315c..946a91834aec 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -4216,7 +4216,8 @@ int f2fs_init_post_read_processing(void);
>  void f2fs_destroy_post_read_processing(void);
>  int f2fs_init_wq(struct f2fs_sb_info *sbi);
>  void f2fs_destroy_wq(struct f2fs_sb_info *sbi);
> -extern const struct iomap_ops f2fs_iomap_ops;
> +int f2fs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		    struct iomap *srcmap);
>  
>  /*
>   * gc.c
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 4b52c56d71f0..74514b117257 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -4884,7 +4884,7 @@ static ssize_t f2fs_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
>  	 * F2FS_DIO_READ counter will be decremented correctly in all cases.
>  	 */
>  	inc_page_count(sbi, F2FS_DIO_READ);
> -	dio = __iomap_dio_rw(iocb, to, &f2fs_iomap_ops,
> +	dio = __iomap_dio_rw(iocb, to, f2fs_iomap_next,
>  			     &f2fs_iomap_dio_read_ops, 0, NULL, 0);
>  	if (IS_ERR_OR_NULL(dio)) {
>  		ret = PTR_ERR_OR_ZERO(dio);
> @@ -5220,7 +5220,7 @@ static ssize_t f2fs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from,
>  	dio_flags = 0;
>  	if (pos + count > inode->i_size)
>  		dio_flags |= IOMAP_DIO_FORCE_WAIT;
> -	dio = __iomap_dio_rw(iocb, from, &f2fs_iomap_ops,
> +	dio = __iomap_dio_rw(iocb, from, f2fs_iomap_next,
>  			     &f2fs_iomap_dio_write_ops, dio_flags, iocb, 0);
>  	if (IS_ERR_OR_NULL(dio)) {
>  		ret = PTR_ERR_OR_ZERO(dio);
> diff --git a/fs/fuse/dax.c b/fs/fuse/dax.c
> index e8d8c9f5d728..a6e9721552ba 100644
> --- a/fs/fuse/dax.c
> +++ b/fs/fuse/dax.c
> @@ -660,10 +660,6 @@ static int fuse_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
>  			     fuse_iomap_end);
>  }
>  
> -static const struct iomap_ops fuse_iomap_ops = {
> -	.iomap_next = fuse_iomap_next,
> -};
> -
>  static void fuse_wait_dax_page(struct inode *inode)
>  {
>  	filemap_invalidate_unlock(inode->i_mapping);
> @@ -691,7 +687,7 @@ ssize_t fuse_dax_read_iter(struct kiocb *iocb, struct iov_iter *to)
>  		inode_lock_shared(inode);
>  	}
>  
> -	ret = dax_iomap_rw(iocb, to, &fuse_iomap_ops);
> +	ret = dax_iomap_rw(iocb, to, fuse_iomap_next);
>  	inode_unlock_shared(inode);
>  
>  	/* TODO file_accessed(iocb->f_filp) */
> @@ -746,7 +742,7 @@ ssize_t fuse_dax_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  	if (file_extending_write(iocb, from))
>  		ret = fuse_dax_direct_write(iocb, from);
>  	else
> -		ret = dax_iomap_rw(iocb, from, &fuse_iomap_ops);
> +		ret = dax_iomap_rw(iocb, from, fuse_iomap_next);
>  
>  out:
>  	inode_unlock(inode);
> @@ -781,7 +777,7 @@ static vm_fault_t __fuse_dax_fault(struct vm_fault *vmf, unsigned int order,
>  	 * to populate page cache or access memory we are trying to free.
>  	 */
>  	filemap_invalidate_lock_shared(inode->i_mapping);
> -	ret = dax_iomap_fault(vmf, order, &pfn, &error, &fuse_iomap_ops);
> +	ret = dax_iomap_fault(vmf, order, &pfn, &error, fuse_iomap_next);
>  	if ((ret & VM_FAULT_ERROR) && error == -EAGAIN) {
>  		error = 0;
>  		retry = true;
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index 5c0d400629cc..b3e95a28623d 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -896,10 +896,6 @@ static int fuse_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
>  	return iomap_process(iter, iomap, srcmap, fuse_iomap_begin, NULL);
>  }
>  
> -static const struct iomap_ops fuse_iomap_ops = {
> -	.iomap_next	= fuse_iomap_next,
> -};
> -
>  struct fuse_fill_read_data {
>  	struct file *file;
>  
> @@ -1020,7 +1016,7 @@ static int fuse_read_folio(struct file *file, struct folio *folio)
>  		return -EIO;
>  	}
>  
> -	iomap_read_folio(&fuse_iomap_ops, &ctx, NULL);
> +	iomap_read_folio(fuse_iomap_next, &ctx, NULL);
>  	fuse_invalidate_atime(inode);
>  	return 0;
>  }
> @@ -1121,7 +1117,7 @@ static void fuse_readahead(struct readahead_control *rac)
>  	if (fuse_is_bad(inode))
>  		return;
>  
> -	iomap_readahead(&fuse_iomap_ops, &ctx, NULL);
> +	iomap_readahead(fuse_iomap_next, &ctx, NULL);
>  }
>  
>  static ssize_t fuse_cache_read_iter(struct kiocb *iocb, struct iov_iter *to)
> @@ -1553,7 +1549,7 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  		 * and granular dirty tracking for large folios.
>  		 */
>  		written = iomap_file_buffered_write(iocb, from,
> -						    &fuse_iomap_ops,
> +						    fuse_iomap_next,
>  						    &fuse_iomap_write_ops,
>  						    file);
>  	} else {
> diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
> index 0a7b8076af3a..66bc19c011cc 100644
> --- a/fs/gfs2/aops.c
> +++ b/fs/gfs2/aops.c
> @@ -425,7 +425,7 @@ static int gfs2_read_folio(struct file *file, struct folio *folio)
>  
>  	if (!gfs2_is_jdata(ip) ||
>  	    (i_blocksize(inode) == PAGE_SIZE && !folio_buffers(folio))) {
> -		iomap_bio_read_folio(folio, &gfs2_iomap_ops);
> +		iomap_bio_read_folio(folio, gfs2_iomap_next);
>  	} else if (gfs2_is_stuffed(ip)) {
>  		error = stuffed_read_folio(ip, folio);
>  	} else {
> @@ -500,7 +500,7 @@ static void gfs2_readahead(struct readahead_control *rac)
>  	else if (gfs2_is_jdata(ip))
>  		mpage_readahead(rac, gfs2_block_map);
>  	else
> -		iomap_bio_readahead(rac, &gfs2_iomap_ops);
> +		iomap_bio_readahead(rac, gfs2_iomap_next);
>  }
>  
>  /**
> @@ -571,7 +571,7 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock)
>  		return 0;
>  
>  	if (!gfs2_is_stuffed(ip))
> -		dblock = iomap_bmap(mapping, lblock, &gfs2_iomap_ops);
> +		dblock = iomap_bmap(mapping, lblock, gfs2_iomap_next);
>  
>  	gfs2_glock_dq_uninit(&i_gh);
>  
> diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
> index 6cb1d4513882..1b96f5622be6 100644
> --- a/fs/gfs2/bmap.c
> +++ b/fs/gfs2/bmap.c
> @@ -1200,17 +1200,13 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length,
>  	return 0;
>  }
>  
> -static int gfs2_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> -			   struct iomap *srcmap)
> +int gfs2_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		    struct iomap *srcmap)
>  {
>  	return iomap_process(iter, iomap, srcmap, gfs2_iomap_begin,
>  			     gfs2_iomap_end);
>  }
>  
> -const struct iomap_ops gfs2_iomap_ops = {
> -	.iomap_next = gfs2_iomap_next,
> -};
> -
>  /**
>   * gfs2_block_map - Map one or more blocks of an inode to a disk block
>   * @inode: The inode
> @@ -1324,7 +1320,7 @@ static int gfs2_block_zero_range(struct inode *inode, loff_t from, loff_t length
>  	if (from >= inode->i_size)
>  		return 0;
>  	length = min(length, inode->i_size - from);
> -	return iomap_zero_range(inode, from, length, NULL, &gfs2_iomap_ops,
> +	return iomap_zero_range(inode, from, length, NULL, gfs2_iomap_next,
>  			&gfs2_iomap_write_ops, NULL);
>  }
>  
> diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h
> index e3d6efdfd890..2c2b7ab39259 100644
> --- a/fs/gfs2/bmap.h
> +++ b/fs/gfs2/bmap.h
> @@ -43,7 +43,8 @@ static inline void gfs2_write_calc_reserv(const struct gfs2_inode *ip,
>  	}
>  }
>  
> -extern const struct iomap_ops gfs2_iomap_ops;
> +int gfs2_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
>  extern const struct iomap_write_ops gfs2_iomap_write_ops;
>  extern const struct iomap_writeback_ops gfs2_writeback_ops;
>  
> diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
> index b8c10de113ba..ef5f521a46c0 100644
> --- a/fs/gfs2/file.c
> +++ b/fs/gfs2/file.c
> @@ -844,7 +844,7 @@ static ssize_t gfs2_file_direct_read(struct kiocb *iocb, struct iov_iter *to,
>  		goto out_uninit;
>  	pagefault_disable();
>  	to->nofault = true;
> -	ret = iomap_dio_rw(iocb, to, &gfs2_iomap_ops, NULL,
> +	ret = iomap_dio_rw(iocb, to, gfs2_iomap_next, NULL,
>  			   IOMAP_DIO_PARTIAL, NULL, read);
>  	to->nofault = false;
>  	pagefault_enable();
> @@ -910,7 +910,7 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from,
>  		goto out_unlock;
>  
>  	from->nofault = true;
> -	ret = iomap_dio_rw(iocb, from, &gfs2_iomap_ops, NULL,
> +	ret = iomap_dio_rw(iocb, from, gfs2_iomap_next, NULL,
>  			   IOMAP_DIO_PARTIAL, NULL, written);
>  	from->nofault = false;
>  	if (ret <= 0) {
> @@ -1062,7 +1062,7 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
>  		goto out_unlock;
>  
>  	pagefault_disable();
> -	ret = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops,
> +	ret = iomap_file_buffered_write(iocb, from, gfs2_iomap_next,
>  			&gfs2_iomap_write_ops, NULL);
>  	pagefault_enable();
>  	if (ret > 0)
> diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
> index 8a77794bbd4a..737a3b6c5268 100644
> --- a/fs/gfs2/inode.c
> +++ b/fs/gfs2/inode.c
> @@ -2217,7 +2217,7 @@ static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
>  		goto out;
>  
>  	pagefault_disable();
> -	ret = iomap_fiemap(inode, fieinfo, start, len, &gfs2_iomap_ops);
> +	ret = iomap_fiemap(inode, fieinfo, start, len, gfs2_iomap_next);
>  	pagefault_enable();
>  
>  	gfs2_glock_dq_uninit(&gh);
> @@ -2242,7 +2242,7 @@ loff_t gfs2_seek_data(struct file *file, loff_t offset)
>  	inode_lock_shared(inode);
>  	ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
>  	if (!ret)
> -		ret = iomap_seek_data(inode, offset, &gfs2_iomap_ops);
> +		ret = iomap_seek_data(inode, offset, gfs2_iomap_next);
>  	gfs2_glock_dq_uninit(&gh);
>  	inode_unlock_shared(inode);
>  
> @@ -2261,7 +2261,7 @@ loff_t gfs2_seek_hole(struct file *file, loff_t offset)
>  	inode_lock_shared(inode);
>  	ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
>  	if (!ret)
> -		ret = iomap_seek_hole(inode, offset, &gfs2_iomap_ops);
> +		ret = iomap_seek_hole(inode, offset, gfs2_iomap_next);
>  	gfs2_glock_dq_uninit(&gh);
>  	inode_unlock_shared(inode);
>  
> diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
> index 1df9f28fb40b..08d5df5fb3cf 100644
> --- a/fs/hpfs/file.c
> +++ b/fs/hpfs/file.c
> @@ -162,10 +162,6 @@ static int hpfs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
>  	return iomap_process(iter, iomap, srcmap, hpfs_iomap_begin, NULL);
>  }
>  
> -static const struct iomap_ops hpfs_iomap_ops = {
> -	.iomap_next		= hpfs_iomap_next,
> -};
> -
>  static int hpfs_read_folio(struct file *file, struct folio *folio)
>  {
>  	return mpage_read_folio(folio, hpfs_get_block);
> @@ -242,7 +238,7 @@ static int hpfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
>  
>  	inode_lock(inode);
>  	len = min_t(u64, len, i_size_read(inode));
> -	ret = iomap_fiemap(inode, fieinfo, start, len, &hpfs_iomap_ops);
> +	ret = iomap_fiemap(inode, fieinfo, start, len, hpfs_iomap_next);
>  	inode_unlock(inode);
>  
>  	return ret;
> diff --git a/fs/internal.h b/fs/internal.h
> index 355d93f92208..19601f8406dc 100644
> --- a/fs/internal.h
> +++ b/fs/internal.h
> @@ -8,7 +8,6 @@
>  struct super_block;
>  struct file_system_type;
>  struct iomap;
> -struct iomap_ops;
>  struct linux_binprm;
>  struct path;
>  struct mount;
> diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
> index 3f0932e46fd6..0aa8abc438c1 100644
> --- a/fs/iomap/buffered-io.c
> +++ b/fs/iomap/buffered-io.c
> @@ -626,7 +626,7 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
>  	return 0;
>  }
>  
> -void iomap_read_folio(const struct iomap_ops *ops,
> +void iomap_read_folio(iomap_next_fn iomap_next,
>  		struct iomap_read_folio_ctx *ctx, void *private)
>  {
>  	struct folio *folio = ctx->cur_folio;
> @@ -650,7 +650,7 @@ void iomap_read_folio(const struct iomap_ops *ops,
>  		fsverity_readahead(ctx->vi, folio->index,
>  				   folio_nr_pages(folio));
>  
> -	while ((ret = iomap_iter(&iter, ops)) > 0) {
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0) {
>  		iter.status = iomap_read_folio_iter(&iter, ctx,
>  				&bytes_submitted);
>  		iomap_read_submit(&iter, ctx);
> @@ -688,22 +688,22 @@ static int iomap_readahead_iter(struct iomap_iter *iter,
>  
>  /**
>   * iomap_readahead - Attempt to read pages from a file.
> - * @ops: The operations vector for the filesystem.
> + * @iomap_next: The iomap_next callback for the filesystem.
>   * @ctx: The ctx used for issuing readahead.
>   * @private: The filesystem-specific information for issuing iomap_iter.
>   *
>   * This function is for filesystems to call to implement their readahead
>   * address_space operation.
>   *
> - * Context: The @ops callbacks may submit I/O (eg to read the addresses of
> + * Context: The @iomap_next callback may submit I/O (eg to read the addresses of
>   * blocks from disc), and may wait for it.  The caller may be trying to
>   * access a different page, and so sleeping excessively should be avoided.
>   * It may allocate memory, but should avoid costly allocations.  This
>   * function is called with memalloc_nofs set, so allocations will not cause
>   * the filesystem to be reentered.
>   */
> -void iomap_readahead(const struct iomap_ops *ops,
> -		struct iomap_read_folio_ctx *ctx, void *private)
> +void iomap_readahead(iomap_next_fn iomap_next, struct iomap_read_folio_ctx *ctx,
> +		void *private)
>  {
>  	struct readahead_control *rac = ctx->rac;
>  	struct iomap_iter iter = {
> @@ -725,7 +725,7 @@ void iomap_readahead(const struct iomap_ops *ops,
>  		fsverity_readahead(ctx->vi, readahead_index(rac),
>  				readahead_count(rac));
>  
> -	while (iomap_iter(&iter, ops) > 0) {
> +	while (iomap_iter(&iter, iomap_next) > 0) {
>  		iter.status = iomap_readahead_iter(&iter, ctx,
>  					&cur_bytes_submitted);
>  		iomap_read_submit(&iter, ctx);
> @@ -1268,7 +1268,7 @@ static int iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i,
>  
>  ssize_t
>  iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *i,
> -		const struct iomap_ops *ops,
> +		iomap_next_fn iomap_next,
>  		const struct iomap_write_ops *write_ops, void *private)
>  {
>  	struct iomap_iter iter = {
> @@ -1285,7 +1285,7 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *i,
>  	if (iocb->ki_flags & IOCB_DONTCACHE)
>  		iter.flags |= IOMAP_DONTCACHE;
>  
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = iomap_write_iter(&iter, i, write_ops);
>  
>  	if (unlikely(iter.pos == iocb->ki_pos))
> @@ -1297,7 +1297,7 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *i,
>  EXPORT_SYMBOL_GPL(iomap_file_buffered_write);
>  
>  int iomap_fsverity_write(struct file *file, loff_t pos, size_t length,
> -		const void *buf, const struct iomap_ops *ops,
> +		const void *buf, iomap_next_fn iomap_next,
>  		const struct iomap_write_ops *write_ops)
>  {
>  	int			ret;
> @@ -1314,7 +1314,7 @@ int iomap_fsverity_write(struct file *file, loff_t pos, size_t length,
>  
>  	iov_iter_kvec(&iiter, WRITE, &kvec, 1, length);
>  
> -	ret = iomap_file_buffered_write(&iocb, &iiter, ops, write_ops, NULL);
> +	ret = iomap_file_buffered_write(&iocb, &iiter, iomap_next, write_ops, NULL);
>  	if (ret < 0)
>  		return ret;
>  	return ret == length ? 0 : -EIO;
> @@ -1586,7 +1586,7 @@ static int iomap_unshare_iter(struct iomap_iter *iter,
>  
>  int
>  iomap_file_unshare(struct inode *inode, loff_t pos, loff_t len,
> -		const struct iomap_ops *ops,
> +		iomap_next_fn iomap_next,
>  		const struct iomap_write_ops *write_ops)
>  {
>  	struct iomap_iter iter = {
> @@ -1601,7 +1601,7 @@ iomap_file_unshare(struct inode *inode, loff_t pos, loff_t len,
>  		return 0;
>  
>  	iter.len = min(len, size - pos);
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = iomap_unshare_iter(&iter, write_ops);
>  	return ret;
>  }
> @@ -1710,7 +1710,7 @@ EXPORT_SYMBOL_GPL(iomap_fill_dirty_folios);
>  
>  int
>  iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
> -		const struct iomap_ops *ops,
> +		iomap_next_fn iomap_next,
>  		const struct iomap_write_ops *write_ops, void *private)
>  {
>  	struct folio_batch fbatch;
> @@ -1735,7 +1735,7 @@ iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
>  	 */
>  	range_dirty = filemap_range_needs_writeback(mapping, iter.pos,
>  					iter.pos + iter.len - 1);
> -	while ((ret = iomap_iter(&iter, ops)) > 0) {
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0) {
>  		const struct iomap *srcmap = iomap_iter_srcmap(&iter);
>  
>  		if (!(iter.iomap.flags & IOMAP_F_FOLIO_BATCH) &&
> @@ -1761,7 +1761,7 @@ EXPORT_SYMBOL_GPL(iomap_zero_range);
>  
>  int
>  iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
> -		const struct iomap_ops *ops,
> +		iomap_next_fn iomap_next,
>  		const struct iomap_write_ops *write_ops, void *private)
>  {
>  	unsigned int blocksize = i_blocksize(inode);
> @@ -1770,7 +1770,7 @@ iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
>  	/* Block boundary? Nothing to do */
>  	if (!off)
>  		return 0;
> -	return iomap_zero_range(inode, pos, blocksize - off, did_zero, ops,
> +	return iomap_zero_range(inode, pos, blocksize - off, did_zero, iomap_next,
>  			write_ops, private);
>  }
>  EXPORT_SYMBOL_GPL(iomap_truncate_page);
> @@ -1795,7 +1795,7 @@ static int iomap_folio_mkwrite_iter(struct iomap_iter *iter,
>  	return iomap_iter_advance(iter, length);
>  }
>  
> -vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, const struct iomap_ops *ops,
> +vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, iomap_next_fn iomap_next,
>  		void *private)
>  {
>  	struct iomap_iter iter = {
> @@ -1812,7 +1812,7 @@ vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, const struct iomap_ops *ops,
>  		goto out_unlock;
>  	iter.pos = folio_pos(folio);
>  	iter.len = ret;
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = iomap_folio_mkwrite_iter(&iter, folio);
>  
>  	if (ret < 0)
> diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
> index b485e3b191da..e299d186f743 100644
> --- a/fs/iomap/direct-io.c
> +++ b/fs/iomap/direct-io.c
> @@ -676,7 +676,7 @@ static int iomap_dio_iter(struct iomap_iter *iter, struct iomap_dio *dio)
>   */
>  struct iomap_dio *
>  __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
> -		const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
> +		iomap_next_fn iomap_next, const struct iomap_dio_ops *dops,
>  		unsigned int dio_flags, void *private, size_t done_before)
>  {
>  	struct inode *inode = file_inode(iocb->ki_filp);
> @@ -800,7 +800,7 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
>  	inode_dio_begin(inode);
>  
>  	blk_start_plug(&plug);
> -	while ((ret = iomap_iter(&iomi, ops)) > 0) {
> +	while ((ret = iomap_iter(&iomi, iomap_next)) > 0) {
>  		iomi.status = iomap_dio_iter(&iomi, dio);
>  
>  		/*
> @@ -890,12 +890,12 @@ EXPORT_SYMBOL_GPL(__iomap_dio_rw);
>  
>  ssize_t
>  iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
> -		const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
> +		iomap_next_fn iomap_next, const struct iomap_dio_ops *dops,
>  		unsigned int dio_flags, void *private, size_t done_before)
>  {
>  	struct iomap_dio *dio;
>  
> -	dio = __iomap_dio_rw(iocb, iter, ops, dops, dio_flags, private,
> +	dio = __iomap_dio_rw(iocb, iter, iomap_next, dops, dio_flags, private,
>  			     done_before);
>  	if (IS_ERR_OR_NULL(dio))
>  		return PTR_ERR_OR_ZERO(dio);
> diff --git a/fs/iomap/fiemap.c b/fs/iomap/fiemap.c
> index d11dadff8286..fc488f05d8ce 100644
> --- a/fs/iomap/fiemap.c
> +++ b/fs/iomap/fiemap.c
> @@ -56,7 +56,7 @@ static int iomap_fiemap_iter(struct iomap_iter *iter,
>  }
>  
>  int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
> -		u64 start, u64 len, const struct iomap_ops *ops)
> +		u64 start, u64 len, iomap_next_fn iomap_next)
>  {
>  	struct iomap_iter iter = {
>  		.inode		= inode,
> @@ -73,7 +73,7 @@ int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
>  	if (ret)
>  		return ret;
>  
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = iomap_fiemap_iter(&iter, fi, &prev);
>  
>  	if (prev.type != IOMAP_HOLE) {
> @@ -92,7 +92,7 @@ EXPORT_SYMBOL_GPL(iomap_fiemap);
>  /* legacy ->bmap interface.  0 is the error return (!) */
>  sector_t
>  iomap_bmap(struct address_space *mapping, sector_t bno,
> -		const struct iomap_ops *ops)
> +		iomap_next_fn iomap_next)
>  {
>  	struct iomap_iter iter = {
>  		.inode	= mapping->host,
> @@ -107,7 +107,7 @@ iomap_bmap(struct address_space *mapping, sector_t bno,
>  		return 0;
>  
>  	bno = 0;
> -	while ((ret = iomap_iter(&iter, ops)) > 0) {
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0) {
>  		if (iter.iomap.type == IOMAP_MAPPED)
>  			bno = iomap_sector(&iter.iomap, iter.pos) >> blkshift;
>  		/* leave iter.status unset to abort loop */
> diff --git a/fs/iomap/iter.c b/fs/iomap/iter.c
> index 466c491bdef6..984045af310a 100644
> --- a/fs/iomap/iter.c
> +++ b/fs/iomap/iter.c
> @@ -42,7 +42,7 @@ static inline void iomap_iter_done(struct iomap_iter *iter)
>  /**
>   * iomap_iter - iterate over a ranges in a file
>   * @iter: iteration structue
> - * @ops: iomap ops provided by the file system
> + * @iomap_next: iomap_next callback provided by the file system
>   *
>   * Iterate over filesystem-provided space mappings for the provided file range.
>   *
> @@ -54,13 +54,13 @@ static inline void iomap_iter_done(struct iomap_iter *iter)
>   * of the loop body:  leave @iter.status unchanged, or set it to a negative
>   * errno.
>   */
> -int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
> +int iomap_iter(struct iomap_iter *iter, iomap_next_fn iomap_next)
>  {
>  	int ret;
>  
> -	trace_iomap_iter(iter, ops, _RET_IP_);
> +	trace_iomap_iter(iter, iomap_next, _RET_IP_);
>  
> -	ret = ops->iomap_next(iter, &iter->iomap, &iter->srcmap);
> +	ret = iomap_next(iter, &iter->iomap, &iter->srcmap);
>  	iter->status = 0;
>  	if (ret > 0)
>  		iomap_iter_done(iter);
> diff --git a/fs/iomap/seek.c b/fs/iomap/seek.c
> index 6cbc587c93da..1bc5053d3fc1 100644
> --- a/fs/iomap/seek.c
> +++ b/fs/iomap/seek.c
> @@ -27,7 +27,7 @@ static int iomap_seek_hole_iter(struct iomap_iter *iter,
>  }
>  
>  loff_t
> -iomap_seek_hole(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
> +iomap_seek_hole(struct inode *inode, loff_t pos, iomap_next_fn iomap_next)
>  {
>  	loff_t size = i_size_read(inode);
>  	struct iomap_iter iter = {
> @@ -42,7 +42,7 @@ iomap_seek_hole(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
>  		return -ENXIO;
>  
>  	iter.len = size - pos;
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = iomap_seek_hole_iter(&iter, &pos);
>  	if (ret < 0)
>  		return ret;
> @@ -73,7 +73,7 @@ static int iomap_seek_data_iter(struct iomap_iter *iter,
>  }
>  
>  loff_t
> -iomap_seek_data(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
> +iomap_seek_data(struct inode *inode, loff_t pos, iomap_next_fn iomap_next)
>  {
>  	loff_t size = i_size_read(inode);
>  	struct iomap_iter iter = {
> @@ -88,7 +88,7 @@ iomap_seek_data(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
>  		return -ENXIO;
>  
>  	iter.len = size - pos;
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = iomap_seek_data_iter(&iter, &pos);
>  	if (ret < 0)
>  		return ret;
> diff --git a/fs/iomap/swapfile.c b/fs/iomap/swapfile.c
> index 0db77c449467..b8bb34deddfc 100644
> --- a/fs/iomap/swapfile.c
> +++ b/fs/iomap/swapfile.c
> @@ -139,7 +139,7 @@ static int iomap_swapfile_iter(struct iomap_iter *iter,
>   */
>  int iomap_swapfile_activate(struct swap_info_struct *sis,
>  		struct file *swap_file, sector_t *pagespan,
> -		const struct iomap_ops *ops)
> +		iomap_next_fn iomap_next)
>  {
>  	struct inode *inode = swap_file->f_mapping->host;
>  	struct iomap_iter iter = {
> @@ -163,7 +163,7 @@ int iomap_swapfile_activate(struct swap_info_struct *sis,
>  	if (ret)
>  		return ret;
>  
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = iomap_swapfile_iter(&iter, &iter.iomap, &isi);
>  	if (ret < 0)
>  		return ret;
> diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
> index 1fbf832ad165..43ad597ed491 100644
> --- a/fs/ntfs/aops.c
> +++ b/fs/ntfs/aops.c
> @@ -97,7 +97,7 @@ static int ntfs_read_folio(struct file *file, struct folio *folio)
>  			return ntfs_read_compressed_block(folio);
>  	}
>  
> -	iomap_read_folio(&ntfs_read_iomap_ops, &ctx, NULL);
> +	iomap_read_folio(ntfs_read_iomap_next, &ctx, NULL);
>  	return 0;
>  }
>  
> @@ -238,7 +238,7 @@ static void ntfs_readahead(struct readahead_control *rac)
>  	 */
>  	if (!NInoNonResident(ni) || NInoCompressed(ni))
>  		return;
> -	iomap_readahead(&ntfs_read_iomap_ops, &ctx, NULL);
> +	iomap_readahead(ntfs_read_iomap_next, &ctx, NULL);
>  }
>  
>  static int ntfs_writepages(struct address_space *mapping,
> @@ -274,7 +274,7 @@ static int ntfs_swap_activate(struct swap_info_struct *sis,
>  		struct file *swap_file, sector_t *span)
>  {
>  	return iomap_swapfile_activate(sis, swap_file, span,
> -			&ntfs_read_iomap_ops);
> +			ntfs_read_iomap_next);
>  }
>  
>  const struct address_space_operations ntfs_aops = {
> diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
> index 6a7b638e523d..a4f99128b46c 100644
> --- a/fs/ntfs/file.c
> +++ b/fs/ntfs/file.c
> @@ -281,7 +281,7 @@ static int ntfs_setattr_size(struct inode *vi, struct iattr *attr)
>  				round_up(old_size, PAGE_SIZE) - old_size,
>  				attr->ia_size - old_size);
>  		err = iomap_zero_range(vi, old_size, len,
> -				NULL, &ntfs_seek_iomap_ops,
> +				NULL, ntfs_seek_iomap_next,
>  				&ntfs_iomap_folio_ops, NULL);
>  	}
>  
> @@ -417,12 +417,12 @@ static loff_t ntfs_file_llseek(struct file *file, loff_t offset, int whence)
>  	switch (whence) {
>  	case SEEK_HOLE:
>  		inode_lock_shared(inode);
> -		offset = iomap_seek_hole(inode, offset, &ntfs_seek_iomap_ops);
> +		offset = iomap_seek_hole(inode, offset, ntfs_seek_iomap_next);
>  		inode_unlock_shared(inode);
>  		break;
>  	case SEEK_DATA:
>  		inode_lock_shared(inode);
> -		offset = iomap_seek_data(inode, offset, &ntfs_seek_iomap_ops);
> +		offset = iomap_seek_data(inode, offset, ntfs_seek_iomap_next);
>  		inode_unlock_shared(inode);
>  		break;
>  	default:
> @@ -458,7 +458,7 @@ static ssize_t ntfs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
>  		}
>  
>  		file_accessed(iocb->ki_filp);
> -		ret = iomap_dio_rw(iocb, to, &ntfs_read_iomap_ops, NULL, 0,
> +		ret = iomap_dio_rw(iocb, to, ntfs_read_iomap_next, NULL, 0,
>  				NULL, 0);
>  	} else {
>  		ret = generic_file_read_iter(iocb, to);
> @@ -496,7 +496,7 @@ static ssize_t ntfs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  {
>  	ssize_t ret;
>  
> -	ret = iomap_dio_rw(iocb, from, &ntfs_dio_iomap_ops,
> +	ret = iomap_dio_rw(iocb, from, ntfs_dio_iomap_next,
>  			&ntfs_write_dio_ops, 0, NULL, 0);
>  	if (ret == -ENOTBLK)
>  		ret = 0;
> @@ -511,7 +511,7 @@ static ssize_t ntfs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  		offset = iocb->ki_pos;
>  		iocb->ki_flags &= ~IOCB_DIRECT;
>  		written = iomap_file_buffered_write(iocb, from,
> -				&ntfs_write_iomap_ops, &ntfs_iomap_folio_ops,
> +				ntfs_write_iomap_next, &ntfs_iomap_folio_ops,
>  				NULL);
>  		if (written < 0) {
>  			ret = written;
> @@ -594,7 +594,7 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  	if (NInoNonResident(ni) && iocb->ki_flags & IOCB_DIRECT)
>  		ret = ntfs_dio_write_iter(iocb, from);
>  	else
> -		ret = iomap_file_buffered_write(iocb, from, &ntfs_write_iomap_ops,
> +		ret = iomap_file_buffered_write(iocb, from, ntfs_write_iomap_next,
>  				&ntfs_iomap_folio_ops, NULL);
>  out:
>  	if (ret < 0 && ret != -EIOCBQUEUED) {
> @@ -623,7 +623,7 @@ static vm_fault_t ntfs_filemap_page_mkwrite(struct vm_fault *vmf)
>  	sb_start_pagefault(inode->i_sb);
>  	file_update_time(vmf->vma->vm_file);
>  
> -	ret = iomap_page_mkwrite(vmf, &ntfs_page_mkwrite_iomap_ops, NULL);
> +	ret = iomap_page_mkwrite(vmf, ntfs_page_mkwrite_iomap_next, NULL);
>  	sb_end_pagefault(inode->i_sb);
>  	return ret;
>  }
> @@ -670,7 +670,7 @@ static int ntfs_file_mmap_prepare(struct vm_area_desc *desc)
>  static int ntfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
>  		u64 start, u64 len)
>  {
> -	return iomap_fiemap(inode, fieinfo, start, len, &ntfs_read_iomap_ops);
> +	return iomap_fiemap(inode, fieinfo, start, len, ntfs_read_iomap_next);
>  }
>  
>  static const char *ntfs_get_link(struct dentry *dentry, struct inode *inode,
> @@ -911,7 +911,7 @@ static int ntfs_punch_hole(struct ntfs_inode *ni, int mode, loff_t offset,
>  				   ntfs_cluster_to_bytes(vol, start_vcn + 1),
>  				   end_offset);
>  			err = iomap_zero_range(vi, offset, to - offset,
> -					       NULL, &ntfs_seek_iomap_ops,
> +					       NULL, ntfs_seek_iomap_next,
>  					       &ntfs_iomap_folio_ops, NULL);
>  			if (err < 0)
>  				goto out;
> @@ -927,7 +927,7 @@ static int ntfs_punch_hole(struct ntfs_inode *ni, int mode, loff_t offset,
>  		from = ntfs_cluster_to_bytes(vol, end_vcn - 1);
>  		if (from < ni->initialized_size) {
>  			err = iomap_zero_range(vi, from, end_offset - from,
> -					       NULL, &ntfs_seek_iomap_ops,
> +					       NULL, ntfs_seek_iomap_next,
>  					       &ntfs_iomap_folio_ops, NULL);
>  			if (err < 0)
>  				goto out;
> @@ -1131,7 +1131,7 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t offset, loff_t le
>  					   round_up(old_size, PAGE_SIZE) - old_size,
>  					   offset - old_size);
>  			err = iomap_zero_range(vi, old_size, len, NULL,
> -					       &ntfs_seek_iomap_ops,
> +					       ntfs_seek_iomap_next,
>  					       &ntfs_iomap_folio_ops, NULL);
>  		}
>  		NInoSetFileNameDirty(ni);
> diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
> index c2715521e562..05132d92e87b 100644
> --- a/fs/ntfs/inode.c
> +++ b/fs/ntfs/inode.c
> @@ -2415,7 +2415,7 @@ int ntfs_extend_initialized_size(struct inode *vi, const loff_t offset,
>  	if (!NInoCompressed(ni) && old_init_size < offset) {
>  		err = iomap_zero_range(vi, old_init_size,
>  				       offset - old_init_size,
> -				       NULL, &ntfs_seek_iomap_ops,
> +				       NULL, ntfs_seek_iomap_next,
>  				       &ntfs_iomap_folio_ops, NULL);
>  		if (err)
>  			return err;
> diff --git a/fs/ntfs/iomap.c b/fs/ntfs/iomap.c
> index 0f9f02e1593e..502f08f01354 100644
> --- a/fs/ntfs/iomap.c
> +++ b/fs/ntfs/iomap.c
> @@ -277,16 +277,12 @@ static int ntfs_read_iomap_begin(struct inode *inode, loff_t offset, loff_t leng
>  			srcmap, true);
>  }
>  
> -static int ntfs_read_iomap_next(const struct iomap_iter *iter,
> -		struct iomap *iomap, struct iomap *srcmap)
> +int ntfs_read_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap)
>  {
>  	return iomap_process(iter, iomap, srcmap, ntfs_read_iomap_begin, NULL);
>  }
>  
> -const struct iomap_ops ntfs_read_iomap_ops = {
> -	.iomap_next = ntfs_read_iomap_next,
> -};
> -
>  /*
>   * Check that the cached iomap still matches the NTFS runlist before
>   * iomap_zero_range() is called. if the runlist changes while iomap is
> @@ -342,20 +338,12 @@ static int ntfs_zero_read_iomap_next(const struct iomap_iter *iter,
>  			ntfs_zero_read_iomap_end);
>  }
>  
> -static const struct iomap_ops ntfs_zero_read_iomap_ops = {
> -	.iomap_next = ntfs_zero_read_iomap_next,
> -};
> -
> -static int ntfs_seek_iomap_next(const struct iomap_iter *iter,
> +int ntfs_seek_iomap_next(const struct iomap_iter *iter,
>  		struct iomap *iomap, struct iomap *srcmap)
>  {
>  	return iomap_process(iter, iomap, srcmap, ntfs_seek_iomap_begin, NULL);
>  }
>  
> -const struct iomap_ops ntfs_seek_iomap_ops = {
> -	.iomap_next = ntfs_seek_iomap_next,
> -};
> -
>  int ntfs_dio_zero_range(struct inode *inode, loff_t offset, loff_t length)
>  {
>  	if ((offset | length) & (SECTOR_SIZE - 1))
> @@ -373,7 +361,7 @@ static int ntfs_zero_range(struct inode *inode, loff_t offset, loff_t length)
>  	return iomap_zero_range(inode,
>  				offset, length,
>  				NULL,
> -				&ntfs_zero_read_iomap_ops,
> +				ntfs_zero_read_iomap_next,
>  				&ntfs_zero_iomap_folio_ops,
>  				NULL);
>  }
> @@ -782,17 +770,13 @@ static int ntfs_write_iomap_end(struct inode *inode, loff_t pos, loff_t length,
>  	return written;
>  }
>  
> -static int ntfs_write_iomap_next(const struct iomap_iter *iter,
> -		struct iomap *iomap, struct iomap *srcmap)
> +int ntfs_write_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap)
>  {
>  	return iomap_process(iter, iomap, srcmap, ntfs_write_iomap_begin,
>  			ntfs_write_iomap_end);
>  }
>  
> -const struct iomap_ops ntfs_write_iomap_ops = {
> -	.iomap_next		= ntfs_write_iomap_next,
> -};
> -
>  static int ntfs_page_mkwrite_iomap_begin(struct inode *inode, loff_t offset,
>  				  loff_t length, unsigned int flags,
>  				  struct iomap *iomap, struct iomap *srcmap)
> @@ -801,17 +785,13 @@ static int ntfs_page_mkwrite_iomap_begin(struct inode *inode, loff_t offset,
>  			NTFS_IOMAP_FLAGS_MKWRITE);
>  }
>  
> -static int ntfs_page_mkwrite_iomap_next(const struct iomap_iter *iter,
> +int ntfs_page_mkwrite_iomap_next(const struct iomap_iter *iter,
>  		struct iomap *iomap, struct iomap *srcmap)
>  {
>  	return iomap_process(iter, iomap, srcmap, ntfs_page_mkwrite_iomap_begin,
>  			ntfs_write_iomap_end);
>  }
>  
> -const struct iomap_ops ntfs_page_mkwrite_iomap_ops = {
> -	.iomap_next		= ntfs_page_mkwrite_iomap_next,
> -};
> -
>  static int ntfs_dio_iomap_begin(struct inode *inode, loff_t offset,
>  				  loff_t length, unsigned int flags,
>  				  struct iomap *iomap, struct iomap *srcmap)
> @@ -820,17 +800,13 @@ static int ntfs_dio_iomap_begin(struct inode *inode, loff_t offset,
>  			NTFS_IOMAP_FLAGS_DIO);
>  }
>  
> -static int ntfs_dio_iomap_next(const struct iomap_iter *iter,
> -		struct iomap *iomap, struct iomap *srcmap)
> +int ntfs_dio_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap)
>  {
>  	return iomap_process(iter, iomap, srcmap, ntfs_dio_iomap_begin,
>  			ntfs_write_iomap_end);
>  }
>  
> -const struct iomap_ops ntfs_dio_iomap_ops = {
> -	.iomap_next		= ntfs_dio_iomap_next,
> -};
> -
>  static ssize_t ntfs_writeback_range(struct iomap_writepage_ctx *wpc,
>  		struct folio *folio, u64 offset, unsigned int len, u64 end_pos)
>  {
> diff --git a/fs/ntfs/iomap.h b/fs/ntfs/iomap.h
> index 3abc1d493e91..69443de1fefd 100644
> --- a/fs/ntfs/iomap.h
> +++ b/fs/ntfs/iomap.h
> @@ -12,11 +12,16 @@
>  #include "volume.h"
>  #include "inode.h"
>  
> -extern const struct iomap_ops ntfs_write_iomap_ops;
> -extern const struct iomap_ops ntfs_read_iomap_ops;
> -extern const struct iomap_ops ntfs_seek_iomap_ops;
> -extern const struct iomap_ops ntfs_page_mkwrite_iomap_ops;
> -extern const struct iomap_ops ntfs_dio_iomap_ops;
> +int ntfs_write_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
> +int ntfs_read_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
> +int ntfs_seek_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
> +int ntfs_page_mkwrite_iomap_next(const struct iomap_iter *iter,
> +		struct iomap *iomap, struct iomap *srcmap);
> +int ntfs_dio_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
>  extern const struct iomap_writeback_ops ntfs_writeback_ops;
>  extern const struct iomap_write_ops ntfs_iomap_folio_ops;
>  extern int ntfs_dio_zero_range(struct inode *inode, loff_t offset, loff_t length);
> diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
> index d601f088618c..55844b42920a 100644
> --- a/fs/ntfs3/file.c
> +++ b/fs/ntfs3/file.c
> @@ -315,7 +315,7 @@ static int ntfs_extend_initialized_size(struct file *file,
>  	}
>  
>  	err = iomap_zero_range(inode, valid, new_valid - valid, NULL,
> -			       &ntfs_iomap_ops, &ntfs_iomap_folio_ops, NULL);
> +			       ntfs_iomap_next, &ntfs_iomap_folio_ops, NULL);
>  	if (err) {
>  		ni->i_valid = valid;
>  		ntfs_inode_warn(inode,
> @@ -554,7 +554,7 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
>  		/* Zero head of punch. */
>  		if (tmp > from) {
>  			err = iomap_zero_range(inode, from, tmp - from, NULL,
> -					       &ntfs_iomap_ops,
> +					       ntfs_iomap_next,
>  					       &ntfs_iomap_folio_ops, NULL);
>  			if (err)
>  				goto out;
> @@ -572,7 +572,7 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
>  		/* Zero tail of punch. */
>  		if (vbo < end_a && end_a < end) {
>  			err = iomap_zero_range(inode, end_a, end - end_a, NULL,
> -					       &ntfs_iomap_ops,
> +					       ntfs_iomap_next,
>  					       &ntfs_iomap_folio_ops, NULL);
>  			if (err)
>  				goto out;
> @@ -872,7 +872,7 @@ static ssize_t ntfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
>  				goto out;
>  		}
>  
> -		err = iomap_dio_rw(iocb, iter, &ntfs_iomap_ops, NULL, dio_flags,
> +		err = iomap_dio_rw(iocb, iter, ntfs_iomap_next, NULL, dio_flags,
>  				   NULL, 0);
>  
>  		if (err <= 0)
> @@ -1286,7 +1286,7 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  	    !ntfs_should_use_dio(iocb, from)) {
>  		iocb->ki_flags &= ~IOCB_DIRECT;
>  
> -		ret = iomap_file_buffered_write(iocb, from, &ntfs_iomap_ops,
> +		ret = iomap_file_buffered_write(iocb, from, ntfs_iomap_next,
>  						&ntfs_iomap_folio_ops, NULL);
>  		inode_unlock(inode);
>  
> @@ -1303,7 +1303,7 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  			goto out;
>  	}
>  
> -	ret = iomap_dio_rw(iocb, from, &ntfs_iomap_ops, NULL,
> +	ret = iomap_dio_rw(iocb, from, ntfs_iomap_next, NULL,
>  			   IOMAP_DIO_FORCE_WAIT, NULL, 0);
>  
>  	if (ret == -ENOTBLK) {
> @@ -1316,7 +1316,7 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  		vbo = iocb->ki_pos;
>  
>  		iocb->ki_flags &= ~IOCB_DIRECT;
> -		err = iomap_file_buffered_write(iocb, from, &ntfs_iomap_ops,
> +		err = iomap_file_buffered_write(iocb, from, ntfs_iomap_next,
>  						&ntfs_iomap_folio_ops, NULL);
>  		if (err < 0) {
>  			ret = err;
> @@ -1465,7 +1465,7 @@ int ntfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
>  
>  	inode_lock_shared(inode);
>  
> -	err = iomap_fiemap(inode, fieinfo, start, len, &ntfs_iomap_ops);
> +	err = iomap_fiemap(inode, fieinfo, start, len, ntfs_iomap_next);
>  
>  	inode_unlock_shared(inode);
>  	return err;
> diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c
> index c5676c51a3a4..8a454ab6ee2a 100644
> --- a/fs/ntfs3/inode.c
> +++ b/fs/ntfs3/inode.c
> @@ -576,7 +576,7 @@ static sector_t ntfs_bmap(struct address_space *mapping, sector_t block)
>  		ni_allocate_da_blocks(ni);
>  	}
>  
> -	return iomap_bmap(mapping, block, &ntfs_iomap_ops);
> +	return iomap_bmap(mapping, block, ntfs_iomap_next);
>  }
>  
>  static void ntfs_iomap_read_end_io(struct bio *bio)
> @@ -649,7 +649,7 @@ static int ntfs_read_folio(struct file *file, struct folio *folio)
>  		return err;
>  	}
>  
> -	iomap_read_folio(&ntfs_iomap_ops, &ctx, NULL);
> +	iomap_read_folio(ntfs_iomap_next, &ctx, NULL);
>  	return 0;
>  }
>  
> @@ -673,7 +673,7 @@ static void ntfs_readahead(struct readahead_control *rac)
>  		return;
>  	}
>  
> -	iomap_readahead(&ntfs_iomap_ops, &ctx, NULL);
> +	iomap_readahead(ntfs_iomap_next, &ctx, NULL);
>  }
>  
>  int ntfs_set_size(struct inode *inode, u64 new_size)
> @@ -2101,17 +2101,13 @@ const struct address_space_operations ntfs_aops_cmpr = {
>  	.invalidate_folio = iomap_invalidate_folio,
>  };
>  
> -static int ntfs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +int ntfs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
>  			   struct iomap *srcmap)
>  {
>  	return iomap_process(iter, iomap, srcmap, ntfs_iomap_begin,
>  			     ntfs_iomap_end);
>  }
>  
> -const struct iomap_ops ntfs_iomap_ops = {
> -	.iomap_next	= ntfs_iomap_next,
> -};
> -
>  const struct iomap_write_ops ntfs_iomap_folio_ops = {
>  	.put_folio = ntfs_iomap_put_folio,
>  };
> diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h
> index d98d7e474476..e00dae3ce700 100644
> --- a/fs/ntfs3/ntfs_fs.h
> +++ b/fs/ntfs3/ntfs_fs.h
> @@ -785,7 +785,8 @@ int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
>  int ntfs_link_inode(struct inode *inode, struct dentry *dentry);
>  int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry);
>  void ntfs_evict_inode(struct inode *inode);
> -extern const struct iomap_ops ntfs_iomap_ops;
> +int ntfs_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		    struct iomap *srcmap);
>  extern const struct iomap_write_ops ntfs_iomap_folio_ops;
>  extern const struct inode_operations ntfs_link_inode_operations;
>  extern const struct address_space_operations ntfs_aops;
> diff --git a/fs/remap_range.c b/fs/remap_range.c
> index 26afbbbfb10c..3d0a355dc90e 100644
> --- a/fs/remap_range.c
> +++ b/fs/remap_range.c
> @@ -277,7 +277,7 @@ int
>  __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
>  				struct file *file_out, loff_t pos_out,
>  				loff_t *len, unsigned int remap_flags,
> -				const struct iomap_ops *dax_read_ops)
> +				iomap_next_fn dax_read_next)
>  {
>  	struct inode *inode_in = file_inode(file_in);
>  	struct inode *inode_out = file_inode(file_out);
> @@ -340,10 +340,10 @@ __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
>  		if (!IS_DAX(inode_in))
>  			ret = vfs_dedupe_file_range_compare(file_in, pos_in,
>  					file_out, pos_out, *len, &is_same);
> -		else if (dax_read_ops)
> +		else if (dax_read_next)
>  			ret = dax_dedupe_file_range_compare(inode_in, pos_in,
>  					inode_out, pos_out, *len, &is_same,
> -					dax_read_ops);
> +					dax_read_next);
>  		else
>  			return -EINVAL;
>  		if (ret)
> diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
> index 2a0c54256e93..91480cb6a4d8 100644
> --- a/fs/xfs/xfs_aops.c
> +++ b/fs/xfs/xfs_aops.c
> @@ -752,7 +752,7 @@ xfs_vm_bmap(
>  	 */
>  	if (xfs_is_cow_inode(ip) || XFS_IS_REALTIME_INODE(ip))
>  		return 0;
> -	return iomap_bmap(mapping, block, &xfs_read_iomap_ops);
> +	return iomap_bmap(mapping, block, xfs_read_iomap_next);
>  }
>  
>  static void
> @@ -793,7 +793,7 @@ xfs_vm_read_folio(
>  	struct iomap_read_folio_ctx	ctx = { .cur_folio = folio };
>  
>  	ctx.ops = xfs_get_iomap_read_ops(folio->mapping);
> -	iomap_read_folio(&xfs_read_iomap_ops, &ctx, NULL);
> +	iomap_read_folio(xfs_read_iomap_next, &ctx, NULL);
>  	return 0;
>  }
>  
> @@ -804,7 +804,7 @@ xfs_vm_readahead(
>  	struct iomap_read_folio_ctx	ctx = { .rac = rac };
>  
>  	ctx.ops = xfs_get_iomap_read_ops(rac->mapping),
> -	iomap_readahead(&xfs_read_iomap_ops, &ctx, NULL);
> +	iomap_readahead(xfs_read_iomap_next, &ctx, NULL);
>  }
>  
>  static int
> @@ -850,7 +850,7 @@ xfs_vm_swap_activate(
>  	sis->bdev = xfs_inode_buftarg(ip)->bt_bdev;
>  
>  	return iomap_swapfile_activate(sis, swap_file, span,
> -			&xfs_read_iomap_ops);
> +			xfs_read_iomap_next);
>  }
>  
>  const struct address_space_operations xfs_address_space_operations = {
> diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> index 7f8bef1a9954..a987ffbf3c02 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -269,7 +269,7 @@ xfs_file_dio_read(
>  		dio_ops = &xfs_dio_read_bounce_ops;
>  		dio_flags |= IOMAP_DIO_BOUNCE;
>  	}
> -	ret = iomap_dio_rw(iocb, to, &xfs_read_iomap_ops, dio_ops, dio_flags,
> +	ret = iomap_dio_rw(iocb, to, xfs_read_iomap_next, dio_ops, dio_flags,
>  			NULL, 0);
>  	xfs_iunlock(ip, XFS_IOLOCK_SHARED);
>  
> @@ -292,7 +292,7 @@ xfs_file_dax_read(
>  	ret = xfs_ilock_iocb(iocb, XFS_IOLOCK_SHARED);
>  	if (ret)
>  		return ret;
> -	ret = dax_iomap_rw(iocb, to, &xfs_read_iomap_ops);
> +	ret = dax_iomap_rw(iocb, to, xfs_read_iomap_next);
>  	xfs_iunlock(ip, XFS_IOLOCK_SHARED);
>  
>  	file_accessed(iocb->ki_filp);
> @@ -742,7 +742,7 @@ xfs_file_dio_write_aligned(
>  	struct xfs_inode	*ip,
>  	struct kiocb		*iocb,
>  	struct iov_iter		*from,
> -	const struct iomap_ops	*ops,
> +	iomap_next_fn		iomap_next,
>  	const struct iomap_dio_ops *dops,
>  	struct xfs_zone_alloc_ctx *ac)
>  {
> @@ -777,7 +777,7 @@ xfs_file_dio_write_aligned(
>  	if (mapping_stable_writes(iocb->ki_filp->f_mapping))
>  		dio_flags |= IOMAP_DIO_BOUNCE;
>  	trace_xfs_file_direct_write(iocb, from);
> -	ret = iomap_dio_rw(iocb, from, ops, dops, dio_flags, ac, 0);
> +	ret = iomap_dio_rw(iocb, from, iomap_next, dops, dio_flags, ac, 0);
>  out_unlock:
>  	xfs_iunlock(ip, iolock);
>  	return ret;
> @@ -799,7 +799,7 @@ xfs_file_dio_write_zoned(
>  	if (ret < 0)
>  		return ret;
>  	ret = xfs_file_dio_write_aligned(ip, iocb, from,
> -			&xfs_zoned_direct_write_iomap_ops,
> +			xfs_zoned_direct_write_iomap_next,
>  			&xfs_dio_zoned_write_ops, &ac);
>  	xfs_zoned_space_unreserve(ip->i_mount, &ac);
>  	return ret;
> @@ -824,16 +824,16 @@ xfs_file_dio_write_atomic(
>  	unsigned int		iolock = XFS_IOLOCK_SHARED;
>  	ssize_t			ret, ocount = iov_iter_count(from);
>  	unsigned int		dio_flags = 0;
> -	const struct iomap_ops	*dops;
> +	iomap_next_fn		dops;
>  
>  	/*
>  	 * HW offload should be faster, so try that first if it is already
>  	 * known that the write length is not too large.
>  	 */
>  	if (ocount > xfs_inode_buftarg(ip)->bt_awu_max)
> -		dops = &xfs_atomic_write_cow_iomap_ops;
> +		dops = xfs_atomic_write_cow_iomap_next;
>  	else
> -		dops = &xfs_direct_write_iomap_ops;
> +		dops = xfs_direct_write_iomap_next;
>  
>  retry:
>  	ret = xfs_ilock_iocb_for_write(iocb, &iolock);
> @@ -862,9 +862,9 @@ xfs_file_dio_write_atomic(
>  	 * possible. The REQ_ATOMIC-based method is typically not possible if
>  	 * the write spans multiple extents or the disk blocks are misaligned.
>  	 */
> -	if (ret == -ENOPROTOOPT && dops == &xfs_direct_write_iomap_ops) {
> +	if (ret == -ENOPROTOOPT && dops == xfs_direct_write_iomap_next) {
>  		xfs_iunlock(ip, iolock);
> -		dops = &xfs_atomic_write_cow_iomap_ops;
> +		dops = xfs_atomic_write_cow_iomap_next;
>  		goto retry;
>  	}
>  
> @@ -947,7 +947,7 @@ xfs_file_dio_write_unaligned(
>  		flags |= IOMAP_DIO_BOUNCE;
>  
>  	trace_xfs_file_direct_write(iocb, from);
> -	ret = iomap_dio_rw(iocb, from, &xfs_direct_write_iomap_ops,
> +	ret = iomap_dio_rw(iocb, from, xfs_direct_write_iomap_next,
>  			   &xfs_dio_write_ops, flags, NULL, 0);
>  
>  	/*
> @@ -987,7 +987,7 @@ xfs_file_dio_write(
>  	if (iocb->ki_flags & IOCB_ATOMIC)
>  		return xfs_file_dio_write_atomic(ip, iocb, from);
>  	return xfs_file_dio_write_aligned(ip, iocb, from,
> -			&xfs_direct_write_iomap_ops, &xfs_dio_write_ops, NULL);
> +			xfs_direct_write_iomap_next, &xfs_dio_write_ops, NULL);
>  }
>  
>  static noinline ssize_t
> @@ -1011,7 +1011,7 @@ xfs_file_dax_write(
>  	pos = iocb->ki_pos;
>  
>  	trace_xfs_file_dax_write(iocb, from);
> -	ret = dax_iomap_rw(iocb, from, &xfs_dax_write_iomap_ops);
> +	ret = dax_iomap_rw(iocb, from, xfs_dax_write_iomap_next);
>  	if (ret > 0 && iocb->ki_pos > i_size_read(inode)) {
>  		i_size_write(inode, iocb->ki_pos);
>  		error = xfs_setfilesize(ip, pos, ret);
> @@ -1054,7 +1054,7 @@ xfs_file_buffered_write(
>  
>  	trace_xfs_file_buffered_write(iocb, from);
>  	ret = iomap_file_buffered_write(iocb, from,
> -			&xfs_buffered_write_iomap_ops, &xfs_iomap_write_ops,
> +			xfs_buffered_write_iomap_next, &xfs_iomap_write_ops,
>  			NULL);
>  
>  	/*
> @@ -1135,7 +1135,7 @@ xfs_file_buffered_write_zoned(
>  retry:
>  	trace_xfs_file_buffered_write(iocb, from);
>  	ret = iomap_file_buffered_write(iocb, from,
> -			&xfs_buffered_write_iomap_ops, &xfs_iomap_write_ops,
> +			xfs_buffered_write_iomap_next, &xfs_iomap_write_ops,
>  			&ac);
>  	if (ret == -ENOSPC && !cleared_space) {
>  		/*
> @@ -1856,10 +1856,10 @@ xfs_file_llseek(
>  	default:
>  		return generic_file_llseek(file, offset, whence);
>  	case SEEK_HOLE:
> -		offset = iomap_seek_hole(inode, offset, &xfs_seek_iomap_ops);
> +		offset = iomap_seek_hole(inode, offset, xfs_seek_iomap_next);
>  		break;
>  	case SEEK_DATA:
> -		offset = iomap_seek_data(inode, offset, &xfs_seek_iomap_ops);
> +		offset = iomap_seek_data(inode, offset, xfs_seek_iomap_next);
>  		break;
>  	}
>  
> @@ -1883,8 +1883,8 @@ xfs_dax_fault_locked(
>  	}
>  	ret = dax_iomap_fault(vmf, order, &pfn, NULL,
>  			(write_fault && !vmf->cow_page) ?
> -				&xfs_dax_write_iomap_ops :
> -				&xfs_read_iomap_ops);
> +				xfs_dax_write_iomap_next :
> +				xfs_read_iomap_next);
>  	if (ret & VM_FAULT_NEEDDSYNC)
>  		ret = dax_finish_sync_fault(vmf, order, pfn);
>  	return ret;
> @@ -1948,7 +1948,7 @@ __xfs_write_fault(
>  	if (IS_DAX(inode))
>  		ret = xfs_dax_fault_locked(vmf, order, true);
>  	else
> -		ret = iomap_page_mkwrite(vmf, &xfs_buffered_write_iomap_ops,
> +		ret = iomap_page_mkwrite(vmf, xfs_buffered_write_iomap_next,
>  				ac);
>  	xfs_iunlock(ip, lock_mode);
>  
> diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
> index 4fa1a5c985db..71c4bb024f04 100644
> --- a/fs/xfs/xfs_iomap.c
> +++ b/fs/xfs/xfs_iomap.c
> @@ -1037,7 +1037,7 @@ xfs_direct_write_iomap_begin(
>  	return error;
>  }
>  
> -static int
> +int
>  xfs_direct_write_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -1047,10 +1047,6 @@ xfs_direct_write_iomap_next(
>  			NULL);
>  }
>  
> -const struct iomap_ops xfs_direct_write_iomap_ops = {
> -	.iomap_next		= xfs_direct_write_iomap_next,
> -};
> -
>  #ifdef CONFIG_XFS_RT
>  /*
>   * This is really simple.  The space has already been reserved before taking the
> @@ -1099,7 +1095,7 @@ xfs_zoned_direct_write_iomap_begin(
>  	return 0;
>  }
>  
> -static int
> +int
>  xfs_zoned_direct_write_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -1109,9 +1105,6 @@ xfs_zoned_direct_write_iomap_next(
>  			xfs_zoned_direct_write_iomap_begin, NULL);
>  }
>  
> -const struct iomap_ops xfs_zoned_direct_write_iomap_ops = {
> -	.iomap_next		= xfs_zoned_direct_write_iomap_next,
> -};
>  #endif /* CONFIG_XFS_RT */
>  
>  #ifdef DEBUG
> @@ -1294,7 +1287,7 @@ xfs_atomic_write_cow_iomap_begin(
>  	return error;
>  }
>  
> -static int
> +int
>  xfs_atomic_write_cow_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -1304,10 +1297,6 @@ xfs_atomic_write_cow_iomap_next(
>  			xfs_atomic_write_cow_iomap_begin, NULL);
>  }
>  
> -const struct iomap_ops xfs_atomic_write_cow_iomap_ops = {
> -	.iomap_next		= xfs_atomic_write_cow_iomap_next,
> -};
> -
>  static int
>  xfs_dax_write_iomap_end(
>  	struct inode		*inode,
> @@ -1328,7 +1317,7 @@ xfs_dax_write_iomap_end(
>  	return xfs_reflink_end_cow(ip, pos, written);
>  }
>  
> -static int
> +int
>  xfs_dax_write_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -1338,10 +1327,6 @@ xfs_dax_write_iomap_next(
>  			xfs_dax_write_iomap_end);
>  }
>  
> -const struct iomap_ops xfs_dax_write_iomap_ops = {
> -	.iomap_next	= xfs_dax_write_iomap_next,
> -};
> -
>  /*
>   * Convert a hole to a delayed allocation.
>   */
> @@ -2207,7 +2192,7 @@ xfs_buffered_write_iomap_end(
>  	return 0;
>  }
>  
> -static int
> +int
>  xfs_buffered_write_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -2218,10 +2203,6 @@ xfs_buffered_write_iomap_next(
>  			xfs_buffered_write_iomap_end);
>  }
>  
> -const struct iomap_ops xfs_buffered_write_iomap_ops = {
> -	.iomap_next		= xfs_buffered_write_iomap_next,
> -};
> -
>  static int
>  xfs_read_iomap_begin(
>  	struct inode		*inode,
> @@ -2263,7 +2244,7 @@ xfs_read_iomap_begin(
>  				 shared ? IOMAP_F_SHARED : 0, seq);
>  }
>  
> -static int
> +int
>  xfs_read_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -2272,10 +2253,6 @@ xfs_read_iomap_next(
>  	return iomap_process(iter, iomap, srcmap, xfs_read_iomap_begin, NULL);
>  }
>  
> -const struct iomap_ops xfs_read_iomap_ops = {
> -	.iomap_next		= xfs_read_iomap_next,
> -};
> -
>  static int
>  xfs_seek_iomap_begin(
>  	struct inode		*inode,
> @@ -2360,7 +2337,7 @@ xfs_seek_iomap_begin(
>  	return error;
>  }
>  
> -static int
> +int
>  xfs_seek_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -2369,10 +2346,6 @@ xfs_seek_iomap_next(
>  	return iomap_process(iter, iomap, srcmap, xfs_seek_iomap_begin, NULL);
>  }
>  
> -const struct iomap_ops xfs_seek_iomap_ops = {
> -	.iomap_next		= xfs_seek_iomap_next,
> -};
> -
>  static int
>  xfs_xattr_iomap_begin(
>  	struct inode		*inode,
> @@ -2416,7 +2389,7 @@ xfs_xattr_iomap_begin(
>  	return xfs_bmbt_to_iomap(ip, iomap, &imap, flags, IOMAP_F_XATTR, seq);
>  }
>  
> -static int
> +int
>  xfs_xattr_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -2425,10 +2398,6 @@ xfs_xattr_iomap_next(
>  	return iomap_process(iter, iomap, srcmap, xfs_xattr_iomap_begin, NULL);
>  }
>  
> -const struct iomap_ops xfs_xattr_iomap_ops = {
> -	.iomap_next		= xfs_xattr_iomap_next,
> -};
> -
>  int
>  xfs_zero_range(
>  	struct xfs_inode	*ip,
> @@ -2443,9 +2412,9 @@ xfs_zero_range(
>  
>  	if (IS_DAX(inode))
>  		return dax_zero_range(inode, pos, len, did_zero,
> -				      &xfs_dax_write_iomap_ops);
> +				      xfs_dax_write_iomap_next);
>  	return iomap_zero_range(inode, pos, len, did_zero,
> -			&xfs_buffered_write_iomap_ops, &xfs_iomap_write_ops,
> +			xfs_buffered_write_iomap_next, &xfs_iomap_write_ops,
>  			ac);
>  }
>  
> @@ -2460,8 +2429,8 @@ xfs_truncate_page(
>  
>  	if (IS_DAX(inode))
>  		return dax_truncate_page(inode, pos, did_zero,
> -					&xfs_dax_write_iomap_ops);
> +					xfs_dax_write_iomap_next);
>  	return iomap_truncate_page(inode, pos, did_zero,
> -			&xfs_buffered_write_iomap_ops, &xfs_iomap_write_ops,
> +			xfs_buffered_write_iomap_next, &xfs_iomap_write_ops,
>  			ac);
>  }
> diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h
> index ebcce7d49446..01875d20fb66 100644
> --- a/fs/xfs/xfs_iomap.h
> +++ b/fs/xfs/xfs_iomap.h
> @@ -49,14 +49,22 @@ xfs_aligned_fsb_count(
>  	return count_fsb;
>  }
>  
> -extern const struct iomap_ops xfs_buffered_write_iomap_ops;
> -extern const struct iomap_ops xfs_direct_write_iomap_ops;
> -extern const struct iomap_ops xfs_zoned_direct_write_iomap_ops;
> -extern const struct iomap_ops xfs_read_iomap_ops;
> -extern const struct iomap_ops xfs_seek_iomap_ops;
> -extern const struct iomap_ops xfs_xattr_iomap_ops;
> -extern const struct iomap_ops xfs_dax_write_iomap_ops;
> -extern const struct iomap_ops xfs_atomic_write_cow_iomap_ops;
> +int xfs_buffered_write_iomap_next(const struct iomap_iter *iter,
> +		struct iomap *iomap, struct iomap *srcmap);
> +int xfs_direct_write_iomap_next(const struct iomap_iter *iter,
> +		struct iomap *iomap, struct iomap *srcmap);
> +int xfs_zoned_direct_write_iomap_next(const struct iomap_iter *iter,
> +		struct iomap *iomap, struct iomap *srcmap);
> +int xfs_read_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
> +int xfs_seek_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
> +int xfs_xattr_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
> +int xfs_dax_write_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
> +int xfs_atomic_write_cow_iomap_next(const struct iomap_iter *iter,
> +		struct iomap *iomap, struct iomap *srcmap);
>  extern const struct iomap_write_ops xfs_iomap_write_ops;
>  
>  #endif /* __XFS_IOMAP_H__*/
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index 6339f4956ecb..5c3d9a365f93 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -1239,10 +1239,10 @@ xfs_vn_fiemap(
>  	if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) {
>  		fieinfo->fi_flags &= ~FIEMAP_FLAG_XATTR;
>  		error = iomap_fiemap(inode, fieinfo, start, length,
> -				&xfs_xattr_iomap_ops);
> +				xfs_xattr_iomap_next);
>  	} else {
>  		error = iomap_fiemap(inode, fieinfo, start, length,
> -				&xfs_read_iomap_ops);
> +				xfs_read_iomap_next);
>  	}
>  	xfs_iunlock(XFS_I(inode), XFS_IOLOCK_SHARED);
>  
> diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
> index a5c188b78138..2b9792626bab 100644
> --- a/fs/xfs/xfs_reflink.c
> +++ b/fs/xfs/xfs_reflink.c
> @@ -1683,7 +1683,7 @@ xfs_reflink_remap_prep(
>  				pos_out, len, remap_flags);
>  	else
>  		ret = dax_remap_file_range_prep(file_in, pos_in, file_out,
> -				pos_out, len, remap_flags, &xfs_read_iomap_ops);
> +				pos_out, len, remap_flags, xfs_read_iomap_next);
>  	if (ret || *len == 0)
>  		goto out_unlock;
>  
> @@ -1878,10 +1878,10 @@ xfs_reflink_unshare(
>  
>  	if (IS_DAX(inode))
>  		error = dax_file_unshare(inode, offset, len,
> -				&xfs_dax_write_iomap_ops);
> +				xfs_dax_write_iomap_next);
>  	else
>  		error = iomap_file_unshare(inode, offset, len,
> -				&xfs_buffered_write_iomap_ops,
> +				xfs_buffered_write_iomap_next,
>  				&xfs_iomap_write_ops);
>  	if (error)
>  		goto out;
> diff --git a/fs/zonefs/file.c b/fs/zonefs/file.c
> index a29a8756d660..3ef1a655dbfe 100644
> --- a/fs/zonefs/file.c
> +++ b/fs/zonefs/file.c
> @@ -64,10 +64,6 @@ static int zonefs_read_iomap_next(const struct iomap_iter *iter,
>  			     NULL);
>  }
>  
> -static const struct iomap_ops zonefs_read_iomap_ops = {
> -	.iomap_next	= zonefs_read_iomap_next,
> -};
> -
>  static int zonefs_write_iomap_begin(struct inode *inode, loff_t offset,
>  				    loff_t length, unsigned int flags,
>  				    struct iomap *iomap, struct iomap *srcmap)
> @@ -120,19 +116,15 @@ static int zonefs_write_iomap_next(const struct iomap_iter *iter,
>  			     NULL);
>  }
>  
> -static const struct iomap_ops zonefs_write_iomap_ops = {
> -	.iomap_next	= zonefs_write_iomap_next,
> -};
> -
>  static int zonefs_read_folio(struct file *unused, struct folio *folio)
>  {
> -	iomap_bio_read_folio(folio, &zonefs_read_iomap_ops);
> +	iomap_bio_read_folio(folio, zonefs_read_iomap_next);
>  	return 0;
>  }
>  
>  static void zonefs_readahead(struct readahead_control *rac)
>  {
> -	iomap_bio_readahead(rac, &zonefs_read_iomap_ops);
> +	iomap_bio_readahead(rac, zonefs_read_iomap_next);
>  }
>  
>  /*
> @@ -193,7 +185,7 @@ static int zonefs_swap_activate(struct swap_info_struct *sis,
>  	}
>  
>  	return iomap_swapfile_activate(sis, swap_file, span,
> -				       &zonefs_read_iomap_ops);
> +				       zonefs_read_iomap_next);
>  }
>  
>  const struct address_space_operations zonefs_file_aops = {
> @@ -323,7 +315,7 @@ static vm_fault_t zonefs_filemap_page_mkwrite(struct vm_fault *vmf)
>  
>  	/* Serialize against truncates */
>  	filemap_invalidate_lock_shared(inode->i_mapping);
> -	ret = iomap_page_mkwrite(vmf, &zonefs_write_iomap_ops, NULL);
> +	ret = iomap_page_mkwrite(vmf, zonefs_write_iomap_next, NULL);
>  	filemap_invalidate_unlock_shared(inode->i_mapping);
>  
>  	sb_end_pagefault(inode->i_sb);
> @@ -539,7 +531,7 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
>  	 * page invalidation. Overwrite that error code with EBUSY so that
>  	 * the user can make sense of the error.
>  	 */
> -	ret = iomap_dio_rw(iocb, from, &zonefs_write_iomap_ops,
> +	ret = iomap_dio_rw(iocb, from, zonefs_write_iomap_next,
>  			   &zonefs_write_dio_ops, 0, NULL, 0);
>  	if (ret == -ENOTBLK)
>  		ret = -EBUSY;
> @@ -589,7 +581,7 @@ static ssize_t zonefs_file_buffered_write(struct kiocb *iocb,
>  	if (ret <= 0)
>  		goto inode_unlock;
>  
> -	ret = iomap_file_buffered_write(iocb, from, &zonefs_write_iomap_ops,
> +	ret = iomap_file_buffered_write(iocb, from, zonefs_write_iomap_next,
>  			NULL, NULL);
>  	if (ret == -EIO)
>  		zonefs_io_error(inode, true);
> @@ -684,7 +676,7 @@ static ssize_t zonefs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
>  			goto inode_unlock;
>  		}
>  		file_accessed(iocb->ki_filp);
> -		ret = iomap_dio_rw(iocb, to, &zonefs_read_iomap_ops,
> +		ret = iomap_dio_rw(iocb, to, zonefs_read_iomap_next,
>  				   &zonefs_read_dio_ops, 0, NULL, 0);
>  	} else {
>  		ret = generic_file_read_iter(iocb, to);
> diff --git a/include/linux/dax.h b/include/linux/dax.h
> index fe6c3ded1b50..a5a88f5186bf 100644
> --- a/include/linux/dax.h
> +++ b/include/linux/dax.h
> @@ -3,6 +3,7 @@
>  #define _LINUX_DAX_H
>  
>  #include <linux/fs.h>
> +#include <linux/iomap.h>
>  #include <linux/mm.h>
>  #include <linux/radix-tree.h>
>  
> @@ -10,9 +11,6 @@ typedef unsigned long dax_entry_t;
>  
>  struct dax_device;
>  struct gendisk;
> -struct iomap_ops;
> -struct iomap_iter;
> -struct iomap;
>  
>  enum dax_access_mode {
>  	DAX_ACCESS,
> @@ -213,11 +211,11 @@ static inline void dax_unlock_mapping_entry(struct address_space *mapping,
>  #endif
>  
>  int dax_file_unshare(struct inode *inode, loff_t pos, loff_t len,
> -		const struct iomap_ops *ops);
> +		iomap_next_fn iomap_next);
>  int dax_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
> -		const struct iomap_ops *ops);
> +		iomap_next_fn iomap_next);
>  int dax_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
> -		const struct iomap_ops *ops);
> +		iomap_next_fn iomap_next);
>  
>  static inline bool dax_page_is_idle(struct page *page)
>  {
> @@ -266,10 +264,10 @@ int dax_holder_notify_failure(struct dax_device *dax_dev, u64 off, u64 len,
>  void dax_flush(struct dax_device *dax_dev, void *addr, size_t size);
>  
>  ssize_t dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
> -		const struct iomap_ops *ops);
> +		iomap_next_fn iomap_next);
>  vm_fault_t dax_iomap_fault(struct vm_fault *vmf, unsigned int order,
>  			unsigned long *pfnp, int *errp,
> -			const struct iomap_ops *ops);
> +			iomap_next_fn iomap_next);
>  vm_fault_t dax_finish_sync_fault(struct vm_fault *vmf,
>  		unsigned int order, unsigned long pfn);
>  int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index);
> @@ -288,11 +286,11 @@ void dax_break_layout_final(struct inode *inode);
>  int dax_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
>  				  struct inode *dest, loff_t destoff,
>  				  loff_t len, bool *is_same,
> -				  const struct iomap_ops *ops);
> +				  iomap_next_fn iomap_next);
>  int dax_remap_file_range_prep(struct file *file_in, loff_t pos_in,
>  			      struct file *file_out, loff_t pos_out,
>  			      loff_t *len, unsigned int remap_flags,
> -			      const struct iomap_ops *ops);
> +			      iomap_next_fn iomap_next);
>  static inline bool dax_mapping(struct address_space *mapping)
>  {
>  	return mapping->host && IS_DAX(mapping->host);
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index d10897b3a1e3..2eb063438a3b 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -70,7 +70,8 @@ struct fsnotify_mark_connector;
>  struct fs_context;
>  struct fs_parameter_spec;
>  struct file_kattr;
> -struct iomap_ops;
> +struct iomap_iter;
> +struct iomap;
>  struct delegated_inode;
>  
>  extern void __init inode_init(void);
> @@ -2079,7 +2080,9 @@ int remap_verify_area(struct file *file, loff_t pos, loff_t len, bool write);
>  int __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
>  				    struct file *file_out, loff_t pos_out,
>  				    loff_t *len, unsigned int remap_flags,
> -				    const struct iomap_ops *dax_read_ops);
> +				    int (*dax_read_next)(const struct iomap_iter *iter,
> +							 struct iomap *iomap,
> +							 struct iomap *srcmap));
>  int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
>  				  struct file *file_out, loff_t pos_out,
>  				  loff_t *count, unsigned int remap_flags);
> diff --git a/include/linux/iomap.h b/include/linux/iomap.h
> index 52d6f585b941..3b41f123a92d 100644
> --- a/include/linux/iomap.h
> +++ b/include/linux/iomap.h
> @@ -237,12 +237,6 @@ typedef int (*iomap_end_fn)(struct inode *inode, loff_t pos, loff_t length,
>  typedef int (*iomap_next_fn)(const struct iomap_iter *iter, struct iomap *iomap,
>  		struct iomap *srcmap);
>  
> -struct iomap_ops {
> -	iomap_begin_fn iomap_begin;
> -	iomap_end_fn iomap_end;
> -	iomap_next_fn iomap_next;
> -};
> -
>  /**
>   * struct iomap_iter - Iterate through a range of a file
>   * @inode: Set at the start of the iteration and should not change.
> @@ -271,7 +265,7 @@ struct iomap_iter {
>  	void *private;
>  };
>  
> -int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops);
> +int iomap_iter(struct iomap_iter *iter, iomap_next_fn iomap_next);
>  int iomap_iter_advance(struct iomap_iter *iter, u64 count);
>  
>  /**
> @@ -365,14 +359,14 @@ static inline bool iomap_want_unshare_iter(const struct iomap_iter *iter)
>  }
>  
>  ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from,
> -		const struct iomap_ops *ops,
> +		iomap_next_fn iomap_next,
>  		const struct iomap_write_ops *write_ops, void *private);
>  int iomap_fsverity_write(struct file *file, loff_t pos, size_t length,
> -		const void *buf, const struct iomap_ops *ops,
> +		const void *buf, iomap_next_fn iomap_next,
>  		const struct iomap_write_ops *write_ops);
> -void iomap_read_folio(const struct iomap_ops *ops,
> +void iomap_read_folio(iomap_next_fn iomap_next,
>  		struct iomap_read_folio_ctx *ctx, void *private);
> -void iomap_readahead(const struct iomap_ops *ops,
> +void iomap_readahead(iomap_next_fn iomap_next,
>  		struct iomap_read_folio_ctx *ctx, void *private);
>  bool iomap_is_partially_uptodate(struct folio *, size_t from, size_t count);
>  struct folio *iomap_get_folio(struct iomap_iter *iter, loff_t pos, size_t len);
> @@ -380,17 +374,17 @@ bool iomap_release_folio(struct folio *folio, gfp_t gfp_flags);
>  void iomap_invalidate_folio(struct folio *folio, size_t offset, size_t len);
>  bool iomap_dirty_folio(struct address_space *mapping, struct folio *folio);
>  int iomap_file_unshare(struct inode *inode, loff_t pos, loff_t len,
> -		const struct iomap_ops *ops,
> +		iomap_next_fn iomap_next,
>  		const struct iomap_write_ops *write_ops);
>  unsigned int iomap_fill_dirty_folios(struct iomap_iter *iter, loff_t *start,
>  		loff_t end, unsigned int *iomap_flags);
>  int iomap_zero_range(struct inode *inode, loff_t pos, loff_t len,
> -		bool *did_zero, const struct iomap_ops *ops,
> +		bool *did_zero, iomap_next_fn iomap_next,
>  		const struct iomap_write_ops *write_ops, void *private);
>  int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
> -		const struct iomap_ops *ops,
> +		iomap_next_fn iomap_next,
>  		const struct iomap_write_ops *write_ops, void *private);
> -vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, const struct iomap_ops *ops,
> +vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, iomap_next_fn iomap_next,
>  		void *private);
>  typedef void (*iomap_punch_t)(struct inode *inode, loff_t offset, loff_t length,
>  		struct iomap *iomap);
> @@ -399,13 +393,13 @@ void iomap_write_delalloc_release(struct inode *inode, loff_t start_byte,
>  		iomap_punch_t punch);
>  
>  int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
> -		u64 start, u64 len, const struct iomap_ops *ops);
> +		u64 start, u64 len, iomap_next_fn iomap_next);
>  loff_t iomap_seek_hole(struct inode *inode, loff_t offset,
> -		const struct iomap_ops *ops);
> +		iomap_next_fn iomap_next);
>  loff_t iomap_seek_data(struct inode *inode, loff_t offset,
> -		const struct iomap_ops *ops);
> +		iomap_next_fn iomap_next);
>  sector_t iomap_bmap(struct address_space *mapping, sector_t bno,
> -		const struct iomap_ops *ops);
> +		iomap_next_fn iomap_next);
>  
>  /*
>   * Flags for iomap_ioend->io_flags.
> @@ -612,10 +606,10 @@ struct iomap_dio_ops {
>  #define IOMAP_DIO_BOUNCE		(1 << 4)
>  
>  ssize_t iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
> -		const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
> +		iomap_next_fn iomap_next, const struct iomap_dio_ops *dops,
>  		unsigned int dio_flags, void *private, size_t done_before);
>  struct iomap_dio *__iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
> -		const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
> +		iomap_next_fn iomap_next, const struct iomap_dio_ops *dops,
>  		unsigned int dio_flags, void *private, size_t done_before);
>  ssize_t iomap_dio_complete(struct iomap_dio *dio);
>  void iomap_dio_bio_end_io(struct bio *bio);
> @@ -626,7 +620,7 @@ struct swap_info_struct;
>  
>  int iomap_swapfile_activate(struct swap_info_struct *sis,
>  		struct file *swap_file, sector_t *pagespan,
> -		const struct iomap_ops *ops);
> +		iomap_next_fn iomap_next);
>  #else
>  # define iomap_swapfile_activate(sis, swapfile, pagespan, ops)	(-EIO)
>  #endif /* CONFIG_SWAP */
> @@ -640,25 +634,25 @@ int iomap_bio_read_folio_range(const struct iomap_iter *iter,
>  extern const struct iomap_read_ops iomap_bio_read_ops;
>  
>  static inline void iomap_bio_read_folio(struct folio *folio,
> -		const struct iomap_ops *ops)
> +		iomap_next_fn iomap_next)
>  {
>  	struct iomap_read_folio_ctx ctx = {
>  		.ops		= &iomap_bio_read_ops,
>  		.cur_folio	= folio,
>  	};
>  
> -	iomap_read_folio(ops, &ctx, NULL);
> +	iomap_read_folio(iomap_next, &ctx, NULL);
>  }
>  
>  static inline void iomap_bio_readahead(struct readahead_control *rac,
> -		const struct iomap_ops *ops)
> +		iomap_next_fn iomap_next)
>  {
>  	struct iomap_read_folio_ctx ctx = {
>  		.ops		= &iomap_bio_read_ops,
>  		.rac		= rac,
>  	};
>  
> -	iomap_readahead(ops, &ctx, NULL);
> +	iomap_readahead(iomap_next, &ctx, NULL);
>  }
>  #endif /* CONFIG_BLOCK */
>  
> -- 
> 2.52.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model
  2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
                   ` (17 preceding siblings ...)
  2026-07-01  0:09 ` [PATCH v2 18/18] Documentation: iomap: update docs to reflect iomap_next model Joanne Koong
@ 2026-07-02 13:49 ` Christoph Hellwig
  2026-07-03  1:08   ` Joanne Koong
  18 siblings, 1 reply; 53+ messages in thread
From: Christoph Hellwig @ 2026-07-02 13:49 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, djwong, willy, hsiangkao, linux-fsdevel, linux-xfs

What tree does this apply to?  I tried 7.2-rc1, Linus current
master, vfs/vfs.fixes and had slightly different failures to apply
with each one.

On Tue, Jun 30, 2026 at 05:09:15PM -0700, Joanne Koong wrote:
> This series implements a suggestion by Christoph for finishing the conversion
> of iomap to an iterator model. This revives Matthew's previous RFC [1], which
> had the same intention.

Btw, this evolved from my original suggestion to something that actually
looks much better, so don't give me too much credit :)


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 01/18] iomap: add ->iomap_next() and iomap_process() helper
  2026-07-01  0:09 ` [PATCH v2 01/18] iomap: add ->iomap_next() and iomap_process() helper Joanne Koong
@ 2026-07-02 14:00   ` Christoph Hellwig
  2026-07-02 23:01     ` Joanne Koong
  2026-07-02 16:23   ` Darrick J. Wong
  1 sibling, 1 reply; 53+ messages in thread
From: Christoph Hellwig @ 2026-07-02 14:00 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	open list

On Tue, Jun 30, 2026 at 05:09:16PM -0700, Joanne Koong wrote:
> +static int iomap_iter_legacy(struct iomap_iter *iter, const struct iomap_ops *ops)

Overly long line here.  Not that it really matters too much given
that this goes away by the end of the series.

> + * Iterate over filesystem-provided space mappings for the provided file range.
> + *
> + * This function handles cleanup of resources acquired for iteration when the
> + * filesystem indicates there are no more space mappings, which means that this
> + * function must be called in a loop that continues as long it returns a
> + * positive value.  If 0 or a negative value is returned, the caller must not
> + * return to the loop body.  Within a loop body, there are two ways to break out
> + * of the loop body:  leave @iter.status unchanged, or set it to a negative
> + * errno.
> + */
> +int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
> +{
> +	if (ops->iomap_next)
> +		return iomap_iter_next(iter, ops);
> +
> +	return iomap_iter_legacy(iter, ops);

Maybe inline the code currently in iomap_iter_next here from the
start, as that what we're getting to by the end of the series anyway.
And just do a:

	if (!ops->iomap_next))
		return iomap_iter_legacy(iter, ops);

at the beginning?

> +int iomap_iter_continue(const struct iomap_iter *iter, struct iomap *iomap,
> 

It seems like this is largely just factored out form the old iomap_iter().
Can you do a prep patch before this one which factors this out?
Preferably in a way that keeps the code in roughly the same place to
minimize the git blame disturbance?


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 02/18] xfs: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 ` [PATCH v2 02/18] xfs: convert iomap ops to ->iomap_next() Joanne Koong
@ 2026-07-02 14:03   ` Christoph Hellwig
  2026-07-02 16:48     ` Darrick J. Wong
  2026-07-02 16:43   ` Darrick J. Wong
  1 sibling, 1 reply; 53+ messages in thread
From: Christoph Hellwig @ 2026-07-02 14:03 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Carlos Maiolino, open list

> -	 * The retry mechanism is based on the ->iomap_begin method returning
> +	 * The retry mechanism is based on the ->iomap_next method returning

Nit: Maybe the drop the "->" in preparation of the last patch that would
make it slightly misleading with the ops struct removal?

> +static int
> +xfs_direct_write_iomap_next(
> +	const struct iomap_iter *iter,
> +	struct iomap		*iomap,
> +	struct iomap		*srcmap)
> +{
> +	return iomap_process(iter, iomap, srcmap, xfs_direct_write_iomap_begin,
> +			NULL);
> +}

I wonder if we want a "simple" version of iomap_process that only takes
a begin callback, as most current ops seems to be that way.  Then again
between needing at least one longer function name it's probably not
helping much with readability.  So not sure, just dropping it here if
anyone has a good idea or storng opinion.

Otherwise looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 10/18] block: convert iomap ops to ->iomap_next()
  2026-07-01  0:55   ` Keith Busch
@ 2026-07-02 14:03     ` Christoph Hellwig
  2026-07-03  0:06     ` Joanne Koong
  1 sibling, 0 replies; 53+ messages in thread
From: Christoph Hellwig @ 2026-07-02 14:03 UTC (permalink / raw)
  To: Keith Busch
  Cc: Joanne Koong, brauner, hch, djwong, willy, hsiangkao,
	linux-fsdevel, linux-xfs, Jens Axboe, open list:BLOCK LAYER,
	open list

On Tue, Jun 30, 2026 at 06:55:22PM -0600, Keith Busch wrote:
> On Tue, Jun 30, 2026 at 05:09:25PM -0700, Joanne Koong wrote:
> >  static const struct iomap_ops blkdev_iomap_ops = {
> > -	.iomap_begin		= blkdev_iomap_begin,
> > +	.iomap_next		= blkdev_iomap_next,
> >  };
> 
> I think it's generally safe to use the same mailing list for the entire
> series. There's no context here on what "iomap_next" is because I'm
> subscribed only to linux-block. I found the rest here:

Yeah, without that some people always get screwed over reviewing the
series.

> FWIW, everything looks good to me.
> 
> Reviewed-by: Keith Busch <kbusch@kernel.org>

Same here:

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 16/18] iomap: remove ->iomap_begin()/->iomap_end() legacy path
  2026-07-01  0:09 ` [PATCH v2 16/18] iomap: remove ->iomap_begin()/->iomap_end() legacy path Joanne Koong
@ 2026-07-02 14:04   ` Christoph Hellwig
  2026-07-02 16:51   ` Darrick J. Wong
  1 sibling, 0 replies; 53+ messages in thread
From: Christoph Hellwig @ 2026-07-02 14:04 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	open list

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops
  2026-07-01  0:09 ` [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops Joanne Koong
  2026-07-01 10:04   ` Jan Kara
@ 2026-07-02 14:07   ` Christoph Hellwig
  2026-07-02 16:51     ` Darrick J. Wong
  2026-07-02 16:58   ` Darrick J. Wong
  2 siblings, 1 reply; 53+ messages in thread
From: Christoph Hellwig @ 2026-07-02 14:07 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Jens Axboe, Chris Mason, David Sterba, Alexander Viro, Jan Kara,
	Dan Williams, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Sandeep Dhavale, Hongbo Li, Chunhai Guo, Namjae Jeon,
	Sungjong Seo, Yuezhang Mo, Theodore Ts'o, Andreas Dilger,
	Baokun Li, Ojaswin Mujoo, Ritesh Harjani (IBM), Zhang Yi,
	Jaegeuk Kim, Miklos Szeredi, Andreas Gruenbacher, Mikulas Patocka,
	Hyunchul Lee, Konstantin Komarov, Carlos Maiolino, Damien Le Moal,
	Naohiro Aota, Johannes Thumshirn, open list:BLOCK LAYER,
	open list, open list:BTRFS FILE SYSTEM,
	open list:FILESYSTEM DIRECT ACCESS (DAX),
	open list:EROFS FILE SYSTEM, open list:EXT2 FILE SYSTEM,
	open list:F2FS FILE SYSTEM, open list:FUSE FILESYSTEM [CORE],
	open list:GFS2 FILE SYSTEM, open list:NTFS3 FILESYSTEM

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>

In terms of merge logistics, I wonder if we should delay this and
the previous patch to the next merge window so that we can minimize the
cross-subsystem merge pain with more file system iomap conversion.
If none of them actually happen until rc6 or so, orif  the merges aren't
painful we could still pick them up late in the merge window.


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 18/18] Documentation: iomap: update docs to reflect iomap_next model
  2026-07-01  0:09 ` [PATCH v2 18/18] Documentation: iomap: update docs to reflect iomap_next model Joanne Koong
@ 2026-07-02 14:07   ` Christoph Hellwig
  2026-07-02 19:26   ` Darrick J. Wong
  1 sibling, 0 replies; 53+ messages in thread
From: Christoph Hellwig @ 2026-07-02 14:07 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Jonathan Corbet, Shuah Khan, open list:DOCUMENTATION, open list

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 01/18] iomap: add ->iomap_next() and iomap_process() helper
  2026-07-01  0:09 ` [PATCH v2 01/18] iomap: add ->iomap_next() and iomap_process() helper Joanne Koong
  2026-07-02 14:00   ` Christoph Hellwig
@ 2026-07-02 16:23   ` Darrick J. Wong
  2026-07-02 22:41     ` Joanne Koong
  1 sibling, 1 reply; 53+ messages in thread
From: Darrick J. Wong @ 2026-07-02 16:23 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, willy, hsiangkao, linux-fsdevel, linux-xfs,
	open list

On Tue, Jun 30, 2026 at 05:09:16PM -0700, Joanne Koong wrote:
> Have one ->iomap_next() callback instead of ->iomap_begin() and
> ->iomap_end(). ->iomap_next() finishes the previous mapping if needed,
> and produces the next mapping. This lets performance-critical callers
> inline the iteration with a fixed callback, which the compiler is able
> to call directly instead of indirectly.

Er... what is being called directly here?  The iomap_{begin,end}
functions?  It looks to me like ->iomap_next is still an indirect call
even at the end of the series, right?  That's still a net reduction of
indirect calls at least.

Oh, wait, it's the __always_inline iomap_process function that a smart
compiler can use to turn the indirect calls into direct ones, isn't it?
It might be useful to add a comment to that function saying that out
loud so that dolts like me will pick up on why it's critical for it to
be an inline function.

I like how this is going. :)

> iomap_iter() uses ->iomap_next() when the filesystem provides that
> callback and otherwise falls back to the ->iomap_begin()/->iomap_end()
> path, so filesystems can be converted one at a time.

> Add a iomap_process() inline helper that does most of the logic needed
> in an ->iomap_next() implementation.
> 
> Suggested-by: Christoph Hellwig <hch@lst.de>
> Suggested-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> ---
>  fs/iomap/iter.c       | 113 ++++++++++++++++++++++++++++++++++++------
>  include/linux/iomap.h |  91 +++++++++++++++++++++++++++-------
>  2 files changed, 171 insertions(+), 33 deletions(-)
> 
> diff --git a/fs/iomap/iter.c b/fs/iomap/iter.c
> index e4a29829591a..1062e4e34c38 100644
> --- a/fs/iomap/iter.c
> +++ b/fs/iomap/iter.c
> @@ -39,22 +39,7 @@ static inline void iomap_iter_done(struct iomap_iter *iter)
>  		trace_iomap_iter_srcmap(iter->inode, &iter->srcmap);
>  }
>  
> -/**
> - * iomap_iter - iterate over a ranges in a file
> - * @iter: iteration structue
> - * @ops: iomap ops provided by the file system
> - *
> - * Iterate over filesystem-provided space mappings for the provided file range.
> - *
> - * This function handles cleanup of resources acquired for iteration when the
> - * filesystem indicates there are no more space mappings, which means that this
> - * function must be called in a loop that continues as long it returns a
> - * positive value.  If 0 or a negative value is returned, the caller must not
> - * return to the loop body.  Within a loop body, there are two ways to break out
> - * of the loop body:  leave @iter.status unchanged, or set it to a negative
> - * errno.
> - */
> -int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
> +static int iomap_iter_legacy(struct iomap_iter *iter, const struct iomap_ops *ops)
>  {
>  	bool stale = iter->iomap.flags & IOMAP_F_STALE;
>  	ssize_t advanced;
> @@ -114,3 +99,99 @@ int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
>  	iomap_iter_done(iter);
>  	return 1;
>  }
> +
> +static int iomap_iter_next(struct iomap_iter *iter, const struct iomap_ops *ops)
> +{
> +	int ret;
> +
> +	trace_iomap_iter(iter, ops, _RET_IP_);
> +
> +	ret = ops->iomap_next(iter, &iter->iomap, &iter->srcmap);
> +	iter->status = 0;
> +	if (ret > 0)
> +		iomap_iter_done(iter);
> +
> +	return ret;
> +}
> +
> +/**
> + * iomap_iter - iterate over a ranges in a file
> + * @iter: iteration structue
> + * @ops: iomap ops provided by the file system
> + *
> + * Iterate over filesystem-provided space mappings for the provided file range.
> + *
> + * This function handles cleanup of resources acquired for iteration when the
> + * filesystem indicates there are no more space mappings, which means that this
> + * function must be called in a loop that continues as long it returns a
> + * positive value.  If 0 or a negative value is returned, the caller must not
> + * return to the loop body.  Within a loop body, there are two ways to break out
> + * of the loop body:  leave @iter.status unchanged, or set it to a negative
> + * errno.
> + */
> +int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
> +{
> +	if (ops->iomap_next)
> +		return iomap_iter_next(iter, ops);
> +
> +	return iomap_iter_legacy(iter, ops);
> +}
> +
> +/**
> + * iomap_iter_continue - decide whether iteration should continue
> + * @iter: iteration structure
> + * @iomap: the mapping that was just processed
> + * @srcmap: the source mapping that was just processed
> + *
> + * Helper for ->iomap_next() implementations, normally called via
> + * iomap_process().  Called after the previous mapping has been finished to
> + * determine whether there is more of the file range left to process.
> + *
> + * Returns 1 if there is more work to do, in which case @iomap and @srcmap are
> + * cleared so the caller can produce the next mapping; zero if the range is
> + * fully consumed; or a negative errno on error.  Any folio batch attached to
> + * the mapping is released before returning.
> + */
> +int iomap_iter_continue(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap, int ret)
> +{
> +	bool stale = iomap->flags & IOMAP_F_STALE;
> +	ssize_t advanced = iter->pos - iter->iter_start_pos;

These both could be const, right?

--D

> +
> +	if (!iomap->length)
> +		return 1;
> +
> +	/*
> +	 * Use iter->len to determine whether to continue onto the next mapping.
> +	 * Explicitly terminate on error status or if the current iter has not
> +	 * advanced at all (i.e. no work was done for some reason) unless the
> +	 * mapping has been marked stale and needs to be reprocessed.
> +	 */
> +	if (ret < 0 && !advanced)
> +		return ret;
> +
> +	/* detect old return semantics where this would advance */
> +	if (WARN_ON_ONCE(iter->status > 0))
> +		ret = -EIO;
> +	else if (iter->status < 0)
> +		ret = iter->status;
> +	else if (iter->len == 0 || (!advanced && !stale))
> +		ret = 0;
> +	else
> +		ret = 1;
> +
> +	if (iomap->flags & IOMAP_F_FOLIO_BATCH) {
> +		folio_batch_release(iter->fbatch);
> +		folio_batch_reinit(iter->fbatch);
> +		iomap->flags &= ~IOMAP_F_FOLIO_BATCH;
> +	}
> +
> +	if (ret <= 0)
> +		return ret;
> +
> +	memset(iomap, 0, sizeof(*iomap));
> +	memset(srcmap, 0, sizeof(*srcmap));
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(iomap_iter_continue);
> diff --git a/include/linux/iomap.h b/include/linux/iomap.h
> index 3582ed1fe236..8a78f47c557b 100644
> --- a/include/linux/iomap.h
> +++ b/include/linux/iomap.h
> @@ -212,24 +212,35 @@ struct iomap_write_ops {
>  #define IOMAP_ATOMIC		(1 << 9) /* torn-write protection */
>  #define IOMAP_DONTCACHE		(1 << 10)
>  
> -struct iomap_ops {
> -	/*
> -	 * Return the existing mapping at pos, or reserve space starting at
> -	 * pos for up to length, as long as we can do it as a single mapping.
> -	 * The actual length is returned in iomap->length.
> -	 */
> -	int (*iomap_begin)(struct inode *inode, loff_t pos, loff_t length,
> -			unsigned flags, struct iomap *iomap,
> -			struct iomap *srcmap);
> +/*
> + * Return the existing mapping at pos, or reserve space starting at pos for up
> + * to length, as long as we can do it as a single mapping.
> + * The actual length is returned in iomap->length.
> + */
> +typedef int (*iomap_begin_fn)(struct inode *inode, loff_t pos, loff_t length,
> +		unsigned flags, struct iomap *iomap, struct iomap *srcmap);
>  
> -	/*
> -	 * Commit and/or unreserve space previous allocated using iomap_begin.
> -	 * Written indicates the length of the successful write operation which
> -	 * needs to be commited, while the rest needs to be unreserved.
> -	 * Written might be zero if no data was written.
> -	 */
> -	int (*iomap_end)(struct inode *inode, loff_t pos, loff_t length,
> -			ssize_t written, unsigned flags, struct iomap *iomap);
> +/*
> + * Commit and/or unreserve space previous allocated using iomap_begin.
> + * Written indicates the length of the successful write operation which needs
> + * to be commited, while the rest needs to be unreserved.
> + * Written might be zero if no data was written.
> + */
> +typedef int (*iomap_end_fn)(struct inode *inode, loff_t pos, loff_t length,
> +		ssize_t written, unsigned flags, struct iomap *iomap);
> +
> +/*
> + * Produce the next mapping (finishing the previous one if needed).
> + * Return 1 to continue iterating, 0 if the range is fully consumed, or a
> + * negative error on failure.
> + */
> +typedef int (*iomap_next_fn)(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
> +
> +struct iomap_ops {
> +	iomap_begin_fn iomap_begin;
> +	iomap_end_fn iomap_end;
> +	iomap_next_fn iomap_next;
>  };
>  
>  /**
> @@ -317,6 +328,9 @@ static inline const struct iomap *iomap_iter_srcmap(const struct iomap_iter *i)
>  	return &i->iomap;
>  }
>  
> +int iomap_iter_continue(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap, int ret);
> +
>  /*
>   * Return the file offset for the first unchanged block after a short write.
>   *
> @@ -648,4 +662,47 @@ static inline void iomap_bio_readahead(struct readahead_control *rac,
>  }
>  #endif /* CONFIG_BLOCK */
>  
> +/**
> + * iomap_process - finish the previous mapping and produce the next one
> + * @iter: iteration structure
> + * @iomap: mapping to finish and then repopulate
> + * @srcmap: source mapping to finish and then repopulate
> + * @begin: callback that produces a mapping for the current position
> + * @end: optional callback that finishes the previous mapping, or NULL
> + *
> + * Inline helper that implements the common body of an ->iomap_next()
> + * callback: it finishes the previous mapping via @end (if present), decides
> + * via iomap_iter_continue() whether to keep going, and obtains the next
> + * mapping via @begin.
> + *
> + * Returns 1 to continue iterating, 0 once the range is fully consumed, or a
> + * negative errno on error.
> + */
> +static __always_inline int iomap_process(const struct iomap_iter *iter,
> +		struct iomap *iomap, struct iomap *srcmap, iomap_begin_fn begin,
> +		iomap_end_fn end)
> +{
> +	int ret = 0;
> +
> +	if (iomap->length && end) {
> +		ssize_t advanced = iter->pos - iter->iter_start_pos;
> +		loff_t len;
> +
> +		len = iomap_length_trim(iter, iter->iter_start_pos,
> +				iter->len + advanced);
> +
> +		ret = end(iter->inode, iter->iter_start_pos, len, advanced,
> +				iter->flags, iomap);
> +	}
> +
> +	ret = iomap_iter_continue(iter, iomap, srcmap, ret);
> +	if (ret <= 0)
> +		return ret;
> +
> +	ret = begin(iter->inode, iter->pos, iter->len, iter->flags, iomap,
> +			srcmap);
> +
> +	return ret < 0 ? ret : 1;
> +}
> +
>  #endif /* LINUX_IOMAP_H */
> -- 
> 2.52.0
> 
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 02/18] xfs: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 ` [PATCH v2 02/18] xfs: convert iomap ops to ->iomap_next() Joanne Koong
  2026-07-02 14:03   ` Christoph Hellwig
@ 2026-07-02 16:43   ` Darrick J. Wong
  2026-07-02 23:59     ` Joanne Koong
  1 sibling, 1 reply; 53+ messages in thread
From: Darrick J. Wong @ 2026-07-02 16:43 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Carlos Maiolino, open list

On Tue, Jun 30, 2026 at 05:09:17PM -0700, Joanne Koong wrote:
> Convert xfs iomap_ops to the new ->iomap_next() callback. This uses the
> iomap_process() helper, which finishes the previous mapping if needed
> and produces the next one. No functional changes are intended.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> ---
>  fs/xfs/xfs_file.c  |  4 +-
>  fs/xfs/xfs_iomap.c | 96 +++++++++++++++++++++++++++++++++++++++++-----
>  2 files changed, 88 insertions(+), 12 deletions(-)
> 
> diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> index 845a97c9b063..7f8bef1a9954 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -857,9 +857,9 @@ xfs_file_dio_write_atomic(
>  			NULL, 0);
>  
>  	/*
> -	 * The retry mechanism is based on the ->iomap_begin method returning
> +	 * The retry mechanism is based on the ->iomap_next method returning
>  	 * -ENOPROTOOPT, which would be when the REQ_ATOMIC-based write is not
> -	 * possible. The REQ_ATOMIC-based method typically not be possible if
> +	 * possible. The REQ_ATOMIC-based method is typically not possible if
>  	 * the write spans multiple extents or the disk blocks are misaligned.
>  	 */
>  	if (ret == -ENOPROTOOPT && dops == &xfs_direct_write_iomap_ops) {
> diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
> index 225c3de88d03..4fa1a5c985db 100644
> --- a/fs/xfs/xfs_iomap.c
> +++ b/fs/xfs/xfs_iomap.c
> @@ -1037,8 +1037,18 @@ xfs_direct_write_iomap_begin(
>  	return error;
>  }
>  
> +static int
> +xfs_direct_write_iomap_next(
> +	const struct iomap_iter *iter,
> +	struct iomap		*iomap,
> +	struct iomap		*srcmap)

<unvarnished brainstream ahead>

Now that I see the callsites, I think the "next" name could use some
bikeshedding <cough>.  The purpose of this function is either

(a) to look up the first mapping to start iterating;
(b) to release whatever resources were attached during the current
    iteration and look up the next mapping to continue iterating; or
(c) to decide that it's time to stop iterating.

From that it seems obvious to me that xfs_direct_write_iomap_next yields
iomaps for iteration.  In Python those are called generator functions;
in Rust they're called objects that implement the Iterator trait (or
iterators for short).

How about s/iomap_next/iomap_iter/ ?

Then this function would be called xfs_direct_write_iomap_iter, which
IMO is a closer description of what the function does, which is to say
iterates iomaps for direct writes.

(Yes, my brain might be polluted with thinking that "iomap next" refers
to a major shift, in the sense of "linux next". :P)

> +{
> +	return iomap_process(iter, iomap, srcmap, xfs_direct_write_iomap_begin,
> +			NULL);

But then "iomap_iter" sets up a new problem: should iomap_process have a
new name that goes along with that?  iomap_iter is already taken for the
legacy path.  If we were emulating python I'd suggest iomap_iter_yield
but this is C so we get to reinvent everything from scratch so who
knows.

--D

> +}
> +
>  const struct iomap_ops xfs_direct_write_iomap_ops = {
> -	.iomap_begin		= xfs_direct_write_iomap_begin,
> +	.iomap_next		= xfs_direct_write_iomap_next,

>  };
>  
>  #ifdef CONFIG_XFS_RT
> @@ -1089,8 +1099,18 @@ xfs_zoned_direct_write_iomap_begin(
>  	return 0;
>  }
>  
> +static int
> +xfs_zoned_direct_write_iomap_next(
> +	const struct iomap_iter *iter,
> +	struct iomap		*iomap,
> +	struct iomap		*srcmap)
> +{
> +	return iomap_process(iter, iomap, srcmap,
> +			xfs_zoned_direct_write_iomap_begin, NULL);
> +}
> +
>  const struct iomap_ops xfs_zoned_direct_write_iomap_ops = {
> -	.iomap_begin		= xfs_zoned_direct_write_iomap_begin,
> +	.iomap_next		= xfs_zoned_direct_write_iomap_next,
>  };
>  #endif /* CONFIG_XFS_RT */
>  
> @@ -1274,8 +1294,18 @@ xfs_atomic_write_cow_iomap_begin(
>  	return error;
>  }
>  
> +static int
> +xfs_atomic_write_cow_iomap_next(
> +	const struct iomap_iter *iter,
> +	struct iomap		*iomap,
> +	struct iomap		*srcmap)
> +{
> +	return iomap_process(iter, iomap, srcmap,
> +			xfs_atomic_write_cow_iomap_begin, NULL);
> +}
> +
>  const struct iomap_ops xfs_atomic_write_cow_iomap_ops = {
> -	.iomap_begin		= xfs_atomic_write_cow_iomap_begin,
> +	.iomap_next		= xfs_atomic_write_cow_iomap_next,
>  };
>  
>  static int
> @@ -1298,9 +1328,18 @@ xfs_dax_write_iomap_end(
>  	return xfs_reflink_end_cow(ip, pos, written);
>  }
>  
> +static int
> +xfs_dax_write_iomap_next(
> +	const struct iomap_iter *iter,
> +	struct iomap		*iomap,
> +	struct iomap		*srcmap)
> +{
> +	return iomap_process(iter, iomap, srcmap, xfs_direct_write_iomap_begin,
> +			xfs_dax_write_iomap_end);
> +}
> +
>  const struct iomap_ops xfs_dax_write_iomap_ops = {
> -	.iomap_begin	= xfs_direct_write_iomap_begin,
> -	.iomap_end	= xfs_dax_write_iomap_end,
> +	.iomap_next	= xfs_dax_write_iomap_next,
>  };
>  
>  /*
> @@ -2168,9 +2207,19 @@ xfs_buffered_write_iomap_end(
>  	return 0;
>  }
>  
> +static int
> +xfs_buffered_write_iomap_next(
> +	const struct iomap_iter *iter,
> +	struct iomap		*iomap,
> +	struct iomap		*srcmap)
> +{
> +	return iomap_process(iter, iomap, srcmap,
> +			xfs_buffered_write_iomap_begin,
> +			xfs_buffered_write_iomap_end);
> +}
> +
>  const struct iomap_ops xfs_buffered_write_iomap_ops = {
> -	.iomap_begin		= xfs_buffered_write_iomap_begin,
> -	.iomap_end		= xfs_buffered_write_iomap_end,
> +	.iomap_next		= xfs_buffered_write_iomap_next,
>  };
>  
>  static int
> @@ -2214,8 +2263,17 @@ xfs_read_iomap_begin(
>  				 shared ? IOMAP_F_SHARED : 0, seq);
>  }
>  
> +static int
> +xfs_read_iomap_next(
> +	const struct iomap_iter *iter,
> +	struct iomap		*iomap,
> +	struct iomap		*srcmap)
> +{
> +	return iomap_process(iter, iomap, srcmap, xfs_read_iomap_begin, NULL);
> +}
> +
>  const struct iomap_ops xfs_read_iomap_ops = {
> -	.iomap_begin		= xfs_read_iomap_begin,
> +	.iomap_next		= xfs_read_iomap_next,
>  };
>  
>  static int
> @@ -2302,8 +2360,17 @@ xfs_seek_iomap_begin(
>  	return error;
>  }
>  
> +static int
> +xfs_seek_iomap_next(
> +	const struct iomap_iter *iter,
> +	struct iomap		*iomap,
> +	struct iomap		*srcmap)
> +{
> +	return iomap_process(iter, iomap, srcmap, xfs_seek_iomap_begin, NULL);
> +}
> +
>  const struct iomap_ops xfs_seek_iomap_ops = {
> -	.iomap_begin		= xfs_seek_iomap_begin,
> +	.iomap_next		= xfs_seek_iomap_next,
>  };
>  
>  static int
> @@ -2349,8 +2416,17 @@ xfs_xattr_iomap_begin(
>  	return xfs_bmbt_to_iomap(ip, iomap, &imap, flags, IOMAP_F_XATTR, seq);
>  }
>  
> +static int
> +xfs_xattr_iomap_next(
> +	const struct iomap_iter *iter,
> +	struct iomap		*iomap,
> +	struct iomap		*srcmap)
> +{
> +	return iomap_process(iter, iomap, srcmap, xfs_xattr_iomap_begin, NULL);
> +}
> +
>  const struct iomap_ops xfs_xattr_iomap_ops = {
> -	.iomap_begin		= xfs_xattr_iomap_begin,
> +	.iomap_next		= xfs_xattr_iomap_next,
>  };
>  
>  int
> -- 
> 2.52.0
> 
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 02/18] xfs: convert iomap ops to ->iomap_next()
  2026-07-02 14:03   ` Christoph Hellwig
@ 2026-07-02 16:48     ` Darrick J. Wong
  0 siblings, 0 replies; 53+ messages in thread
From: Darrick J. Wong @ 2026-07-02 16:48 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Joanne Koong, brauner, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Carlos Maiolino, open list

On Thu, Jul 02, 2026 at 04:03:01PM +0200, Christoph Hellwig wrote:
> > -	 * The retry mechanism is based on the ->iomap_begin method returning
> > +	 * The retry mechanism is based on the ->iomap_next method returning
> 
> Nit: Maybe the drop the "->" in preparation of the last patch that would
> make it slightly misleading with the ops struct removal?
> 
> > +static int
> > +xfs_direct_write_iomap_next(
> > +	const struct iomap_iter *iter,
> > +	struct iomap		*iomap,
> > +	struct iomap		*srcmap)
> > +{
> > +	return iomap_process(iter, iomap, srcmap, xfs_direct_write_iomap_begin,
> > +			NULL);
> > +}
> 
> I wonder if we want a "simple" version of iomap_process that only takes
> a begin callback, as most current ops seems to be that way.  Then again
> between needing at least one longer function name it's probably not
> helping much with readability.  So not sure, just dropping it here if
> anyone has a good idea or storng opinion.

You /could/ use a bunch of fugly macros to simulate a default NULL
iomap_end_fn parameter.

#define __default_iomap_end(a,b,...) b
#define default_iomap_end(...) __default_iomap_end(,##__VA_ARGS,NULL)

#define iomap_process(iter, iomap, srcmap, iomap_begin, ...) \
	__iomap_process((iter), (iomap), (srcmap), (iomap_begin),
			default_iomap_end(__VA_ARGS__))

--D

> 
> Otherwise looks good:
> 
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops
  2026-07-02 14:07   ` Christoph Hellwig
@ 2026-07-02 16:51     ` Darrick J. Wong
  2026-07-03  1:47       ` Joanne Koong
  0 siblings, 1 reply; 53+ messages in thread
From: Darrick J. Wong @ 2026-07-02 16:51 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Joanne Koong, brauner, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Jens Axboe, Chris Mason, David Sterba, Alexander Viro, Jan Kara,
	Dan Williams, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Sandeep Dhavale, Hongbo Li, Chunhai Guo, Namjae Jeon,
	Sungjong Seo, Yuezhang Mo, Theodore Ts'o, Andreas Dilger,
	Baokun Li, Ojaswin Mujoo, Ritesh Harjani (IBM), Zhang Yi,
	Jaegeuk Kim, Miklos Szeredi, Andreas Gruenbacher, Mikulas Patocka,
	Hyunchul Lee, Konstantin Komarov, Carlos Maiolino, Damien Le Moal,
	Naohiro Aota, Johannes Thumshirn, open list:BLOCK LAYER,
	open list, open list:BTRFS FILE SYSTEM,
	open list:FILESYSTEM DIRECT ACCESS (DAX),
	open list:EROFS FILE SYSTEM, open list:EXT2 FILE SYSTEM,
	open list:F2FS FILE SYSTEM, open list:FUSE FILESYSTEM [CORE],
	open list:GFS2 FILE SYSTEM, open list:NTFS3 FILESYSTEM

On Thu, Jul 02, 2026 at 04:07:05PM +0200, Christoph Hellwig wrote:
> Looks good:
> 
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> 
> In terms of merge logistics, I wonder if we should delay this and
> the previous patch to the next merge window so that we can minimize the
> cross-subsystem merge pain with more file system iomap conversion.
> If none of them actually happen until rc6 or so, orif  the merges aren't
> painful we could still pick them up late in the merge window.

I'd say everything but this patch should go in during the merge window
for 7.3, along with clear instructions to brauner/torvalds to expect
this patch to appear right before 7.3-rc1 gets tagged, to clean up all
the other changes that come in.

--D

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 16/18] iomap: remove ->iomap_begin()/->iomap_end() legacy path
  2026-07-01  0:09 ` [PATCH v2 16/18] iomap: remove ->iomap_begin()/->iomap_end() legacy path Joanne Koong
  2026-07-02 14:04   ` Christoph Hellwig
@ 2026-07-02 16:51   ` Darrick J. Wong
  1 sibling, 0 replies; 53+ messages in thread
From: Darrick J. Wong @ 2026-07-02 16:51 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, willy, hsiangkao, linux-fsdevel, linux-xfs,
	open list

On Tue, Jun 30, 2026 at 05:09:31PM -0700, Joanne Koong wrote:
> With all in-tree filesystems implementing ->iomap_next(), drop the
> ->iomap_begin()/->iomap_end() path.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>

Yeah, the legacy path can go away. :)

Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>

--D

> ---
>  fs/iomap/iter.c       | 87 +++++--------------------------------------
>  include/linux/iomap.h |  4 +-
>  2 files changed, 11 insertions(+), 80 deletions(-)
> 
> diff --git a/fs/iomap/iter.c b/fs/iomap/iter.c
> index 1062e4e34c38..466c491bdef6 100644
> --- a/fs/iomap/iter.c
> +++ b/fs/iomap/iter.c
> @@ -39,81 +39,6 @@ static inline void iomap_iter_done(struct iomap_iter *iter)
>  		trace_iomap_iter_srcmap(iter->inode, &iter->srcmap);
>  }
>  
> -static int iomap_iter_legacy(struct iomap_iter *iter, const struct iomap_ops *ops)
> -{
> -	bool stale = iter->iomap.flags & IOMAP_F_STALE;
> -	ssize_t advanced;
> -	u64 olen;
> -	int ret;
> -
> -	trace_iomap_iter(iter, ops, _RET_IP_);
> -
> -	if (!iter->iomap.length)
> -		goto begin;
> -
> -	/*
> -	 * Calculate how far the iter was advanced and the original length bytes
> -	 * for ->iomap_end().
> -	 */
> -	advanced = iter->pos - iter->iter_start_pos;
> -	olen = iter->len + advanced;
> -
> -	if (ops->iomap_end) {
> -		ret = ops->iomap_end(iter->inode, iter->iter_start_pos,
> -				iomap_length_trim(iter, iter->iter_start_pos,
> -						  olen),
> -				advanced, iter->flags, &iter->iomap);
> -		if (ret < 0 && !advanced)
> -			return ret;
> -	}
> -
> -	/* detect old return semantics where this would advance */
> -	if (WARN_ON_ONCE(iter->status > 0))
> -		iter->status = -EIO;
> -
> -	/*
> -	 * Use iter->len to determine whether to continue onto the next mapping.
> -	 * Explicitly terminate on error status or if the current iter has not
> -	 * advanced at all (i.e. no work was done for some reason) unless the
> -	 * mapping has been marked stale and needs to be reprocessed.
> -	 */
> -	if (iter->status < 0)
> -		ret = iter->status;
> -	else if (iter->len == 0 || (!advanced && !stale))
> -		ret = 0;
> -	else
> -		ret = 1;
> -	iomap_iter_clean_fbatch(iter);
> -	iter->status = 0;
> -	if (ret <= 0)
> -		return ret;
> -
> -	memset(&iter->iomap, 0, sizeof(iter->iomap));
> -	memset(&iter->srcmap, 0, sizeof(iter->srcmap));
> -
> -begin:
> -	ret = ops->iomap_begin(iter->inode, iter->pos, iter->len, iter->flags,
> -			       &iter->iomap, &iter->srcmap);
> -	if (ret < 0)
> -		return ret;
> -	iomap_iter_done(iter);
> -	return 1;
> -}
> -
> -static int iomap_iter_next(struct iomap_iter *iter, const struct iomap_ops *ops)
> -{
> -	int ret;
> -
> -	trace_iomap_iter(iter, ops, _RET_IP_);
> -
> -	ret = ops->iomap_next(iter, &iter->iomap, &iter->srcmap);
> -	iter->status = 0;
> -	if (ret > 0)
> -		iomap_iter_done(iter);
> -
> -	return ret;
> -}
> -
>  /**
>   * iomap_iter - iterate over a ranges in a file
>   * @iter: iteration structue
> @@ -131,10 +56,16 @@ static int iomap_iter_next(struct iomap_iter *iter, const struct iomap_ops *ops)
>   */
>  int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
>  {
> -	if (ops->iomap_next)
> -		return iomap_iter_next(iter, ops);
> +	int ret;
> +
> +	trace_iomap_iter(iter, ops, _RET_IP_);
>  
> -	return iomap_iter_legacy(iter, ops);
> +	ret = ops->iomap_next(iter, &iter->iomap, &iter->srcmap);
> +	iter->status = 0;
> +	if (ret > 0)
> +		iomap_iter_done(iter);
> +
> +	return ret;
>  }
>  
>  /**
> diff --git a/include/linux/iomap.h b/include/linux/iomap.h
> index 8a78f47c557b..52d6f585b941 100644
> --- a/include/linux/iomap.h
> +++ b/include/linux/iomap.h
> @@ -194,7 +194,7 @@ struct iomap_write_ops {
>  };
>  
>  /*
> - * Flags for iomap_begin / iomap_end.  No flag implies a read.
> + * Flags for iomap_next.  No flag implies a read.
>   */
>  #define IOMAP_WRITE		(1 << 0) /* writing, must allocate blocks */
>  #define IOMAP_ZERO		(1 << 1) /* zeroing operation, may skip holes */
> @@ -254,7 +254,7 @@ struct iomap_ops {
>   *	incremental iter advance.
>   * @status: Status of the most recent iteration. Zero on success or a negative
>   *	errno on error.
> - * @flags: Zero or more of the iomap_begin flags above.
> + * @flags: Zero or more of the iomap_next flags above.
>   * @iomap: Map describing the I/O iteration
>   * @srcmap: Source map for COW operations
>   */
> -- 
> 2.52.0
> 
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops
  2026-07-01  0:09 ` [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops Joanne Koong
  2026-07-01 10:04   ` Jan Kara
  2026-07-02 14:07   ` Christoph Hellwig
@ 2026-07-02 16:58   ` Darrick J. Wong
  2026-07-03  0:17     ` Joanne Koong
  2 siblings, 1 reply; 53+ messages in thread
From: Darrick J. Wong @ 2026-07-02 16:58 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Jens Axboe, Chris Mason, David Sterba, Alexander Viro, Jan Kara,
	Dan Williams, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Sandeep Dhavale, Hongbo Li, Chunhai Guo, Namjae Jeon,
	Sungjong Seo, Yuezhang Mo, Theodore Ts'o, Andreas Dilger,
	Baokun Li, Ojaswin Mujoo, Ritesh Harjani (IBM), Zhang Yi,
	Jaegeuk Kim, Miklos Szeredi, Andreas Gruenbacher, Mikulas Patocka,
	Hyunchul Lee, Konstantin Komarov, Carlos Maiolino, Damien Le Moal,
	Naohiro Aota, Johannes Thumshirn, open list:BLOCK LAYER,
	open list, open list:BTRFS FILE SYSTEM,
	open list:FILESYSTEM DIRECT ACCESS (DAX),
	open list:EROFS FILE SYSTEM, open list:EXT2 FILE SYSTEM,
	open list:F2FS FILE SYSTEM, open list:FUSE FILESYSTEM [CORE],
	open list:GFS2 FILE SYSTEM, open list:NTFS3 FILESYSTEM

On Tue, Jun 30, 2026 at 05:09:32PM -0700, Joanne Koong wrote:
> Now that all filesystems implement ->iomap_next() and the legacy
> ->iomap_begin()/->iomap_end() fallback is gone, struct iomap_ops only
> wraps a single iomap_next function pointer. Drop the struct entirely and
> pass the iomap_next_fn directly to iomap_iter() and all the iomap/dax
> entry points; filesystems pass their ->iomap_next function instead of an
> ops struct.
> 
> No functional change intended.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>

I'm gonna cut out quite a bit of this patch to reduce the reply size.

> ---
<snip>
>  fs/iomap/buffered-io.c | 38 ++++++++++++++---------------
>  fs/iomap/direct-io.c   |  8 +++---
>  fs/iomap/fiemap.c      |  8 +++---
>  fs/iomap/iter.c        |  8 +++---
>  fs/iomap/seek.c        |  8 +++---
>  fs/iomap/swapfile.c    |  4 +--
<snip>
>  fs/remap_range.c       |  6 ++---
>  fs/xfs/xfs_aops.c      |  8 +++---
>  fs/xfs/xfs_file.c      | 40 +++++++++++++++---------------
>  fs/xfs/xfs_iomap.c     | 55 +++++++++---------------------------------
>  fs/xfs/xfs_iomap.h     | 24 ++++++++++++------
>  fs/xfs/xfs_iops.c      |  4 +--
>  fs/xfs/xfs_reflink.c   |  6 ++---
>  fs/zonefs/file.c       | 22 ++++++-----------
>  include/linux/dax.h    | 18 ++++++--------
>  include/linux/fs.h     |  7 ++++--
>  include/linux/iomap.h  | 46 +++++++++++++++--------------------
>  54 files changed, 302 insertions(+), 411 deletions(-)
> 
<snip>

> diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
> index 3f0932e46fd6..0aa8abc438c1 100644
> --- a/fs/iomap/buffered-io.c
> +++ b/fs/iomap/buffered-io.c
> @@ -626,7 +626,7 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
>  	return 0;
>  }
>  
> -void iomap_read_folio(const struct iomap_ops *ops,
> +void iomap_read_folio(iomap_next_fn iomap_next,

If you took my earlier suggestion to rename the typedef to
iomap_iter_fn, then this parameter ought to be named iter_fn.

>  		struct iomap_read_folio_ctx *ctx, void *private)
>  {
>  	struct folio *folio = ctx->cur_folio;
> @@ -650,7 +650,7 @@ void iomap_read_folio(const struct iomap_ops *ops,
>  		fsverity_readahead(ctx->vi, folio->index,
>  				   folio_nr_pages(folio));
>  
> -	while ((ret = iomap_iter(&iter, ops)) > 0) {
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0) {
>  		iter.status = iomap_read_folio_iter(&iter, ctx,
>  				&bytes_submitted);
>  		iomap_read_submit(&iter, ctx);
> @@ -688,22 +688,22 @@ static int iomap_readahead_iter(struct iomap_iter *iter,
>  
>  /**
>   * iomap_readahead - Attempt to read pages from a file.
> - * @ops: The operations vector for the filesystem.
> + * @iomap_next: The iomap_next callback for the filesystem.

"The iomap iteration function for the filesystem" ?

Using the term "iomap_next" in the definition for iomap_next isn't that
helpful.

>   * @ctx: The ctx used for issuing readahead.
>   * @private: The filesystem-specific information for issuing iomap_iter.
>   *
>   * This function is for filesystems to call to implement their readahead
>   * address_space operation.
>   *
> - * Context: The @ops callbacks may submit I/O (eg to read the addresses of
> + * Context: The @iomap_next callback may submit I/O (eg to read the addresses of
>   * blocks from disc), and may wait for it.  The caller may be trying to
>   * access a different page, and so sleeping excessively should be avoided.
>   * It may allocate memory, but should avoid costly allocations.  This
>   * function is called with memalloc_nofs set, so allocations will not cause
>   * the filesystem to be reentered.
>   */
> -void iomap_readahead(const struct iomap_ops *ops,
> -		struct iomap_read_folio_ctx *ctx, void *private)
> +void iomap_readahead(iomap_next_fn iomap_next, struct iomap_read_folio_ctx *ctx,
> +		void *private)
>  {
>  	struct readahead_control *rac = ctx->rac;
>  	struct iomap_iter iter = {
> @@ -725,7 +725,7 @@ void iomap_readahead(const struct iomap_ops *ops,
>  		fsverity_readahead(ctx->vi, readahead_index(rac),
>  				readahead_count(rac));
>  
> -	while (iomap_iter(&iter, ops) > 0) {
> +	while (iomap_iter(&iter, iomap_next) > 0) {
>  		iter.status = iomap_readahead_iter(&iter, ctx,
>  					&cur_bytes_submitted);
>  		iomap_read_submit(&iter, ctx);
> @@ -1268,7 +1268,7 @@ static int iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i,
>  
>  ssize_t
>  iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *i,
> -		const struct iomap_ops *ops,
> +		iomap_next_fn iomap_next,
>  		const struct iomap_write_ops *write_ops, void *private)
>  {
>  	struct iomap_iter iter = {
> @@ -1285,7 +1285,7 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *i,
>  	if (iocb->ki_flags & IOCB_DONTCACHE)
>  		iter.flags |= IOMAP_DONTCACHE;
>  
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = iomap_write_iter(&iter, i, write_ops);
>  
>  	if (unlikely(iter.pos == iocb->ki_pos))
> @@ -1297,7 +1297,7 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *i,
>  EXPORT_SYMBOL_GPL(iomap_file_buffered_write);
>  
>  int iomap_fsverity_write(struct file *file, loff_t pos, size_t length,
> -		const void *buf, const struct iomap_ops *ops,
> +		const void *buf, iomap_next_fn iomap_next,
>  		const struct iomap_write_ops *write_ops)
>  {
>  	int			ret;
> @@ -1314,7 +1314,7 @@ int iomap_fsverity_write(struct file *file, loff_t pos, size_t length,
>  
>  	iov_iter_kvec(&iiter, WRITE, &kvec, 1, length);
>  
> -	ret = iomap_file_buffered_write(&iocb, &iiter, ops, write_ops, NULL);
> +	ret = iomap_file_buffered_write(&iocb, &iiter, iomap_next, write_ops, NULL);
>  	if (ret < 0)
>  		return ret;
>  	return ret == length ? 0 : -EIO;
> @@ -1586,7 +1586,7 @@ static int iomap_unshare_iter(struct iomap_iter *iter,
>  
>  int
>  iomap_file_unshare(struct inode *inode, loff_t pos, loff_t len,
> -		const struct iomap_ops *ops,
> +		iomap_next_fn iomap_next,
>  		const struct iomap_write_ops *write_ops)
>  {
>  	struct iomap_iter iter = {
> @@ -1601,7 +1601,7 @@ iomap_file_unshare(struct inode *inode, loff_t pos, loff_t len,
>  		return 0;
>  
>  	iter.len = min(len, size - pos);
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = iomap_unshare_iter(&iter, write_ops);
>  	return ret;
>  }
> @@ -1710,7 +1710,7 @@ EXPORT_SYMBOL_GPL(iomap_fill_dirty_folios);
>  
>  int
>  iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
> -		const struct iomap_ops *ops,
> +		iomap_next_fn iomap_next,
>  		const struct iomap_write_ops *write_ops, void *private)
>  {
>  	struct folio_batch fbatch;
> @@ -1735,7 +1735,7 @@ iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
>  	 */
>  	range_dirty = filemap_range_needs_writeback(mapping, iter.pos,
>  					iter.pos + iter.len - 1);
> -	while ((ret = iomap_iter(&iter, ops)) > 0) {
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0) {
>  		const struct iomap *srcmap = iomap_iter_srcmap(&iter);
>  
>  		if (!(iter.iomap.flags & IOMAP_F_FOLIO_BATCH) &&
> @@ -1761,7 +1761,7 @@ EXPORT_SYMBOL_GPL(iomap_zero_range);
>  
>  int
>  iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
> -		const struct iomap_ops *ops,
> +		iomap_next_fn iomap_next,
>  		const struct iomap_write_ops *write_ops, void *private)
>  {
>  	unsigned int blocksize = i_blocksize(inode);
> @@ -1770,7 +1770,7 @@ iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
>  	/* Block boundary? Nothing to do */
>  	if (!off)
>  		return 0;
> -	return iomap_zero_range(inode, pos, blocksize - off, did_zero, ops,
> +	return iomap_zero_range(inode, pos, blocksize - off, did_zero, iomap_next,
>  			write_ops, private);
>  }
>  EXPORT_SYMBOL_GPL(iomap_truncate_page);
> @@ -1795,7 +1795,7 @@ static int iomap_folio_mkwrite_iter(struct iomap_iter *iter,
>  	return iomap_iter_advance(iter, length);
>  }
>  
> -vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, const struct iomap_ops *ops,
> +vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, iomap_next_fn iomap_next,
>  		void *private)
>  {
>  	struct iomap_iter iter = {
> @@ -1812,7 +1812,7 @@ vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, const struct iomap_ops *ops,
>  		goto out_unlock;
>  	iter.pos = folio_pos(folio);
>  	iter.len = ret;
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = iomap_folio_mkwrite_iter(&iter, folio);
>  
>  	if (ret < 0)
> diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
> index b485e3b191da..e299d186f743 100644
> --- a/fs/iomap/direct-io.c
> +++ b/fs/iomap/direct-io.c
> @@ -676,7 +676,7 @@ static int iomap_dio_iter(struct iomap_iter *iter, struct iomap_dio *dio)
>   */
>  struct iomap_dio *
>  __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
> -		const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
> +		iomap_next_fn iomap_next, const struct iomap_dio_ops *dops,
>  		unsigned int dio_flags, void *private, size_t done_before)
>  {
>  	struct inode *inode = file_inode(iocb->ki_filp);
> @@ -800,7 +800,7 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
>  	inode_dio_begin(inode);
>  
>  	blk_start_plug(&plug);
> -	while ((ret = iomap_iter(&iomi, ops)) > 0) {
> +	while ((ret = iomap_iter(&iomi, iomap_next)) > 0) {
>  		iomi.status = iomap_dio_iter(&iomi, dio);
>  
>  		/*
> @@ -890,12 +890,12 @@ EXPORT_SYMBOL_GPL(__iomap_dio_rw);
>  
>  ssize_t
>  iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
> -		const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
> +		iomap_next_fn iomap_next, const struct iomap_dio_ops *dops,
>  		unsigned int dio_flags, void *private, size_t done_before)
>  {
>  	struct iomap_dio *dio;
>  
> -	dio = __iomap_dio_rw(iocb, iter, ops, dops, dio_flags, private,
> +	dio = __iomap_dio_rw(iocb, iter, iomap_next, dops, dio_flags, private,
>  			     done_before);
>  	if (IS_ERR_OR_NULL(dio))
>  		return PTR_ERR_OR_ZERO(dio);
> diff --git a/fs/iomap/fiemap.c b/fs/iomap/fiemap.c
> index d11dadff8286..fc488f05d8ce 100644
> --- a/fs/iomap/fiemap.c
> +++ b/fs/iomap/fiemap.c
> @@ -56,7 +56,7 @@ static int iomap_fiemap_iter(struct iomap_iter *iter,
>  }
>  
>  int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
> -		u64 start, u64 len, const struct iomap_ops *ops)
> +		u64 start, u64 len, iomap_next_fn iomap_next)
>  {
>  	struct iomap_iter iter = {
>  		.inode		= inode,
> @@ -73,7 +73,7 @@ int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
>  	if (ret)
>  		return ret;
>  
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = iomap_fiemap_iter(&iter, fi, &prev);
>  
>  	if (prev.type != IOMAP_HOLE) {
> @@ -92,7 +92,7 @@ EXPORT_SYMBOL_GPL(iomap_fiemap);
>  /* legacy ->bmap interface.  0 is the error return (!) */
>  sector_t
>  iomap_bmap(struct address_space *mapping, sector_t bno,
> -		const struct iomap_ops *ops)
> +		iomap_next_fn iomap_next)
>  {
>  	struct iomap_iter iter = {
>  		.inode	= mapping->host,
> @@ -107,7 +107,7 @@ iomap_bmap(struct address_space *mapping, sector_t bno,
>  		return 0;
>  
>  	bno = 0;
> -	while ((ret = iomap_iter(&iter, ops)) > 0) {
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0) {
>  		if (iter.iomap.type == IOMAP_MAPPED)
>  			bno = iomap_sector(&iter.iomap, iter.pos) >> blkshift;
>  		/* leave iter.status unset to abort loop */
> diff --git a/fs/iomap/iter.c b/fs/iomap/iter.c
> index 466c491bdef6..984045af310a 100644
> --- a/fs/iomap/iter.c
> +++ b/fs/iomap/iter.c
> @@ -42,7 +42,7 @@ static inline void iomap_iter_done(struct iomap_iter *iter)
>  /**
>   * iomap_iter - iterate over a ranges in a file
>   * @iter: iteration structue
> - * @ops: iomap ops provided by the file system
> + * @iomap_next: iomap_next callback provided by the file system
>   *
>   * Iterate over filesystem-provided space mappings for the provided file range.
>   *
> @@ -54,13 +54,13 @@ static inline void iomap_iter_done(struct iomap_iter *iter)
>   * of the loop body:  leave @iter.status unchanged, or set it to a negative
>   * errno.
>   */
> -int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
> +int iomap_iter(struct iomap_iter *iter, iomap_next_fn iomap_next)
>  {
>  	int ret;
>  
> -	trace_iomap_iter(iter, ops, _RET_IP_);
> +	trace_iomap_iter(iter, iomap_next, _RET_IP_);
>  
> -	ret = ops->iomap_next(iter, &iter->iomap, &iter->srcmap);
> +	ret = iomap_next(iter, &iter->iomap, &iter->srcmap);
>  	iter->status = 0;
>  	if (ret > 0)
>  		iomap_iter_done(iter);
> diff --git a/fs/iomap/seek.c b/fs/iomap/seek.c
> index 6cbc587c93da..1bc5053d3fc1 100644
> --- a/fs/iomap/seek.c
> +++ b/fs/iomap/seek.c
> @@ -27,7 +27,7 @@ static int iomap_seek_hole_iter(struct iomap_iter *iter,
>  }
>  
>  loff_t
> -iomap_seek_hole(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
> +iomap_seek_hole(struct inode *inode, loff_t pos, iomap_next_fn iomap_next)
>  {
>  	loff_t size = i_size_read(inode);
>  	struct iomap_iter iter = {
> @@ -42,7 +42,7 @@ iomap_seek_hole(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
>  		return -ENXIO;
>  
>  	iter.len = size - pos;
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = iomap_seek_hole_iter(&iter, &pos);
>  	if (ret < 0)
>  		return ret;
> @@ -73,7 +73,7 @@ static int iomap_seek_data_iter(struct iomap_iter *iter,
>  }
>  
>  loff_t
> -iomap_seek_data(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
> +iomap_seek_data(struct inode *inode, loff_t pos, iomap_next_fn iomap_next)
>  {
>  	loff_t size = i_size_read(inode);
>  	struct iomap_iter iter = {
> @@ -88,7 +88,7 @@ iomap_seek_data(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
>  		return -ENXIO;
>  
>  	iter.len = size - pos;
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = iomap_seek_data_iter(&iter, &pos);
>  	if (ret < 0)
>  		return ret;
> diff --git a/fs/iomap/swapfile.c b/fs/iomap/swapfile.c
> index 0db77c449467..b8bb34deddfc 100644
> --- a/fs/iomap/swapfile.c
> +++ b/fs/iomap/swapfile.c
> @@ -139,7 +139,7 @@ static int iomap_swapfile_iter(struct iomap_iter *iter,
>   */
>  int iomap_swapfile_activate(struct swap_info_struct *sis,
>  		struct file *swap_file, sector_t *pagespan,
> -		const struct iomap_ops *ops)
> +		iomap_next_fn iomap_next)
>  {
>  	struct inode *inode = swap_file->f_mapping->host;
>  	struct iomap_iter iter = {
> @@ -163,7 +163,7 @@ int iomap_swapfile_activate(struct swap_info_struct *sis,
>  	if (ret)
>  		return ret;
>  
> -	while ((ret = iomap_iter(&iter, ops)) > 0)
> +	while ((ret = iomap_iter(&iter, iomap_next)) > 0)
>  		iter.status = iomap_swapfile_iter(&iter, &iter.iomap, &isi);
>  	if (ret < 0)
>  		return ret;

<snip>

> diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
> index 2a0c54256e93..91480cb6a4d8 100644
> --- a/fs/xfs/xfs_aops.c
> +++ b/fs/xfs/xfs_aops.c
> @@ -752,7 +752,7 @@ xfs_vm_bmap(
>  	 */
>  	if (xfs_is_cow_inode(ip) || XFS_IS_REALTIME_INODE(ip))
>  		return 0;
> -	return iomap_bmap(mapping, block, &xfs_read_iomap_ops);
> +	return iomap_bmap(mapping, block, xfs_read_iomap_next);
>  }
>  
>  static void
> @@ -793,7 +793,7 @@ xfs_vm_read_folio(
>  	struct iomap_read_folio_ctx	ctx = { .cur_folio = folio };
>  
>  	ctx.ops = xfs_get_iomap_read_ops(folio->mapping);
> -	iomap_read_folio(&xfs_read_iomap_ops, &ctx, NULL);
> +	iomap_read_folio(xfs_read_iomap_next, &ctx, NULL);
>  	return 0;
>  }
>  
> @@ -804,7 +804,7 @@ xfs_vm_readahead(
>  	struct iomap_read_folio_ctx	ctx = { .rac = rac };
>  
>  	ctx.ops = xfs_get_iomap_read_ops(rac->mapping),
> -	iomap_readahead(&xfs_read_iomap_ops, &ctx, NULL);
> +	iomap_readahead(xfs_read_iomap_next, &ctx, NULL);
>  }
>  
>  static int
> @@ -850,7 +850,7 @@ xfs_vm_swap_activate(
>  	sis->bdev = xfs_inode_buftarg(ip)->bt_bdev;
>  
>  	return iomap_swapfile_activate(sis, swap_file, span,
> -			&xfs_read_iomap_ops);
> +			xfs_read_iomap_next);
>  }
>  
>  const struct address_space_operations xfs_address_space_operations = {
> diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> index 7f8bef1a9954..a987ffbf3c02 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -269,7 +269,7 @@ xfs_file_dio_read(
>  		dio_ops = &xfs_dio_read_bounce_ops;
>  		dio_flags |= IOMAP_DIO_BOUNCE;
>  	}
> -	ret = iomap_dio_rw(iocb, to, &xfs_read_iomap_ops, dio_ops, dio_flags,
> +	ret = iomap_dio_rw(iocb, to, xfs_read_iomap_next, dio_ops, dio_flags,
>  			NULL, 0);
>  	xfs_iunlock(ip, XFS_IOLOCK_SHARED);
>  
> @@ -292,7 +292,7 @@ xfs_file_dax_read(
>  	ret = xfs_ilock_iocb(iocb, XFS_IOLOCK_SHARED);
>  	if (ret)
>  		return ret;
> -	ret = dax_iomap_rw(iocb, to, &xfs_read_iomap_ops);
> +	ret = dax_iomap_rw(iocb, to, xfs_read_iomap_next);
>  	xfs_iunlock(ip, XFS_IOLOCK_SHARED);
>  
>  	file_accessed(iocb->ki_filp);
> @@ -742,7 +742,7 @@ xfs_file_dio_write_aligned(
>  	struct xfs_inode	*ip,
>  	struct kiocb		*iocb,
>  	struct iov_iter		*from,
> -	const struct iomap_ops	*ops,
> +	iomap_next_fn		iomap_next,
>  	const struct iomap_dio_ops *dops,
>  	struct xfs_zone_alloc_ctx *ac)
>  {
> @@ -777,7 +777,7 @@ xfs_file_dio_write_aligned(
>  	if (mapping_stable_writes(iocb->ki_filp->f_mapping))
>  		dio_flags |= IOMAP_DIO_BOUNCE;
>  	trace_xfs_file_direct_write(iocb, from);
> -	ret = iomap_dio_rw(iocb, from, ops, dops, dio_flags, ac, 0);
> +	ret = iomap_dio_rw(iocb, from, iomap_next, dops, dio_flags, ac, 0);
>  out_unlock:
>  	xfs_iunlock(ip, iolock);
>  	return ret;
> @@ -799,7 +799,7 @@ xfs_file_dio_write_zoned(
>  	if (ret < 0)
>  		return ret;
>  	ret = xfs_file_dio_write_aligned(ip, iocb, from,
> -			&xfs_zoned_direct_write_iomap_ops,
> +			xfs_zoned_direct_write_iomap_next,
>  			&xfs_dio_zoned_write_ops, &ac);
>  	xfs_zoned_space_unreserve(ip->i_mount, &ac);
>  	return ret;
> @@ -824,16 +824,16 @@ xfs_file_dio_write_atomic(
>  	unsigned int		iolock = XFS_IOLOCK_SHARED;
>  	ssize_t			ret, ocount = iov_iter_count(from);
>  	unsigned int		dio_flags = 0;
> -	const struct iomap_ops	*dops;
> +	iomap_next_fn		dops;
>  
>  	/*
>  	 * HW offload should be faster, so try that first if it is already
>  	 * known that the write length is not too large.
>  	 */
>  	if (ocount > xfs_inode_buftarg(ip)->bt_awu_max)
> -		dops = &xfs_atomic_write_cow_iomap_ops;
> +		dops = xfs_atomic_write_cow_iomap_next;
>  	else
> -		dops = &xfs_direct_write_iomap_ops;
> +		dops = xfs_direct_write_iomap_next;

Probably ought to be called iter_fn, or at least something that isn't
"dops".

>  
>  retry:
>  	ret = xfs_ilock_iocb_for_write(iocb, &iolock);
> @@ -862,9 +862,9 @@ xfs_file_dio_write_atomic(
>  	 * possible. The REQ_ATOMIC-based method is typically not possible if
>  	 * the write spans multiple extents or the disk blocks are misaligned.
>  	 */
> -	if (ret == -ENOPROTOOPT && dops == &xfs_direct_write_iomap_ops) {
> +	if (ret == -ENOPROTOOPT && dops == xfs_direct_write_iomap_next) {
>  		xfs_iunlock(ip, iolock);
> -		dops = &xfs_atomic_write_cow_iomap_ops;
> +		dops = xfs_atomic_write_cow_iomap_next;
>  		goto retry;
>  	}
>  
> @@ -947,7 +947,7 @@ xfs_file_dio_write_unaligned(
>  		flags |= IOMAP_DIO_BOUNCE;
>  
>  	trace_xfs_file_direct_write(iocb, from);
> -	ret = iomap_dio_rw(iocb, from, &xfs_direct_write_iomap_ops,
> +	ret = iomap_dio_rw(iocb, from, xfs_direct_write_iomap_next,
>  			   &xfs_dio_write_ops, flags, NULL, 0);
>  
>  	/*
> @@ -987,7 +987,7 @@ xfs_file_dio_write(
>  	if (iocb->ki_flags & IOCB_ATOMIC)
>  		return xfs_file_dio_write_atomic(ip, iocb, from);
>  	return xfs_file_dio_write_aligned(ip, iocb, from,
> -			&xfs_direct_write_iomap_ops, &xfs_dio_write_ops, NULL);
> +			xfs_direct_write_iomap_next, &xfs_dio_write_ops, NULL);
>  }
>  
>  static noinline ssize_t
> @@ -1011,7 +1011,7 @@ xfs_file_dax_write(
>  	pos = iocb->ki_pos;
>  
>  	trace_xfs_file_dax_write(iocb, from);
> -	ret = dax_iomap_rw(iocb, from, &xfs_dax_write_iomap_ops);
> +	ret = dax_iomap_rw(iocb, from, xfs_dax_write_iomap_next);
>  	if (ret > 0 && iocb->ki_pos > i_size_read(inode)) {
>  		i_size_write(inode, iocb->ki_pos);
>  		error = xfs_setfilesize(ip, pos, ret);
> @@ -1054,7 +1054,7 @@ xfs_file_buffered_write(
>  
>  	trace_xfs_file_buffered_write(iocb, from);
>  	ret = iomap_file_buffered_write(iocb, from,
> -			&xfs_buffered_write_iomap_ops, &xfs_iomap_write_ops,
> +			xfs_buffered_write_iomap_next, &xfs_iomap_write_ops,
>  			NULL);
>  
>  	/*
> @@ -1135,7 +1135,7 @@ xfs_file_buffered_write_zoned(
>  retry:
>  	trace_xfs_file_buffered_write(iocb, from);
>  	ret = iomap_file_buffered_write(iocb, from,
> -			&xfs_buffered_write_iomap_ops, &xfs_iomap_write_ops,
> +			xfs_buffered_write_iomap_next, &xfs_iomap_write_ops,
>  			&ac);
>  	if (ret == -ENOSPC && !cleared_space) {
>  		/*
> @@ -1856,10 +1856,10 @@ xfs_file_llseek(
>  	default:
>  		return generic_file_llseek(file, offset, whence);
>  	case SEEK_HOLE:
> -		offset = iomap_seek_hole(inode, offset, &xfs_seek_iomap_ops);
> +		offset = iomap_seek_hole(inode, offset, xfs_seek_iomap_next);
>  		break;
>  	case SEEK_DATA:
> -		offset = iomap_seek_data(inode, offset, &xfs_seek_iomap_ops);
> +		offset = iomap_seek_data(inode, offset, xfs_seek_iomap_next);
>  		break;
>  	}
>  
> @@ -1883,8 +1883,8 @@ xfs_dax_fault_locked(
>  	}
>  	ret = dax_iomap_fault(vmf, order, &pfn, NULL,
>  			(write_fault && !vmf->cow_page) ?
> -				&xfs_dax_write_iomap_ops :
> -				&xfs_read_iomap_ops);
> +				xfs_dax_write_iomap_next :
> +				xfs_read_iomap_next);
>  	if (ret & VM_FAULT_NEEDDSYNC)
>  		ret = dax_finish_sync_fault(vmf, order, pfn);
>  	return ret;
> @@ -1948,7 +1948,7 @@ __xfs_write_fault(
>  	if (IS_DAX(inode))
>  		ret = xfs_dax_fault_locked(vmf, order, true);
>  	else
> -		ret = iomap_page_mkwrite(vmf, &xfs_buffered_write_iomap_ops,
> +		ret = iomap_page_mkwrite(vmf, xfs_buffered_write_iomap_next,
>  				ac);
>  	xfs_iunlock(ip, lock_mode);
>  
> diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
> index 4fa1a5c985db..71c4bb024f04 100644
> --- a/fs/xfs/xfs_iomap.c
> +++ b/fs/xfs/xfs_iomap.c
> @@ -1037,7 +1037,7 @@ xfs_direct_write_iomap_begin(
>  	return error;
>  }
>  
> -static int
> +int
>  xfs_direct_write_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -1047,10 +1047,6 @@ xfs_direct_write_iomap_next(
>  			NULL);
>  }
>  
> -const struct iomap_ops xfs_direct_write_iomap_ops = {
> -	.iomap_next		= xfs_direct_write_iomap_next,
> -};
> -
>  #ifdef CONFIG_XFS_RT
>  /*
>   * This is really simple.  The space has already been reserved before taking the
> @@ -1099,7 +1095,7 @@ xfs_zoned_direct_write_iomap_begin(
>  	return 0;
>  }
>  
> -static int
> +int
>  xfs_zoned_direct_write_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -1109,9 +1105,6 @@ xfs_zoned_direct_write_iomap_next(
>  			xfs_zoned_direct_write_iomap_begin, NULL);
>  }
>  
> -const struct iomap_ops xfs_zoned_direct_write_iomap_ops = {
> -	.iomap_next		= xfs_zoned_direct_write_iomap_next,
> -};
>  #endif /* CONFIG_XFS_RT */
>  
>  #ifdef DEBUG
> @@ -1294,7 +1287,7 @@ xfs_atomic_write_cow_iomap_begin(
>  	return error;
>  }
>  
> -static int
> +int
>  xfs_atomic_write_cow_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -1304,10 +1297,6 @@ xfs_atomic_write_cow_iomap_next(
>  			xfs_atomic_write_cow_iomap_begin, NULL);
>  }
>  
> -const struct iomap_ops xfs_atomic_write_cow_iomap_ops = {
> -	.iomap_next		= xfs_atomic_write_cow_iomap_next,
> -};
> -
>  static int
>  xfs_dax_write_iomap_end(
>  	struct inode		*inode,
> @@ -1328,7 +1317,7 @@ xfs_dax_write_iomap_end(
>  	return xfs_reflink_end_cow(ip, pos, written);
>  }
>  
> -static int
> +int
>  xfs_dax_write_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -1338,10 +1327,6 @@ xfs_dax_write_iomap_next(
>  			xfs_dax_write_iomap_end);
>  }
>  
> -const struct iomap_ops xfs_dax_write_iomap_ops = {
> -	.iomap_next	= xfs_dax_write_iomap_next,
> -};
> -
>  /*
>   * Convert a hole to a delayed allocation.
>   */
> @@ -2207,7 +2192,7 @@ xfs_buffered_write_iomap_end(
>  	return 0;
>  }
>  
> -static int
> +int
>  xfs_buffered_write_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -2218,10 +2203,6 @@ xfs_buffered_write_iomap_next(
>  			xfs_buffered_write_iomap_end);
>  }
>  
> -const struct iomap_ops xfs_buffered_write_iomap_ops = {
> -	.iomap_next		= xfs_buffered_write_iomap_next,
> -};
> -
>  static int
>  xfs_read_iomap_begin(
>  	struct inode		*inode,
> @@ -2263,7 +2244,7 @@ xfs_read_iomap_begin(
>  				 shared ? IOMAP_F_SHARED : 0, seq);
>  }
>  
> -static int
> +int
>  xfs_read_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -2272,10 +2253,6 @@ xfs_read_iomap_next(
>  	return iomap_process(iter, iomap, srcmap, xfs_read_iomap_begin, NULL);
>  }
>  
> -const struct iomap_ops xfs_read_iomap_ops = {
> -	.iomap_next		= xfs_read_iomap_next,
> -};
> -
>  static int
>  xfs_seek_iomap_begin(
>  	struct inode		*inode,
> @@ -2360,7 +2337,7 @@ xfs_seek_iomap_begin(
>  	return error;
>  }
>  
> -static int
> +int
>  xfs_seek_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -2369,10 +2346,6 @@ xfs_seek_iomap_next(
>  	return iomap_process(iter, iomap, srcmap, xfs_seek_iomap_begin, NULL);
>  }
>  
> -const struct iomap_ops xfs_seek_iomap_ops = {
> -	.iomap_next		= xfs_seek_iomap_next,
> -};
> -
>  static int
>  xfs_xattr_iomap_begin(
>  	struct inode		*inode,
> @@ -2416,7 +2389,7 @@ xfs_xattr_iomap_begin(
>  	return xfs_bmbt_to_iomap(ip, iomap, &imap, flags, IOMAP_F_XATTR, seq);
>  }
>  
> -static int
> +int
>  xfs_xattr_iomap_next(
>  	const struct iomap_iter *iter,
>  	struct iomap		*iomap,
> @@ -2425,10 +2398,6 @@ xfs_xattr_iomap_next(
>  	return iomap_process(iter, iomap, srcmap, xfs_xattr_iomap_begin, NULL);
>  }
>  
> -const struct iomap_ops xfs_xattr_iomap_ops = {
> -	.iomap_next		= xfs_xattr_iomap_next,
> -};
> -
>  int
>  xfs_zero_range(
>  	struct xfs_inode	*ip,
> @@ -2443,9 +2412,9 @@ xfs_zero_range(
>  
>  	if (IS_DAX(inode))
>  		return dax_zero_range(inode, pos, len, did_zero,
> -				      &xfs_dax_write_iomap_ops);
> +				      xfs_dax_write_iomap_next);
>  	return iomap_zero_range(inode, pos, len, did_zero,
> -			&xfs_buffered_write_iomap_ops, &xfs_iomap_write_ops,
> +			xfs_buffered_write_iomap_next, &xfs_iomap_write_ops,
>  			ac);
>  }
>  
> @@ -2460,8 +2429,8 @@ xfs_truncate_page(
>  
>  	if (IS_DAX(inode))
>  		return dax_truncate_page(inode, pos, did_zero,
> -					&xfs_dax_write_iomap_ops);
> +					xfs_dax_write_iomap_next);
>  	return iomap_truncate_page(inode, pos, did_zero,
> -			&xfs_buffered_write_iomap_ops, &xfs_iomap_write_ops,
> +			xfs_buffered_write_iomap_next, &xfs_iomap_write_ops,
>  			ac);
>  }
> diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h
> index ebcce7d49446..01875d20fb66 100644
> --- a/fs/xfs/xfs_iomap.h
> +++ b/fs/xfs/xfs_iomap.h
> @@ -49,14 +49,22 @@ xfs_aligned_fsb_count(
>  	return count_fsb;
>  }
>  
> -extern const struct iomap_ops xfs_buffered_write_iomap_ops;
> -extern const struct iomap_ops xfs_direct_write_iomap_ops;
> -extern const struct iomap_ops xfs_zoned_direct_write_iomap_ops;
> -extern const struct iomap_ops xfs_read_iomap_ops;
> -extern const struct iomap_ops xfs_seek_iomap_ops;
> -extern const struct iomap_ops xfs_xattr_iomap_ops;
> -extern const struct iomap_ops xfs_dax_write_iomap_ops;
> -extern const struct iomap_ops xfs_atomic_write_cow_iomap_ops;
> +int xfs_buffered_write_iomap_next(const struct iomap_iter *iter,
> +		struct iomap *iomap, struct iomap *srcmap);
> +int xfs_direct_write_iomap_next(const struct iomap_iter *iter,
> +		struct iomap *iomap, struct iomap *srcmap);
> +int xfs_zoned_direct_write_iomap_next(const struct iomap_iter *iter,
> +		struct iomap *iomap, struct iomap *srcmap);
> +int xfs_read_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
> +int xfs_seek_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
> +int xfs_xattr_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
> +int xfs_dax_write_iomap_next(const struct iomap_iter *iter, struct iomap *iomap,
> +		struct iomap *srcmap);
> +int xfs_atomic_write_cow_iomap_next(const struct iomap_iter *iter,
> +		struct iomap *iomap, struct iomap *srcmap);
>  extern const struct iomap_write_ops xfs_iomap_write_ops;
>  
>  #endif /* __XFS_IOMAP_H__*/
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index 6339f4956ecb..5c3d9a365f93 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -1239,10 +1239,10 @@ xfs_vn_fiemap(
>  	if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) {
>  		fieinfo->fi_flags &= ~FIEMAP_FLAG_XATTR;
>  		error = iomap_fiemap(inode, fieinfo, start, length,
> -				&xfs_xattr_iomap_ops);
> +				xfs_xattr_iomap_next);
>  	} else {
>  		error = iomap_fiemap(inode, fieinfo, start, length,
> -				&xfs_read_iomap_ops);
> +				xfs_read_iomap_next);
>  	}
>  	xfs_iunlock(XFS_I(inode), XFS_IOLOCK_SHARED);
>  
> diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
> index a5c188b78138..2b9792626bab 100644
> --- a/fs/xfs/xfs_reflink.c
> +++ b/fs/xfs/xfs_reflink.c
> @@ -1683,7 +1683,7 @@ xfs_reflink_remap_prep(
>  				pos_out, len, remap_flags);
>  	else
>  		ret = dax_remap_file_range_prep(file_in, pos_in, file_out,
> -				pos_out, len, remap_flags, &xfs_read_iomap_ops);
> +				pos_out, len, remap_flags, xfs_read_iomap_next);
>  	if (ret || *len == 0)
>  		goto out_unlock;
>  
> @@ -1878,10 +1878,10 @@ xfs_reflink_unshare(
>  
>  	if (IS_DAX(inode))
>  		error = dax_file_unshare(inode, offset, len,
> -				&xfs_dax_write_iomap_ops);
> +				xfs_dax_write_iomap_next);
>  	else
>  		error = iomap_file_unshare(inode, offset, len,
> -				&xfs_buffered_write_iomap_ops,
> +				xfs_buffered_write_iomap_next,
>  				&xfs_iomap_write_ops);
>  	if (error)
>  		goto out;

Aside from the name bikeshedding, the logic looks solid. :)

--D

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 18/18] Documentation: iomap: update docs to reflect iomap_next model
  2026-07-01  0:09 ` [PATCH v2 18/18] Documentation: iomap: update docs to reflect iomap_next model Joanne Koong
  2026-07-02 14:07   ` Christoph Hellwig
@ 2026-07-02 19:26   ` Darrick J. Wong
  2026-07-03  1:36     ` Joanne Koong
  1 sibling, 1 reply; 53+ messages in thread
From: Darrick J. Wong @ 2026-07-02 19:26 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Jonathan Corbet, Shuah Khan, open list:DOCUMENTATION, open list

On Tue, Jun 30, 2026 at 05:09:33PM -0700, Joanne Koong wrote:
> Filesystems no longer pass a struct iomap_ops with separate
> ->iomap_begin() and ->iomap_end() callbacks.  Instead, every iomap
> operation takes a single iomap_next() callback directly. iomap_next()
> finishes the previous mapping (if any) and produces the next one. Most
> filesystems build it from begin and end helpers via the iomap_process()
> helper.
> 
> Update the iomap documentation to match this change.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> ---
>  Documentation/filesystems/iomap/design.rst    | 115 +++++++++++++-----
>  .../filesystems/iomap/operations.rst          |  60 +++++----
>  Documentation/filesystems/iomap/porting.rst   |  22 +++-
>  3 files changed, 132 insertions(+), 65 deletions(-)
> 
> diff --git a/Documentation/filesystems/iomap/design.rst b/Documentation/filesystems/iomap/design.rst
> index 0f7672676c0b..7a37e303eea8 100644
> --- a/Documentation/filesystems/iomap/design.rst
> +++ b/Documentation/filesystems/iomap/design.rst
> @@ -75,7 +75,10 @@ At a high level, an iomap operation `looks like this
>  
>  1. For each byte in the operation range...
>  
> -   1. Obtain a space mapping via ``->iomap_begin``
> +   1. Obtain the next space mapping via the ``iomap_next`` callback.
> +      From the second iteration onwards this same callback first finishes
> +      the previous mapping (committing or unreserving space as needed)
> +      and then produces the next one.
>  
>     2. For each sub-unit of work...
>  
> @@ -86,7 +89,13 @@ At a high level, an iomap operation `looks like this
>  
>     3. Increment operation cursor
>  
> -   4. Release the mapping via ``->iomap_end``, if necessary
> +iomap repeats this until the range is fully consumed.  The ``iomap_next``
> +callback returns ``1`` while there is more of the range left to process,
> +``0`` once it is fully consumed, and a negative errno on error.

s/and/or/

> +Filesystems rarely implement ``->iomap_next`` by hand. The ``iomap_process``
> +helper implements the finish-then-produce sequence in +terms of two smaller
> +callbacks, ``begin`` and ``end``. See `The Mapping Callback`_ below for more
> +info.

I wonder, under what circumstances would a filesystem /not/ use
iomap_process()?

>  Each iomap operation will be covered in more detail below.
>  This library was covered previously by an `LWN article
> @@ -189,7 +198,7 @@ The fields are as follows:
>     * **IOMAP_DELALLOC**: A promise to allocate space at a later time
>       ("delayed allocation").
>       If the filesystem returns IOMAP_F_NEW here and the write fails, the
> -     ``->iomap_end`` function must delete the reservation.
> +     ``end`` function must delete the reservation.
>       The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
>  
>     * **IOMAP_MAPPED**: The file range maps to specific space on the
> @@ -208,12 +217,12 @@ The fields are as follows:
>  
>     * **IOMAP_INLINE**: The file range maps to the memory buffer
>       specified by ``inline_data``.
> -     For write operation, the ``->iomap_end`` function presumably
> -     handles persisting the data.
> +     For write operation, the ``end`` function presumably handles
> +     persisting the data.

Unrelated to this patch, but this should say "For write operations, the
end function must persist the data" because iomap_writepages doesn't
handle inline data.

>       The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
>  
>   * ``flags`` describe the status of the space mapping.
> -   These flags should be set by the filesystem in ``->iomap_begin``:
> +   These flags should be set by the filesystem in ``begin``:
>  
>     * **IOMAP_F_NEW**: The space under the mapping is newly allocated.
>       Areas that will not be written to must be zeroed.
> @@ -262,15 +271,15 @@ The fields are as follows:
>       update.
>  
>     These flags can be set by iomap itself during file operations.
> -   The filesystem should supply an ``->iomap_end`` function if it needs
> +   The filesystem should supply an ``end`` function if it needs
>     to observe these flags:
>  
>     * **IOMAP_F_SIZE_CHANGED**: The file size has changed as a result of
>       using this mapping.
>  
>     * **IOMAP_F_STALE**: The mapping was found to be stale.
> -     iomap will call ``->iomap_end`` on this mapping and then
> -     ``->iomap_begin`` to obtain a new mapping.
> +     iomap will call ``end`` on this mapping and then
> +     ``begin`` to obtain a new mapping.
>  
>     Currently, these flags are only set by pagecache operations.
>  
> @@ -289,41 +298,80 @@ The fields are as follows:
>  
>   * ``private`` is a pointer to `filesystem-private information
>     <https://lore.kernel.org/all/20180619164137.13720-7-hch@lst.de/>`_.
> -   This value will be passed unchanged to ``->iomap_end``.
> +   This value will be passed unchanged to ``end``.
>  
>   * ``validity_cookie`` is a magic freshness value set by the filesystem
>     that should be used to detect stale mappings.
>     For pagecache operations this is critical for correct operation
>     because page faults can occur, which implies that filesystem locks
> -   should not be held between ``->iomap_begin`` and ``->iomap_end``.
> +   should not be held between ``begin`` and ``end``.
>     Filesystems with completely static mappings need not set this value.
>     Only pagecache operations revalidate mappings; see the section about
>     ``iomap_valid`` for details.
>  
> -``struct iomap_ops``
> +The Mapping Callback
>  --------------------
>  
> -Every iomap function requires the filesystem to pass an operations
> -structure to obtain a mapping and (optionally) to release the mapping:
> +Every iomap operation takes an ``iomap_next_fn`` callback from the
> +filesystem. iomap calls it once per iteration of the file range:
>  
>  .. code-block:: c
>  
> - struct iomap_ops {
> -     int (*iomap_begin)(struct inode *inode, loff_t pos, loff_t length,
> -                        unsigned flags, struct iomap *iomap,
> -                        struct iomap *srcmap);
> + typedef int (*iomap_next_fn)(const struct iomap_iter *iter,
> +                              struct iomap *iomap, struct iomap *srcmap);
>  
> -     int (*iomap_end)(struct inode *inode, loff_t pos, loff_t length,
> -                      ssize_t written, unsigned flags,
> -                      struct iomap *iomap);
> - };
> +``->iomap_next``
> +~~~~~~~~~~~~~~~~
> +
> +Each call must finish the previous mapping, if any, and then produce the

Each call?  Oh, each implementation of ->iomap_next must finish the
previous mapping.

> +next mapping for the current iteration position described by ``iter``.
> +The mapping is returned through ``iomap`` (and through ``srcmap`` for
> +operations that read from one mapping while writing to another; see
> +``begin`` below).
>  
> -``->iomap_begin``
> +The callback returns ``1`` to continue iterating, ``0`` once the file
> +range has been fully consumed, and a negative errno on error.

s/and/or/

I think there should be a transition sentence here along the lines of

"Most filesystems are not expected to implement all of these behaviors
in ->iomap_next themselves.  They should instead call iomap_process as
described below."

Or demote the next section so it's more obvious that the "iomap_process"
and "->iomap_next" sections aren't independent?

> +
> +``iomap_process``
>  ~~~~~~~~~~~~~~~~~
>  
> -iomap operations call ``->iomap_begin`` to obtain one file mapping for
> -the range of bytes specified by ``pos`` and ``length`` for the file
> -``inode``.
> +Filesystems rarely need a hand-written ``iomap_next`` callback.  The
> +``iomap_process`` helper implements the finish-then-produce sequence in
> +terms of two smaller callbacks, ``begin`` and ``end``, so most
> +``->iomap_next`` implementations are simply:
> +
> +.. code-block:: c
> +
> + static int my_iomap_next(const struct iomap_iter *iter,
> +                          struct iomap *iomap, struct iomap *srcmap)
> + {
> +         return iomap_process(iter, iomap, srcmap,
> +                              my_iomap_begin, my_iomap_end);
> + }
> +
> +``end`` may be ``NULL`` when the filesystem has nothing to finish.
> +The two callbacks have these prototypes:
> +
> +.. code-block:: c
> +
> + typedef int (*iomap_begin_fn)(struct inode *inode, loff_t pos,
> +                               loff_t length, unsigned flags,
> +                               struct iomap *iomap, struct iomap *srcmap);
> +
> + typedef int (*iomap_end_fn)(struct inode *inode, loff_t pos,
> +                             loff_t length, ssize_t written,
> +                             unsigned flags, struct iomap *iomap);
> +
> +``iomap_process`` is an inline helper, so when it is called with fixed
> +``begin`` and ``end`` functions the compiler can inline both into the
> +filesystem's ``->iomap_next``, keeping indirect calls out of the
> +iteration hot path.  The two callbacks are described next.
> +
> +``begin``
> +~~~~~~~~~
> +
> +The ``begin`` callback obtains one file mapping for the range of bytes
> +specified by ``pos`` and ``length`` for the file ``inode``.
>  This mapping should be returned through the ``iomap`` pointer.
>  The mapping must cover at least the first byte of the supplied file
>  range, but it does not need to cover the entire requested range.
> @@ -377,18 +425,19 @@ information via ``srcmap``.
>  Only pagecache and fsdax operations support reading from one mapping and
>  writing to another.
>  
> -``->iomap_end``
> -~~~~~~~~~~~~~~~
> +``end``
> +~~~~~~~
>  
> -After the operation completes, the ``->iomap_end`` function, if present,
> -is called to signal that iomap is finished with a mapping.
> +The ``end`` callback, if present, is called when iomap is
> +finished with a mapping: before each subsequent mapping is produced, and
> +once more after the final mapping when the operation completes.
>  Typically, implementations will use this function to tear down any
> -context that were set up in ``->iomap_begin``.
> +context that was set up in ``begin``.
>  For example, a write might wish to commit the reservations for the bytes
>  that were operated upon and unreserve any space that was not operated
>  upon.
>  ``written`` might be zero if no bytes were touched.
> -``flags`` will contain the same value passed to ``->iomap_begin``.
> +``flags`` will contain the same value passed to ``begin``.
>  iomap ops for reads are not likely to need to supply this function.
>  
>  Both functions should return a negative errno code on error, or zero on
> @@ -421,7 +470,7 @@ iomap is concerned:
>     accessing the folio until writeback is underway.
>  
>     * The **lower** level primitive is taken by the filesystem in the
> -     ``->iomap_begin`` and ``->iomap_end`` functions to coordinate
> +     ``begin`` and ``end`` functions to coordinate
>       access to the file space mapping information.
>       The fields of the iomap object should be filled out while holding
>       this primitive.
> diff --git a/Documentation/filesystems/iomap/operations.rst b/Documentation/filesystems/iomap/operations.rst
> index da982ca7e413..e065398dad95 100644
> --- a/Documentation/filesystems/iomap/operations.rst
> +++ b/Documentation/filesystems/iomap/operations.rst
> @@ -17,6 +17,12 @@ Supported File Operations
>  Below are a discussion of the high level file operations that iomap
>  implements.
>  
> +Each operation takes an ``iomap_next_fn`` callback that supplies the file
> +mappings, as described in the iomap design document.  The per-operation
> +``flags`` documented below are passed to that callback; references to
> +``begin`` and ``end`` name the two steps a typical callback is built from
> +via ``iomap_process``.
> +
>  Buffered I/O
>  ============
>  
> @@ -91,9 +97,9 @@ iomap calls these functions:
>      that was set up by ``->get_folio``.
>  
>    - ``iomap_valid``: The filesystem may not hold locks between
> -    ``->iomap_begin`` and ``->iomap_end`` because pagecache operations
> -    can take folio locks, fault on userspace pages, initiate writeback
> -    for memory reclamation, or engage in other time-consuming actions.
> +    ``begin`` and ``end`` because pagecache operations can take folio locks,
> +    fault on userspace pages, initiate writeback for memory reclamation, or
> +    engage in other time-consuming actions.
>      If a file's space mapping data are mutable, it is possible that the
>      mapping for a particular pagecache folio can `change in the time it
>      takes
> @@ -114,12 +120,12 @@ iomap calls these functions:
>      If the mapping is not valid, the mapping will be sampled again.
>  
>      To support making the validity decision, the filesystem's
> -    ``->iomap_begin`` function may set ``struct iomap::validity_cookie``
> +    ``begin`` function may set ``struct iomap::validity_cookie``
>      at the same time that it populates the other iomap fields.
>      A simple validation cookie implementation is a sequence counter.
>      If the filesystem bumps the sequence counter every time it modifies
>      the inode's extent map, it can be placed in the ``struct
> -    iomap::validity_cookie`` during ``->iomap_begin``.
> +    iomap::validity_cookie`` during ``begin``.
>      If the value in the cookie is found to be different to the value
>      the filesystem holds when the mapping is passed back to
>      ``->iomap_valid``, then the iomap should considered stale and the
> @@ -199,7 +205,7 @@ Buffered Readahead and Reads
>  The ``iomap_readahead`` function initiates readahead to the pagecache.
>  The ``iomap_read_folio`` function reads one folio's worth of data into
>  the pagecache.
> -The ``flags`` argument to ``->iomap_begin`` will be set to zero.
> +The ``flags`` argument to ``begin`` will be set to zero.
>  The pagecache takes whatever locks it needs before calling the
>  filesystem.
>  
> @@ -231,7 +237,7 @@ Buffered Writes
>  The ``iomap_file_buffered_write`` function writes an ``iocb`` to the
>  pagecache.
>  ``IOMAP_WRITE`` or ``IOMAP_WRITE`` | ``IOMAP_NOWAIT`` will be passed as
> -the ``flags`` argument to ``->iomap_begin``.
> +the ``flags`` argument to ``begin``.
>  Callers commonly take ``i_rwsem`` in either shared or exclusive mode
>  before calling this function.
>  
> @@ -241,7 +247,7 @@ mmap Write Faults
>  The ``iomap_page_mkwrite`` function handles a write fault to a folio in
>  the pagecache.
>  ``IOMAP_WRITE | IOMAP_FAULT`` will be passed as the ``flags`` argument
> -to ``->iomap_begin``.
> +to ``begin``.
>  Callers commonly take the mmap ``invalidate_lock`` in shared or
>  exclusive mode before calling this function.
>  
> @@ -256,7 +262,7 @@ such `reservations
>  <https://lore.kernel.org/linux-xfs/20220817093627.GZ3600936@dread.disaster.area/>`_
>  because writeback will not consume the reservation.
>  The ``iomap_write_delalloc_release`` can be called from a
> -``->iomap_end`` function to find all the clean areas of the folios
> +``end`` function to find all the clean areas of the folios
>  caching a fresh (``IOMAP_F_NEW``) delalloc mapping.
>  It takes the ``invalidate_lock``.
>  
> @@ -274,7 +280,7 @@ Filesystems can call ``iomap_zero_range`` to perform zeroing of the
>  pagecache for non-truncation file operations that are not aligned to
>  the fsblock size.
>  ``IOMAP_ZERO`` will be passed as the ``flags`` argument to
> -``->iomap_begin``.
> +``begin``.
>  Callers typically hold ``i_rwsem`` and ``invalidate_lock`` in exclusive
>  mode before calling this function.
>  
> @@ -285,7 +291,7 @@ Filesystems can call ``iomap_file_unshare`` to force a file sharing
>  storage with another file to preemptively copy the shared data to newly
>  allocate storage.
>  ``IOMAP_WRITE | IOMAP_UNSHARE`` will be passed as the ``flags`` argument
> -to ``->iomap_begin``.
> +to ``begin``.
>  Callers typically hold ``i_rwsem`` and ``invalidate_lock`` in exclusive
>  mode before calling this function.
>  
> @@ -298,7 +304,7 @@ operation.
>  ``truncate_setsize`` or ``truncate_pagecache`` will take care of
>  everything after the EOF block.
>  ``IOMAP_ZERO`` will be passed as the ``flags`` argument to
> -``->iomap_begin``.
> +``begin``.
>  Callers typically hold ``i_rwsem`` and ``invalidate_lock`` in exclusive
>  mode before calling this function.
>  
> @@ -341,8 +347,8 @@ The fields are as follows:
>      though it will `reuse mappings
>      <https://lore.kernel.org/all/20231207072710.176093-15-hch@lst.de/>`_
>      for runs of contiguous dirty fsblocks within a folio.
> -    Do not return ``IOMAP_INLINE`` mappings here; the ``->iomap_end``
> -    function must deal with persisting written data.
> +    Do not return ``IOMAP_INLINE`` mappings here; the ``end`` function must
> +    deal with persisting written data.
>      Do not return ``IOMAP_DELALLOC`` mappings here; iomap currently
>      requires mapping to allocated space.
>      Filesystems can skip a potentially expensive mapping lookup if the
> @@ -428,7 +434,7 @@ writes for files.
>  .. code-block:: c
>  
>   ssize_t iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
> -                      const struct iomap_ops *ops,
> +                      iomap_next_fn iomap_next,
>                        const struct iomap_dio_ops *dops,
>                        unsigned int dio_flags, void *private,
>                        size_t done_before);
> @@ -511,7 +517,7 @@ Return Values
>   * ``-ENOTBLK``: Fall back to buffered I/O.
>     iomap itself will return this value if it cannot invalidate the page
>     cache before issuing the I/O to storage.
> -   The ``->iomap_begin`` or ``->iomap_end`` functions may also return
> +   The ``begin`` or ``end`` functions may also return
>     this value.
>  
>   * ``-EIOCBQUEUED``: The asynchronous direct I/O request has been
> @@ -526,7 +532,7 @@ A direct I/O read initiates a read I/O from the storage device to the
>  caller's buffer.
>  Dirty parts of the pagecache are flushed to storage before initiating
>  the read io.
> -The ``flags`` value for ``->iomap_begin`` will be ``IOMAP_DIRECT`` with
> +The ``flags`` value for ``begin`` will be ``IOMAP_DIRECT`` with
>  any combination of the following enhancements:
>  
>   * ``IOMAP_NOWAIT``, as defined previously.
> @@ -542,7 +548,7 @@ caller's buffer.
>  Dirty parts of the pagecache are flushed to storage before initiating
>  the write io.
>  The pagecache is invalidated both before and after the write io.
> -The ``flags`` value for ``->iomap_begin`` will be ``IOMAP_DIRECT |
> +The ``flags`` value for ``begin`` will be ``IOMAP_DIRECT |
>  IOMAP_WRITE`` with any combination of the following enhancements:
>  
>   * ``IOMAP_NOWAIT``, as defined previously.
> @@ -644,7 +650,7 @@ fsdax Reads
>  
>  A fsdax read performs a memcpy from storage device to the caller's
>  buffer.
> -The ``flags`` value for ``->iomap_begin`` will be ``IOMAP_DAX`` with any
> +The ``flags`` value for ``begin`` will be ``IOMAP_DAX`` with any
>  combination of the following enhancements:
>  
>   * ``IOMAP_NOWAIT``, as defined previously.
> @@ -657,7 +663,7 @@ fsdax Writes
>  
>  A fsdax write initiates a memcpy to the storage device from the caller's
>  buffer.
> -The ``flags`` value for ``->iomap_begin`` will be ``IOMAP_DAX |
> +The ``flags`` value for ``begin`` will be ``IOMAP_DAX |
>  IOMAP_WRITE`` with any combination of the following enhancements:
>  
>   * ``IOMAP_NOWAIT``, as defined previously.
> @@ -680,9 +686,9 @@ fsdax mmap Faults
>  The ``dax_iomap_fault`` function handles read and write faults to fsdax
>  storage.
>  For a read fault, ``IOMAP_DAX | IOMAP_FAULT`` will be passed as the
> -``flags`` argument to ``->iomap_begin``.
> +``flags`` argument to ``begin``.
>  For a write fault, ``IOMAP_DAX | IOMAP_FAULT | IOMAP_WRITE`` will be
> -passed as the ``flags`` argument to ``->iomap_begin``.
> +passed as the ``flags`` argument to ``begin``.
>  
>  Callers commonly hold the same locks as they do to call their iomap
>  pagecache counterparts.
> @@ -692,7 +698,7 @@ fsdax Truncation, fallocate, and Unsharing
>  
>  For fsdax files, the following functions are provided to replace their
>  iomap pagecache I/O counterparts.
> -The ``flags`` argument to ``->iomap_begin`` are the same as the
> +The ``flags`` argument to ``begin`` are the same as the
>  pagecache counterparts, with ``IOMAP_DAX`` added.
>  
>   * ``dax_file_unshare``
> @@ -720,7 +726,7 @@ SEEK_DATA
>  The ``iomap_seek_data`` function implements the SEEK_DATA "whence" value
>  for llseek.
>  ``IOMAP_REPORT`` will be passed as the ``flags`` argument to
> -``->iomap_begin``.
> +``begin``.
>  
>  For unwritten mappings, the pagecache will be searched.
>  Regions of the pagecache with a folio mapped and uptodate fsblocks
> @@ -735,7 +741,7 @@ SEEK_HOLE
>  The ``iomap_seek_hole`` function implements the SEEK_HOLE "whence" value
>  for llseek.
>  ``IOMAP_REPORT`` will be passed as the ``flags`` argument to
> -``->iomap_begin``.
> +``begin``.
>  
>  For unwritten mappings, the pagecache will be searched.
>  Regions of the pagecache with no folio mapped, or a !uptodate fsblock
> @@ -751,7 +757,7 @@ The ``iomap_swapfile_activate`` function finds all the base-page aligned
>  regions in a file and sets them up as swap space.
>  The file will be ``fsync()``'d before activation.
>  ``IOMAP_REPORT`` will be passed as the ``flags`` argument to
> -``->iomap_begin``.
> +``begin``.
>  All mappings must be mapped or unwritten; cannot be dirty or shared, and
>  cannot span multiple block devices.
>  Callers must hold ``i_rwsem`` in exclusive mode; this is already
> @@ -768,7 +774,7 @@ FS_IOC_FIEMAP
>  The ``iomap_fiemap`` function exports file extent mappings to userspace
>  in the format specified by the ``FS_IOC_FIEMAP`` ioctl.
>  ``IOMAP_REPORT`` will be passed as the ``flags`` argument to
> -``->iomap_begin``.
> +``begin``.
>  Callers commonly hold ``i_rwsem`` in shared mode before calling this
>  function.
>  
> diff --git a/Documentation/filesystems/iomap/porting.rst b/Documentation/filesystems/iomap/porting.rst
> index 3d49a32c0fff..3591b5f28021 100644
> --- a/Documentation/filesystems/iomap/porting.rst
> +++ b/Documentation/filesystems/iomap/porting.rst
> @@ -50,8 +50,20 @@ Build the kernel, run fstests with the ``-g all`` option across a wide
>  variety of your filesystem's supported configurations to build a
>  baseline of which tests pass and which ones fail.
>  
> -The recommended approach is first to implement ``->iomap_begin`` (and
> -``->iomap_end`` if necessary) to allow iomap to obtain a read-only
> +Every iomap operation is driven by an ``iomap_next`` callback.
> +Filesystems normally do not write one by hand: implement ``begin``
> +(and ``end`` if necessary) and wire them up through
> +``iomap_process``::
> +
> + static int my_iomap_next(const struct iomap_iter *iter,
> +                          struct iomap *iomap, struct iomap *srcmap)
> + {
> +         return iomap_process(iter, iomap, srcmap,
> +                              my_iomap_begin, my_iomap_end);
> + }
> +
> +The recommended approach is first to implement ``begin`` (and
> +``end`` if necessary) to allow iomap to obtain a read-only


<nod> Looks fine.

--D

>  mapping of a file range.
>  In most cases, this is a relatively trivial conversion of the existing
>  ``get_block()`` function for read-only mappings.
> @@ -62,7 +74,7 @@ If FIEMAP is returning the correct information, it's a good sign that
>  other read-only mapping operations will do the right thing.
>  
>  Next, modify the filesystem's ``get_block(create = false)``
> -implementation to use the new ``->iomap_begin`` implementation to map
> +implementation to use the new ``begin`` implementation to map
>  file space for selected read operations.
>  Hide behind a debugging knob the ability to switch on the iomap mapping
>  functions for selected call paths.
> @@ -82,14 +94,14 @@ I/O path because of bufferheads.
>  The buffered read I/O paths doesn't need to be converted yet, though the
>  direct I/O read path should be converted in this phase.
>  
> -At this point, you should look over your ``->iomap_begin`` function.
> +At this point, you should look over your ``begin`` function.
>  If it switches between large blocks of code based on dispatching of the
>  ``flags`` argument, you should consider breaking it up into
>  per-operation iomap ops with smaller, more cohesive functions.
>  XFS is a good example of this.
>  
>  The next thing to do is implement ``get_blocks(create == true)``
> -functionality in the ``->iomap_begin``/``->iomap_end`` methods.
> +functionality in the ``begin``/``end`` methods.
>  It is strongly recommended to create separate mapping functions and
>  iomap ops for write operations.
>  Then convert the direct I/O write path to iomap, and start running fsx
> -- 
> 2.52.0
> 
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 01/18] iomap: add ->iomap_next() and iomap_process() helper
  2026-07-02 16:23   ` Darrick J. Wong
@ 2026-07-02 22:41     ` Joanne Koong
  0 siblings, 0 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-02 22:41 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: brauner, hch, willy, hsiangkao, linux-fsdevel, linux-xfs,
	open list

On Thu, Jul 2, 2026 at 9:23 AM Darrick J. Wong <djwong@kernel.org> wrote:
>
> On Tue, Jun 30, 2026 at 05:09:16PM -0700, Joanne Koong wrote:
> > Have one ->iomap_next() callback instead of ->iomap_begin() and
> > ->iomap_end(). ->iomap_next() finishes the previous mapping if needed,
> > and produces the next mapping. This lets performance-critical callers
> > inline the iteration with a fixed callback, which the compiler is able
> > to call directly instead of indirectly.
>
> Er... what is being called directly here?  The iomap_{begin,end}
> functions?  It looks to me like ->iomap_next is still an indirect call
> even at the end of the series, right?  That's still a net reduction of
> indirect calls at least.
>
> Oh, wait, it's the __always_inline iomap_process function that a smart
> compiler can use to turn the indirect calls into direct ones, isn't it?
> It might be useful to add a comment to that function saying that out
> loud so that dolts like me will pick up on why it's critical for it to
> be an inline function.

Ahh the sentence was confusingly / ambiguously worded, sorry about
that - I was trying to say that it lets callers have the ability to
inline iomap_iter() with passing a const iomap_next callback as an arg
which lets the iomap_next callback be a plain direct call. But your
interpretation of it is also true. I'll add the comment you suggested
to spell what you mentioned out and reword the commit message to make
what I was trying to say more clear.

>
> I like how this is going. :)
>
> > iomap_iter() uses ->iomap_next() when the filesystem provides that
> > callback and otherwise falls back to the ->iomap_begin()/->iomap_end()
> > path, so filesystems can be converted one at a time.
>
> > Add a iomap_process() inline helper that does most of the logic needed
> > in an ->iomap_next() implementation.
> >
> > Suggested-by: Christoph Hellwig <hch@lst.de>
> > Suggested-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > ---
> >  fs/iomap/iter.c       | 113 ++++++++++++++++++++++++++++++++++++------
> >  include/linux/iomap.h |  91 +++++++++++++++++++++++++++-------
> >  2 files changed, 171 insertions(+), 33 deletions(-)
> >
> > diff --git a/fs/iomap/iter.c b/fs/iomap/iter.c
> > index e4a29829591a..1062e4e34c38 100644
> > --- a/fs/iomap/iter.c
> > +++ b/fs/iomap/iter.c
> > +
> > +/**
> > + * iomap_iter_continue - decide whether iteration should continue
> > + * @iter: iteration structure
> > + * @iomap: the mapping that was just processed
> > + * @srcmap: the source mapping that was just processed
> > + *
> > + * Helper for ->iomap_next() implementations, normally called via
> > + * iomap_process().  Called after the previous mapping has been finished to
> > + * determine whether there is more of the file range left to process.
> > + *
> > + * Returns 1 if there is more work to do, in which case @iomap and @srcmap are
> > + * cleared so the caller can produce the next mapping; zero if the range is
> > + * fully consumed; or a negative errno on error.  Any folio batch attached to
> > + * the mapping is released before returning.
> > + */
> > +int iomap_iter_continue(const struct iomap_iter *iter, struct iomap *iomap,
> > +             struct iomap *srcmap, int ret)
> > +{
> > +     bool stale = iomap->flags & IOMAP_F_STALE;
> > +     ssize_t advanced = iter->pos - iter->iter_start_pos;
>
> These both could be const, right?
>

I'll mark these as const. Thanks for looking at these patches!

Thanks,
Joanne

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 01/18] iomap: add ->iomap_next() and iomap_process() helper
  2026-07-02 14:00   ` Christoph Hellwig
@ 2026-07-02 23:01     ` Joanne Koong
  0 siblings, 0 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-02 23:01 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: brauner, djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	open list

On Thu, Jul 2, 2026 at 7:00 AM Christoph Hellwig <hch@lst.de> wrote:
>
> On Tue, Jun 30, 2026 at 05:09:16PM -0700, Joanne Koong wrote:
> > +static int iomap_iter_legacy(struct iomap_iter *iter, const struct iomap_ops *ops)
>
> Overly long line here.  Not that it really matters too much given
> that this goes away by the end of the series.

I'll fix this.

>
> > + * Iterate over filesystem-provided space mappings for the provided file range.
> > + *
> > + * This function handles cleanup of resources acquired for iteration when the
> > + * filesystem indicates there are no more space mappings, which means that this
> > + * function must be called in a loop that continues as long it returns a
> > + * positive value.  If 0 or a negative value is returned, the caller must not
> > + * return to the loop body.  Within a loop body, there are two ways to break out
> > + * of the loop body:  leave @iter.status unchanged, or set it to a negative
> > + * errno.
> > + */
> > +int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
> > +{
> > +     if (ops->iomap_next)
> > +             return iomap_iter_next(iter, ops);
> > +
> > +     return iomap_iter_legacy(iter, ops);
>
> Maybe inline the code currently in iomap_iter_next here from the
> start, as that what we're getting to by the end of the series anyway.
> And just do a:
>
>         if (!ops->iomap_next))
>                 return iomap_iter_legacy(iter, ops);
>
> at the beginning?

Sounds good, I'll make this change.

>
> > +int iomap_iter_continue(const struct iomap_iter *iter, struct iomap *iomap,
> >
>
> It seems like this is largely just factored out form the old iomap_iter().
> Can you do a prep patch before this one which factors this out?
> Preferably in a way that keeps the code in roughly the same place to
> minimize the git blame disturbance?

Sounds good, I'll extract this shared logic out into a preparatory patch.

Thanks,
Joanne

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 02/18] xfs: convert iomap ops to ->iomap_next()
  2026-07-02 16:43   ` Darrick J. Wong
@ 2026-07-02 23:59     ` Joanne Koong
  2026-07-03  1:21       ` Joanne Koong
  2026-07-03  1:38       ` Darrick J. Wong
  0 siblings, 2 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-02 23:59 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: brauner, hch, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Carlos Maiolino, open list

On Thu, Jul 2, 2026 at 9:43 AM Darrick J. Wong <djwong@kernel.org> wrote:
>
> On Tue, Jun 30, 2026 at 05:09:17PM -0700, Joanne Koong wrote:
> > Convert xfs iomap_ops to the new ->iomap_next() callback. This uses the
> > iomap_process() helper, which finishes the previous mapping if needed
> > and produces the next one. No functional changes are intended.
> >
> > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > ---
> >  fs/xfs/xfs_file.c  |  4 +-
> >  fs/xfs/xfs_iomap.c | 96 +++++++++++++++++++++++++++++++++++++++++-----
> >  2 files changed, 88 insertions(+), 12 deletions(-)
> >
> > diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> > index 845a97c9b063..7f8bef1a9954 100644
> > --- a/fs/xfs/xfs_file.c
> > +++ b/fs/xfs/xfs_file.c
> > @@ -857,9 +857,9 @@ xfs_file_dio_write_atomic(
> >                       NULL, 0);
> >
> >       /*
> > -      * The retry mechanism is based on the ->iomap_begin method returning
> > +      * The retry mechanism is based on the ->iomap_next method returning
> >        * -ENOPROTOOPT, which would be when the REQ_ATOMIC-based write is not
> > -      * possible. The REQ_ATOMIC-based method typically not be possible if
> > +      * possible. The REQ_ATOMIC-based method is typically not possible if
> >        * the write spans multiple extents or the disk blocks are misaligned.
> >        */
> >       if (ret == -ENOPROTOOPT && dops == &xfs_direct_write_iomap_ops) {
> > diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
> > index 225c3de88d03..4fa1a5c985db 100644
> > --- a/fs/xfs/xfs_iomap.c
> > +++ b/fs/xfs/xfs_iomap.c
> > @@ -1037,8 +1037,18 @@ xfs_direct_write_iomap_begin(
> >       return error;
> >  }
> >
> > +static int
> > +xfs_direct_write_iomap_next(
> > +     const struct iomap_iter *iter,
> > +     struct iomap            *iomap,
> > +     struct iomap            *srcmap)
>
> <unvarnished brainstream ahead>
>
> Now that I see the callsites, I think the "next" name could use some
> bikeshedding <cough>.  The purpose of this function is either
>
> (a) to look up the first mapping to start iterating;
> (b) to release whatever resources were attached during the current
>     iteration and look up the next mapping to continue iterating; or
> (c) to decide that it's time to stop iterating.
>
> From that it seems obvious to me that xfs_direct_write_iomap_next yields
> iomaps for iteration.  In Python those are called generator functions;
> in Rust they're called objects that implement the Iterator trait (or
> iterators for short).
>
> How about s/iomap_next/iomap_iter/ ?
>
> Then this function would be called xfs_direct_write_iomap_iter, which
> IMO is a closer description of what the function does, which is to say
> iterates iomaps for direct writes.
>
> (Yes, my brain might be polluted with thinking that "iomap next" refers
> to a major shift, in the sense of "linux next". :P)

Thanks for sharing your thoughts. The idea makes sense to me in theory
but I think in rust and python the "iter" naming is reserved for the
iterator object itself and the method / callback for advancing and
yielding the next item in the iteration is named "next" (eg
Iterator::next in rust and __next__() in python)? I wonder if the
s/_next/_iter gets confusing with multiple things in iomap already
called iter (eg the struct iomap_iter, the iomap_iter() function). I'm
not sure, I'm happy to rename this if that's the preference.

Thanks,
Joanne

>
> > +{
> > +     return iomap_process(iter, iomap, srcmap, xfs_direct_write_iomap_begin,
> > +                     NULL);
>
> But then "iomap_iter" sets up a new problem: should iomap_process have a
> new name that goes along with that?  iomap_iter is already taken for the
> legacy path.  If we were emulating python I'd suggest iomap_iter_yield
> but this is C so we get to reinvent everything from scratch so who
> knows.
>
> --D
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 10/18] block: convert iomap ops to ->iomap_next()
  2026-07-01  0:55   ` Keith Busch
  2026-07-02 14:03     ` Christoph Hellwig
@ 2026-07-03  0:06     ` Joanne Koong
  1 sibling, 0 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-03  0:06 UTC (permalink / raw)
  To: Keith Busch
  Cc: brauner, hch, djwong, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Jens Axboe, open list:BLOCK LAYER, open list

On Tue, Jun 30, 2026 at 5:55 PM Keith Busch <kbusch@kernel.org> wrote:
>
> On Tue, Jun 30, 2026 at 05:09:25PM -0700, Joanne Koong wrote:
> >  static const struct iomap_ops blkdev_iomap_ops = {
> > -     .iomap_begin            = blkdev_iomap_begin,
> > +     .iomap_next             = blkdev_iomap_next,
> >  };
>
> I think it's generally safe to use the same mailing list for the entire
> series. There's no context here on what "iomap_next" is because I'm
> subscribed only to linux-block. I found the rest here:
>
>   https://lore.kernel.org/linux-fsdevel/20260701000949.1666714-1-joannelkoong@gmail.com/

Ahh I see, thanks for the heads up Keith. I'll do that from now on.

Thanks,
Joanne

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops
  2026-07-02 16:58   ` Darrick J. Wong
@ 2026-07-03  0:17     ` Joanne Koong
  2026-07-03  1:42       ` Darrick J. Wong
  0 siblings, 1 reply; 53+ messages in thread
From: Joanne Koong @ 2026-07-03  0:17 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: brauner, hch, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Jens Axboe, Chris Mason, David Sterba, Alexander Viro, Jan Kara,
	Dan Williams, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Sandeep Dhavale, Hongbo Li, Chunhai Guo, Namjae Jeon,
	Sungjong Seo, Yuezhang Mo, Theodore Ts'o, Andreas Dilger,
	Baokun Li, Ojaswin Mujoo, Ritesh Harjani (IBM), Zhang Yi,
	Jaegeuk Kim, Miklos Szeredi, Andreas Gruenbacher, Mikulas Patocka,
	Hyunchul Lee, Konstantin Komarov, Carlos Maiolino, Damien Le Moal,
	Naohiro Aota, Johannes Thumshirn, open list:BLOCK LAYER,
	open list, open list:BTRFS FILE SYSTEM,
	open list:FILESYSTEM DIRECT ACCESS (DAX),
	open list:EROFS FILE SYSTEM, open list:EXT2 FILE SYSTEM,
	open list:F2FS FILE SYSTEM, open list:FUSE FILESYSTEM [CORE],
	open list:GFS2 FILE SYSTEM, open list:NTFS3 FILESYSTEM

On Thu, Jul 2, 2026 at 9:58 AM Darrick J. Wong <djwong@kernel.org> wrote:
>
> > diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
> > index 3f0932e46fd6..0aa8abc438c1 100644
> > --- a/fs/iomap/buffered-io.c
> > +++ b/fs/iomap/buffered-io.c
> > @@ -626,7 +626,7 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
> >       return 0;
> >  }
> >
> > -void iomap_read_folio(const struct iomap_ops *ops,
> > +void iomap_read_folio(iomap_next_fn iomap_next,
>
> If you took my earlier suggestion to rename the typedef to
> iomap_iter_fn, then this parameter ought to be named iter_fn.

Hmm... maybe at that point, it's self-explanatory enough that the arg
could just be called "iter" instead of "iter_fn"?

>
> >               struct iomap_read_folio_ctx *ctx, void *private)
> >  {
> >       struct folio *folio = ctx->cur_folio;
> > @@ -650,7 +650,7 @@ void iomap_read_folio(const struct iomap_ops *ops,
> >               fsverity_readahead(ctx->vi, folio->index,
> >                                  folio_nr_pages(folio));
> >
> > -     while ((ret = iomap_iter(&iter, ops)) > 0) {
> > +     while ((ret = iomap_iter(&iter, iomap_next)) > 0) {
> >               iter.status = iomap_read_folio_iter(&iter, ctx,
> >                               &bytes_submitted);
> >               iomap_read_submit(&iter, ctx);
> > @@ -688,22 +688,22 @@ static int iomap_readahead_iter(struct iomap_iter *iter,
> >
> >  /**
> >   * iomap_readahead - Attempt to read pages from a file.
> > - * @ops: The operations vector for the filesystem.
> > + * @iomap_next: The iomap_next callback for the filesystem.
>
> "The iomap iteration function for the filesystem" ?
>
> Using the term "iomap_next" in the definition for iomap_next isn't that
> helpful.

Agreed, I'll replace this with your suggestion.

>
> >       return ret;
> > @@ -824,16 +824,16 @@ xfs_file_dio_write_atomic(
> >       unsigned int            iolock = XFS_IOLOCK_SHARED;
> >       ssize_t                 ret, ocount = iov_iter_count(from);
> >       unsigned int            dio_flags = 0;
> > -     const struct iomap_ops  *dops;
> > +     iomap_next_fn           dops;
> >
> >       /*
> >        * HW offload should be faster, so try that first if it is already
> >        * known that the write length is not too large.
> >        */
> >       if (ocount > xfs_inode_buftarg(ip)->bt_awu_max)
> > -             dops = &xfs_atomic_write_cow_iomap_ops;
> > +             dops = xfs_atomic_write_cow_iomap_next;
> >       else
> > -             dops = &xfs_direct_write_iomap_ops;
> > +             dops = xfs_direct_write_iomap_next;
>
> Probably ought to be called iter_fn, or at least something that isn't
> "dops".

Nice spotting, I'll rename this in the next version.

Thanks,
Joanne

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model
  2026-07-02 13:49 ` [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Christoph Hellwig
@ 2026-07-03  1:08   ` Joanne Koong
  0 siblings, 0 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-03  1:08 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: brauner, hch, djwong, willy, hsiangkao, linux-fsdevel, linux-xfs

On Thu, Jul 2, 2026 at 6:49 AM Christoph Hellwig <hch@infradead.org> wrote:
>
> What tree does this apply to?  I tried 7.2-rc1, Linus current
> master, vfs/vfs.fixes and had slightly different failures to apply
> with each one.

This is on top of Christian's vfs iomap tree (vfs-7.3.iomap) on top of
commit f2727952b21d1.

>
> On Tue, Jun 30, 2026 at 05:09:15PM -0700, Joanne Koong wrote:
> > This series implements a suggestion by Christoph for finishing the conversion
> > of iomap to an iterator model. This revives Matthew's previous RFC [1], which
> > had the same intention.
>
> Btw, this evolved from my original suggestion to something that actually
> looks much better, so don't give me too much credit :)

This definitely wouldn't have existed without your suggestion and
guidance :) Thanks for reviewing the series!

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 02/18] xfs: convert iomap ops to ->iomap_next()
  2026-07-02 23:59     ` Joanne Koong
@ 2026-07-03  1:21       ` Joanne Koong
  2026-07-03  1:41         ` Darrick J. Wong
  2026-07-03  1:38       ` Darrick J. Wong
  1 sibling, 1 reply; 53+ messages in thread
From: Joanne Koong @ 2026-07-03  1:21 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: brauner, hch, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Carlos Maiolino, open list

On Thu, Jul 2, 2026 at 4:59 PM Joanne Koong <joannelkoong@gmail.com> wrote:
>
> On Thu, Jul 2, 2026 at 9:43 AM Darrick J. Wong <djwong@kernel.org> wrote:
> >
> > On Tue, Jun 30, 2026 at 05:09:17PM -0700, Joanne Koong wrote:
> > > Convert xfs iomap_ops to the new ->iomap_next() callback. This uses the
> > > iomap_process() helper, which finishes the previous mapping if needed
> > > and produces the next one. No functional changes are intended.
> > >
> > > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > > ---
> > >  fs/xfs/xfs_file.c  |  4 +-
> > >  fs/xfs/xfs_iomap.c | 96 +++++++++++++++++++++++++++++++++++++++++-----
> > >  2 files changed, 88 insertions(+), 12 deletions(-)
> > >
> > > diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> > > index 845a97c9b063..7f8bef1a9954 100644
> > > --- a/fs/xfs/xfs_file.c
> > > +++ b/fs/xfs/xfs_file.c
> > > @@ -857,9 +857,9 @@ xfs_file_dio_write_atomic(
> > >                       NULL, 0);
> > >
> > >       /*
> > > -      * The retry mechanism is based on the ->iomap_begin method returning
> > > +      * The retry mechanism is based on the ->iomap_next method returning
> > >        * -ENOPROTOOPT, which would be when the REQ_ATOMIC-based write is not
> > > -      * possible. The REQ_ATOMIC-based method typically not be possible if
> > > +      * possible. The REQ_ATOMIC-based method is typically not possible if
> > >        * the write spans multiple extents or the disk blocks are misaligned.
> > >        */
> > >       if (ret == -ENOPROTOOPT && dops == &xfs_direct_write_iomap_ops) {
> > > diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
> > > index 225c3de88d03..4fa1a5c985db 100644
> > > --- a/fs/xfs/xfs_iomap.c
> > > +++ b/fs/xfs/xfs_iomap.c
> > > @@ -1037,8 +1037,18 @@ xfs_direct_write_iomap_begin(
> > >       return error;
> > >  }
> > >
> > > +static int
> > > +xfs_direct_write_iomap_next(
> > > +     const struct iomap_iter *iter,
> > > +     struct iomap            *iomap,
> > > +     struct iomap            *srcmap)
> >
> > <unvarnished brainstream ahead>
> >
> > Now that I see the callsites, I think the "next" name could use some
> > bikeshedding <cough>.  The purpose of this function is either
> >
> > (a) to look up the first mapping to start iterating;
> > (b) to release whatever resources were attached during the current
> >     iteration and look up the next mapping to continue iterating; or
> > (c) to decide that it's time to stop iterating.
> >
> > From that it seems obvious to me that xfs_direct_write_iomap_next yields
> > iomaps for iteration.  In Python those are called generator functions;
> > in Rust they're called objects that implement the Iterator trait (or
> > iterators for short).
> >
> > How about s/iomap_next/iomap_iter/ ?
> >
> > Then this function would be called xfs_direct_write_iomap_iter, which
> > IMO is a closer description of what the function does, which is to say
> > iterates iomaps for direct writes.
> >
> > (Yes, my brain might be polluted with thinking that "iomap next" refers
> > to a major shift, in the sense of "linux next". :P)
>
> Thanks for sharing your thoughts. The idea makes sense to me in theory
> but I think in rust and python the "iter" naming is reserved for the
> iterator object itself and the method / callback for advancing and
> yielding the next item in the iteration is named "next" (eg
> Iterator::next in rust and __next__() in python)? I wonder if the
> s/_next/_iter gets confusing with multiple things in iomap already
> called iter (eg the struct iomap_iter, the iomap_iter() function). I'm
> not sure, I'm happy to rename this if that's the preference.
>

Ahh okay, I think I see the point you were trying to make. The
callsite functions are like:

ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from,
                iomap_next_fn iomap_next,
                const struct iomap_write_ops *write_ops, void *private);

int iomap_fsverity_write(struct file *file, loff_t pos, size_t length,
                const void *buf, iomap_next_fn iomap_next,
                const struct iomap_write_ops *write_ops);

void iomap_read_folio(iomap_next_fn iomap_next,
                struct iomap_read_folio_ctx *ctx, void *private);

void iomap_readahead(iomap_next_fn iomap_next,
                struct iomap_read_folio_ctx *ctx, void *private);

etc, so it's not clear from the "iomap_next_fn iomap_next" naming that
it handles per-iteration logic, whereas renaming it to "iomap_iter_fn
iomap_iter" makes it more explicit. Am I interpreting this correctly?

I think this is a good idea. If no one has an objection, I'll make
this change for v3.

Thanks,
Joanne

>
> >
> > > +{
> > > +     return iomap_process(iter, iomap, srcmap, xfs_direct_write_iomap_begin,
> > > +                     NULL);
> >
> > But then "iomap_iter" sets up a new problem: should iomap_process have a
> > new name that goes along with that?  iomap_iter is already taken for the
> > legacy path.  If we were emulating python I'd suggest iomap_iter_yield
> > but this is C so we get to reinvent everything from scratch so who
> > knows.
> >
> > --D
> >

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 18/18] Documentation: iomap: update docs to reflect iomap_next model
  2026-07-02 19:26   ` Darrick J. Wong
@ 2026-07-03  1:36     ` Joanne Koong
  2026-07-03  2:00       ` Darrick J. Wong
  0 siblings, 1 reply; 53+ messages in thread
From: Joanne Koong @ 2026-07-03  1:36 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: brauner, hch, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Jonathan Corbet, Shuah Khan, open list:DOCUMENTATION, open list

On Thu, Jul 2, 2026 at 12:27 PM Darrick J. Wong <djwong@kernel.org> wrote:
>
> On Tue, Jun 30, 2026 at 05:09:33PM -0700, Joanne Koong wrote:
> > Filesystems no longer pass a struct iomap_ops with separate
> > ->iomap_begin() and ->iomap_end() callbacks.  Instead, every iomap
> > operation takes a single iomap_next() callback directly. iomap_next()
> > finishes the previous mapping (if any) and produces the next one. Most
> > filesystems build it from begin and end helpers via the iomap_process()
> > helper.
> >
> > Update the iomap documentation to match this change.
> >
> > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > ---
> >  Documentation/filesystems/iomap/design.rst    | 115 +++++++++++++-----
> >  .../filesystems/iomap/operations.rst          |  60 +++++----
> >  Documentation/filesystems/iomap/porting.rst   |  22 +++-
> >  3 files changed, 132 insertions(+), 65 deletions(-)
> >
> > diff --git a/Documentation/filesystems/iomap/design.rst b/Documentation/filesystems/iomap/design.rst
> > index 0f7672676c0b..7a37e303eea8 100644
> > --- a/Documentation/filesystems/iomap/design.rst
> > +++ b/Documentation/filesystems/iomap/design.rst
> > @@ -75,7 +75,10 @@ At a high level, an iomap operation `looks like this
> >
> >  1. For each byte in the operation range...
> >
> > -   1. Obtain a space mapping via ``->iomap_begin``
> > +   1. Obtain the next space mapping via the ``iomap_next`` callback.
> > +      From the second iteration onwards this same callback first finishes
> > +      the previous mapping (committing or unreserving space as needed)
> > +      and then produces the next one.
> >
> >     2. For each sub-unit of work...
> >
> > @@ -86,7 +89,13 @@ At a high level, an iomap operation `looks like this
> >
> >     3. Increment operation cursor
> >
> > -   4. Release the mapping via ``->iomap_end``, if necessary
> > +iomap repeats this until the range is fully consumed.  The ``iomap_next``
> > +callback returns ``1`` while there is more of the range left to process,
> > +``0`` once it is fully consumed, and a negative errno on error.
>
> s/and/or/
>
> > +Filesystems rarely implement ``->iomap_next`` by hand. The ``iomap_process``
> > +helper implements the finish-then-produce sequence in +terms of two smaller
> > +callbacks, ``begin`` and ``end``. See `The Mapping Callback`_ below for more
> > +info.
>
> I wonder, under what circumstances would a filesystem /not/ use
> iomap_process()?

Hmm, maybe a situation where they need to share or carry some
filesystem-specific state / info between finishing the mapping and
producing the next one?

>
> >  Each iomap operation will be covered in more detail below.
> >  This library was covered previously by an `LWN article
> > @@ -189,7 +198,7 @@ The fields are as follows:
> >     * **IOMAP_DELALLOC**: A promise to allocate space at a later time
> >       ("delayed allocation").
> >       If the filesystem returns IOMAP_F_NEW here and the write fails, the
> > -     ``->iomap_end`` function must delete the reservation.
> > +     ``end`` function must delete the reservation.
> >       The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
> >
> >     * **IOMAP_MAPPED**: The file range maps to specific space on the
> > @@ -208,12 +217,12 @@ The fields are as follows:
> >
> >     * **IOMAP_INLINE**: The file range maps to the memory buffer
> >       specified by ``inline_data``.
> > -     For write operation, the ``->iomap_end`` function presumably
> > -     handles persisting the data.
> > +     For write operation, the ``end`` function presumably handles
> > +     persisting the data.
>
> Unrelated to this patch, but this should say "For write operations, the
> end function must persist the data" because iomap_writepages doesn't
> handle inline data.
>
> >       The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
> >
> >   * ``flags`` describe the status of the space mapping.
> > -   These flags should be set by the filesystem in ``->iomap_begin``:
> > +   These flags should be set by the filesystem in ``begin``:
>>
> > +``->iomap_next``
> > +~~~~~~~~~~~~~~~~
> > +
> > +Each call must finish the previous mapping, if any, and then produce the
>
> Each call?  Oh, each implementation of ->iomap_next must finish the
> previous mapping.
>
> > +next mapping for the current iteration position described by ``iter``.
> > +The mapping is returned through ``iomap`` (and through ``srcmap`` for
> > +operations that read from one mapping while writing to another; see
> > +``begin`` below).
> >
> > -``->iomap_begin``
> > +The callback returns ``1`` to continue iterating, ``0`` once the file
> > +range has been fully consumed, and a negative errno on error.
>
> s/and/or/
>
> I think there should be a transition sentence here along the lines of
>
> "Most filesystems are not expected to implement all of these behaviors
> in ->iomap_next themselves.  They should instead call iomap_process as
> described below."
>
> Or demote the next section so it's more obvious that the "iomap_process"
> and "->iomap_next" sections aren't independent?
>

Sounds good, I'll incorporate all the suggestions you recommended.

Thanks,
Joanne

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 02/18] xfs: convert iomap ops to ->iomap_next()
  2026-07-02 23:59     ` Joanne Koong
  2026-07-03  1:21       ` Joanne Koong
@ 2026-07-03  1:38       ` Darrick J. Wong
  1 sibling, 0 replies; 53+ messages in thread
From: Darrick J. Wong @ 2026-07-03  1:38 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Carlos Maiolino, open list

On Thu, Jul 02, 2026 at 04:59:39PM -0700, Joanne Koong wrote:
> On Thu, Jul 2, 2026 at 9:43 AM Darrick J. Wong <djwong@kernel.org> wrote:
> >
> > On Tue, Jun 30, 2026 at 05:09:17PM -0700, Joanne Koong wrote:
> > > Convert xfs iomap_ops to the new ->iomap_next() callback. This uses the
> > > iomap_process() helper, which finishes the previous mapping if needed
> > > and produces the next one. No functional changes are intended.
> > >
> > > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > > ---
> > >  fs/xfs/xfs_file.c  |  4 +-
> > >  fs/xfs/xfs_iomap.c | 96 +++++++++++++++++++++++++++++++++++++++++-----
> > >  2 files changed, 88 insertions(+), 12 deletions(-)
> > >
> > > diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> > > index 845a97c9b063..7f8bef1a9954 100644
> > > --- a/fs/xfs/xfs_file.c
> > > +++ b/fs/xfs/xfs_file.c
> > > @@ -857,9 +857,9 @@ xfs_file_dio_write_atomic(
> > >                       NULL, 0);
> > >
> > >       /*
> > > -      * The retry mechanism is based on the ->iomap_begin method returning
> > > +      * The retry mechanism is based on the ->iomap_next method returning
> > >        * -ENOPROTOOPT, which would be when the REQ_ATOMIC-based write is not
> > > -      * possible. The REQ_ATOMIC-based method typically not be possible if
> > > +      * possible. The REQ_ATOMIC-based method is typically not possible if
> > >        * the write spans multiple extents or the disk blocks are misaligned.
> > >        */
> > >       if (ret == -ENOPROTOOPT && dops == &xfs_direct_write_iomap_ops) {
> > > diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
> > > index 225c3de88d03..4fa1a5c985db 100644
> > > --- a/fs/xfs/xfs_iomap.c
> > > +++ b/fs/xfs/xfs_iomap.c
> > > @@ -1037,8 +1037,18 @@ xfs_direct_write_iomap_begin(
> > >       return error;
> > >  }
> > >
> > > +static int
> > > +xfs_direct_write_iomap_next(
> > > +     const struct iomap_iter *iter,
> > > +     struct iomap            *iomap,
> > > +     struct iomap            *srcmap)
> >
> > <unvarnished brainstream ahead>
> >
> > Now that I see the callsites, I think the "next" name could use some
> > bikeshedding <cough>.  The purpose of this function is either
> >
> > (a) to look up the first mapping to start iterating;
> > (b) to release whatever resources were attached during the current
> >     iteration and look up the next mapping to continue iterating; or
> > (c) to decide that it's time to stop iterating.
> >
> > From that it seems obvious to me that xfs_direct_write_iomap_next yields
> > iomaps for iteration.  In Python those are called generator functions;
> > in Rust they're called objects that implement the Iterator trait (or
> > iterators for short).
> >
> > How about s/iomap_next/iomap_iter/ ?
> >
> > Then this function would be called xfs_direct_write_iomap_iter, which
> > IMO is a closer description of what the function does, which is to say
> > iterates iomaps for direct writes.
> >
> > (Yes, my brain might be polluted with thinking that "iomap next" refers
> > to a major shift, in the sense of "linux next". :P)
> 
> Thanks for sharing your thoughts. The idea makes sense to me in theory
> but I think in rust and python the "iter" naming is reserved for the
> iterator object itself and the method / callback for advancing and
> yielding the next item in the iteration is named "next" (eg
> Iterator::next in rust and __next__() in python)? I wonder if the
> s/_next/_iter gets confusing with multiple things in iomap already
> called iter (eg the struct iomap_iter, the iomap_iter() function). I'm
> not sure, I'm happy to rename this if that's the preference.

That's a good point that the functions themselves are usually some
variant of next.

> Thanks,
> Joanne
> 
> >
> > > +{
> > > +     return iomap_process(iter, iomap, srcmap, xfs_direct_write_iomap_begin,
> > > +                     NULL);
> >
> > But then "iomap_iter" sets up a new problem: should iomap_process have a
> > new name that goes along with that?  iomap_iter is already taken for the
> > legacy path.  If we were emulating python I'd suggest iomap_iter_yield
> > but this is C so we get to reinvent everything from scratch so who
> > knows.

Any thoughts on iomap_yield()?  Though I can live with iomap_next since
that /is/ the least effort action. :)

--D

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 15/18] exfat: convert iomap ops to ->iomap_next()
  2026-07-01  0:09 ` [PATCH v2 15/18] exfat: " Joanne Koong
@ 2026-07-03  1:41   ` Joanne Koong
  0 siblings, 0 replies; 53+ messages in thread
From: Joanne Koong @ 2026-07-03  1:41 UTC (permalink / raw)
  To: brauner, hch
  Cc: djwong, willy, hsiangkao, linux-fsdevel, linux-xfs, Namjae Jeon,
	Sungjong Seo, Yuezhang Mo, open list

On Tue, Jun 30, 2026 at 5:12 PM Joanne Koong <joannelkoong@gmail.com> wrote:
>
> Convert fuse iomap_ops to the new ->iomap_next() callback. This uses the

This should be exfat, not fuse. I'll fix this.

Thanks,
Joanne

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 02/18] xfs: convert iomap ops to ->iomap_next()
  2026-07-03  1:21       ` Joanne Koong
@ 2026-07-03  1:41         ` Darrick J. Wong
  0 siblings, 0 replies; 53+ messages in thread
From: Darrick J. Wong @ 2026-07-03  1:41 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Carlos Maiolino, open list

On Thu, Jul 02, 2026 at 06:21:00PM -0700, Joanne Koong wrote:
> On Thu, Jul 2, 2026 at 4:59 PM Joanne Koong <joannelkoong@gmail.com> wrote:
> >
> > On Thu, Jul 2, 2026 at 9:43 AM Darrick J. Wong <djwong@kernel.org> wrote:
> > >
> > > On Tue, Jun 30, 2026 at 05:09:17PM -0700, Joanne Koong wrote:
> > > > Convert xfs iomap_ops to the new ->iomap_next() callback. This uses the
> > > > iomap_process() helper, which finishes the previous mapping if needed
> > > > and produces the next one. No functional changes are intended.
> > > >
> > > > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > > > ---
> > > >  fs/xfs/xfs_file.c  |  4 +-
> > > >  fs/xfs/xfs_iomap.c | 96 +++++++++++++++++++++++++++++++++++++++++-----
> > > >  2 files changed, 88 insertions(+), 12 deletions(-)
> > > >
> > > > diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> > > > index 845a97c9b063..7f8bef1a9954 100644
> > > > --- a/fs/xfs/xfs_file.c
> > > > +++ b/fs/xfs/xfs_file.c
> > > > @@ -857,9 +857,9 @@ xfs_file_dio_write_atomic(
> > > >                       NULL, 0);
> > > >
> > > >       /*
> > > > -      * The retry mechanism is based on the ->iomap_begin method returning
> > > > +      * The retry mechanism is based on the ->iomap_next method returning
> > > >        * -ENOPROTOOPT, which would be when the REQ_ATOMIC-based write is not
> > > > -      * possible. The REQ_ATOMIC-based method typically not be possible if
> > > > +      * possible. The REQ_ATOMIC-based method is typically not possible if
> > > >        * the write spans multiple extents or the disk blocks are misaligned.
> > > >        */
> > > >       if (ret == -ENOPROTOOPT && dops == &xfs_direct_write_iomap_ops) {
> > > > diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
> > > > index 225c3de88d03..4fa1a5c985db 100644
> > > > --- a/fs/xfs/xfs_iomap.c
> > > > +++ b/fs/xfs/xfs_iomap.c
> > > > @@ -1037,8 +1037,18 @@ xfs_direct_write_iomap_begin(
> > > >       return error;
> > > >  }
> > > >
> > > > +static int
> > > > +xfs_direct_write_iomap_next(
> > > > +     const struct iomap_iter *iter,
> > > > +     struct iomap            *iomap,
> > > > +     struct iomap            *srcmap)
> > >
> > > <unvarnished brainstream ahead>
> > >
> > > Now that I see the callsites, I think the "next" name could use some
> > > bikeshedding <cough>.  The purpose of this function is either
> > >
> > > (a) to look up the first mapping to start iterating;
> > > (b) to release whatever resources were attached during the current
> > >     iteration and look up the next mapping to continue iterating; or
> > > (c) to decide that it's time to stop iterating.
> > >
> > > From that it seems obvious to me that xfs_direct_write_iomap_next yields
> > > iomaps for iteration.  In Python those are called generator functions;
> > > in Rust they're called objects that implement the Iterator trait (or
> > > iterators for short).
> > >
> > > How about s/iomap_next/iomap_iter/ ?
> > >
> > > Then this function would be called xfs_direct_write_iomap_iter, which
> > > IMO is a closer description of what the function does, which is to say
> > > iterates iomaps for direct writes.
> > >
> > > (Yes, my brain might be polluted with thinking that "iomap next" refers
> > > to a major shift, in the sense of "linux next". :P)
> >
> > Thanks for sharing your thoughts. The idea makes sense to me in theory
> > but I think in rust and python the "iter" naming is reserved for the
> > iterator object itself and the method / callback for advancing and
> > yielding the next item in the iteration is named "next" (eg
> > Iterator::next in rust and __next__() in python)? I wonder if the
> > s/_next/_iter gets confusing with multiple things in iomap already
> > called iter (eg the struct iomap_iter, the iomap_iter() function). I'm
> > not sure, I'm happy to rename this if that's the preference.
> >
> 
> Ahh okay, I think I see the point you were trying to make. The
> callsite functions are like:
> 
> ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from,
>                 iomap_next_fn iomap_next,
>                 const struct iomap_write_ops *write_ops, void *private);
> 
> int iomap_fsverity_write(struct file *file, loff_t pos, size_t length,
>                 const void *buf, iomap_next_fn iomap_next,
>                 const struct iomap_write_ops *write_ops);
> 
> void iomap_read_folio(iomap_next_fn iomap_next,
>                 struct iomap_read_folio_ctx *ctx, void *private);
> 
> void iomap_readahead(iomap_next_fn iomap_next,
>                 struct iomap_read_folio_ctx *ctx, void *private);
> 
> etc, so it's not clear from the "iomap_next_fn iomap_next" naming that
> it handles per-iteration logic, whereas renaming it to "iomap_iter_fn
> iomap_iter" makes it more explicit. Am I interpreting this correctly?

Yes.

> I think this is a good idea. If no one has an objection, I'll make
> this change for v3.

Ok by me.  Ignore the email I just sent, please :)

--D

> Thanks,
> Joanne
> 
> >
> > >
> > > > +{
> > > > +     return iomap_process(iter, iomap, srcmap, xfs_direct_write_iomap_begin,
> > > > +                     NULL);
> > >
> > > But then "iomap_iter" sets up a new problem: should iomap_process have a
> > > new name that goes along with that?  iomap_iter is already taken for the
> > > legacy path.  If we were emulating python I'd suggest iomap_iter_yield
> > > but this is C so we get to reinvent everything from scratch so who
> > > knows.
> > >
> > > --D
> > >
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops
  2026-07-03  0:17     ` Joanne Koong
@ 2026-07-03  1:42       ` Darrick J. Wong
  0 siblings, 0 replies; 53+ messages in thread
From: Darrick J. Wong @ 2026-07-03  1:42 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Jens Axboe, Chris Mason, David Sterba, Alexander Viro, Jan Kara,
	Dan Williams, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Sandeep Dhavale, Hongbo Li, Chunhai Guo, Namjae Jeon,
	Sungjong Seo, Yuezhang Mo, Theodore Ts'o, Andreas Dilger,
	Baokun Li, Ojaswin Mujoo, Ritesh Harjani (IBM), Zhang Yi,
	Jaegeuk Kim, Miklos Szeredi, Andreas Gruenbacher, Mikulas Patocka,
	Hyunchul Lee, Konstantin Komarov, Carlos Maiolino, Damien Le Moal,
	Naohiro Aota, Johannes Thumshirn, open list:BLOCK LAYER,
	open list, open list:BTRFS FILE SYSTEM,
	open list:FILESYSTEM DIRECT ACCESS (DAX),
	open list:EROFS FILE SYSTEM, open list:EXT2 FILE SYSTEM,
	open list:F2FS FILE SYSTEM, open list:FUSE FILESYSTEM [CORE],
	open list:GFS2 FILE SYSTEM, open list:NTFS3 FILESYSTEM

On Thu, Jul 02, 2026 at 05:17:02PM -0700, Joanne Koong wrote:
> On Thu, Jul 2, 2026 at 9:58 AM Darrick J. Wong <djwong@kernel.org> wrote:
> >
> > > diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
> > > index 3f0932e46fd6..0aa8abc438c1 100644
> > > --- a/fs/iomap/buffered-io.c
> > > +++ b/fs/iomap/buffered-io.c
> > > @@ -626,7 +626,7 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
> > >       return 0;
> > >  }
> > >
> > > -void iomap_read_folio(const struct iomap_ops *ops,
> > > +void iomap_read_folio(iomap_next_fn iomap_next,
> >
> > If you took my earlier suggestion to rename the typedef to
> > iomap_iter_fn, then this parameter ought to be named iter_fn.
> 
> Hmm... maybe at that point, it's self-explanatory enough that the arg
> could just be called "iter" instead of "iter_fn"?

Dunno.  Seeing as we already have variables named "iter" that are the
actual iteration state object, I think it's clearer to leave the
iteration function as "iter_fn".

> >
> > >               struct iomap_read_folio_ctx *ctx, void *private)
> > >  {
> > >       struct folio *folio = ctx->cur_folio;
> > > @@ -650,7 +650,7 @@ void iomap_read_folio(const struct iomap_ops *ops,
> > >               fsverity_readahead(ctx->vi, folio->index,
> > >                                  folio_nr_pages(folio));
> > >
> > > -     while ((ret = iomap_iter(&iter, ops)) > 0) {
> > > +     while ((ret = iomap_iter(&iter, iomap_next)) > 0) {
> > >               iter.status = iomap_read_folio_iter(&iter, ctx,
> > >                               &bytes_submitted);
> > >               iomap_read_submit(&iter, ctx);
> > > @@ -688,22 +688,22 @@ static int iomap_readahead_iter(struct iomap_iter *iter,
> > >
> > >  /**
> > >   * iomap_readahead - Attempt to read pages from a file.
> > > - * @ops: The operations vector for the filesystem.
> > > + * @iomap_next: The iomap_next callback for the filesystem.
> >
> > "The iomap iteration function for the filesystem" ?
> >
> > Using the term "iomap_next" in the definition for iomap_next isn't that
> > helpful.
> 
> Agreed, I'll replace this with your suggestion.

<nod>

> >
> > >       return ret;
> > > @@ -824,16 +824,16 @@ xfs_file_dio_write_atomic(
> > >       unsigned int            iolock = XFS_IOLOCK_SHARED;
> > >       ssize_t                 ret, ocount = iov_iter_count(from);
> > >       unsigned int            dio_flags = 0;
> > > -     const struct iomap_ops  *dops;
> > > +     iomap_next_fn           dops;
> > >
> > >       /*
> > >        * HW offload should be faster, so try that first if it is already
> > >        * known that the write length is not too large.
> > >        */
> > >       if (ocount > xfs_inode_buftarg(ip)->bt_awu_max)
> > > -             dops = &xfs_atomic_write_cow_iomap_ops;
> > > +             dops = xfs_atomic_write_cow_iomap_next;
> > >       else
> > > -             dops = &xfs_direct_write_iomap_ops;
> > > +             dops = xfs_direct_write_iomap_next;
> >
> > Probably ought to be called iter_fn, or at least something that isn't
> > "dops".
> 
> Nice spotting, I'll rename this in the next version.

<nod>

--D

> Thanks,
> Joanne
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops
  2026-07-02 16:51     ` Darrick J. Wong
@ 2026-07-03  1:47       ` Joanne Koong
  2026-07-03  2:01         ` Darrick J. Wong
  0 siblings, 1 reply; 53+ messages in thread
From: Joanne Koong @ 2026-07-03  1:47 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: Christoph Hellwig, brauner, willy, hsiangkao, linux-fsdevel,
	linux-xfs, Jens Axboe, Chris Mason, David Sterba, Alexander Viro,
	Jan Kara, Dan Williams, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Sandeep Dhavale, Hongbo Li, Chunhai Guo, Namjae Jeon,
	Sungjong Seo, Yuezhang Mo, Theodore Ts'o, Andreas Dilger,
	Baokun Li, Ojaswin Mujoo, Ritesh Harjani (IBM), Zhang Yi,
	Jaegeuk Kim, Miklos Szeredi, Andreas Gruenbacher, Mikulas Patocka,
	Hyunchul Lee, Konstantin Komarov, Carlos Maiolino, Damien Le Moal,
	Naohiro Aota, Johannes Thumshirn, open list:BLOCK LAYER,
	open list, open list:BTRFS FILE SYSTEM,
	open list:FILESYSTEM DIRECT ACCESS (DAX),
	open list:EROFS FILE SYSTEM, open list:EXT2 FILE SYSTEM,
	open list:F2FS FILE SYSTEM, open list:FUSE FILESYSTEM [CORE],
	open list:GFS2 FILE SYSTEM, open list:NTFS3 FILESYSTEM

On Thu, Jul 2, 2026 at 9:51 AM Darrick J. Wong <djwong@kernel.org> wrote:
>
> On Thu, Jul 02, 2026 at 04:07:05PM +0200, Christoph Hellwig wrote:
> > Looks good:
> >
> > Reviewed-by: Christoph Hellwig <hch@lst.de>
> >
> > In terms of merge logistics, I wonder if we should delay this and
> > the previous patch to the next merge window so that we can minimize the
> > cross-subsystem merge pain with more file system iomap conversion.
> > If none of them actually happen until rc6 or so, orif  the merges aren't
> > painful we could still pick them up late in the merge window.
>
> I'd say everything but this patch should go in during the merge window
> for 7.3, along with clear instructions to brauner/torvalds to expect
> this patch to appear right before 7.3-rc1 gets tagged, to clean up all
> the other changes that come in.

Just to clarify, did you mean this patch and the previous one? If i'm
interpreting Christoph's concern correctly, I think he's worried about
other filesystems converting to iomap using the ->iomap_begin() /
->iomap_end() functions still? That sounds like a good plan to me, for
v3 I'll submit everything but this patch and the last one and then
submit these patches (and any cleanup ones that become necessary) to
Christian right before 7.3-rc1 gets tagged (which as I understand it,
is when the merge window is about to close).

Thanks,
Joanne

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 18/18] Documentation: iomap: update docs to reflect iomap_next model
  2026-07-03  1:36     ` Joanne Koong
@ 2026-07-03  2:00       ` Darrick J. Wong
  0 siblings, 0 replies; 53+ messages in thread
From: Darrick J. Wong @ 2026-07-03  2:00 UTC (permalink / raw)
  To: Joanne Koong
  Cc: brauner, hch, willy, hsiangkao, linux-fsdevel, linux-xfs,
	Jonathan Corbet, Shuah Khan, open list:DOCUMENTATION, open list

On Thu, Jul 02, 2026 at 06:36:55PM -0700, Joanne Koong wrote:
> On Thu, Jul 2, 2026 at 12:27 PM Darrick J. Wong <djwong@kernel.org> wrote:
> >
> > On Tue, Jun 30, 2026 at 05:09:33PM -0700, Joanne Koong wrote:
> > > Filesystems no longer pass a struct iomap_ops with separate
> > > ->iomap_begin() and ->iomap_end() callbacks.  Instead, every iomap
> > > operation takes a single iomap_next() callback directly. iomap_next()
> > > finishes the previous mapping (if any) and produces the next one. Most
> > > filesystems build it from begin and end helpers via the iomap_process()
> > > helper.
> > >
> > > Update the iomap documentation to match this change.
> > >
> > > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > > ---
> > >  Documentation/filesystems/iomap/design.rst    | 115 +++++++++++++-----
> > >  .../filesystems/iomap/operations.rst          |  60 +++++----
> > >  Documentation/filesystems/iomap/porting.rst   |  22 +++-
> > >  3 files changed, 132 insertions(+), 65 deletions(-)
> > >
> > > diff --git a/Documentation/filesystems/iomap/design.rst b/Documentation/filesystems/iomap/design.rst
> > > index 0f7672676c0b..7a37e303eea8 100644
> > > --- a/Documentation/filesystems/iomap/design.rst
> > > +++ b/Documentation/filesystems/iomap/design.rst
> > > @@ -75,7 +75,10 @@ At a high level, an iomap operation `looks like this
> > >
> > >  1. For each byte in the operation range...
> > >
> > > -   1. Obtain a space mapping via ``->iomap_begin``
> > > +   1. Obtain the next space mapping via the ``iomap_next`` callback.
> > > +      From the second iteration onwards this same callback first finishes
> > > +      the previous mapping (committing or unreserving space as needed)
> > > +      and then produces the next one.
> > >
> > >     2. For each sub-unit of work...
> > >
> > > @@ -86,7 +89,13 @@ At a high level, an iomap operation `looks like this
> > >
> > >     3. Increment operation cursor
> > >
> > > -   4. Release the mapping via ``->iomap_end``, if necessary
> > > +iomap repeats this until the range is fully consumed.  The ``iomap_next``
> > > +callback returns ``1`` while there is more of the range left to process,
> > > +``0`` once it is fully consumed, and a negative errno on error.
> >
> > s/and/or/
> >
> > > +Filesystems rarely implement ``->iomap_next`` by hand. The ``iomap_process``
> > > +helper implements the finish-then-produce sequence in +terms of two smaller
> > > +callbacks, ``begin`` and ``end``. See `The Mapping Callback`_ below for more
> > > +info.
> >
> > I wonder, under what circumstances would a filesystem /not/ use
> > iomap_process()?
> 
> Hmm, maybe a situation where they need to share or carry some
> filesystem-specific state / info between finishing the mapping and
> producing the next one?

The ->begin method can still set iomap::private and the ->end method can
dispose of it, right?  Oh, wait, no, that doesn't work because you're
talking about ->begin/->end passing something to the next ->begin.

I suppose you could make iomap_iter_continue preserve the iomap/srcmap
private pointer across the memset(0) calls.  But all current users
either rely on private being zeroed by iomap_iter after ->iomap_end
returns, so that would be quite the change.

Hm.  I was thinking that the signature for iomap_process could be
cleaner if you didn't have to pass iomap/srcmap explicitly.
iomap_process could do the (dangerous) casting from the (const struct
iomap_iter *) to the (struct iomap *) pointers before calling ->begin
and ->end.

But if you do have an ->iomap_next function that doesn't use
iomap_process, then it has to do the pointer extraction itself.  We
already expose the innards of struct iomap_iter to callers, so maybe
it's ok to have some gross helpers like:

static inline struct iomap *iomap_iter_iomap(const struct iomap_iter *i)
{
	return (struct iomap *)&i->iomap;
}

static inline struct iomap *iomap_iter_srcmap(const struct iomap_iter *i)
{
	return (struct iomap *)&i->srcmap;
}

I'm not sure *that*'s any cleaner.  And I think it gets confusing with
the other srcmap extraction function.

Eh never mind, I've talked myself out of this. ;)

> > >  Each iomap operation will be covered in more detail below.
> > >  This library was covered previously by an `LWN article
> > > @@ -189,7 +198,7 @@ The fields are as follows:
> > >     * **IOMAP_DELALLOC**: A promise to allocate space at a later time
> > >       ("delayed allocation").
> > >       If the filesystem returns IOMAP_F_NEW here and the write fails, the
> > > -     ``->iomap_end`` function must delete the reservation.
> > > +     ``end`` function must delete the reservation.
> > >       The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
> > >
> > >     * **IOMAP_MAPPED**: The file range maps to specific space on the
> > > @@ -208,12 +217,12 @@ The fields are as follows:
> > >
> > >     * **IOMAP_INLINE**: The file range maps to the memory buffer
> > >       specified by ``inline_data``.
> > > -     For write operation, the ``->iomap_end`` function presumably
> > > -     handles persisting the data.
> > > +     For write operation, the ``end`` function presumably handles
> > > +     persisting the data.
> >
> > Unrelated to this patch, but this should say "For write operations, the
> > end function must persist the data" because iomap_writepages doesn't
> > handle inline data.
> >
> > >       The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
> > >
> > >   * ``flags`` describe the status of the space mapping.
> > > -   These flags should be set by the filesystem in ``->iomap_begin``:
> > > +   These flags should be set by the filesystem in ``begin``:
> >>
> > > +``->iomap_next``
> > > +~~~~~~~~~~~~~~~~
> > > +
> > > +Each call must finish the previous mapping, if any, and then produce the
> >
> > Each call?  Oh, each implementation of ->iomap_next must finish the
> > previous mapping.
> >
> > > +next mapping for the current iteration position described by ``iter``.
> > > +The mapping is returned through ``iomap`` (and through ``srcmap`` for
> > > +operations that read from one mapping while writing to another; see
> > > +``begin`` below).
> > >
> > > -``->iomap_begin``
> > > +The callback returns ``1`` to continue iterating, ``0`` once the file
> > > +range has been fully consumed, and a negative errno on error.
> >
> > s/and/or/
> >
> > I think there should be a transition sentence here along the lines of
> >
> > "Most filesystems are not expected to implement all of these behaviors
> > in ->iomap_next themselves.  They should instead call iomap_process as
> > described below."
> >
> > Or demote the next section so it's more obvious that the "iomap_process"
> > and "->iomap_next" sections aren't independent?
> >
> 
> Sounds good, I'll incorporate all the suggestions you recommended.

<nod>

--D

> Thanks,
> Joanne
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops
  2026-07-03  1:47       ` Joanne Koong
@ 2026-07-03  2:01         ` Darrick J. Wong
  0 siblings, 0 replies; 53+ messages in thread
From: Darrick J. Wong @ 2026-07-03  2:01 UTC (permalink / raw)
  To: Joanne Koong
  Cc: Christoph Hellwig, brauner, willy, hsiangkao, linux-fsdevel,
	linux-xfs, Jens Axboe, Chris Mason, David Sterba, Alexander Viro,
	Jan Kara, Dan Williams, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Sandeep Dhavale, Hongbo Li, Chunhai Guo, Namjae Jeon,
	Sungjong Seo, Yuezhang Mo, Theodore Ts'o, Andreas Dilger,
	Baokun Li, Ojaswin Mujoo, Ritesh Harjani (IBM), Zhang Yi,
	Jaegeuk Kim, Miklos Szeredi, Andreas Gruenbacher, Mikulas Patocka,
	Hyunchul Lee, Konstantin Komarov, Carlos Maiolino, Damien Le Moal,
	Naohiro Aota, Johannes Thumshirn, open list:BLOCK LAYER,
	open list, open list:BTRFS FILE SYSTEM,
	open list:FILESYSTEM DIRECT ACCESS (DAX),
	open list:EROFS FILE SYSTEM, open list:EXT2 FILE SYSTEM,
	open list:F2FS FILE SYSTEM, open list:FUSE FILESYSTEM [CORE],
	open list:GFS2 FILE SYSTEM, open list:NTFS3 FILESYSTEM

On Thu, Jul 02, 2026 at 06:47:43PM -0700, Joanne Koong wrote:
> On Thu, Jul 2, 2026 at 9:51 AM Darrick J. Wong <djwong@kernel.org> wrote:
> >
> > On Thu, Jul 02, 2026 at 04:07:05PM +0200, Christoph Hellwig wrote:
> > > Looks good:
> > >
> > > Reviewed-by: Christoph Hellwig <hch@lst.de>
> > >
> > > In terms of merge logistics, I wonder if we should delay this and
> > > the previous patch to the next merge window so that we can minimize the
> > > cross-subsystem merge pain with more file system iomap conversion.
> > > If none of them actually happen until rc6 or so, orif  the merges aren't
> > > painful we could still pick them up late in the merge window.
> >
> > I'd say everything but this patch should go in during the merge window
> > for 7.3, along with clear instructions to brauner/torvalds to expect
> > this patch to appear right before 7.3-rc1 gets tagged, to clean up all
> > the other changes that come in.
> 
> Just to clarify, did you mean this patch and the previous one? If i'm

Er, yes, patches 16-18 in this series.

> interpreting Christoph's concern correctly, I think he's worried about
> other filesystems converting to iomap using the ->iomap_begin() /
> ->iomap_end() functions still? That sounds like a good plan to me, for
> v3 I'll submit everything but this patch and the last one and then
> submit these patches (and any cleanup ones that become necessary) to
> Christian right before 7.3-rc1 gets tagged (which as I understand it,
> is when the merge window is about to close).

Yes.  And be sure to ask both of them beforehand so there aren't any
youknowwho-style surprises/outrages.

--D

> Thanks,
> Joanne
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

end of thread, other threads:[~2026-07-03  2:01 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-01  0:09 [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Joanne Koong
2026-07-01  0:09 ` [PATCH v2 01/18] iomap: add ->iomap_next() and iomap_process() helper Joanne Koong
2026-07-02 14:00   ` Christoph Hellwig
2026-07-02 23:01     ` Joanne Koong
2026-07-02 16:23   ` Darrick J. Wong
2026-07-02 22:41     ` Joanne Koong
2026-07-01  0:09 ` [PATCH v2 02/18] xfs: convert iomap ops to ->iomap_next() Joanne Koong
2026-07-02 14:03   ` Christoph Hellwig
2026-07-02 16:48     ` Darrick J. Wong
2026-07-02 16:43   ` Darrick J. Wong
2026-07-02 23:59     ` Joanne Koong
2026-07-03  1:21       ` Joanne Koong
2026-07-03  1:41         ` Darrick J. Wong
2026-07-03  1:38       ` Darrick J. Wong
2026-07-01  0:09 ` [PATCH v2 03/18] btrfs: " Joanne Koong
2026-07-01  0:09 ` [PATCH v2 04/18] ntfs3: " Joanne Koong
2026-07-01  0:09 ` [PATCH v2 05/18] ntfs: " Joanne Koong
2026-07-01  0:09 ` [PATCH v2 06/18] ext4: " Joanne Koong
2026-07-01 10:01   ` Jan Kara
2026-07-01  0:09 ` [PATCH v2 07/18] erofs: " Joanne Koong
2026-07-01  0:41   ` Gao Xiang
2026-07-01  0:09 ` [PATCH v2 08/18] zonefs: " Joanne Koong
2026-07-01  0:09 ` [PATCH v2 09/18] ext2: " Joanne Koong
2026-07-01 10:02   ` Jan Kara
2026-07-01  0:09 ` [PATCH v2 10/18] block: " Joanne Koong
2026-07-01  0:55   ` Keith Busch
2026-07-02 14:03     ` Christoph Hellwig
2026-07-03  0:06     ` Joanne Koong
2026-07-01  0:09 ` [PATCH v2 11/18] f2fs: " Joanne Koong
2026-07-01  0:09 ` [PATCH v2 12/18] gfs2: " Joanne Koong
2026-07-01  0:09 ` [PATCH v2 13/18] hpfs: " Joanne Koong
2026-07-01  0:09 ` [PATCH v2 14/18] fuse: " Joanne Koong
2026-07-01  0:09 ` [PATCH v2 15/18] exfat: " Joanne Koong
2026-07-03  1:41   ` Joanne Koong
2026-07-01  0:09 ` [PATCH v2 16/18] iomap: remove ->iomap_begin()/->iomap_end() legacy path Joanne Koong
2026-07-02 14:04   ` Christoph Hellwig
2026-07-02 16:51   ` Darrick J. Wong
2026-07-01  0:09 ` [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops Joanne Koong
2026-07-01 10:04   ` Jan Kara
2026-07-02 14:07   ` Christoph Hellwig
2026-07-02 16:51     ` Darrick J. Wong
2026-07-03  1:47       ` Joanne Koong
2026-07-03  2:01         ` Darrick J. Wong
2026-07-02 16:58   ` Darrick J. Wong
2026-07-03  0:17     ` Joanne Koong
2026-07-03  1:42       ` Darrick J. Wong
2026-07-01  0:09 ` [PATCH v2 18/18] Documentation: iomap: update docs to reflect iomap_next model Joanne Koong
2026-07-02 14:07   ` Christoph Hellwig
2026-07-02 19:26   ` Darrick J. Wong
2026-07-03  1:36     ` Joanne Koong
2026-07-03  2:00       ` Darrick J. Wong
2026-07-02 13:49 ` [PATCH v2 00/18] iomap: convert to in-iter iomap_next() model Christoph Hellwig
2026-07-03  1:08   ` Joanne Koong

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