Add a write_end operation to struct iomap_ops to provide a way of overriding the default behavior of iomap_write_end. This will be used for implementing data journaling in gfs2: in the data journaling case, pages are written into the journal before being written back to their proper on-disk locations. Signed-off-by: Andreas Gruenbacher <agruenba@xxxxxxxxxx> --- fs/ext2/inode.c | 1 + fs/ext4/inode.c | 1 + fs/iomap.c | 53 +++++++++++++++++++++++++++++++------------ fs/xfs/xfs_iomap.c | 1 + include/linux/iomap.h | 12 ++++++++++ 5 files changed, 53 insertions(+), 15 deletions(-) diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 71635909df3b..2744bf15b74b 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -848,6 +848,7 @@ ext2_iomap_end(struct inode *inode, loff_t offset, loff_t length, const struct iomap_ops ext2_iomap_ops = { .iomap_begin = ext2_iomap_begin, + .write_end = iomap_write_end, .iomap_end = ext2_iomap_end, }; #else diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 1e50c5efae67..16dd1b4cc9f9 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3604,6 +3604,7 @@ static int ext4_iomap_end(struct inode *inode, loff_t offset, loff_t length, const struct iomap_ops ext4_iomap_ops = { .iomap_begin = ext4_iomap_begin, + .write_end = iomap_write_end, .iomap_end = ext4_iomap_end, }; diff --git a/fs/iomap.c b/fs/iomap.c index 857c4b7b54eb..8f7dca17300d 100644 --- a/fs/iomap.c +++ b/fs/iomap.c @@ -178,7 +178,7 @@ iomap_write_begin(struct inode *inode, loff_t pos, unsigned len, unsigned flags, return status; } -static int +int iomap_write_end(struct inode *inode, loff_t pos, unsigned len, unsigned copied, struct page *page, struct iomap *iomap) { @@ -197,12 +197,19 @@ iomap_write_end(struct inode *inode, loff_t pos, unsigned len, iomap_write_failed(inode, pos, len); return ret; } +EXPORT_SYMBOL_GPL(iomap_write_end); + +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 +254,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, + status = args->ops->write_end(inode, pos, bytes, copied, page, iomap); if (unlikely(status < 0)) break; @@ -285,10 +292,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 +330,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; @@ -335,14 +347,14 @@ iomap_dirty_actor(struct inode *inode, loff_t pos, loff_t length, void *data, return PTR_ERR(rpage); status = iomap_write_begin(inode, pos, bytes, - AOP_FLAG_NOFS, &page, iomap); + AOP_FLAG_NOFS, &page, iomap); put_page(rpage); if (unlikely(status)) return status; WARN_ON_ONCE(!PageUptodate(page)); - status = iomap_write_end(inode, pos, bytes, bytes, page, iomap); + status = ops->write_end(inode, pos, bytes, bytes, page, iomap); if (unlikely(status <= 0)) { if (WARN_ON_ONCE(status == 0)) return -EIO; @@ -368,7 +380,7 @@ 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, + ret = iomap_apply(inode, pos, len, IOMAP_WRITE, ops, (void *)ops, iomap_dirty_actor); if (ret <= 0) return ret; @@ -381,20 +393,21 @@ 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; status = iomap_write_begin(inode, pos, bytes, AOP_FLAG_NOFS, &page, - iomap); + iomap); if (status) return status; zero_user(page, offset, bytes); mark_page_accessed(page); - return iomap_write_end(inode, pos, bytes, bytes, page, iomap); + return ops->write_end(inode, pos, bytes, bytes, page, iomap); } static int iomap_dax_zero(loff_t pos, unsigned offset, unsigned bytes, @@ -407,11 +420,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 +446,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, + (void *)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 +465,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/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 046469fcc1b8..6b817b83a078 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -1199,6 +1199,7 @@ xfs_file_iomap_end( const struct iomap_ops xfs_iomap_ops = { .iomap_begin = xfs_file_iomap_begin, + .write_end = iomap_write_end, .iomap_end = xfs_file_iomap_end, }; diff --git a/include/linux/iomap.h b/include/linux/iomap.h index c61113c71a60..8cd67afe78d7 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -62,6 +62,8 @@ struct iomap { #define IOMAP_DIRECT (1 << 4) /* direct I/O */ #define IOMAP_NOWAIT (1 << 5) /* Don't wait for writeback */ +struct page; + struct iomap_ops { /* * Return the existing mapping at pos, or reserve space starting at @@ -71,6 +73,13 @@ struct iomap_ops { int (*iomap_begin)(struct inode *inode, loff_t pos, loff_t length, unsigned flags, struct iomap *iomap); + /* + * End writing to a page. Usually initialized to iomap_write_end. + */ + int (*write_end)(struct inode *inode, loff_t pos, unsigned len, + 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 @@ -81,6 +90,9 @@ struct iomap_ops { ssize_t written, unsigned flags, struct iomap *iomap); }; +int iomap_write_end(struct inode *inode, loff_t pos, unsigned len, + unsigned copied, struct page *page, struct iomap *iomap); + ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from, const struct iomap_ops *ops); int iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len, -- 2.17.0