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 | 56 ++++++++++++++++++++++++++++++++----------- include/linux/iomap.h | 8 +++++++ 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/fs/iomap.c b/fs/iomap.c index 8877a915a7e9..34ba1be1d600 100644 --- a/fs/iomap.c +++ b/fs/iomap.c @@ -180,7 +180,8 @@ 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) { int ret; @@ -190,6 +191,9 @@ iomap_write_end(struct inode *inode, loff_t pos, unsigned len, return copied; } + if (ops->page_write_end) + ops->page_write_end(inode, pos, copied, page); + ret = generic_write_end(NULL, inode->i_mapping, pos, len, copied, page, NULL); if (ret < len) @@ -197,11 +201,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; @@ -247,7 +257,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; @@ -284,10 +294,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; @@ -318,6 +332,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; @@ -341,7 +356,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; @@ -367,8 +383,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; @@ -380,7 +396,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; @@ -393,7 +410,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, @@ -406,11 +424,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; @@ -427,15 +450,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; @@ -445,11 +469,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..88ea8b970a95 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); + /* * Commit and/or unreserve space previous allocated using iomap_begin. * Written indicates the length of the successful write operation which -- 2.17.0