summaryrefslogtreecommitdiff
path: root/include/linux/iomap.h
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2025-02-06 13:02:22 +0100
committerChristian Brauner <brauner@kernel.org>2025-02-06 13:02:22 +0100
commitf87897339a4cbf8bd27c731b18787db4131c9077 (patch)
treedc82544d310148ae44bf30d3a977c975601d747c /include/linux/iomap.h
parent2014c95afecee3e76ca4a56956a936e23283f05b (diff)
parentddd402bbbf669c4ada106fd2e4c799e2b5745e3e (diff)
Merge patch series "iomap: allow the file system to submit the writeback bios"
Christoph Hellwig <hch@lst.de> says: This series contains the iomap prep work to support zoned XFS. The biggest changes are: - an option to reuse the ioend code for direct writes in addition to the current use for buffered writeback, which allows the file system to track completions on a per-bio basis instead of the current end_io callback which operates on the entire I/O. Note that it might make sense to split the ioend code from buffered-io.c into its own file with this. Let me know what you think of that and I can include it in the next version - change of the writeback_ops so that the submit_bio call can be done by the file system. Note that btrfs will also need this eventually when it starts using iomap - helpers to split ioend to the zone append queue_limits that plug into the previous item above. - a new ANON_WRITE flags for writes that don't have a block number assigned to them at the iomap level, leaving the file system to do that work in the submission handler. Note that btrfs wants something similar also for compressed I/O, which should be able to reuse this, maybe with minor tweaks. - passing private data to a few more helper The XFS changes to use this will be posted to the xfs list only to not spam fsdevel too much. * patches from https://lore.kernel.org/r/20250206064035.2323428-2-hch@lst.de: iomap: pass private data to iomap_truncate_page iomap: pass private data to iomap_zero_range iomap: pass private data to iomap_page_mkwrite iomap: add a io_private field to struct iomap_ioend iomap: optionally use ioends for direct I/O iomap: factor out a iomap_dio_done helper iomap: move common ioend code to ioend.c iomap: split bios to zone append limits in the submission handlers iomap: add a IOMAP_F_ANON_WRITE flag iomap: simplify io_flags and io_type in struct iomap_ioend iomap: allow the file system to submit the writeback bios Link: https://lore.kernel.org/r/20250206064035.2323428-2-hch@lst.de Signed-off-by: Christian Brauner <brauner@kernel.org>
Diffstat (limited to 'include/linux/iomap.h')
-rw-r--r--include/linux/iomap.h66
1 files changed, 53 insertions, 13 deletions
diff --git a/include/linux/iomap.h b/include/linux/iomap.h
index 75bf54e76f3b..022d7f338c68 100644
--- a/include/linux/iomap.h
+++ b/include/linux/iomap.h
@@ -56,6 +56,10 @@ struct vm_fault;
*
* IOMAP_F_BOUNDARY indicates that I/O and I/O completions for this iomap must
* never be merged with the mapping before it.
+ *
+ * IOMAP_F_ANON_WRITE indicates that (write) I/O does not have a target block
+ * assigned to it yet and the file system will do that in the bio submission
+ * handler, splitting the I/O as needed.
*/
#define IOMAP_F_NEW (1U << 0)
#define IOMAP_F_DIRTY (1U << 1)
@@ -68,6 +72,7 @@ struct vm_fault;
#endif /* CONFIG_BUFFER_HEAD */
#define IOMAP_F_XATTR (1U << 5)
#define IOMAP_F_BOUNDARY (1U << 6)
+#define IOMAP_F_ANON_WRITE (1U << 7)
/*
* Flags set by the core iomap code during operations:
@@ -111,6 +116,8 @@ struct iomap {
static inline sector_t iomap_sector(const struct iomap *iomap, loff_t pos)
{
+ if (iomap->flags & IOMAP_F_ANON_WRITE)
+ return U64_MAX; /* invalid */
return (iomap->addr + pos - iomap->offset) >> SECTOR_SHIFT;
}
@@ -306,12 +313,11 @@ 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);
int iomap_zero_range(struct inode *inode, loff_t pos, loff_t len,
- bool *did_zero, const struct iomap_ops *ops);
+ bool *did_zero, const struct iomap_ops *ops, void *private);
int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
- const struct iomap_ops *ops);
-vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf,
- const struct iomap_ops *ops);
-
+ const struct iomap_ops *ops, void *private);
+vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, const struct iomap_ops *ops,
+ void *private);
typedef void (*iomap_punch_t)(struct inode *inode, loff_t offset, loff_t length,
struct iomap *iomap);
void iomap_write_delalloc_release(struct inode *inode, loff_t start_byte,
@@ -328,16 +334,42 @@ sector_t iomap_bmap(struct address_space *mapping, sector_t bno,
const struct iomap_ops *ops);
/*
+ * Flags for iomap_ioend->io_flags.
+ */
+/* shared COW extent */
+#define IOMAP_IOEND_SHARED (1U << 0)
+/* unwritten extent */
+#define IOMAP_IOEND_UNWRITTEN (1U << 1)
+/* don't merge into previous ioend */
+#define IOMAP_IOEND_BOUNDARY (1U << 2)
+/* is direct I/O */
+#define IOMAP_IOEND_DIRECT (1U << 3)
+
+/*
+ * Flags that if set on either ioend prevent the merge of two ioends.
+ * (IOMAP_IOEND_BOUNDARY also prevents merges, but only one-way)
+ */
+#define IOMAP_IOEND_NOMERGE_FLAGS \
+ (IOMAP_IOEND_SHARED | IOMAP_IOEND_UNWRITTEN | IOMAP_IOEND_DIRECT)
+
+/*
* Structure for writeback I/O completions.
+ *
+ * File systems implementing ->submit_ioend (for buffered I/O) or ->submit_io
+ * for direct I/O) can split a bio generated by iomap. In that case the parent
+ * ioend it was split from is recorded in ioend->io_parent.
*/
struct iomap_ioend {
struct list_head io_list; /* next ioend in chain */
- u16 io_type;
- u16 io_flags; /* IOMAP_F_* */
+ u16 io_flags; /* IOMAP_IOEND_* */
struct inode *io_inode; /* file being written to */
- size_t io_size; /* size of data within eof */
+ size_t io_size; /* size of the extent */
+ atomic_t io_remaining; /* completetion defer count */
+ int io_error; /* stashed away status */
+ struct iomap_ioend *io_parent; /* parent for completions */
loff_t io_offset; /* offset in the file */
sector_t io_sector; /* start sector of ioend */
+ void *io_private; /* file system private data */
struct bio io_bio; /* MUST BE LAST! */
};
@@ -362,12 +394,14 @@ struct iomap_writeback_ops {
loff_t offset, unsigned len);
/*
- * Optional, allows the file systems to perform actions just before
- * submitting the bio and/or override the bio end_io handler for complex
- * operations like copy on write extent manipulation or unwritten extent
- * conversions.
+ * Optional, allows the file systems to hook into bio submission,
+ * including overriding the bi_end_io handler.
+ *
+ * Returns 0 if the bio was successfully submitted, or a negative
+ * error code if status was non-zero or another error happened and
+ * the bio could not be submitted.
*/
- int (*prepare_ioend)(struct iomap_ioend *ioend, int status);
+ int (*submit_ioend)(struct iomap_writepage_ctx *wpc, int status);
/*
* Optional, allows the file system to discard state on a page where
@@ -383,6 +417,10 @@ struct iomap_writepage_ctx {
u32 nr_folios; /* folios added to the ioend */
};
+struct iomap_ioend *iomap_init_ioend(struct inode *inode, struct bio *bio,
+ loff_t file_offset, u16 ioend_flags);
+struct iomap_ioend *iomap_split_ioend(struct iomap_ioend *ioend,
+ unsigned int max_len, bool is_append);
void iomap_finish_ioends(struct iomap_ioend *ioend, int error);
void iomap_ioend_try_merge(struct iomap_ioend *ioend,
struct list_head *more_ioends);
@@ -454,4 +492,6 @@ int iomap_swapfile_activate(struct swap_info_struct *sis,
# define iomap_swapfile_activate(sis, swapfile, pagespan, ops) (-EIO)
#endif /* CONFIG_SWAP */
+extern struct bio_set iomap_ioend_bioset;
+
#endif /* LINUX_IOMAP_H */