Add a page_write_end hook called when done writing to a page, for filesystems that implement data journaling: in that case, pages are written to the journal before being written back to their proper on-disk locations. The new hook is bypassed for IOMAP_INLINE mappings. Signed-off-by: Andreas Gruenbacher <agruenba@xxxxxxxxxx> --- fs/iomap.c | 58 ++++++++++++++++++++++++++++++++----------- include/linux/iomap.h | 8 ++++++ 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/fs/iomap.c b/fs/iomap.c index 48cd67227811..3b34c957d2fd 100644 --- a/fs/iomap.c +++ b/fs/iomap.c @@ -181,16 +181,22 @@ iomap_write_begin(struct inode *inode, loff_t pos, unsigned len, unsigned flags, static int iomap_write_end(struct inode *inode, loff_t pos, unsigned len, - unsigned copied, struct page *page, struct iomap *iomap) + unsigned copied, struct page *page, struct iomap *iomap, + const struct iomap_ops *ops) { + typeof(ops->page_write_end) page_write_end = ops->page_write_end; int ret; if (iomap->type == IOMAP_INLINE) { iomap_write_inline_data(inode, page, iomap, pos, copied); __generic_write_end(inode, pos, copied, page); + if (page_write_end) + page_write_end(inode, pos, copied, page, iomap); return copied; } + if (page_write_end) + page_write_end(inode, pos, copied, page, iomap); ret = generic_write_end(NULL, inode->i_mapping, pos, len, copied, page, NULL); if (ret < len) @@ -198,11 +204,17 @@ iomap_write_end(struct inode *inode, loff_t pos, unsigned len, return ret; } +struct iomap_write_args { + const struct iomap_ops *ops; + struct iov_iter *iter; +}; + static loff_t iomap_write_actor(struct inode *inode, loff_t pos, loff_t length, void *data, struct iomap *iomap) { - struct iov_iter *i = data; + struct iomap_write_args *args = data; + struct iov_iter *i = args->iter; long status = 0; ssize_t written = 0; unsigned int flags = AOP_FLAG_NOFS; @@ -248,7 +260,7 @@ iomap_write_actor(struct inode *inode, loff_t pos, loff_t length, void *data, flush_dcache_page(page); status = iomap_write_end(inode, pos, bytes, copied, page, - iomap); + iomap, args->ops); if (unlikely(status < 0)) break; copied = status; @@ -285,10 +297,14 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *iter, { struct inode *inode = iocb->ki_filp->f_mapping->host; loff_t pos = iocb->ki_pos, ret = 0, written = 0; + struct iomap_write_args args = { + .ops = ops, + .iter = iter, + }; while (iov_iter_count(iter)) { ret = iomap_apply(inode, pos, iov_iter_count(iter), - IOMAP_WRITE, ops, iter, iomap_write_actor); + IOMAP_WRITE, ops, &args, iomap_write_actor); if (ret <= 0) break; pos += ret; @@ -319,6 +335,7 @@ static loff_t iomap_dirty_actor(struct inode *inode, loff_t pos, loff_t length, void *data, struct iomap *iomap) { + const struct iomap_ops *ops = data; long status = 0; ssize_t written = 0; @@ -342,7 +359,8 @@ iomap_dirty_actor(struct inode *inode, loff_t pos, loff_t length, void *data, WARN_ON_ONCE(!PageUptodate(page)); - status = iomap_write_end(inode, pos, bytes, bytes, page, iomap); + status = iomap_write_end(inode, pos, bytes, bytes, page, iomap, + ops); if (unlikely(status <= 0)) { if (WARN_ON_ONCE(status == 0)) return -EIO; @@ -368,8 +386,8 @@ iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len, loff_t ret; while (len) { - ret = iomap_apply(inode, pos, len, IOMAP_WRITE, ops, NULL, - iomap_dirty_actor); + ret = iomap_apply(inode, pos, len, IOMAP_WRITE, ops, + (void *)ops, iomap_dirty_actor); if (ret <= 0) return ret; pos += ret; @@ -381,7 +399,8 @@ iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len, EXPORT_SYMBOL_GPL(iomap_file_dirty); static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset, - unsigned bytes, struct iomap *iomap) + unsigned bytes, const struct iomap_ops *ops, + struct iomap *iomap) { struct page *page; int status; @@ -394,7 +413,8 @@ static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset, zero_user(page, offset, bytes); mark_page_accessed(page); - return iomap_write_end(inode, pos, bytes, bytes, page, iomap); + return iomap_write_end(inode, pos, bytes, bytes, page, iomap, + ops); } static int iomap_dax_zero(loff_t pos, unsigned offset, unsigned bytes, @@ -407,11 +427,16 @@ static int iomap_dax_zero(loff_t pos, unsigned offset, unsigned bytes, offset, bytes); } +struct iomap_zero_range_args { + const struct iomap_ops *ops; + bool *did_zero; +}; + static loff_t iomap_zero_range_actor(struct inode *inode, loff_t pos, loff_t count, void *data, struct iomap *iomap) { - bool *did_zero = data; + struct iomap_zero_range_args *args = data; loff_t written = 0; int status; @@ -428,15 +453,16 @@ iomap_zero_range_actor(struct inode *inode, loff_t pos, loff_t count, if (IS_DAX(inode)) status = iomap_dax_zero(pos, offset, bytes, iomap); else - status = iomap_zero(inode, pos, offset, bytes, iomap); + status = iomap_zero(inode, pos, offset, bytes, + args->ops, iomap); if (status < 0) return status; pos += bytes; count -= bytes; written += bytes; - if (did_zero) - *did_zero = true; + if (args->did_zero) + *args->did_zero = true; } while (count > 0); return written; @@ -446,11 +472,15 @@ int iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero, const struct iomap_ops *ops) { + struct iomap_zero_range_args args = { + .ops = ops, + .did_zero = did_zero, + }; loff_t ret; while (len > 0) { ret = iomap_apply(inode, pos, len, IOMAP_ZERO, - ops, did_zero, iomap_zero_range_actor); + ops, &args, iomap_zero_range_actor); if (ret <= 0) return ret; diff --git a/include/linux/iomap.h b/include/linux/iomap.h index c61113c71a60..ac7f1b2c1cbe 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -8,6 +8,7 @@ struct fiemap_extent_info; struct inode; struct iov_iter; struct kiocb; +struct page; struct vm_area_struct; struct vm_fault; @@ -71,6 +72,13 @@ struct iomap_ops { int (*iomap_begin)(struct inode *inode, loff_t pos, loff_t length, unsigned flags, struct iomap *iomap); + /* + * Called when done writing to a page (optional; skipped for + * IOMAP_INLINE mappings). + */ + void (*page_write_end)(struct inode *inode, loff_t pos, unsigned copied, + struct page *page, struct iomap *iomap); + /* * Commit and/or unreserve space previous allocated using iomap_begin. * Written indicates the length of the successful write operation which -- 2.17.0