diff mbox

[v7,07/12] iomap: Add page_write_end iomap hook

Message ID 20180604123729.23414-8-agruenba@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Andreas Gruenbacher June 4, 2018, 12:37 p.m. UTC
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@redhat.com>
---
 fs/iomap.c            | 56 ++++++++++++++++++++++++++++++++-----------
 include/linux/iomap.h |  8 +++++++
 2 files changed, 50 insertions(+), 14 deletions(-)

Comments

Christoph Hellwig June 4, 2018, 12:50 p.m. UTC | #1
On Mon, Jun 04, 2018 at 02:37:24PM +0200, Andreas Gruenbacher wrote:
> 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.

I'd rather not bypass it in common code.  Can you pass the iomap
to the callback and then do the bypass in gfs2 to keep it generic?
Andreas Grünbacher June 4, 2018, 4:40 p.m. UTC | #2
2018-06-04 14:50 GMT+02:00 Christoph Hellwig <hch@lst.de>:
> On Mon, Jun 04, 2018 at 02:37:24PM +0200, Andreas Gruenbacher wrote:
>> 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.
>
> I'd rather not bypass it in common code.  Can you pass the iomap
> to the callback and then do the bypass in gfs2 to keep it generic?

As you wish. You realize we're in extreme bike shed coloring land though, right?

Andreas
diff mbox

Patch

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