Add a read_folio_sync() handler for buffered writes that filesystems may pass in if they wish to provide a custom handler for synchronously reading in the contents of a folio. Signed-off-by: Joanne Koong <joannelkoong@xxxxxxxxx> --- .../filesystems/iomap/operations.rst | 7 +++++++ fs/iomap/buffered-io.c | 19 ++++++++++++++++--- include/linux/iomap.h | 11 +++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/Documentation/filesystems/iomap/operations.rst b/Documentation/filesystems/iomap/operations.rst index 3b628e370d88..9f0e8a46cc8c 100644 --- a/Documentation/filesystems/iomap/operations.rst +++ b/Documentation/filesystems/iomap/operations.rst @@ -72,6 +72,9 @@ default behaviors of iomap: void (*put_folio)(struct inode *inode, loff_t pos, unsigned copied, struct folio *folio); bool (*iomap_valid)(struct inode *inode, const struct iomap *iomap); + int (*read_folio_sync)(loff_t block_start, struct folio *folio, + size_t off, size_t len, + const struct iomap *iomap, void *private); }; iomap calls these functions: @@ -102,6 +105,10 @@ iomap calls these functions: <https://lore.kernel.org/all/20221123055812.747923-8-david@xxxxxxxxxxxxx/>`_ to allocate, install, and lock that folio. + - ``read_folio_sync``: Called to synchronously read in the range that will + be written to. If this function is not provided, iomap will default to + submitting a bio read request. + For the pagecache, races can happen if writeback doesn't take ``i_rwsem`` or ``invalidate_lock`` and updates mapping information. Races can also happen if the filesystem allows concurrent writes. diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c index 882e55a1d75c..7063a1132694 100644 --- a/fs/iomap/buffered-io.c +++ b/fs/iomap/buffered-io.c @@ -581,10 +581,23 @@ iomap_write_failed(struct inode *inode, loff_t pos, unsigned len) pos + len - 1); } +static int iomap_read_folio_sync(const struct iomap_iter *iter, + loff_t block_start, struct folio *folio, size_t poff, + size_t plen) +{ + const struct iomap_folio_ops *folio_ops = iter->iomap.folio_ops; + const struct iomap *srcmap = iomap_iter_srcmap(iter); + + if (folio_ops && folio_ops->read_folio_sync) + return folio_ops->read_folio_sync(block_start, folio, poff, + plen, srcmap, iter->private); + + return iomap_bio_read_folio_sync(block_start, folio, poff, plen, srcmap); +} + static int __iomap_write_begin(const struct iomap_iter *iter, size_t len, struct folio *folio) { - const struct iomap *srcmap = iomap_iter_srcmap(iter); struct iomap_folio_state *ifs; loff_t pos = iter->pos; loff_t block_size = i_blocksize(iter->inode); @@ -633,8 +646,8 @@ static int __iomap_write_begin(const struct iomap_iter *iter, size_t len, if (iter->flags & IOMAP_NOWAIT) return -EAGAIN; - status = iomap_bio_read_folio_sync(block_start, folio, - poff, plen, srcmap); + status = iomap_read_folio_sync(iter, block_start, folio, + poff, plen); if (status) return status; } diff --git a/include/linux/iomap.h b/include/linux/iomap.h index 522644d62f30..51cf3e863caf 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -174,6 +174,17 @@ struct iomap_folio_ops { * locked by the iomap code. */ bool (*iomap_valid)(struct inode *inode, const struct iomap *iomap); + + /* + * Optional if the filesystem wishes to provide a custom handler for + * reading in the contents of a folio, otherwise iomap will default to + * submitting a bio read request. + * + * The read must be done synchronously. + */ + int (*read_folio_sync)(loff_t block_start, struct folio *folio, + size_t off, size_t len, const struct iomap *iomap, + void *private); }; /* -- 2.47.1