As part of the larger effort to have iomap buffered io code support generic io, replace submit_ioend() with writeback_complete() and move the bio ioend code into a helper function, iomap_bio_writeback_complete(), that callers using bios can directly invoke. No functional changes. Signed-off-by: Joanne Koong <joannelkoong@xxxxxxxxx> --- .../filesystems/iomap/operations.rst | 18 ++++---- fs/iomap/buffered-io-bio.c | 42 ++++++++++++++++++- fs/iomap/buffered-io.c | 38 +++-------------- fs/iomap/internal.h | 4 +- fs/xfs/xfs_aops.c | 14 ++++++- include/linux/iomap.h | 26 ++++++++---- 6 files changed, 88 insertions(+), 54 deletions(-) diff --git a/Documentation/filesystems/iomap/operations.rst b/Documentation/filesystems/iomap/operations.rst index 5d018d504145..47213c810622 100644 --- a/Documentation/filesystems/iomap/operations.rst +++ b/Documentation/filesystems/iomap/operations.rst @@ -291,7 +291,7 @@ The ``ops`` structure must be specified and is as follows: struct iomap_writeback_ops { int (*writeback_folio)(struct iomap_writeback_folio_range *ctx); - int (*submit_ioend)(struct iomap_writepage_ctx *wpc, int status); + int (*writeback_complete)(struct iomap_writepage_ctx *wpc, int status); void (*discard_folio)(struct folio *folio, loff_t pos); }; @@ -319,13 +319,15 @@ The fields are as follows: This function must be supplied by the filesystem. - - ``submit_ioend``: Allows the file systems to hook into writeback bio - submission. - This might include pre-write space accounting updates, or installing - a custom ``->bi_end_io`` function for internal purposes, such as - deferring the ioend completion to a workqueue to run metadata update - transactions from process context before submitting the bio. - This function is optional. + - ``writeback_complete``: Allows the file systems to execute any logic that + needs to happen after ``->writeback_folio`` has been called for all dirty + folios. This might include hooking into writeback bio submission for + pre-write space accounting updates, or installing a custom ``->bi_end_io`` + function for internal purposes, such as deferring the ioend completion to + a workqueue to run metadata update transactions from process context + before submitting the bio. + This function is optional. If this function is not provided, iomap will + default to ``iomap_bio_writeback_complete``. - ``discard_folio``: iomap calls this function after ``->writeback_folio`` fails to schedule I/O for any part of a dirty folio. diff --git a/fs/iomap/buffered-io-bio.c b/fs/iomap/buffered-io-bio.c index e052fc8b46c1..e9f26a938c8d 100644 --- a/fs/iomap/buffered-io-bio.c +++ b/fs/iomap/buffered-io-bio.c @@ -151,7 +151,7 @@ static void iomap_writepage_end_bio(struct bio *bio) iomap_finish_ioend_buffered(ioend); } -void iomap_bio_ioend_error(struct iomap_writepage_ctx *wpc, int error) +static void iomap_ioend_error(struct iomap_writepage_ctx *wpc, int error) { wpc->ioend->io_bio.bi_status = errno_to_blk_status(error); bio_endio(&wpc->ioend->io_bio); @@ -230,7 +230,7 @@ static int iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, if (!wpc->ioend || !iomap_can_add_to_ioend(wpc, pos, ioend_flags)) { new_ioend: - error = iomap_submit_ioend(wpc, 0); + error = iomap_writeback_complete(wpc, 0); if (error) return error; wpc->ioend = iomap_alloc_ioend(wpc, wbc, inode, pos, @@ -337,3 +337,41 @@ int iomap_bio_writeback_folio(struct iomap_writeback_folio_range *ctx, return error; } EXPORT_SYMBOL_GPL(iomap_bio_writeback_folio); + +/* + * Submit an ioend. + * + * If @error is non-zero, it means that we have a situation where some part of + * the submission process has failed after we've marked pages for writeback. + * We cannot cancel ioend directly in that case, so call the bio end I/O handler + * with the error status here to run the normal I/O completion handler to clear + * the writeback bit and let the file system proess the errors. + */ +int iomap_bio_writeback_complete(struct iomap_writepage_ctx *wpc, int error, + iomap_submit_ioend_t submit_ioend) +{ + if (!wpc->ioend) + return error; + + /* + * Let the file systems prepare the I/O submission and hook in an I/O + * comletion handler. This also needs to happen in case after a + * failure happened so that the file system end I/O handler gets called + * to clean up. + */ + if (submit_ioend) { + error = submit_ioend(wpc, error); + } else { + if (WARN_ON_ONCE(wpc->iomap.flags & IOMAP_F_ANON_WRITE)) + error = -EIO; + if (!error) + iomap_submit_bio(&wpc->ioend->io_bio); + } + + if (error) + iomap_ioend_error(wpc, error); + + wpc->ioend = NULL; + return error; +} +EXPORT_SYMBOL_GPL(iomap_bio_writeback_complete); diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c index 2b8d733f65da..bdf917ae56dc 100644 --- a/fs/iomap/buffered-io.c +++ b/fs/iomap/buffered-io.c @@ -1450,39 +1450,13 @@ vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, const struct iomap_ops *ops, } EXPORT_SYMBOL_GPL(iomap_page_mkwrite); -/* - * Submit an ioend. - * - * If @error is non-zero, it means that we have a situation where some part of - * the submission process has failed after we've marked pages for writeback. - * We cannot cancel ioend directly in that case, so call the bio end I/O handler - * with the error status here to run the normal I/O completion handler to clear - * the writeback bit and let the file system proess the errors. - */ -int iomap_submit_ioend(struct iomap_writepage_ctx *wpc, int error) +int iomap_writeback_complete(struct iomap_writepage_ctx *wpc, int error) { - if (!wpc->ioend) - return error; - - /* - * Let the file systems prepare the I/O submission and hook in an I/O - * comletion handler. This also needs to happen in case after a - * failure happened so that the file system end I/O handler gets called - * to clean up. - */ - if (wpc->ops->submit_ioend) { - error = wpc->ops->submit_ioend(wpc, error); - } else { - if (WARN_ON_ONCE(wpc->iomap.flags & IOMAP_F_ANON_WRITE)) - error = -EIO; - if (!error) - iomap_submit_bio(&wpc->ioend->io_bio); - } - - if (error) - iomap_bio_ioend_error(wpc, error); + if (wpc->ops->writeback_complete) + error = wpc->ops->writeback_complete(wpc, error); + else + error = iomap_bio_writeback_complete(wpc, error, NULL); - wpc->ioend = NULL; return error; } @@ -1661,6 +1635,6 @@ iomap_writepages(struct address_space *mapping, struct writeback_control *wbc, wpc->ops = ops; while ((folio = writeback_iter(mapping, wbc, folio, &error))) error = iomap_writepage_map(wpc, wbc, folio); - return iomap_submit_ioend(wpc, error); + return iomap_writeback_complete(wpc, error); } EXPORT_SYMBOL_GPL(iomap_writepages); diff --git a/fs/iomap/internal.h b/fs/iomap/internal.h index 6efb5905bf4f..bfd3f3be845a 100644 --- a/fs/iomap/internal.h +++ b/fs/iomap/internal.h @@ -32,7 +32,7 @@ u32 iomap_finish_ioend_buffered(struct iomap_ioend *ioend); u32 iomap_finish_ioend_direct(struct iomap_ioend *ioend); bool ifs_set_range_uptodate(struct folio *folio, struct iomap_folio_state *ifs, size_t off, size_t len); -int iomap_submit_ioend(struct iomap_writepage_ctx *wpc, int error); +int iomap_writeback_complete(struct iomap_writepage_ctx *wpc, int error); #ifdef CONFIG_BLOCK int iomap_bio_read_folio_sync(loff_t block_start, struct folio *folio, @@ -40,12 +40,10 @@ int iomap_bio_read_folio_sync(loff_t block_start, struct folio *folio, void iomap_bio_readpage(const struct iomap *iomap, loff_t pos, struct iomap_readpage_ctx *ctx, size_t poff, size_t plen, loff_t length); -void iomap_bio_ioend_error(struct iomap_writepage_ctx *wpc, int error); void iomap_submit_bio(struct bio *bio); #else #define iomap_bio_read_folio_sync(...) (-ENOSYS) #define iomap_bio_readpage(...) ((void)0) -#define iomap_bio_ioend_error(...) ((void)0) #define iomap_submit_bio(...) ((void)0) #endif /* CONFIG_BLOCK */ diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 8878c015bd48..63745ff68250 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -493,6 +493,11 @@ xfs_submit_ioend( return 0; } +static int xfs_writeback_complete(struct iomap_writepage_ctx *wpc, int error) +{ + return iomap_bio_writeback_complete(wpc, error, xfs_submit_ioend); +} + /* * If the folio has delalloc blocks on it, the caller is asking us to punch them * out. If we don't, we can leave a stale delalloc mapping covered by a clean @@ -532,7 +537,7 @@ xfs_discard_folio( static const struct iomap_writeback_ops xfs_writeback_ops = { .writeback_folio = xfs_writeback_folio, - .submit_ioend = xfs_submit_ioend, + .writeback_complete = xfs_writeback_complete, .discard_folio = xfs_discard_folio, }; @@ -630,9 +635,14 @@ xfs_zoned_submit_ioend( return 0; } +static int xfs_zoned_writeback_complete(struct iomap_writepage_ctx *wpc, int error) +{ + return iomap_bio_writeback_complete(wpc, error, xfs_zoned_submit_ioend); +} + static const struct iomap_writeback_ops xfs_zoned_writeback_ops = { .writeback_folio = xfs_zoned_writeback_folio, - .submit_ioend = xfs_zoned_submit_ioend, + .writeback_complete = xfs_zoned_writeback_complete, .discard_folio = xfs_discard_folio, }; diff --git a/include/linux/iomap.h b/include/linux/iomap.h index fe827948035d..f4350e59fe7e 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -437,14 +437,10 @@ struct iomap_writeback_ops { int (*writeback_folio)(struct iomap_writeback_folio_range *ctx); /* - * 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. + * Optional, allows the file system to call into this once + * ->writeback_folio() on all dirty ranges have been issued. */ - int (*submit_ioend)(struct iomap_writepage_ctx *wpc, int status); + int (*writeback_complete)(struct iomap_writepage_ctx *wpc, int status); /* * Optional, allows the file system to discard state on a page where @@ -563,4 +559,20 @@ typedef int iomap_map_blocks_t(struct iomap_writepage_ctx *wpc, int iomap_bio_writeback_folio(struct iomap_writeback_folio_range *ctx, iomap_map_blocks_t map_blocks); +#ifdef CONFIG_BLOCK +/* + * 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. + */ +typedef int iomap_submit_ioend_t(struct iomap_writepage_ctx *wpc, int error); +int iomap_bio_writeback_complete(struct iomap_writepage_ctx *wpc, int error, + iomap_submit_ioend_t submit_ioend); +#else +#define iomap_bio_writeback_complete(...) (-ENOSYS) +#endif /* CONFIG_BLOCK */ + #endif /* LINUX_IOMAP_H */ -- 2.47.1