From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
To: linux-xfs@vger.kernel.org, linux-fsdevel@vger.kernel.org
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Subject: [PATCH 8/8] iomap: Add writethrough for O_SYNC
Date: Wed, 11 Aug 2021 03:46:47 +0100 [thread overview]
Message-ID: <20210811024647.3067739-9-willy@infradead.org> (raw)
In-Reply-To: <20210811024647.3067739-1-willy@infradead.org>
For O_SYNC writes, if the filesystem has already allocated blocks for
the range, we can avoid marking the page as dirty and skip straight to
marking the page as writeback.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
fs/iomap/buffered-io.c | 78 +++++++++++++++++++++++++++++++++++-------
1 file changed, 66 insertions(+), 12 deletions(-)
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index eb068e21d3bb..93b889338172 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -657,8 +657,45 @@ iomap_write_begin(struct inode *inode, loff_t pos, unsigned len, unsigned flags,
return status;
}
-static size_t __iomap_write_end(struct inode *inode, loff_t pos, size_t len,
- size_t copied, struct page *page)
+/* Rearrange file so we don't need this forward declaration */
+static struct iomap_ioend *iomap_add_to_ioend(struct inode *inode,
+ loff_t pos, size_t len, struct page *page,
+ struct iomap_page *iop, struct iomap *iomap,
+ struct iomap_ioend *ioend, struct writeback_control *wbc,
+ struct list_head *iolist);
+
+/* Returns true if we can skip dirtying the page */
+static bool iomap_write_through(struct iomap_write_ctx *iwc,
+ struct iomap *iomap, struct inode *inode, struct page *page,
+ loff_t pos, size_t len)
+{
+ unsigned int blksize = i_blocksize(inode);
+
+ if (!iwc || !iwc->write_through)
+ return false;
+ if (PageDirty(page))
+ return true;
+ if (PageWriteback(page))
+ return false;
+
+ /* Can't allocate blocks here because we don't have ->prepare_ioend */
+ if (iomap->type != IOMAP_MAPPED || iomap->type != IOMAP_UNWRITTEN ||
+ iomap->flags & IOMAP_F_SHARED)
+ return false;
+
+ len = round_up(pos + len - 1, blksize);
+ pos = round_down(pos, blksize);
+ len -= pos;
+ iwc->ioend = iomap_add_to_ioend(inode, pos, len, page,
+ iomap_page_create(inode, page), iomap, iwc->ioend, NULL,
+ &iwc->iolist);
+ set_page_writeback(page);
+ return true;
+}
+
+static size_t __iomap_write_end(struct iomap_write_ctx *iwc,
+ struct iomap *iomap, struct inode *inode, loff_t pos,
+ size_t len, size_t copied, struct page *page)
{
flush_dcache_page(page);
@@ -676,7 +713,8 @@ static size_t __iomap_write_end(struct inode *inode, loff_t pos, size_t len,
if (unlikely(copied < len && !PageUptodate(page)))
return 0;
iomap_set_range_uptodate(page, offset_in_page(pos), len);
- __set_page_dirty_nobuffers(page);
+ if (!iomap_write_through(iwc, iomap, inode, page, pos, len))
+ __set_page_dirty_nobuffers(page);
return copied;
}
@@ -698,9 +736,9 @@ static size_t iomap_write_end_inline(struct inode *inode, struct page *page,
}
/* Returns the number of bytes copied. May be 0. Cannot be an errno. */
-static size_t iomap_write_end(struct inode *inode, loff_t pos, size_t len,
- size_t copied, struct page *page, struct iomap *iomap,
- struct iomap *srcmap)
+static size_t iomap_write_end(struct iomap_write_ctx *iwc, struct inode *inode,
+ loff_t pos, size_t len, size_t copied, struct page *page,
+ struct iomap *iomap, struct iomap *srcmap)
{
const struct iomap_page_ops *page_ops = iomap->page_ops;
loff_t old_size = inode->i_size;
@@ -712,7 +750,8 @@ static size_t iomap_write_end(struct inode *inode, loff_t pos, size_t len,
ret = block_write_end(NULL, inode->i_mapping, pos, len, copied,
page, NULL);
} else {
- ret = __iomap_write_end(inode, pos, len, copied, page);
+ ret = __iomap_write_end(iwc, iomap, inode, pos, len, copied,
+ page);
}
/*
@@ -780,8 +819,8 @@ iomap_write_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
copied = copy_page_from_iter_atomic(page, offset, bytes, i);
- status = iomap_write_end(inode, pos, bytes, copied, page, iomap,
- srcmap);
+ status = iomap_write_end(iwc, inode, pos, bytes, copied, page,
+ iomap, srcmap);
if (unlikely(copied != status))
iov_iter_revert(i, copied - status);
@@ -808,6 +847,10 @@ iomap_write_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
return written ? written : status;
}
+/* Also rearrange */
+static int iomap_submit_ioend(struct iomap_writepage_ctx *wpc,
+ struct iomap_ioend *ioend, int error);
+
ssize_t
iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *iter,
const struct iomap_ops *ops)
@@ -817,6 +860,7 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *iter,
.iolist = LIST_HEAD_INIT(iwc.iolist),
.write_through = iocb->ki_flags & IOCB_SYNC,
};
+ struct iomap_ioend *ioend, *next;
struct inode *inode = iocb->ki_filp->f_mapping->host;
loff_t pos = iocb->ki_pos, ret = 0, written = 0;
@@ -829,6 +873,15 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *iter,
written += ret;
}
+ if (ret > 0)
+ ret = 0;
+
+ list_for_each_entry_safe(ioend, next, &iwc.iolist, io_list) {
+ list_del_init(&ioend->io_list);
+ ret = iomap_submit_ioend(NULL, ioend, ret);
+ }
+ if (iwc.ioend)
+ ret = iomap_submit_ioend(NULL, iwc.ioend, ret);
return written ? written : ret;
}
EXPORT_SYMBOL_GPL(iomap_file_buffered_write);
@@ -857,8 +910,8 @@ iomap_unshare_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
if (unlikely(status))
return status;
- status = iomap_write_end(inode, pos, bytes, bytes, page, iomap,
- srcmap);
+ status = iomap_write_end(NULL, inode, pos, bytes, bytes, page,
+ iomap, srcmap);
if (WARN_ON_ONCE(status == 0))
return -EIO;
@@ -908,7 +961,8 @@ static s64 iomap_zero(struct inode *inode, loff_t pos, u64 length,
zero_user(page, offset, bytes);
mark_page_accessed(page);
- return iomap_write_end(inode, pos, bytes, bytes, page, iomap, srcmap);
+ return iomap_write_end(NULL, inode, pos, bytes, bytes, page, iomap,
+ srcmap);
}
static loff_t iomap_zero_range_actor(struct inode *inode, loff_t pos,
--
2.30.2
next prev parent reply other threads:[~2021-08-11 2:54 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-11 2:46 [PATCH 0/8] iomap writethrough for O_SYNC writes Matthew Wilcox (Oracle)
2021-08-11 2:46 ` [PATCH 1/8] iomap: Pass struct iomap to iomap_alloc_ioend() Matthew Wilcox (Oracle)
2021-08-11 2:46 ` [PATCH 2/8] iomap: Remove iomap_writepage_ctx from iomap_can_add_to_ioend() Matthew Wilcox (Oracle)
2021-08-11 2:46 ` [PATCH 3/8] iomap: Do not pass iomap_writepage_ctx to iomap_add_to_ioend() Matthew Wilcox (Oracle)
2021-08-11 2:46 ` [PATCH 4/8] iomap: Accept a NULL iomap_writepage_ctx in iomap_submit_ioend() Matthew Wilcox (Oracle)
2021-08-11 2:46 ` [PATCH 5/8] iomap: Pass iomap_write_ctx to iomap_write_actor() Matthew Wilcox (Oracle)
2021-08-11 2:46 ` [PATCH 6/8] iomap: Allow a NULL writeback_control argument to iomap_alloc_ioend() Matthew Wilcox (Oracle)
2021-08-11 2:46 ` [PATCH 7/8] iomap: Pass a length to iomap_add_to_ioend() Matthew Wilcox (Oracle)
2021-08-11 2:46 ` Matthew Wilcox (Oracle) [this message]
2021-08-12 13:16 ` [PATCH 8/8] iomap: Add writethrough for O_SYNC Christoph Hellwig
2021-08-12 13:28 ` Matthew Wilcox
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210811024647.3067739-9-willy@infradead.org \
--to=willy@infradead.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-xfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).