Linux block layer
 help / color / mirror / Atom feed
* [PATCH v7 3/9] dt-bindings: bluetooth: qcom: Add NVMEM BD address cell
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
  To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
	Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
	Russell King, Saravana Kannan, Christian Marangi
  Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
	linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
	Loic Poulain, Bartosz Golaszewski
In-Reply-To: <20260701-block-as-nvmem-v7-0-3fe8205ef0a8@oss.qualcomm.com>

Add support for an NVMEM cell provider for "local-bd-address",
allowing the Bluetooth stack to retrieve controller's BD address
from non-volatile storage such as an EEPROM or an eMMC partition.

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
 .../devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml
index c8e9c55c1afb4c8e05ba2dae41ce2db4194b4a0f..7cb28f30c9af032082f23311f2fc89a32f266f17 100644
--- a/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml
+++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml
@@ -22,4 +22,13 @@ properties:
     description:
       boot firmware is incorrectly passing the address in big-endian order
 
+  nvmem-cells:
+    maxItems: 1
+    description:
+      Nvmem data cell that contains a 6 byte BD address with the most
+      significant byte first (big-endian).
+
+  nvmem-cell-names:
+    const: local-bd-address
+
 additionalProperties: true

-- 
2.34.1


^ permalink raw reply related

* [PATCH v7 5/9] block: implement NVMEM provider
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
  To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
	Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
	Russell King, Saravana Kannan, Christian Marangi
  Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
	linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
	Loic Poulain, Bartosz Golaszewski
In-Reply-To: <20260701-block-as-nvmem-v7-0-3fe8205ef0a8@oss.qualcomm.com>

From: Daniel Golle <daniel@makrotopia.org>

On embedded devices using an eMMC it is common that one or more partitions
on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM
data. Allow referencing the partition in device tree for the kernel and
Wi-Fi drivers accessing it via the NVMEM layer.

NVMEM is registered for a block device whose OF node describes an NVMEM
layout, either via an "nvmem-layout" child or by being a "fixed-layout"
node itself (e.g. an eMMC boot partition associated through its mmc-card
node).

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Co-developed-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
 block/Kconfig             |   9 ++++
 block/Makefile            |   1 +
 block/blk-nvmem.c         | 109 ++++++++++++++++++++++++++++++++++++++++++++++
 block/blk.h               |   8 ++++
 block/genhd.c             |   4 ++
 include/linux/blk_types.h |   4 ++
 6 files changed, 135 insertions(+)

diff --git a/block/Kconfig b/block/Kconfig
index 15027963472d7b40e27b9097a5993c457b5b3054..0b33747e16dc33473683706f75c92bdf8b648f7c 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -209,6 +209,15 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
 	  by falling back to the kernel crypto API when inline
 	  encryption hardware is not present.
 
+config BLK_NVMEM
+	bool "Block device NVMEM provider"
+	depends on OF
+	depends on NVMEM
+	help
+	  Allow block devices (or partitions) to act as NVMEM providers,
+	  typically used with eMMC to store MAC addresses or Wi-Fi
+	  calibration data on embedded devices.
+
 source "block/partitions/Kconfig"
 
 config BLK_PM
diff --git a/block/Makefile b/block/Makefile
index 7dce2e44276c4274c11a0a61121c83d9c43d6e0c..d7ac389e71902bc091a8800ea266190a43b3e63d 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -36,3 +36,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION)	+= blk-crypto.o blk-crypto-profile.o \
 					   blk-crypto-sysfs.o
 obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK)	+= blk-crypto-fallback.o
 obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED)	+= holder.o
+obj-$(CONFIG_BLK_NVMEM)                += blk-nvmem.o
diff --git a/block/blk-nvmem.c b/block/blk-nvmem.c
new file mode 100644
index 0000000000000000000000000000000000000000..49e9b5d4410d5e935c4ad9674c6909453fe027ff
--- /dev/null
+++ b/block/blk-nvmem.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * block device NVMEM provider
+ *
+ * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org>
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * Useful on devices using a partition on an eMMC for MAC addresses or
+ * Wi-Fi calibration EEPROM data.
+ */
+
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/file.h>
+#include <linux/nvmem-provider.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/pagemap.h>
+#include <linux/property.h>
+
+#include "blk.h"
+
+static int blk_nvmem_reg_read(void *priv, unsigned int from, void *val, size_t bytes)
+{
+	dev_t devt = (dev_t)(uintptr_t)priv;
+	size_t bytes_left = bytes;
+	loff_t pos = from;
+	int ret = 0;
+
+	struct file *bdev_file __free(fput) =
+		bdev_file_open_by_dev(devt, BLK_OPEN_READ, NULL, NULL);
+	if (IS_ERR(bdev_file))
+		return PTR_ERR(bdev_file);
+
+	while (bytes_left) {
+		pgoff_t f_index = pos >> PAGE_SHIFT;
+		struct folio *folio;
+		size_t folio_off;
+		size_t to_read;
+
+		folio = read_mapping_folio(bdev_file->f_mapping, f_index, NULL);
+		if (IS_ERR(folio)) {
+			ret = PTR_ERR(folio);
+			break;
+		}
+
+		folio_off = offset_in_folio(folio, pos);
+		to_read = min(bytes_left, folio_size(folio) - folio_off);
+		memcpy_from_folio(val, folio, folio_off, to_read);
+		pos += to_read;
+		bytes_left -= to_read;
+		val += to_read;
+		folio_put(folio);
+	}
+
+	return ret;
+}
+
+int blk_nvmem_add(struct block_device *bdev)
+{
+	struct device *dev = &bdev->bd_device;
+	struct nvmem_config config = {};
+
+	/* skip devices which do not have a device tree node */
+	if (!dev_of_node(dev))
+		return 0;
+
+	/* skip devices without an nvmem layout defined */
+	struct device_node *child __free(device_node) =
+		of_get_child_by_name(dev_of_node(dev), "nvmem-layout");
+	if (!child && !of_device_is_compatible(dev_of_node(dev), "fixed-layout"))
+		return 0;
+
+	/*
+	 * skip block device too large to be represented as NVMEM devices,
+	 * nvmem_config.size is a signed int
+	 */
+	if (bdev_nr_bytes(bdev) > INT_MAX) {
+		dev_warn(dev, "block device too large to be an NVMEM provider\n");
+		return 0;
+	}
+
+	config.id = NVMEM_DEVID_NONE;
+	config.dev = dev;
+	config.name = dev_name(dev);
+	config.owner = THIS_MODULE;
+	config.priv = (void *)(uintptr_t)dev->devt;
+	config.reg_read = blk_nvmem_reg_read;
+	config.size = bdev_nr_bytes(bdev);
+	config.word_size = 1;
+	config.stride = 1;
+	config.read_only = true;
+	config.root_only = true;
+	config.ignore_wp = true;
+	config.of_node = to_of_node(dev->fwnode);
+
+	bdev->bd_nvmem = nvmem_register(&config);
+	if (IS_ERR(bdev->bd_nvmem))
+		return dev_err_probe(dev, PTR_ERR(bdev->bd_nvmem),
+				     "Failed to register NVMEM device\n");
+
+	return 0;
+}
+
+void blk_nvmem_del(struct block_device *bdev)
+{
+	nvmem_unregister(bdev->bd_nvmem);
+	bdev->bd_nvmem = NULL;
+}
diff --git a/block/blk.h b/block/blk.h
index ec4674cdf2ead4fd259ff5fc42401f591e684ee9..ed0c10168ba7be10855509637f824a9cea2b9ccb 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -757,4 +757,12 @@ static inline void blk_debugfs_unlock(struct request_queue *q,
 	memalloc_noio_restore(memflags);
 }
 
+#ifdef CONFIG_BLK_NVMEM
+int blk_nvmem_add(struct block_device *bdev);
+void blk_nvmem_del(struct block_device *bdev);
+#else
+static inline int blk_nvmem_add(struct block_device *bdev) { return 0; }
+static inline void blk_nvmem_del(struct block_device *bdev) {}
+#endif
+
 #endif /* BLK_INTERNAL_H */
diff --git a/block/genhd.c b/block/genhd.c
index 7d6854fd28e95ae9134309679a7c6a937f5b7db8..1b2382de6fb30c1e5f60f45c04dc03ed3bf5d5f2 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -421,6 +421,8 @@ static void add_disk_final(struct gendisk *disk)
 		 */
 		dev_set_uevent_suppress(ddev, 0);
 		disk_uevent(disk, KOBJ_ADD);
+
+		blk_nvmem_add(disk->part0);
 	}
 
 	blk_apply_bdi_limits(disk->bdi, &disk->queue->limits);
@@ -704,6 +706,8 @@ static void __del_gendisk(struct gendisk *disk)
 
 	disk_del_events(disk);
 
+	blk_nvmem_del(disk->part0);
+
 	/*
 	 * Prevent new openers by unlinked the bdev inode.
 	 */
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 8808ee76e73c09e0ceaac41ba59e86fb0c4efc64..6ed173c649025b95cce9253b27f68f2c7dbab8eb 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -15,6 +15,7 @@
 struct bio_set;
 struct bio;
 struct bio_integrity_payload;
+struct nvmem_device;
 struct page;
 struct io_context;
 struct cgroup_subsys_state;
@@ -73,6 +74,9 @@ struct block_device {
 	int			bd_writers;
 #ifdef CONFIG_SECURITY
 	void			*bd_security;
+#endif
+#ifdef CONFIG_BLK_NVMEM
+	struct nvmem_device	*bd_nvmem;
 #endif
 	/*
 	 * keep this out-of-line as it's both big and not needed in the fast

-- 
2.34.1


^ permalink raw reply related

* [PATCH v7 0/9] Support for block device NVMEM providers
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
  To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
	Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
	Russell King, Saravana Kannan, Christian Marangi
  Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
	linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
	Loic Poulain, Bartosz Golaszewski, Krzysztof Kozlowski,
	Piotr Kwapulinski, Konrad Dybcio

On embedded devices, it is common for factory provisioning to store
device-specific information, such as Ethernet or WiFi MAC addresses,
in a dedicated area of an eMMC partition. This avoids the need for
and additional EEPROM/OTP and leverages the persistence of eMMC.

One example is the Arduino UNO-Q, where the WiFi MAC address and the
Bluetooth Device address are stored in the eMMC Boot1 partition.

Until now, accessing this information required a custom bootloader
to read the data and inject it into the Device Tree before handing
control over to the kernel. This approach is fragile and leads to
device-specific workarounds.

Rather than adding a new NVMEM provider specifically to the eMMC
subsystem, the new support operates at the block layer, allowing any
block device to behave like other non-volatile memories such as EEPROM
or OTP.

This series builds on earlier work by Daniel Golle that enables block
devices to act as NVMEM providers:
https://lore.kernel.org/all/6061aa4201030b9bb2f8d03ef32a564fdb786ed1.1709667858.git.daniel@makrotopia.org/

It also introduces an NVMEM layout description for the Arduino UNO-Q,
allowing device-specific data stored in the eMMC Boot1 partition to
be accessed in a standard way.

WiFi and Ethernet already support retrieving MAC addresses from NVMEM.
Bluetooth requires similar support, which is also addressed.

Note that this is currently limited to MMC-backed block devices, as
only the MMC core associates a firmware node with the block device
(add_disk_fwnode). This can be easily extended in the future to
support additional block drivers.

Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
Changes in v7:
- Rework bindings/dts so that the eMMC boot partition can be a nvmem fixed-layout
  and not a child of fixed-partition. (Rob)
- Add Support for fixed-layout as the nvmem device node itself
- Remove "block: partitions: of: Skip child nodes without reg property"
  This is no more required in this series and will be submitted separately (Rob)
- Add missing linux/cleanup.h and linux/device.h includes (Bartosz)
- simplify nvmem_register() error path using dev_err_probe() (Bartosz)
- nvmem_device forward declaration to blk_types.h (Bartosz)
- Add hci_dev_get_bd_addr_from_nvmem() kernel-doc for return value (Piotr)
- Link to v6: https://lore.kernel.org/r/20260629-block-as-nvmem-v6-0-f02513dcd46d@oss.qualcomm.com

Changes in v6:
- blk_nvmem_add() returns int, error properly propagated (Bartosz)
- Redundant if (bdev->bd_nvmem) guard removed in blk_nvmem_del() (Bartosz)
- Size guard changed from UINT_MAX → INT_MAX to avoid signed overflow in config.size (sashiko)
- BLK_OPEN_RESTRICT_WRITES removed from blk_nvmem_reg_read() (sashiko)
- Link to v5: https://lore.kernel.org/r/20260612-block-as-nvmem-v5-0-95e0b30fff90@oss.qualcomm.com

Changes in v5:
- Fixed ath10k binding issue + extended commit message (Krzysztof)
- Moved blk-nvmem handling to block core instead of a class_interface
  This allows correct/robust integration with block device life cycle (Bartosz).
- block: partitions: of: Skip child nodes without reg property (sashiko)
- Link to v4: https://lore.kernel.org/r/20260609-block-as-nvmem-v4-0-45712e6b22c6@oss.qualcomm.com

Changes in v4:
- Fix squash issue (dts commit incorrectly squashed) (Konrad)
- Use devres for nvmem resources (Bartosz)
- use __free() destructor helper when possible (Bartosz)
- Fix value return checking for bdev_file_open_by_dev
- Link to v3: https://lore.kernel.org/r/20260608-block-as-nvmem-v3-0-82681f50aa35@oss.qualcomm.com

Changes in v3:
- Fixed missing 'fixed-partitions' compatible in partition (Rob)
- Fixed clashing nvmem cells, document calibration along mac (Sashiko)
- Remove workaround to handle dangling nvmem references after
  unregistering, this is a generic nvmem framework issue handled
  in Bartosz's series:
   https://lore.kernel.org/all/20260429-nvmem-unbind-v3-0-2a694f95395b@oss.qualcomm.com/
- Validate mac (is_valid_ether_addr) before copying to output buffer
- Link to v2: https://lore.kernel.org/r/20260507-block-as-nvmem-v2-0-bf17edd5134e@oss.qualcomm.com

Changes in v2:
- Fix example nvmem-layout cells to use compatible = "mac-base"
- Squash WiFi MAC and Bluetooth BD address consumer patches into the nvmem layout patch
- Fix possible use-after-free in blk-nvmem: bnv (nvmem priv) linked to nvmem lifetime
- Simplify nvmem-cell-names from items: - const: to plain const:
- Factor out common NVMEM EUI-48 retrieval logic
- Reorder changes
- Link to v1: https://lore.kernel.org/r/20260428-block-as-nvmem-v1-0-6ad23e75190a@oss.qualcomm.com

---
Daniel Golle (1):
      block: implement NVMEM provider

Loic Poulain (8):
      dt-bindings: mmc: Document fixed-layout NVMEM provider support
      dt-bindings: net: wireless: qcom,ath10k: Document NVMEM cells
      dt-bindings: bluetooth: qcom: Add NVMEM BD address cell
      nvmem: layouts: Support fixed-layout as the nvmem device node itself
      net: of_net: Add of_get_nvmem_eui48() helper for EUI-48 lookup
      Bluetooth: hci_sync: Add NVMEM-backed BD address retrieval
      Bluetooth: qca: Set NVMEM BD address quirks when address is invalid
      arm64: dts: qcom: arduino-imola: Describe NVMEM layout for WiFi/BT addresses

 .../devicetree/bindings/mmc/mmc-card.yaml          |  23 ++++-
 .../net/bluetooth/qcom,bluetooth-common.yaml       |   9 ++
 .../bindings/net/wireless/qcom,ath10k.yaml         |  16 +++
 arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts |  32 ++++++
 block/Kconfig                                      |   9 ++
 block/Makefile                                     |   1 +
 block/blk-nvmem.c                                  | 109 +++++++++++++++++++++
 block/blk.h                                        |   8 ++
 block/genhd.c                                      |   4 +
 drivers/bluetooth/btqca.c                          |   5 +-
 drivers/nvmem/layouts.c                            |  13 ++-
 include/linux/blk_types.h                          |   4 +
 include/linux/of_net.h                             |   7 ++
 include/net/bluetooth/hci.h                        |  18 ++++
 net/bluetooth/hci_sync.c                           |  41 +++++++-
 net/core/of_net.c                                  |  49 ++++++---
 16 files changed, 332 insertions(+), 16 deletions(-)
---
base-commit: c58ba8c7e9ab26b5e8d91f8ca0e0a16c2ae318e9
change-id: 20260428-block-as-nvmem-4b308e8bda9a

Best regards,
-- 
Loic Poulain <loic.poulain@oss.qualcomm.com>


^ permalink raw reply

* [PATCH v7 4/9] nvmem: layouts: Support fixed-layout as the nvmem device node itself
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
  To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
	Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
	Russell King, Saravana Kannan, Christian Marangi
  Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
	linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
	Loic Poulain
In-Reply-To: <20260701-block-as-nvmem-v7-0-3fe8205ef0a8@oss.qualcomm.com>

of_nvmem_layout_get_container() only looks for a child node named
"nvmem-layout" to locate the cell definitions. This does not cover
providers whose device tree node is itself the fixed-layout container,
such as an eMMC boot partition block device whose fwnode points directly
at a "fixed-layout" compatible partitions node.

When no "nvmem-layout" child is present, fall back to returning the nvmem
device node itself if it is compatible with "fixed-layout", so that its
cells are parsed by nvmem_add_cells_from_fixed_layout().

Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
 drivers/nvmem/layouts.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/nvmem/layouts.c b/drivers/nvmem/layouts.c
index b90584e1b99eab4217cbe7ec48373e18a7caf0dc..efa631ce7283bdd6c8ecda75915911b5e3a33c99 100644
--- a/drivers/nvmem/layouts.c
+++ b/drivers/nvmem/layouts.c
@@ -167,7 +167,18 @@ static int nvmem_layout_bus_populate(struct nvmem_device *nvmem,
 
 struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
 {
-	return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
+	struct device_node *np;
+
+	/* Search for nvmem-layout child */
+	np = of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
+	if (np)
+		return np;
+
+	/* The nvmem of_node is itself a fixed-layout node */
+	if (of_device_is_compatible(nvmem->dev.of_node, "fixed-layout"))
+		return of_node_get(nvmem->dev.of_node);
+
+	return NULL;
 }
 EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container);
 

-- 
2.34.1


^ permalink raw reply related

* [PATCH v7 2/9] dt-bindings: net: wireless: qcom,ath10k: Document NVMEM cells
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
  To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
	Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
	Russell King, Saravana Kannan, Christian Marangi
  Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
	linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
	Loic Poulain, Bartosz Golaszewski, Krzysztof Kozlowski
In-Reply-To: <20260701-block-as-nvmem-v7-0-3fe8205ef0a8@oss.qualcomm.com>

Document the NVMEM cells supported by the ath10k driver, the
mac-address, pre-calibration data, and calibration data.

Since such data may also originate from chipset OTP or be supplied
via other device tree structures. All of these cells are optional
and can be provided independently, in any combination.

Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
 .../devicetree/bindings/net/wireless/qcom,ath10k.yaml    | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
index c21d66c7cd558ab792524be9afec8b79272d1c87..878c5d833a9cb073520c256c1b72d0f1489e7f4a 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
@@ -92,6 +92,22 @@ properties:
 
   ieee80211-freq-limit: true
 
+  nvmem-cells:
+    minItems: 1
+    maxItems: 3
+    description:
+      References to nvmem cells for MAC address and/or calibration data.
+      Supported cell names are mac-address, calibration, and pre-calibration.
+
+  nvmem-cell-names:
+    minItems: 1
+    maxItems: 3
+    items:
+      enum:
+        - mac-address
+        - calibration
+        - pre-calibration
+
   qcom,calibration-data:
     $ref: /schemas/types.yaml#/definitions/uint8-array
     description:

-- 
2.34.1


^ permalink raw reply related

* [PATCH v7 1/9] dt-bindings: mmc: Document fixed-layout NVMEM provider support
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
  To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
	Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
	Russell King, Saravana Kannan, Christian Marangi
  Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
	linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
	Loic Poulain
In-Reply-To: <20260701-block-as-nvmem-v7-0-3fe8205ef0a8@oss.qualcomm.com>

Allow an eMMC hardware partition node to describe an NVMEM layout so the
partition can be exposed as an NVMEM provider. This lets a partition
(e.g. an eMMC boot partition) store device-specific information such as a
WiFi MAC address or a Bluetooth BD address and reference it through NVMEM
cells.

Accept "fixed-layout" as the partition node compatible, in addition to
"fixed-partitions", so the layout can be described directly on the
partition node.

Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
 .../devicetree/bindings/mmc/mmc-card.yaml          | 23 +++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mmc/mmc-card.yaml b/Documentation/devicetree/bindings/mmc/mmc-card.yaml
index a61d6c96df759102f9c1fbfd548b026a77921cae..0422894508478c8d0ca68292b58a5fdbee218358 100644
--- a/Documentation/devicetree/bindings/mmc/mmc-card.yaml
+++ b/Documentation/devicetree/bindings/mmc/mmc-card.yaml
@@ -38,7 +38,9 @@ patternProperties:
     properties:
       compatible:
         contains:
-          const: fixed-partitions
+          enum:
+            - fixed-partitions
+            - fixed-layout
 
 required:
   - compatible
@@ -86,6 +88,25 @@ examples:
                     read-only;
                 };
             };
+
+            partitions-boot2 {
+                compatible = "fixed-layout";
+
+                #address-cells = <1>;
+                #size-cells = <1>;
+
+                mac-addr@4400 {
+                    compatible = "mac-base";
+                    reg = <0x4400 0x6>;
+                    #nvmem-cell-cells = <1>;
+                };
+
+                bd-addr@5400 {
+                    compatible = "mac-base";
+                    reg = <0x5400 0x6>;
+                    #nvmem-cell-cells = <1>;
+                };
+            };
         };
     };
 

-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH v6 1/9] block: partitions: of: Skip child nodes without reg property
From: Loic Poulain @ 2026-07-01 13:35 UTC (permalink / raw)
  To: Rob Herring
  Cc: Ulf Hansson, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Jens Axboe, Johannes Berg, Jeff Johnson,
	Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
	Balakrishna Godavarthi, Rocky Liao, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Srinivas Kandagatla,
	Andrew Lunn, Heiner Kallweit, Russell King, Saravana Kannan,
	Christian Marangi, linux-mmc, devicetree, linux-kernel,
	linux-arm-msm, linux-block, linux-wireless, ath10k,
	linux-bluetooth, netdev, daniel, stable, Bartosz Golaszewski
In-Reply-To: <CAL_JsqKFjk-mdaAAOzNB6rFiJbw5gd4eDpRBLQL-4q+uJKnp3g@mail.gmail.com>

On Tue, Jun 30, 2026 at 11:46 PM Rob Herring <robh@kernel.org> wrote:
>
> On Tue, Jun 30, 2026 at 2:59 PM Loic Poulain
> <loic.poulain@oss.qualcomm.com> wrote:
> >
> > Hi Rob,
> >
> > On Tue, Jun 30, 2026 at 8:02 PM Rob Herring <robh@kernel.org> wrote:
> > >
> > > On Mon, Jun 29, 2026 at 10:55:20AM +0200, Loic Poulain wrote:
> > > > Child nodes of a fixed-partitions node are not necessarily partition
> > > > entries, for example an nvmem-layout node has no reg property. The
> > > > current code passes a NULL reg pointer and uninitialized len to the
> > > > length check, which can result in a kernel panic or silent failure to
> > > > register any partitions.
> > >
> > > That does not sound right to me. A fixed-partitions node should only be
> > > defining partitions with address ranges. I would expect a partition node
> > > could be nvmem-layout, but not the whole address range. If you wanted
> > > the latter, then just do:
> > >
> > > partitions {
> > >   ...
> > > };
> > >
> > > nvmem-layout {
> > >   ...
> > > };
> >
> > In our case, the nvmem-layout needs to be associated with a specific
> > eMMC hardware partition, nvmem cells can be a simple sub-range within
> > the global eMMC, each hardware partition (boot0, boot1, user...)
> > having its own address spaces.
> >
> > That said, your point about not abusing fixed-partitions is valid. I
> > initially dropped the compatible = "fixed-partitions" from the
> > partitions-boot1 node when it only carries an nvmem-layout and no
> > actual partition entries, making it a plain named container node. But
> > it's a bit fragile if we want to support both nvmem-layout and
> > fixed-partitions.
> >
> > Regarding your expectation of a partition node being a nvmem-layout,
> > do you mean that the nvmem-layout should live under a fixed-partitions
> > node? Something along these lines:
> >
> > partitions-boot1 {
> >       compatible = "fixed-partitions";
> >       #address-cells = <1>;
> >       #size-cells = <1>;
> >
> >       nvmem@4400 {
>
> partition@4400
>
> >           reg = <0x4400 0x1000>;
> >
> >           nvmem-layout {
> >               compatible = "fixed-layout";
> >               #address-cells = <1>;
> >               #size-cells = <1>;
> >
> >               wifi_mac_addr: mac-addr@0 {
> >                   compatible = "mac-base";
> >                   reg = <0x0 0x6>;
> >                   #nvmem-cell-cells = <1>;
> >               };
> >       [...]
>
> Either this or replacing "fixed-partitions" with "fixed-layout" if you
> want to make the whole boot1 partition nvmem-layout looks like the
> right way to me.

Well, now I think both approaches make sense. We should support a
fixed-layout on the entire hw-part/block, while also allowing it
within individual logical partitions.
Support for the former would only require a small rework/addition in
this series (to have the hw boot partition a fixed-layout) . The
latter could come in a follow-up series, as it would require some
additional fwnode logic.

>
> > That makes some sense, this would require extra work for the
> > emmc/block layer to also associate fwnodes with logical partitions,
> > not just the whole disk/hw (hw part), Is that the direction you'd like
> > us to go?
>
> Yes.
>
> > Also, Note that regardless of which approach we settle on, this
> > specific fix/patch remains necessary to validate the partition node
> > and prevent NULL-deref.
>
> Fair enough, though the reasoning for it would be different and
> perhaps should give a warning.

Sure.

Thanks,
Loic

^ permalink raw reply

* Re: [PATCH v2 3/6] firmware: qcom: scm: Add support for setting Bluetooth power modes
From: Konrad Dybcio @ 2026-07-01 13:31 UTC (permalink / raw)
  To: George Moussalem, Jens Axboe, Ulf Hansson, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Johannes Berg, Jeff Johnson,
	Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
	Balakrishna Godavarthi, Rocky Liao, Saravana Kannan, Andrew Lunn,
	Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Bjorn Andersson,
	Konrad Dybcio, Mathieu Poirier, Philipp Zabel
  Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
	ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <SN7PR19MB6736B784D6A16CBA531DBD5C9DF62@SN7PR19MB6736.namprd19.prod.outlook.com>

On 7/1/26 3:15 PM, George Moussalem wrote:
> On 7/1/26 14:40, Konrad Dybcio wrote:
>> On 6/29/26 3:01 PM, George Moussalem via B4 Relay wrote:
>>> From: George Moussalem <george.moussalem@outlook.com>
>>>
>>> The Bluetooth subsystem (BTSS) on the IPQ5018 SoC supports setting power
>>> modes which are required to be configured through a Secure Channel
>>> Manager (SCM) call to TrustZone. However, not all Trusted Execution
>>> Environment (QSEE) images support this call, so first check if the call
>>> is available.
>>>
>>> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
>>> ---
>>
>> I'm amazed changing this setting is a secure operation
>>
>> [...]
>>
>>> +/**
>>> + * qcom_scm_pas_set_bluetooth_power_mode() - Configure power optimization mode
>>> + *					     for the Bluetooth subsystem (BTSS)
>>> + * @pas_id:	peripheral authentication service id
>>> + * @val:	0x0 for normal operation, 0x4 for ECO mode
>>
>> If there's just two values, maybe we should make this take a `bool eco_mode`?
> 
> that was the direction I was going in initially but then thought that
> there may be more (undocumented) power modes I'm unaware off so changed
> it to u32. I'll change it back to bool.

We can always change back if needed

Konrad

^ permalink raw reply

* Re: [PATCH v2 3/6] firmware: qcom: scm: Add support for setting Bluetooth power modes
From: George Moussalem @ 2026-07-01 13:15 UTC (permalink / raw)
  To: Konrad Dybcio, Jens Axboe, Ulf Hansson, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Johannes Berg, Jeff Johnson,
	Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
	Balakrishna Godavarthi, Rocky Liao, Saravana Kannan, Andrew Lunn,
	Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Bjorn Andersson,
	Konrad Dybcio, Mathieu Poirier, Philipp Zabel
  Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
	ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <175f7835-df18-4bc6-8267-ceef35696af8@oss.qualcomm.com>

On 7/1/26 14:40, Konrad Dybcio wrote:
> On 6/29/26 3:01 PM, George Moussalem via B4 Relay wrote:
>> From: George Moussalem <george.moussalem@outlook.com>
>>
>> The Bluetooth subsystem (BTSS) on the IPQ5018 SoC supports setting power
>> modes which are required to be configured through a Secure Channel
>> Manager (SCM) call to TrustZone. However, not all Trusted Execution
>> Environment (QSEE) images support this call, so first check if the call
>> is available.
>>
>> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
>> ---
> 
> I'm amazed changing this setting is a secure operation
> 
> [...]
> 
>> +/**
>> + * qcom_scm_pas_set_bluetooth_power_mode() - Configure power optimization mode
>> + *					     for the Bluetooth subsystem (BTSS)
>> + * @pas_id:	peripheral authentication service id
>> + * @val:	0x0 for normal operation, 0x4 for ECO mode
> 
> If there's just two values, maybe we should make this take a `bool eco_mode`?

that was the direction I was going in initially but then thought that
there may be more (undocumented) power modes I'm unaware off so changed
it to u32. I'll change it back to bool.

> 
>> + *
>> + * Return: 0 on success, negative errno on failure.
>> + * Returns -EOPNOTSUPP if the firmware configuration call is unavailable.
>> + */
>> +int qcom_scm_pas_set_bluetooth_power_mode(u32 pas_id, u32 val)
>> +{
>> +	if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
>> +					  QCOM_SCM_PIL_PAS_BT_PWR_MODE))
>> +		return -EOPNOTSUPP;
>> +
>> +	return __qcom_scm_pas_set_bluetooth_power_mode(pas_id, val);
> 
> Let's just inline the whole definition here - it's single-use anyway

will update, thanks.

> 
> Konrad

Cheers,
George


^ permalink raw reply

* [ANNOUNCE] Alpine Linux Persistence and Storage Summit 2026
From: Christoph Hellwig @ 2026-07-01 11:43 UTC (permalink / raw)
  To: linux-block

We proudly announce the 9th Alpine Linux Persistence and Storage Summit
(ALPSS), which will be held September 28th to October 1st at the
Lizumerhuette (https://www.lizumer-huette.at/) in Austria.

The goal of this conference is to discuss the hot topics in Linux storage
and file systems, such as persistent memory, NVMe, zoned storage, and I/O
scheduling in a cool and relaxed setting with spectacular views in the
Austrian alps.

We plan to have a small selection of short and to the point talks with
lots of room for discussion in small groups, as well as ample downtime
to enjoy the surroundings.

Attendance is free except for the accommodation and food at the lodge
but the number of seats is strictly limited.  Cost for accommodation and
half board is between 73 and 92 EUR depending on the room category,
with additional discounts for members of an alpine society.

To attend please request an invitation by mailing your favorite topic(s)
to:

	alpss-pc@penguingang.at

If you are interested in giving a short and crisp talk please send an
abstract to the same address.  Attendance requests that propose a talk
will be prioritized.

We will start sending out invites on August 1st, and plan to publish
the official schedule in the beginning of September.

The Lizumerhuette is an Alpine Society lodge in a high alpine environment.
A hike of approximately 2 hours is required to the lodge, and no other
accommodations are available within walking distance.

Reservations for the lodge are handled as part of the ALPSS registration
and do NOT use the usual lodge reservation system.  Please let us know if
your require vegetarian, vegan or gluten free food or have any other
dietary restriction.

Check our website at https://www.alpss.at/ for more details.

Thank you on behalf of the program committee:

    Christoph Hellwig
    Johannes Thumshirn
    Richard Weinberger

^ permalink raw reply

* Re: [PATCH v2] block: avoid potential deadlock on zone revalidation failure
From: Jens Axboe @ 2026-07-01 11:42 UTC (permalink / raw)
  To: linux-block, Damien Le Moal; +Cc: Christoph Hellwig
In-Reply-To: <20260701082155.1369996-1-dlemoal@kernel.org>


On Wed, 01 Jul 2026 17:21:55 +0900, Damien Le Moal wrote:
> If revalidating the zones of a zoned block device with
> blk_revalidate_disk_zones() fails during a SCSI disk rescan, the following
> lockdep splat is thrown:
> 
> [  347.251859] [  T11230] sda: failed to revalidate zones
> 
> [  347.261380] [  T11230] ======================================================
> [  347.263882] [  T11230] WARNING: possible circular locking dependency detected
> [  347.266353] [  T11230] 7.1.0+ #1194 Not tainted
> [  347.268052] [  T11230] ------------------------------------------------------
> [  347.270537] [  T11230] tcsh/11230 is trying to acquire lock:
> [  347.272555] [  T11230] ffffffff8f91d400 (wq_pool_mutex){+.+.}-{4:4}, at: destroy_workqueue+0x15d/0x8d0
> [  347.275914] [  T11230]
>                           but task is already holding lock:
> [  347.278646] [  T11230] ffff88812fa1bcc0 (&q->q_usage_counter(io)#5){++++}-{0:0}, at: blk_mq_freeze_queue_nomemsave+0x16/0x30
> [  347.282503] [  T11230]
>                           which lock already depends on the new lock.
> 
> [...]

Applied, thanks!

[1/1] block: avoid potential deadlock on zone revalidation failure
      commit: 3dd63dba8f9cb6990a40af7ed66ee0159f475819

Best regards,
-- 
Jens Axboe




^ permalink raw reply

* Re: [PATCH v2] block: avoid potential deadlock on zone revalidation failure
From: Christoph Hellwig @ 2026-07-01 11:20 UTC (permalink / raw)
  To: Damien Le Moal; +Cc: Jens Axboe, linux-block, Christoph Hellwig
In-Reply-To: <20260701082155.1369996-1-dlemoal@kernel.org>

Still looks good:

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


^ permalink raw reply

* Re: [PATCH v2 4/6] Bluetooth: Introduce Qualcomm IPQ5018 IPC based HCI driver
From: Konrad Dybcio @ 2026-07-01 11:19 UTC (permalink / raw)
  To: george.moussalem, Jens Axboe, Ulf Hansson, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Johannes Berg, Jeff Johnson,
	Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
	Balakrishna Godavarthi, Rocky Liao, Saravana Kannan, Andrew Lunn,
	Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Bjorn Andersson,
	Konrad Dybcio, Mathieu Poirier, Philipp Zabel
  Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
	ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <20260629-ipq5018-bluetooth-v2-4-02770f03b6bb@outlook.com>

On 6/29/26 3:01 PM, George Moussalem via B4 Relay wrote:
> From: George Moussalem <george.moussalem@outlook.com>
> 
> Add support for the Bluetooth controller found in the IPQ5018 SoC.
> This driver implements firmware loading and the transport layer between
> the HCI core and the Bluetooth controller.
> 
> The firmware is loaded by the host into the dedicated reserved memory
> carveout and authenticated by TrustZone. A Secure Channel Manager (SCM)
> call safely brings the peripheral core out of reset.
> 
> A shared memory ring buffer topology handles runtime data frame
> transport between the host APSS and the controller.
> 
> An outgoing APCS IPC bit and an incoming GIC interrupt handle host/guest
> signaling.
> 
> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
> ---

[...]

> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/elf.h>
> +#include <linux/firmware.h>
> +#include <linux/firmware/qcom/qcom_scm.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_reserved_mem.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +#include <linux/skbuff.h>
> +#include <linux/slab.h>
> +#include <linux/soc/qcom/mdt_loader.h>
> +#include <linux/types.h>
> +#include <linux/workqueue.h>

I don't know for sure, but the amount of the includes suggests some may
be unnecessary

[...]

> +static void btqcomipc_update_stats(struct hci_dev *hdev, struct sk_buff *skb);

I don't think the forward-declaration is necessary


> +static struct ring_buffer_info *btss_get_tx_rbuf(struct qcom_btss *desc,
> +						 bool *is_sbuf_full)
> +{
> +	u8 idx;
> +	struct ring_buffer_info *rinfo;
> +
> +	for (rinfo = &(desc->tx_ctxt->sring_buf_info);	rinfo != NULL;
> +		rinfo = (struct ring_buffer_info *)(uintptr_t)(rinfo->next)) {
> +		idx = (rinfo->widx + 1) % (desc->tx_ctxt->smsg_buf_cnt);

That's one complex for-loop! Maybe move the assignments into the loop body

[...]

> +	/* Account for HCI packet type as it's not included in the skb payload */
> +	len = (skb) ? skb->len + 1 : 0;

Unnecessary parentheses, also in some other places

> +	memset(&aux_ptr, 0, sizeof(struct ipc_aux_ptr));

You can do aux_ptr = { } at declaration

Konrad

^ permalink raw reply

* Re: [PATCH v3 1/7] list: Add mutable iterator variants
From: Kaitao Cheng @ 2026-07-01 11:07 UTC (permalink / raw)
  To: Jani Nikula, David Laight, Christian König,
	David Hildenbrand (Arm), Alexei Starovoitov
  Cc: Andrew Morton, Jens Axboe, Tejun Heo, Alexander Viro,
	Christian Brauner, Daniel Borkmann, Andrii Nakryiko,
	Johannes Weiner, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Thomas Gleixner,
	Juri Lelli, Vincent Guittot, Paul Moore, Andy Shevchenko,
	Paul E. McKenney, Shakeel Butt, David Howells, Simona Vetter,
	Randy Dunlap, Luca Ceresoli, Philipp Stanner, linux-block,
	linux-kernel, cgroups, linux-ntfs-dev, linux-fsdevel, io-uring,
	audit, bpf, netdev, dri-devel, linux-perf-users,
	linux-trace-kernel, kexec, live-patching, linux-modules,
	linux-crypto, linux-pm, rcu, sched-ext, linux-mm, virtualization,
	damon, llvm, Kaitao Cheng, Muchun Song
In-Reply-To: <734f66ca51485ee3ec9788c0eaaead681e00664b@intel.com>

在 2026/6/25 19:00, Jani Nikula 写道:
> On Thu, 25 Jun 2026, Kaitao Cheng <kaitao.cheng@linux.dev> wrote:
>> 在 2026/6/24 22:23, David Laight 写道:
>>> On Wed, 24 Jun 2026 15:23:47 +0200
>>> Christian König <christian.koenig@amd.com> wrote:
>>>> On 6/24/26 15:14, Kaitao Cheng wrote:
>>>>> 在 2026/6/22 16:42, David Laight 写道:  
>>>>>> On Mon, 22 Jun 2026 12:05:31 +0800
>>>>>> Kaitao Cheng <kaitao.cheng@linux.dev> wrote:
>>>>>>  
>>>>>>> From: Kaitao Cheng <chengkaitao@kylinos.cn>
>>>>>>>
>>>>>>> The list_for_each*_safe() helpers are used when the loop body may
>>>>>>> remove the current entry.  Their API exposes the temporary cursor at
>>>>>>> every call site, even though most users only need it for the iterator
>>>>>>> implementation and never reference it in the loop body.
>>>>>>>
>>>>>>> Add *_mutable() variants for list and hlist iteration.  The new helpers
>>>>>>> support both forms: callers may keep passing an explicit temporary cursor
>>>>>>> when they need to inspect or reset it, or omit it and let the helper use
>>>>>>> a unique internal cursor.  
>>>>>>
>>>>>> I'm not really sure 'mutable' means anything either.
>>>>>> It is possible to make it valid for the loop body (or even other threads)
>>>>>> to delete arbitrary list items - but that needs significant extra overheads.
>>>>>>
>>>>>> It might be worth doing something that doesn't need the extra variable,
>>>>>> but there is little point doing all the churn just to rename things.
>>>>>>  
>>>>>>>
>>>>>>> This makes call sites that only mutate the list through the current entry
>>>>>>> less noisy, while keeping the existing *_safe() helpers available for
>>>>>>> compatibility.
>>>>>>>
>>>>>>> Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
>>>>>>> ---
>>>>>>>  include/linux/list.h | 269 +++++++++++++++++++++++++++++++++++++------
>>>>>>>  1 file changed, 231 insertions(+), 38 deletions(-)
>>>>>>>
>>>>>>> diff --git a/include/linux/list.h b/include/linux/list.h
>>>>>>> index 09d979976b3b..1081def7cea9 100644
>>>>>>> --- a/include/linux/list.h
>>>>>>> +++ b/include/linux/list.h
>>>>>>> @@ -7,6 +7,7 @@
>>>>>>>  #include <linux/stddef.h>
>>>>>>>  #include <linux/poison.h>
>>>>>>>  #include <linux/const.h>
>>>>>>> +#include <linux/args.h>
>>>>>>>  
>>>>>>>  #include <asm/barrier.h>
>>>>>>>  
>>>>>>> @@ -763,28 +764,72 @@ static inline void list_splice_tail_init(struct list_head *list,
>>>>>>>  #define list_for_each_prev(pos, head) \
>>>>>>>  	for (pos = (head)->prev; !list_is_head(pos, (head)); pos = pos->prev)
>>>>>>>  
>>>>>>> -/**
>>>>>>> - * list_for_each_safe - iterate over a list safe against removal of list entry
>>>>>>> - * @pos:	the &struct list_head to use as a loop cursor.
>>>>>>> - * @n:		another &struct list_head to use as temporary storage
>>>>>>> - * @head:	the head for your list.
>>>>>>> +/*
>>>>>>> + * list_for_each_safe is an old interface, use list_for_each_mutable instead.
>>>>>>>   */
>>>>>>>  #define list_for_each_safe(pos, n, head) \
>>>>>>>  	for (pos = (head)->next, n = pos->next; \
>>>>>>>  	     !list_is_head(pos, (head)); \
>>>>>>>  	     pos = n, n = pos->next)
>>>>>>>  
>>>>>>> +#define __list_for_each_mutable_internal(pos, tmp, head)		\
>>>>>>> +	for (typeof(pos) tmp = (pos = (head)->next)->next;		\  
>>>>>>
>>>>>> Use auto
>>>>>>  
>>>>>>> +	     !list_is_head(pos, (head));				\
>>>>>>> +	     pos = tmp, tmp = pos->next)
>>>>>>> +
>>>>>>> +#define __list_for_each_mutable1(pos, head)				\
>>>>>>> +	__list_for_each_mutable_internal(pos, __UNIQUE_ID(next), head)
>>>>>>> +
>>>>>>> +#define __list_for_each_mutable2(pos, next, head)			\
>>>>>>> +	list_for_each_safe(pos, next, head)
>>>>>>> +
>>>>>>>  /**
>>>>>>> - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
>>>>>>> + * list_for_each_mutable - iterate over a list safe against entry removal
>>>>>>>   * @pos:	the &struct list_head to use as a loop cursor.
>>>>>>> - * @n:		another &struct list_head to use as temporary storage
>>>>>>> - * @head:	the head for your list.
>>>>>>> + * @...:	either (head) or (next, head)
>>>>>>> + *
>>>>>>> + * next:	another &struct list_head to use as optional temporary storage.
>>>>>>> + *		The temporary cursor is internal unless explicitly supplied by
>>>>>>> + *		the caller.
>>>>>>> + * head:	the head for your list.
>>>>>>> + */
>>>>>>> +#define list_for_each_mutable(pos, ...)					\
>>>>>>> +	CONCATENATE(__list_for_each_mutable, COUNT_ARGS(__VA_ARGS__))	\
>>>>>>> +		(pos, __VA_ARGS__)  
>>>>>>
>>>>>> The variable argument count logic really just slows down compilation.
>>>>>> Maybe there aren't enough copies of this code to make that significant.
>>>>>> But just because you can do it doesn't mean it is a gooD idea.
>>>>>> I'm also not sure it really adds anything to the readability.
>>>>>>
>>>>>> And, it you are going to make the middle argument optional there is
>>>>>> no need to change the macro name.  
>>>>>
>>>>> Christian König and Jani Nikula also disagree with the variadic-argument
>>>>> implementation approach. If we abandon that method, it means we will
>>>>> inevitably need to add some new macros. If mutable is not a good name,
>>>>> suggestions for better alternatives would be welcome; coming up with a
>>>>> suitable name is indeed rather tricky.  
>>>>
>>>> I don't think you need to add a new macro for the specific use case that people want to modify the next element of the iteration.
>>>>
>>>> If I remember your numbers correctly that is a really corner case and keeping using the existing *_safe() macros for that sounds perfectly fine to me.
>>>
>>> IIRC currently you have a choice of either:
>>> 	define               Item that can't be deleted
>>> 	list_for_each()	     The current item.
>>> 	list_for_each_safe() The next item.
>>> There is also likely to be code that updates the variables to allow
>>> for other scenarios.
>>>
>>> Note that if increase a reference count and release a lock then list_for_each()
>>> is likely safer than list_for_each_safe() :-)
>>>
>>> list.h has 9 variants of the 'safe' loop.
>>> The bloat of another 9 is getting excessive.
>>>
>>> It has to be said that this is one of my least favourite type of list...
>>
>> Hi Christian König, David Laight, Jani Nikula, David Hildenbrand,
>> Andy Shevchenko, Alexei Starovoitov
>>
>> For ease of discussion, I need to summarize the currently possible
>> approaches and briefly describe their respective pros and cons,
>> using the list_for_each_entry* interfaces as examples.
>>
>> 1. Add list_for_each_entry_mutable, while keeping list_for_each_entry
>> and list_for_each_entry_safe unchanged. list_for_each_entry_mutable
>> would be used specifically for safe deletion scenarios that do not
>> need to expose the temporary cursor externally. The code can refer to
>> the v1 version.
>>
>> Pros: Does not depend on immediate per-subsystem adaptation and can be
>>       merged directly.
>> Cons: Requires adding a whole set of mutable interfaces, which makes the
>>       code somewhat redundant.
> 
> Seems fine, and the original _safe naming is ambiguous anyway.
> 
>> 2. Directly optimize away the temporary cursor in list_for_each_entry_safe
>> and define it inside the loop instead, changing the interface from four
>> arguments to three.
>>
>> Pros: Does not add redundant interfaces.
>> Cons: (1) Users need to manually update special cases that use the
>>       traversal variable of list_for_each_entry_safe, the new
>>       list_for_each_entry_safe would no longer apply there and would
>>       need to be open-coded.
>>       (2) Because the macro arguments changes, all list_for_each_entry_safe
>>       callers would need to be modified and merged together, making it
>>       difficult to merge such a large amount of code at once.
> 
> This won't fly because there are literally thousands of
> list_for_each_entry_safe() users.
> 
>> 3. Use a variadic macro approach to optimize list_for_each_entry_safe,
>> so that it supports both three and four arguments.
>>
>> Pros: (1) Does not add redundant interfaces.
>>       (2) Does not depend on immediate per-subsystem adaptation and can
>>       be merged directly.
>> Cons: (1) Increases compile time.
>>       (2) Makes the interface harder for users to use.
> 
> Basically I'm against any variadic macro tricks where the optional
> argument is not the last argument. That's just way too surprising, and
> goes against common practice in just about all other languages.
> 
>> 4. Optimize list_for_each_entry by defining the temporary cursor internally,
>> making it compatible with the functionality of list_for_each_entry_safe.
>> The code can refer to the v2 version.
>>
>> Pros: (1) Does not add redundant interfaces.
>>       (2) The number of externally visible arguments of list_for_each_entry
>>       remains unchanged, still three.
>> Cons: (1) list_for_each_entry and list_for_each_entry_safe would be merged
>>       into one, and list_for_each_entry_safe would gradually be deprecated.
>>       (2) Users need to manually update special cases that use the traversal
>>       variable of list_for_each_entry, the new list_for_each_entry would no
>>       longer apply there and would need to be open-coded. There are 15 such
>>       cases in total.
> 
> This sounds good to me, though I take it there's some code size increase
> and/or performance penalty?
> 
> Maybe the 15 cases are questionable anyway?
> 
>> 5. Use a variadic macro approach to optimize list_for_each_entry, so that
>> it supports both three and four arguments.
>>
>> Pros: (1) Does not add redundant interfaces.
>>       (2) Does not depend on immediate per-subsystem adaptation and can be
>>       merged directly.
>> Cons: (1) Increases compile time.
>>       (2) list_for_each_entry and list_for_each_entry_safe would be merged
>>       into one, and list_for_each_entry_safe would gradually be deprecated.
> 
> Please don't do the macro tricks.
> 
>> 6. Make no changes, keep the current logic unchanged, and close the current
>> email discussion.
> 
> I like hiding the temporary stuff when possible.
> 
> BR,
> Jani.

Hi all,
If there are no objections, I will make the changes using the first approach.


Hi David Laight,
You previously expressed a different opinion. Do you have any further comments
on the current proposed approach?

-- 
Thanks
Kaitao Cheng


^ permalink raw reply

* Re: [PATCH v2 3/6] firmware: qcom: scm: Add support for setting Bluetooth power modes
From: Konrad Dybcio @ 2026-07-01 10:40 UTC (permalink / raw)
  To: george.moussalem, Jens Axboe, Ulf Hansson, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Johannes Berg, Jeff Johnson,
	Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
	Balakrishna Godavarthi, Rocky Liao, Saravana Kannan, Andrew Lunn,
	Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Bjorn Andersson,
	Konrad Dybcio, Mathieu Poirier, Philipp Zabel
  Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
	ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <20260629-ipq5018-bluetooth-v2-3-02770f03b6bb@outlook.com>

On 6/29/26 3:01 PM, George Moussalem via B4 Relay wrote:
> From: George Moussalem <george.moussalem@outlook.com>
> 
> The Bluetooth subsystem (BTSS) on the IPQ5018 SoC supports setting power
> modes which are required to be configured through a Secure Channel
> Manager (SCM) call to TrustZone. However, not all Trusted Execution
> Environment (QSEE) images support this call, so first check if the call
> is available.
> 
> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
> ---

I'm amazed changing this setting is a secure operation

[...]

> +/**
> + * qcom_scm_pas_set_bluetooth_power_mode() - Configure power optimization mode
> + *					     for the Bluetooth subsystem (BTSS)
> + * @pas_id:	peripheral authentication service id
> + * @val:	0x0 for normal operation, 0x4 for ECO mode

If there's just two values, maybe we should make this take a `bool eco_mode`?

> + *
> + * Return: 0 on success, negative errno on failure.
> + * Returns -EOPNOTSUPP if the firmware configuration call is unavailable.
> + */
> +int qcom_scm_pas_set_bluetooth_power_mode(u32 pas_id, u32 val)
> +{
> +	if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
> +					  QCOM_SCM_PIL_PAS_BT_PWR_MODE))
> +		return -EOPNOTSUPP;
> +
> +	return __qcom_scm_pas_set_bluetooth_power_mode(pas_id, val);

Let's just inline the whole definition here - it's single-use anyway

Konrad

^ permalink raw reply

* Re: [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops
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
In-Reply-To: <20260701000949.1666714-18-joannelkoong@gmail.com>

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

* Re: [PATCH v2 2/6] Bluetooth: btqca: Add IPQ5018 support
From: Bartosz Golaszewski @ 2026-07-01  9:59 UTC (permalink / raw)
  To: george.moussalem
  Cc: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
	Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
	Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
	Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
	Mathieu Poirier, Philipp Zabel, George Moussalem via B4 Relay,
	linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
	ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <20260629-ipq5018-bluetooth-v2-2-02770f03b6bb@outlook.com>

On Mon, 29 Jun 2026 15:01:45 +0200, George Moussalem via B4 Relay
<devnull+george.moussalem.outlook.com@kernel.org> said:
> From: George Moussalem <george.moussalem@outlook.com>
>
> Add the IPQ5018 SoC type and support for loading its firmware.
>
> The firmware tested has been taken from GPL sources of various router
> boards. Firmware files needed are:
> - qca/bt_fw_patch.mbn
> - qca/mpnv10.bin
>
> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
> ---

Acked-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>

^ permalink raw reply

* Re: [PATCH v2 3/6] firmware: qcom: scm: Add support for setting Bluetooth power modes
From: Bartosz Golaszewski @ 2026-07-01  9:58 UTC (permalink / raw)
  To: george.moussalem
  Cc: George Moussalem via B4 Relay, linux-block, linux-kernel,
	linux-mmc, devicetree, linux-wireless, ath10k, linux-arm-msm,
	linux-bluetooth, netdev, linux-remoteproc, Jens Axboe,
	Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Johannes Berg, Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
	Saravana Kannan, Andrew Lunn, Heiner Kallweit, Russell King,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Bjorn Andersson, Konrad Dybcio, Mathieu Poirier,
	Philipp Zabel
In-Reply-To: <20260629-ipq5018-bluetooth-v2-3-02770f03b6bb@outlook.com>

On Mon, 29 Jun 2026 15:01:46 +0200, George Moussalem via B4 Relay
<devnull+george.moussalem.outlook.com@kernel.org> said:
> From: George Moussalem <george.moussalem@outlook.com>
>
> The Bluetooth subsystem (BTSS) on the IPQ5018 SoC supports setting power
> modes which are required to be configured through a Secure Channel
> Manager (SCM) call to TrustZone. However, not all Trusted Execution
> Environment (QSEE) images support this call, so first check if the call
> is available.
>
> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
> ---

Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>

^ permalink raw reply

* Re: Re: [PATCH] mempool: optimize mempool resizing
From: Vitaly Wool @ 2026-07-01  9:03 UTC (permalink / raw)
  To: Andrew Morton, Jens Axboe, Damien Le Moal, Keith Busch,
	Christoph Hellwig
  Cc: Sagi Grimberg, Vlastimil Babka, Harry Yoo, Hao Li,
	Christoph Lameter, David Rientjes, Roman Gushchin, linux-block,
	linux-nvme, linux-mm, Vitaly Wool
In-Reply-To: <20260625131738.b7c10540e5c598cc9b60e19d@linux-foundation.org>

Hello Andrew,


On Thursday, June 25, 2026 at 10:17:38 pm +02:00, Andrew Morton <akpm@linux-foundation.org> wrote:
> > On Thu, 25 Jun 2026 21:49:15 +0200 Vitaly Wool <vitaly.wool@konsulko.se> wrote:
> > 
> > From: Vitaly Vul <vitaly.vul@partner.samsung.com>
> > 
> > Resizing mempool to a bigger size currently requires a new allocation and a
> > data copy to a new larger elements array which doesn't go well with the
> > idea of having a fast and deadlock free memory allocations during exreme VM
> > load.
> >
> > This patch introduces a new parameter max_nr for a part of the mempool API,
> > which denotes the maximum size of the pool. With it in place we can avoid
> > any allocations in mempool_resize() since we can either grant the resizing
> > request or reject it basing on thr maximum allowed size of the elements
> > array. For those few users of the mempool API that actually use
> > mempool_resize() it is a clear upgrade because the maximum number of
> > elements is known upfront.
> >
> > Derivative APIs (like mempool_init_kmalloc_pool()) are mostly left intact,
> > substituted by the new mempool_init_kmalloc_resizable_pool() API where the
> > pool is actually meant to be resizable.
> 
> Thanks.
> 
> It would be helpful to have a description of what inspired this work.
> Presumably there is some observed problem in nvme or in zone-blockdev
> use? Can you please describe the problems and also describe what
> effect the patch had upon them?

We are using mempool for a variable number of large buffers, the maximal size of the pool is always known. However, as these buffers are large, we don't want to waste too much memory on a saturated full sized pool.

Besides, it takes a lot of time (seconds!) to saturate such a pool and we would absolutely love to avoid that.

Basing on the above, one can conclude that we're using mempool_resize() quite often. And for that to be efficient, we need to know if we can grow the pool  without having to re-allocate the elements array and copy the data. 

Since all the existing users of mempool_resize() actually know the maximum pool size for their respective cases, the easiest way to implement this is to introduce the hard maximum, and that is what this patch is doing.

<snip>
> Seems strange to return -EINVAL if new_min_nr is too low, but -ENOSPC
> if it is too large.
> 
> Also, (pet peeve), ENOSPC means "No space left on device". If this
> errno ever makes it back to userspace, the operator will be running
> `df' and wondering what the heck happened.

Hmm, I see your point. Let's go with -EiNVAL in both cases.

> Also, AI review had things to say:
> https://sashiko.dev/#/patchset/20260625194915.387663-1-vitaly.wool@konsulko.se

Sashiko is doing a great job indeed. My 2c on that:

1. mempool_create() should create pools with max_nr = max(min_nr*2, 1); and this will be fixed in the next version of the patch.
2. There were no forward-progress guarantees during pool growth in mempool_resize(), this patch just makes things simpler and more obvious.
3. pool->min_nr update will be fixed in the next version of the patch.

Thanks,
Vitaly

^ permalink raw reply

* [PATCH v2] block: avoid potential deadlock on zone revalidation failure
From: Damien Le Moal @ 2026-07-01  8:21 UTC (permalink / raw)
  To: Jens Axboe, linux-block; +Cc: Christoph Hellwig

If revalidating the zones of a zoned block device with
blk_revalidate_disk_zones() fails during a SCSI disk rescan, the following
lockdep splat is thrown:

[  347.251859] [  T11230] sda: failed to revalidate zones

[  347.261380] [  T11230] ======================================================
[  347.263882] [  T11230] WARNING: possible circular locking dependency detected
[  347.266353] [  T11230] 7.1.0+ #1194 Not tainted
[  347.268052] [  T11230] ------------------------------------------------------
[  347.270537] [  T11230] tcsh/11230 is trying to acquire lock:
[  347.272555] [  T11230] ffffffff8f91d400 (wq_pool_mutex){+.+.}-{4:4}, at: destroy_workqueue+0x15d/0x8d0
[  347.275914] [  T11230]
                          but task is already holding lock:
[  347.278646] [  T11230] ffff88812fa1bcc0 (&q->q_usage_counter(io)#5){++++}-{0:0}, at: blk_mq_freeze_queue_nomemsave+0x16/0x30
[  347.282503] [  T11230]
                          which lock already depends on the new lock.

[  347.286239] [  T11230]
                          the existing dependency chain (in reverse order) is:
[  347.289408] [  T11230]
                          -> #2 (&q->q_usage_counter(io)#5){++++}-{0:0}:
[  347.292437] [  T11230]        blk_alloc_queue+0x5ca/0x750
[  347.294379] [  T11230]        blk_mq_alloc_queue+0x14c/0x240
[  347.296375] [  T11230]        scsi_alloc_sdev+0x871/0xd10 [scsi_mod]
[  347.298619] [  T11230]        scsi_probe_and_add_lun+0x600/0xc50 [scsi_mod]
[  347.301056] [  T11230]        __scsi_scan_target+0x187/0x3b0 [scsi_mod]
[  347.303385] [  T11230]        scsi_scan_channel+0xf2/0x180 [scsi_mod]
[  347.305651] [  T11230]        scsi_scan_host_selected+0x20b/0x2d0 [scsi_mod]
[  347.308119] [  T11230]        do_scan_async+0x42/0x420 [scsi_mod]
[  347.310276] [  T11230]        async_run_entry_fn+0x94/0x5a0
[  347.312284] [  T11230]        process_one_work+0x8da/0x1690
[  347.314287] [  T11230]        worker_thread+0x5fe/0x1010
[  347.316216] [  T11230]        kthread+0x358/0x450
[  347.317675] [  T11230]        ret_from_fork+0x5b9/0x8e0
[  347.319181] [  T11230]        ret_from_fork_asm+0x11/0x20
[  347.320778] [  T11230]
                          -> #1 (fs_reclaim){+.+.}-{0:0}:
[  347.322890] [  T11230]        fs_reclaim_acquire+0xd5/0x120
[  347.324464] [  T11230]        __kmalloc_cache_node_noprof+0x39/0x620
[  347.326223] [  T11230]        init_rescuer+0x19b/0x560
[  347.327697] [  T11230]        workqueue_init+0x33b/0x6a0
[  347.329224] [  T11230]        kernel_init_freeable+0x2eb/0x600
[  347.330881] [  T11230]        kernel_init+0x1c/0x140
[  347.332334] [  T11230]        ret_from_fork+0x5b9/0x8e0
[  347.333847] [  T11230]        ret_from_fork_asm+0x11/0x20
[  347.335360] [  T11230]
                          -> #0 (wq_pool_mutex){+.+.}-{4:4}:
[  347.337510] [  T11230]        __lock_acquire+0xdea/0x2260
[  347.339030] [  T11230]        lock_acquire+0x187/0x2f0
[  347.340495] [  T11230]        __mutex_lock+0x1ab/0x2600
[  347.341464] [  T11230]        destroy_workqueue+0x15d/0x8d0
[  347.342485] [  T11230]        disk_free_zone_resources+0xd5/0x560
[  347.343577] [  T11230]        blk_revalidate_disk_zones+0x620/0xac7
[  347.344723] [  T11230]        sd_zbc_revalidate_zones+0x1dd/0x790 [sd_mod]
[  347.345938] [  T11230]        sd_revalidate_disk+0xc66/0x8e60 [sd_mod]
[  347.347112] [  T11230]        scsi_rescan_device+0x1f9/0x310 [scsi_mod]
[  347.348318] [  T11230]        store_rescan_field+0x19/0x20 [scsi_mod]
[  347.349507] [  T11230]        kernfs_fop_write_iter+0x3d2/0x5e0
[  347.350565] [  T11230]        vfs_write+0x469/0x1000
[  347.351484] [  T11230]        ksys_write+0x116/0x250
[  347.352403] [  T11230]        do_syscall_64+0xf0/0x6e0
[  347.353361] [  T11230]        entry_SYSCALL_64_after_hwframe+0x4b/0x53
[  347.354533] [  T11230]
                          other info that might help us debug this:

[  347.356432] [  T11230] Chain exists of:
                            wq_pool_mutex --> fs_reclaim --> &q->q_usage_counter(io)#5

[  347.358919] [  T11230]  Possible unsafe locking scenario:

[  347.360307] [  T11230]        CPU0                    CPU1
[  347.361327] [  T11230]        ----                    ----
[  347.362340] [  T11230]   lock(&q->q_usage_counter(io)#5);
[  347.363344] [  T11230]                                lock(fs_reclaim);
[  347.364526] [  T11230]                                lock(&q->q_usage_counter(io)#5);
[  347.365968] [  T11230]   lock(wq_pool_mutex);
[  347.366811] [  T11230]
                           *** DEADLOCK ***

This happens because SCSI disk rescan is executed from a work context
and a failure of blk_revalidate_disk_zones() causes a call to
disk_free_zone_resources() which will free the disk zone write plug
workqueue.

Avoid this by delaying the destruction of the disk zone write plug
workqueue to disk_release(). Do this by introducing the function
disk_release_zone_resources() and using this new function from
disk_release(). This new function destroys the zone write plugs workqueue
and calls disk_free_zone_resources(), thus allowing to remove the call to
destroy_workqueue() from disk_free_zone_resources().
disk_alloc_zone_resources() is modified to not create the disk zone
write plug work queue if it already exists.

Fixes: a8f59e5a5dea ("block: use a per disk workqueue for zone write plugging")
Cc: stable@vger.kernek.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
---
Changes from v1:
 - Added missing drain_workqueue() call in disk_free_zone_resources() to
   ensure that we have no work in it before destroying the hash table.
 - Added review tags

 block/blk-zoned.c | 42 ++++++++++++++++++++++++++++--------------
 block/blk.h       |  4 ++--
 block/genhd.c     |  2 +-
 3 files changed, 31 insertions(+), 17 deletions(-)

diff --git a/block/blk-zoned.c b/block/blk-zoned.c
index bea817f3de56..ca30caec838e 100644
--- a/block/blk-zoned.c
+++ b/block/blk-zoned.c
@@ -1923,11 +1923,20 @@ static int disk_alloc_zone_resources(struct gendisk *disk,
 	if (!disk->zone_wplugs_pool)
 		goto free_hash;
 
-	disk->zone_wplugs_wq =
-		alloc_workqueue("%s_zwplugs", WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU,
-				pool_size, disk->disk_name);
-	if (!disk->zone_wplugs_wq)
-		goto destroy_pool;
+	/*
+	 * We may already have a zone write plug workqueue as this function may
+	 * be called after disk_free_zone_resources(), which does not destroy
+	 * the workqueue (the zone write plugs workqueue is destroyed at
+	 * disk_release() time).
+	 */
+	if (!disk->zone_wplugs_wq) {
+		disk->zone_wplugs_wq =
+			alloc_workqueue("%s_zwplugs",
+					WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU,
+					pool_size, disk->disk_name);
+		if (!disk->zone_wplugs_wq)
+			goto destroy_pool;
+	}
 
 	disk->zone_wplugs_worker =
 		kthread_create(disk_zone_wplugs_worker, disk,
@@ -1935,15 +1944,12 @@ static int disk_alloc_zone_resources(struct gendisk *disk,
 	if (IS_ERR(disk->zone_wplugs_worker)) {
 		ret = PTR_ERR(disk->zone_wplugs_worker);
 		disk->zone_wplugs_worker = NULL;
-		goto destroy_wq;
+		goto destroy_pool;
 	}
 	wake_up_process(disk->zone_wplugs_worker);
 
 	return 0;
 
-destroy_wq:
-	destroy_workqueue(disk->zone_wplugs_wq);
-	disk->zone_wplugs_wq = NULL;
 destroy_pool:
 	mempool_destroy(disk->zone_wplugs_pool);
 	disk->zone_wplugs_pool = NULL;
@@ -1999,7 +2005,7 @@ static void disk_set_zones_cond_array(struct gendisk *disk, u8 *zones_cond)
 	kfree_rcu_mightsleep(zones_cond);
 }
 
-void disk_free_zone_resources(struct gendisk *disk)
+static void disk_free_zone_resources(struct gendisk *disk)
 {
 	if (disk->zone_wplugs_worker) {
 		kthread_stop(disk->zone_wplugs_worker);
@@ -2007,10 +2013,8 @@ void disk_free_zone_resources(struct gendisk *disk)
 	}
 	WARN_ON_ONCE(!list_empty(&disk->zone_wplugs_list));
 
-	if (disk->zone_wplugs_wq) {
-		destroy_workqueue(disk->zone_wplugs_wq);
-		disk->zone_wplugs_wq = NULL;
-	}
+	if (disk->zone_wplugs_wq)
+		drain_workqueue(disk->zone_wplugs_wq);
 
 	disk_destroy_zone_wplugs_hash_table(disk);
 
@@ -2020,6 +2024,16 @@ void disk_free_zone_resources(struct gendisk *disk)
 	disk->nr_zones = 0;
 }
 
+void disk_release_zone_resources(struct gendisk *disk)
+{
+	if (disk->zone_wplugs_wq) {
+		destroy_workqueue(disk->zone_wplugs_wq);
+		disk->zone_wplugs_wq = NULL;
+	}
+
+	disk_free_zone_resources(disk);
+}
+
 struct blk_revalidate_zone_args {
 	struct gendisk	*disk;
 	u8		*zones_cond;
diff --git a/block/blk.h b/block/blk.h
index 25af8ac5ef0f..fb95d3c58950 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -528,7 +528,7 @@ static inline void ioc_clear_queue(struct request_queue *q)
 
 #ifdef CONFIG_BLK_DEV_ZONED
 void disk_init_zone_resources(struct gendisk *disk);
-void disk_free_zone_resources(struct gendisk *disk);
+void disk_release_zone_resources(struct gendisk *disk);
 static inline bool bio_zone_write_plugging(struct bio *bio)
 {
 	return bio_flagged(bio, BIO_ZONE_WRITE_PLUGGING);
@@ -581,7 +581,7 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, blk_mode_t mode,
 static inline void disk_init_zone_resources(struct gendisk *disk)
 {
 }
-static inline void disk_free_zone_resources(struct gendisk *disk)
+static inline void disk_release_zone_resources(struct gendisk *disk)
 {
 }
 static inline bool bio_zone_write_plugging(struct bio *bio)
diff --git a/block/genhd.c b/block/genhd.c
index f84b6a355b57..30ac0ffe6517 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1300,7 +1300,7 @@ static void disk_release(struct device *dev)
 
 	disk_release_events(disk);
 	kfree(disk->random);
-	disk_free_zone_resources(disk);
+	disk_release_zone_resources(disk);
 	xa_destroy(&disk->part_tbl);
 
 	kobject_put(&disk->queue_kobj);
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH v5 0/5] crypto: skcipher - multi-data-unit dispatch as a template
From: Eric Biggers @ 2026-07-01  7:19 UTC (permalink / raw)
  To: Leonid Ravich
  Cc: linux-crypto, dm-devel, linux-block, linux-kernel, herbert, davem,
	snitzer, mpatocka, axboe
In-Reply-To: <20260630083431.2772-1-lravich@amazon.com>

On Tue, Jun 30, 2026 at 08:34:26AM +0000, Leonid Ravich wrote:
> This is v5. It reworks the multi-data-unit support from the in-core
> auto-splitter of v4 into a crypto template, dun(...), addressing the v4
> review: there is now no added cost on the core skcipher path, no
> per-algorithm capability flag, and the per-data-unit split lives in an
> algorithm rather than in crypto_skcipher_encrypt/decrypt the shape
> Herbert suggested, which removes the "overhead for everyone" Eric
> objected to.

No, this didn't address my feedback.  It moved things around but still
adds additional overhead for everyone to support an out-of-tree driver,
which also hasn't been shown to be any better than just using the CPU.

- Eric

^ permalink raw reply

* [PATCH v5 5/5] blk-crypto: fallback - batch a segment's data units via dun()
From: Leonid Ravich @ 2026-07-01  6:53 UTC (permalink / raw)
  To: linux-crypto, dm-devel
  Cc: linux-block, linux-kernel, herbert, davem, ebiggers, snitzer,
	mpatocka, axboe
In-Reply-To: <20260630083431.2772-1-lravich@amazon.com>

blk-crypto-fallback open-codes a per-data-unit loop, issuing one
skcipher request per data unit with the IV walked as a DUN counter.
Allocate dun(<cipher>,le) instead of the bare cipher so a contiguous bio
segment is encrypted/decrypted as one multi-data-unit request, the
crypto layer walking the per-unit IV.  Every blk-crypto mode feeds the
DUN as a little-endian counter, and dun() handles any counter width up
to 32 bytes, so all modes -- including Adiantum (32-byte IV) -- are
wrapped and the open-coded inner per-unit loop is removed from both the
encrypt and decrypt paths.  This makes blk-crypto-fallback a second
consumer of the template (after dm-crypt) and lets a higher-priority
hardware dun(...) driver, if present, handle the request in one pass.

Output is unchanged: the template's little-endian per-unit counter is
exactly blk_crypto_dun_to_iv()/bio_crypt_dun_increment().

Signed-off-by: Leonid Ravich <lravich@amazon.com>
---
 block/Kconfig               |  1 +
 block/blk-crypto-fallback.c | 74 ++++++++++++++++++-------------------
 2 files changed, 36 insertions(+), 39 deletions(-)

diff --git a/block/Kconfig b/block/Kconfig
index 15027963472d..0c9025f9b0f6 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -204,6 +204,7 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
 	depends on BLK_INLINE_ENCRYPTION
 	select CRYPTO
 	select CRYPTO_SKCIPHER
+	select CRYPTO_DUN # batches a segment's data units per crypto request
 	help
 	  Enabling this lets the block layer handle inline encryption
 	  by falling back to the kernel crypto API when inline
diff --git a/block/blk-crypto-fallback.c b/block/blk-crypto-fallback.c
index 61f595410832..8337d56ba1dc 100644
--- a/block/blk-crypto-fallback.c
+++ b/block/blk-crypto-fallback.c
@@ -250,7 +250,6 @@ static void __blk_crypto_fallback_encrypt_bio(struct bio *src_bio,
 	unsigned int nr_enc_pages, enc_idx;
 	struct page **enc_pages;
 	struct bio *enc_bio;
-	unsigned int i;
 
 	skcipher_request_set_callback(ciph_req,
 			CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
@@ -260,9 +259,6 @@ static void __blk_crypto_fallback_encrypt_bio(struct bio *src_bio,
 	sg_init_table(&src, 1);
 	sg_init_table(&dst, 1);
 
-	skcipher_request_set_crypt(ciph_req, &src, &dst, data_unit_size,
-				   iv.bytes);
-
 	/*
 	 * Encrypt each page in the source bio.  Because the source bio could
 	 * have bio_vecs that span more than a single page, but the encrypted
@@ -287,29 +283,26 @@ static void __blk_crypto_fallback_encrypt_bio(struct bio *src_bio,
 		__bio_add_page(enc_bio, enc_page, src_bv.bv_len,
 				src_bv.bv_offset);
 
-		sg_set_page(&src, src_bv.bv_page, data_unit_size,
-			    src_bv.bv_offset);
-		sg_set_page(&dst, enc_page, data_unit_size, src_bv.bv_offset);
-
 		/*
 		 * Increment the index now that the encrypted page is added to
 		 * the bio.  This is important for the error unwind path.
 		 */
 		enc_idx++;
 
-		/*
-		 * Encrypt each data unit in this page.
-		 */
-		for (i = 0; i < src_bv.bv_len; i += data_unit_size) {
-			blk_crypto_dun_to_iv(curr_dun, &iv);
-			if (crypto_skcipher_encrypt(ciph_req)) {
-				enc_bio->bi_status = BLK_STS_IOERR;
-				goto out_free_enc_bio;
-			}
-			bio_crypt_dun_increment(curr_dun, 1);
-			src.offset += data_unit_size;
-			dst.offset += data_unit_size;
+		/* Encrypt the whole segment as one multi-data-unit request. */
+		blk_crypto_dun_to_iv(curr_dun, &iv);
+		sg_set_page(&src, src_bv.bv_page, src_bv.bv_len,
+			    src_bv.bv_offset);
+		sg_set_page(&dst, enc_page, src_bv.bv_len, src_bv.bv_offset);
+		skcipher_request_set_crypt(ciph_req, &src, &dst, src_bv.bv_len,
+					   iv.bytes);
+		skcipher_request_set_data_unit_size(ciph_req, data_unit_size);
+		if (crypto_skcipher_encrypt(ciph_req)) {
+			enc_bio->bi_status = BLK_STS_IOERR;
+			goto out_free_enc_bio;
 		}
+		bio_crypt_dun_increment(curr_dun,
+					src_bv.bv_len / data_unit_size);
 
 		bio_advance_iter_single(src_bio, &src_bio->bi_iter,
 				src_bv.bv_len);
@@ -380,7 +373,6 @@ static blk_status_t __blk_crypto_fallback_decrypt_bio(struct bio *bio,
 	struct scatterlist sg;
 	struct bio_vec bv;
 	const int data_unit_size = bc->bc_key->crypto_cfg.data_unit_size;
-	unsigned int i;
 
 	skcipher_request_set_callback(ciph_req,
 			CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
@@ -388,26 +380,20 @@ static blk_status_t __blk_crypto_fallback_decrypt_bio(struct bio *bio,
 
 	memcpy(curr_dun, bc->bc_dun, sizeof(curr_dun));
 	sg_init_table(&sg, 1);
-	skcipher_request_set_crypt(ciph_req, &sg, &sg, data_unit_size,
-				   iv.bytes);
 
-	/* Decrypt each segment in the bio */
+	/* One dun() request per segment; the crypto layer walks the per-unit DUN. */
 	__bio_for_each_segment(bv, bio, iter, iter) {
-		struct page *page = bv.bv_page;
-
 		if (!IS_ALIGNED(bv.bv_len | bv.bv_offset, data_unit_size))
 			return BLK_STS_INVAL;
 
-		sg_set_page(&sg, page, data_unit_size, bv.bv_offset);
-
-		/* Decrypt each data unit in the segment */
-		for (i = 0; i < bv.bv_len; i += data_unit_size) {
-			blk_crypto_dun_to_iv(curr_dun, &iv);
-			if (crypto_skcipher_decrypt(ciph_req))
-				return BLK_STS_IOERR;
-			bio_crypt_dun_increment(curr_dun, 1);
-			sg.offset += data_unit_size;
-		}
+		blk_crypto_dun_to_iv(curr_dun, &iv);
+		sg_set_page(&sg, bv.bv_page, bv.bv_len, bv.bv_offset);
+		skcipher_request_set_crypt(ciph_req, &sg, &sg, bv.bv_len,
+					   iv.bytes);
+		skcipher_request_set_data_unit_size(ciph_req, data_unit_size);
+		if (crypto_skcipher_decrypt(ciph_req))
+			return BLK_STS_IOERR;
+		bio_crypt_dun_increment(curr_dun, bv.bv_len / data_unit_size);
 	}
 
 	return BLK_STS_OK;
@@ -621,6 +607,7 @@ static int blk_crypto_fallback_init(void)
 int blk_crypto_fallback_start_using_mode(enum blk_crypto_mode_num mode_num)
 {
 	const char *cipher_str = blk_crypto_modes[mode_num].cipher_str;
+	char dun_str[CRYPTO_MAX_ALG_NAME];
 	struct blk_crypto_fallback_keyslot *slotp;
 	unsigned int i;
 	int err = 0;
@@ -641,15 +628,24 @@ int blk_crypto_fallback_start_using_mode(enum blk_crypto_mode_num mode_num)
 	if (err)
 		goto out;
 
+	/*
+	 * Wrap in dun() to handle a whole segment per request (a higher-priority
+	 * hardware dun() wins if present).  The blk-crypto DUN is little-endian.
+	 */
+	if (snprintf(dun_str, sizeof(dun_str), "dun(%s,le)", cipher_str) >=
+	    (int)sizeof(dun_str)) {
+		err = -EINVAL;
+		goto out;
+	}
+
 	for (i = 0; i < blk_crypto_num_keyslots; i++) {
 		slotp = &blk_crypto_keyslots[i];
-		slotp->tfms[mode_num] = crypto_alloc_sync_skcipher(cipher_str,
-				0, 0);
+		slotp->tfms[mode_num] = crypto_alloc_sync_skcipher(dun_str, 0, 0);
 		if (IS_ERR(slotp->tfms[mode_num])) {
 			err = PTR_ERR(slotp->tfms[mode_num]);
 			if (err == -ENOENT) {
 				pr_warn_once("Missing crypto API support for \"%s\"\n",
-					     cipher_str);
+					     dun_str);
 				err = -ENOPKG;
 			}
 			slotp->tfms[mode_num] = NULL;
-- 
2.47.3


^ permalink raw reply related

* Re: [PATCH] block: avoid potential deadlock on zone revalidation failure
From: Hannes Reinecke @ 2026-07-01  6:52 UTC (permalink / raw)
  To: Damien Le Moal, Jens Axboe, linux-block; +Cc: Christoph Hellwig
In-Reply-To: <20260625062824.2013244-1-dlemoal@kernel.org>

On 6/25/26 8:28 AM, Damien Le Moal wrote:
> If revalidating the zones of a zoned block device with
> blk_revalidate_disk_zones() fails during a SCSI disk rescan, the following
> lockdep splat is thrown:
> 
> [  347.251859] [  T11230] sda: failed to revalidate zones
> 
> [  347.261380] [  T11230] ======================================================
> [  347.263882] [  T11230] WARNING: possible circular locking dependency detected
> [  347.266353] [  T11230] 7.1.0+ #1194 Not tainted
> [  347.268052] [  T11230] ------------------------------------------------------
> [  347.270537] [  T11230] tcsh/11230 is trying to acquire lock:
> [  347.272555] [  T11230] ffffffff8f91d400 (wq_pool_mutex){+.+.}-{4:4}, at: destroy_workqueue+0x15d/0x8d0
> [  347.275914] [  T11230]
>                            but task is already holding lock:
> [  347.278646] [  T11230] ffff88812fa1bcc0 (&q->q_usage_counter(io)#5){++++}-{0:0}, at: blk_mq_freeze_queue_nomemsave+0x16/0x30
> [  347.282503] [  T11230]
>                            which lock already depends on the new lock.
> 
> [  347.286239] [  T11230]
>                            the existing dependency chain (in reverse order) is:
> [  347.289408] [  T11230]
>                            -> #2 (&q->q_usage_counter(io)#5){++++}-{0:0}:
> [  347.292437] [  T11230]        blk_alloc_queue+0x5ca/0x750
> [  347.294379] [  T11230]        blk_mq_alloc_queue+0x14c/0x240
> [  347.296375] [  T11230]        scsi_alloc_sdev+0x871/0xd10 [scsi_mod]
> [  347.298619] [  T11230]        scsi_probe_and_add_lun+0x600/0xc50 [scsi_mod]
> [  347.301056] [  T11230]        __scsi_scan_target+0x187/0x3b0 [scsi_mod]
> [  347.303385] [  T11230]        scsi_scan_channel+0xf2/0x180 [scsi_mod]
> [  347.305651] [  T11230]        scsi_scan_host_selected+0x20b/0x2d0 [scsi_mod]
> [  347.308119] [  T11230]        do_scan_async+0x42/0x420 [scsi_mod]
> [  347.310276] [  T11230]        async_run_entry_fn+0x94/0x5a0
> [  347.312284] [  T11230]        process_one_work+0x8da/0x1690
> [  347.314287] [  T11230]        worker_thread+0x5fe/0x1010
> [  347.316216] [  T11230]        kthread+0x358/0x450
> [  347.317675] [  T11230]        ret_from_fork+0x5b9/0x8e0
> [  347.319181] [  T11230]        ret_from_fork_asm+0x11/0x20
> [  347.320778] [  T11230]
>                            -> #1 (fs_reclaim){+.+.}-{0:0}:
> [  347.322890] [  T11230]        fs_reclaim_acquire+0xd5/0x120
> [  347.324464] [  T11230]        __kmalloc_cache_node_noprof+0x39/0x620
> [  347.326223] [  T11230]        init_rescuer+0x19b/0x560
> [  347.327697] [  T11230]        workqueue_init+0x33b/0x6a0
> [  347.329224] [  T11230]        kernel_init_freeable+0x2eb/0x600
> [  347.330881] [  T11230]        kernel_init+0x1c/0x140
> [  347.332334] [  T11230]        ret_from_fork+0x5b9/0x8e0
> [  347.333847] [  T11230]        ret_from_fork_asm+0x11/0x20
> [  347.335360] [  T11230]
>                            -> #0 (wq_pool_mutex){+.+.}-{4:4}:
> [  347.337510] [  T11230]        __lock_acquire+0xdea/0x2260
> [  347.339030] [  T11230]        lock_acquire+0x187/0x2f0
> [  347.340495] [  T11230]        __mutex_lock+0x1ab/0x2600
> [  347.341464] [  T11230]        destroy_workqueue+0x15d/0x8d0
> [  347.342485] [  T11230]        disk_free_zone_resources+0xd5/0x560
> [  347.343577] [  T11230]        blk_revalidate_disk_zones+0x620/0xac7
> [  347.344723] [  T11230]        sd_zbc_revalidate_zones+0x1dd/0x790 [sd_mod]
> [  347.345938] [  T11230]        sd_revalidate_disk+0xc66/0x8e60 [sd_mod]
> [  347.347112] [  T11230]        scsi_rescan_device+0x1f9/0x310 [scsi_mod]
> [  347.348318] [  T11230]        store_rescan_field+0x19/0x20 [scsi_mod]
> [  347.349507] [  T11230]        kernfs_fop_write_iter+0x3d2/0x5e0
> [  347.350565] [  T11230]        vfs_write+0x469/0x1000
> [  347.351484] [  T11230]        ksys_write+0x116/0x250
> [  347.352403] [  T11230]        do_syscall_64+0xf0/0x6e0
> [  347.353361] [  T11230]        entry_SYSCALL_64_after_hwframe+0x4b/0x53
> [  347.354533] [  T11230]
>                            other info that might help us debug this:
> 
> [  347.356432] [  T11230] Chain exists of:
>                              wq_pool_mutex --> fs_reclaim --> &q->q_usage_counter(io)#5
> 
> [  347.358919] [  T11230]  Possible unsafe locking scenario:
> 
> [  347.360307] [  T11230]        CPU0                    CPU1
> [  347.361327] [  T11230]        ----                    ----
> [  347.362340] [  T11230]   lock(&q->q_usage_counter(io)#5);
> [  347.363344] [  T11230]                                lock(fs_reclaim);
> [  347.364526] [  T11230]                                lock(&q->q_usage_counter(io)#5);
> [  347.365968] [  T11230]   lock(wq_pool_mutex);
> [  347.366811] [  T11230]
>                             *** DEADLOCK ***
> 
> This happens because SCSI disk rescan is executed from a work context
> and a failure of blk_revalidate_disk_zones() causes a call to
> disk_free_zone_resources() which will free the disk zone write plug
> workqueue.
> 
> Avoid this by delaying the destruction of the disk zone write plug
> workqueue to disk_release(). Do this by introducing the function
> disk_release_zone_resources() and using this new function from
> disk_release(). This new function calls disk_free_zone_resources() and
> destroys the zone write plugs workqueue, thus allowing to remove the
> call to destroy_workqueue() from disk_free_zone_resources().
> disk_alloc_zone_resources() is modified to not create the disk zone
> write plug work queue if it already exists.
> 
> Fixes: a8f59e5a5dea ("block: use a per disk workqueue for zone write plugging")
> Cc: stable@vger.kernek.org
> Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
> ---
>   block/blk-zoned.c | 40 +++++++++++++++++++++++++---------------
>   block/blk.h       |  4 ++--
>   block/genhd.c     |  2 +-
>   3 files changed, 28 insertions(+), 18 deletions(-)
> 
> diff --git a/block/blk-zoned.c b/block/blk-zoned.c
> index bea817f3de56..133600ebe05c 100644
> --- a/block/blk-zoned.c
> +++ b/block/blk-zoned.c
> @@ -1923,11 +1923,20 @@ static int disk_alloc_zone_resources(struct gendisk *disk,
>   	if (!disk->zone_wplugs_pool)
>   		goto free_hash;
>   
> -	disk->zone_wplugs_wq =
> -		alloc_workqueue("%s_zwplugs", WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU,
> -				pool_size, disk->disk_name);
> -	if (!disk->zone_wplugs_wq)
> -		goto destroy_pool;
> +	/*
> +	 * We may already have a zone write plug workqueue as this function may
> +	 * be called after disk_free_zone_resources(), which does not destroy
> +	 * the workqueue (the zone write plugs workqueue is destroyed at
> +	 * disk_release() time).
> +	 */
> +	if (!disk->zone_wplugs_wq) {
> +		disk->zone_wplugs_wq =
> +			alloc_workqueue("%s_zwplugs",
> +					WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU,
> +					pool_size, disk->disk_name);
> +		if (!disk->zone_wplugs_wq)
> +			goto destroy_pool;
> +	}
>   
>   	disk->zone_wplugs_worker =
>   		kthread_create(disk_zone_wplugs_worker, disk,
> @@ -1935,15 +1944,12 @@ static int disk_alloc_zone_resources(struct gendisk *disk,
>   	if (IS_ERR(disk->zone_wplugs_worker)) {
>   		ret = PTR_ERR(disk->zone_wplugs_worker);
>   		disk->zone_wplugs_worker = NULL;
> -		goto destroy_wq;
> +		goto destroy_pool;
>   	}
>   	wake_up_process(disk->zone_wplugs_worker);
>   
>   	return 0;
>   
> -destroy_wq:
> -	destroy_workqueue(disk->zone_wplugs_wq);
> -	disk->zone_wplugs_wq = NULL;
>   destroy_pool:
>   	mempool_destroy(disk->zone_wplugs_pool);
>   	disk->zone_wplugs_pool = NULL;
> @@ -1999,7 +2005,7 @@ static void disk_set_zones_cond_array(struct gendisk *disk, u8 *zones_cond)
>   	kfree_rcu_mightsleep(zones_cond);
>   }
>   
> -void disk_free_zone_resources(struct gendisk *disk)
> +static void disk_free_zone_resources(struct gendisk *disk)
>   {
>   	if (disk->zone_wplugs_worker) {
>   		kthread_stop(disk->zone_wplugs_worker);
> @@ -2007,11 +2013,6 @@ void disk_free_zone_resources(struct gendisk *disk)
>   	}
>   	WARN_ON_ONCE(!list_empty(&disk->zone_wplugs_list));
>   
> -	if (disk->zone_wplugs_wq) {
> -		destroy_workqueue(disk->zone_wplugs_wq);
> -		disk->zone_wplugs_wq = NULL;
> -	}
> -
>   	disk_destroy_zone_wplugs_hash_table(disk);
>   
>   	disk_set_zones_cond_array(disk, NULL);
> @@ -2020,6 +2021,15 @@ void disk_free_zone_resources(struct gendisk *disk)
>   	disk->nr_zones = 0;
>   }
>   
> +void disk_release_zone_resources(struct gendisk *disk)
> +{
> +	disk_free_zone_resources(disk);
> +	if (disk->zone_wplugs_wq) {
> +		destroy_workqueue(disk->zone_wplugs_wq);
> +		disk->zone_wplugs_wq = NULL;
> +	}
> +}
> +
>   struct blk_revalidate_zone_args {
>   	struct gendisk	*disk;
>   	u8		*zones_cond;
> diff --git a/block/blk.h b/block/blk.h
> index 25af8ac5ef0f..fb95d3c58950 100644
> --- a/block/blk.h
> +++ b/block/blk.h
> @@ -528,7 +528,7 @@ static inline void ioc_clear_queue(struct request_queue *q)
>   
>   #ifdef CONFIG_BLK_DEV_ZONED
>   void disk_init_zone_resources(struct gendisk *disk);
> -void disk_free_zone_resources(struct gendisk *disk);
> +void disk_release_zone_resources(struct gendisk *disk);
>   static inline bool bio_zone_write_plugging(struct bio *bio)
>   {
>   	return bio_flagged(bio, BIO_ZONE_WRITE_PLUGGING);
> @@ -581,7 +581,7 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, blk_mode_t mode,
>   static inline void disk_init_zone_resources(struct gendisk *disk)
>   {
>   }
> -static inline void disk_free_zone_resources(struct gendisk *disk)
> +static inline void disk_release_zone_resources(struct gendisk *disk)
>   {
>   }
>   static inline bool bio_zone_write_plugging(struct bio *bio)
> diff --git a/block/genhd.c b/block/genhd.c
> index f84b6a355b57..30ac0ffe6517 100644
> --- a/block/genhd.c
> +++ b/block/genhd.c
> @@ -1300,7 +1300,7 @@ static void disk_release(struct device *dev)
>   
>   	disk_release_events(disk);
>   	kfree(disk->random);
> -	disk_free_zone_resources(disk);
> +	disk_release_zone_resources(disk);
>   	xa_destroy(&disk->part_tbl);
>   
>   	kobject_put(&disk->queue_kobj);

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.de                                +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply

* Re: [PATCH v2 10/18] block: convert iomap ops to ->iomap_next()
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
In-Reply-To: <20260701000949.1666714-11-joannelkoong@gmail.com>

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

* [PATCH v2 17/18] iomap: pass iomap_next_fn directly instead of struct iomap_ops
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
In-Reply-To: <20260701000949.1666714-1-joannelkoong@gmail.com>

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


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