* [PATCH 00/11] fuse: convert to using folios and iomap
@ 2024-08-27 20:45 Josef Bacik
2024-08-27 20:45 ` [PATCH 01/11] fuse: convert readahead to use folios Josef Bacik
` (11 more replies)
0 siblings, 12 replies; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 20:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
Hello,
This is a prep series for my work to enable large folios on fuse. It has two
dependencies, one is Joanne's writeback clean patches
https://lore.kernel.org/linux-fsdevel/20240826211908.75190-1-joannelkoong@gmail.com/
and an iomap patch to allow us to pass the file through the buffered write path
https://lore.kernel.org/linux-fsdevel/7f55c7c32275004ba00cddf862d970e6e633f750.1724755651.git.josef@toxicpanda.com/
I've run these through an fstests run with passthrough_hp --direct-io,
everything looks good.
The last remaining bit that needs to be made to use folios is the splice/pipe
code, which I need to be a lot more careful about. The next step is to plumb
through the ability to handle large folios. But this is a decent start and
removes the bulk of FUSE's use of struct page, and is relatively safe and
straightforward. Thanks,
Josef
Josef Bacik (11):
fuse: convert readahead to use folios
fuse: convert fuse_send_write_pages to use folios
fuse: convert fuse_fill_write_pages to use folios
fuse: convert fuse_page_mkwrite to use folios
fuse: use kiocb_modified in buffered write path
fuse: use iomap for writeback cache buffered writes
fuse: convert fuse_do_readpage to use folios
fuse: convert fuse_writepage_need_send to take a folio
fuse: use the folio based vmstat helpers
fuse: convert fuse_retrieve to use folios
fuse: convert fuse_notify_store to use folios
fs/fuse/dev.c | 38 ++++---
fs/fuse/file.c | 296 +++++++++++++++++++++++++------------------------
2 files changed, 172 insertions(+), 162 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 01/11] fuse: convert readahead to use folios
2024-08-27 20:45 [PATCH 00/11] fuse: convert to using folios and iomap Josef Bacik
@ 2024-08-27 20:45 ` Josef Bacik
2024-08-27 21:46 ` Matthew Wilcox
2024-08-27 20:45 ` [PATCH 02/11] fuse: convert fuse_send_write_pages " Josef Bacik
` (10 subsequent siblings)
11 siblings, 1 reply; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 20:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
Currently we're using the __readahead_batch() helper which populates our
fuse_args_pages->pages array with pages. Convert this to use the newer
folio based pattern which is to call readahead_folio() to get the next
folio in the read ahead batch. I've updated the code to use things like
folio_size() and to take into account larger folio sizes, but this is
purely to make that eventual work easier to do, we currently will not
get large folios so this is more future proofing than actual support.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/fuse/file.c | 36 +++++++++++++++++++++++++++++-------
1 file changed, 29 insertions(+), 7 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 88f872c02349..5024bc5a1da2 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -483,6 +483,18 @@ static void fuse_wait_on_page_writeback(struct inode *inode, pgoff_t index)
wait_event(fi->page_waitq, !fuse_page_is_writeback(inode, index));
}
+/*
+ * Wait for page writeback in the range to be completed. This will work for
+ * folio_size() > PAGE_SIZE, even tho we don't currently allow that.
+ */
+static void fuse_wait_on_folio_writeback(struct inode *inode,
+ struct folio *folio)
+{
+ for (pgoff_t index = folio_index(folio);
+ index < folio_next_index(folio); index++)
+ fuse_wait_on_page_writeback(inode, index);
+}
+
/*
* Wait for all pending writepages on the inode to finish.
*
@@ -997,6 +1009,8 @@ static void fuse_readahead(struct readahead_control *rac)
for (;;) {
struct fuse_io_args *ia;
struct fuse_args_pages *ap;
+ struct folio *folio;
+ unsigned nr_folios = 0;
if (fc->num_background >= fc->congestion_threshold &&
rac->ra->async_size >= readahead_count(rac))
@@ -1006,7 +1020,14 @@ static void fuse_readahead(struct readahead_control *rac)
*/
break;
- nr_pages = readahead_count(rac) - nr_pages;
+ /*
+ * readahead_folio() updates the readahead_count(), so this will
+ * always return the remaining pages count. NOTE: this is in
+ * PAGE_SIZE increments, which for now we do not support large
+ * folios, but in the future we could end up with 1 folio
+ * covering multiple PAGE_SIZE increments.
+ */
+ nr_pages = readahead_count(rac);
if (nr_pages > max_pages)
nr_pages = max_pages;
if (nr_pages == 0)
@@ -1015,13 +1036,14 @@ static void fuse_readahead(struct readahead_control *rac)
if (!ia)
return;
ap = &ia->ap;
- nr_pages = __readahead_batch(rac, ap->pages, nr_pages);
- for (i = 0; i < nr_pages; i++) {
- fuse_wait_on_page_writeback(inode,
- readahead_index(rac) + i);
- ap->descs[i].length = PAGE_SIZE;
+
+ while (nr_folios < nr_pages &&
+ (folio = readahead_folio(rac)) != NULL) {
+ fuse_wait_on_folio_writeback(inode, folio);
+ ap->pages[i] = &folio->page;
+ ap->descs[i].length = folio_size(folio);
+ ap->num_pages++;
}
- ap->num_pages = nr_pages;
fuse_send_readpages(ia, rac->file);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 02/11] fuse: convert fuse_send_write_pages to use folios
2024-08-27 20:45 [PATCH 00/11] fuse: convert to using folios and iomap Josef Bacik
2024-08-27 20:45 ` [PATCH 01/11] fuse: convert readahead to use folios Josef Bacik
@ 2024-08-27 20:45 ` Josef Bacik
2024-08-27 21:53 ` Matthew Wilcox
2024-08-27 20:45 ` [PATCH 03/11] fuse: convert fuse_fill_write_pages " Josef Bacik
` (9 subsequent siblings)
11 siblings, 1 reply; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 20:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
Convert this to grab the folio from the fuse_args_pages and use the
appropriate folio related functions.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/fuse/file.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 5024bc5a1da2..3621dbc17167 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1177,23 +1177,23 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia,
offset = ap->descs[0].offset;
count = ia->write.out.size;
for (i = 0; i < ap->num_pages; i++) {
- struct page *page = ap->pages[i];
+ struct folio *folio = page_folio(ap->pages[i]);
if (err) {
- ClearPageUptodate(page);
+ folio_clear_uptodate(folio);
} else {
if (count >= PAGE_SIZE - offset)
count -= PAGE_SIZE - offset;
else {
if (short_write)
- ClearPageUptodate(page);
+ folio_clear_uptodate(folio);
count = 0;
}
offset = 0;
}
if (ia->write.page_locked && (i == ap->num_pages - 1))
- unlock_page(page);
- put_page(page);
+ folio_unlock(folio);
+ folio_put(folio);
}
return err;
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 03/11] fuse: convert fuse_fill_write_pages to use folios
2024-08-27 20:45 [PATCH 00/11] fuse: convert to using folios and iomap Josef Bacik
2024-08-27 20:45 ` [PATCH 01/11] fuse: convert readahead to use folios Josef Bacik
2024-08-27 20:45 ` [PATCH 02/11] fuse: convert fuse_send_write_pages " Josef Bacik
@ 2024-08-27 20:45 ` Josef Bacik
2024-08-27 21:30 ` Joanne Koong
2024-08-27 20:45 ` [PATCH 04/11] fuse: convert fuse_page_mkwrite " Josef Bacik
` (8 subsequent siblings)
11 siblings, 1 reply; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 20:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
Convert this to grab the folio directly, and update all the helpers to
use the folio related functions.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/fuse/file.c | 28 +++++++++++++++-------------
1 file changed, 15 insertions(+), 13 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 3621dbc17167..8cd3911446b6 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1215,7 +1215,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
do {
size_t tmp;
- struct page *page;
+ struct folio *folio;
pgoff_t index = pos >> PAGE_SHIFT;
size_t bytes = min_t(size_t, PAGE_SIZE - offset,
iov_iter_count(ii));
@@ -1227,25 +1227,27 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
if (fault_in_iov_iter_readable(ii, bytes))
break;
- err = -ENOMEM;
- page = grab_cache_page_write_begin(mapping, index);
- if (!page)
+ folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,
+ mapping_gfp_mask(mapping));
+ if (!IS_ERR(folio)) {
+ err = PTR_ERR(folio);
break;
+ }
if (mapping_writably_mapped(mapping))
- flush_dcache_page(page);
+ flush_dcache_folio(folio);
- tmp = copy_page_from_iter_atomic(page, offset, bytes, ii);
- flush_dcache_page(page);
+ tmp = copy_folio_from_iter_atomic(folio, offset, bytes, ii);
+ flush_dcache_folio(folio);
if (!tmp) {
- unlock_page(page);
- put_page(page);
+ folio_unlock(folio);
+ folio_put(folio);
goto again;
}
err = 0;
- ap->pages[ap->num_pages] = page;
+ ap->pages[ap->num_pages] = &folio->page;
ap->descs[ap->num_pages].length = tmp;
ap->num_pages++;
@@ -1257,10 +1259,10 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
/* If we copied full page, mark it uptodate */
if (tmp == PAGE_SIZE)
- SetPageUptodate(page);
+ folio_mark_uptodate(folio);
- if (PageUptodate(page)) {
- unlock_page(page);
+ if (folio_test_uptodate(folio)) {
+ folio_unlock(folio);
} else {
ia->write.page_locked = true;
break;
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 04/11] fuse: convert fuse_page_mkwrite to use folios
2024-08-27 20:45 [PATCH 00/11] fuse: convert to using folios and iomap Josef Bacik
` (2 preceding siblings ...)
2024-08-27 20:45 ` [PATCH 03/11] fuse: convert fuse_fill_write_pages " Josef Bacik
@ 2024-08-27 20:45 ` Josef Bacik
2024-08-27 20:45 ` [PATCH 05/11] fuse: use kiocb_modified in buffered write path Josef Bacik
` (7 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 20:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
Convert this to grab the folio directly, and update all the helpers to
use the folio related functions.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/fuse/file.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 8cd3911446b6..3cc1917fd1b9 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -2534,17 +2534,17 @@ static void fuse_vma_close(struct vm_area_struct *vma)
*/
static vm_fault_t fuse_page_mkwrite(struct vm_fault *vmf)
{
- struct page *page = vmf->page;
+ struct folio *folio = page_folio(vmf->page);
struct inode *inode = file_inode(vmf->vma->vm_file);
file_update_time(vmf->vma->vm_file);
- lock_page(page);
- if (page->mapping != inode->i_mapping) {
- unlock_page(page);
+ folio_lock(folio);
+ if (folio->mapping != inode->i_mapping) {
+ folio_unlock(folio);
return VM_FAULT_NOPAGE;
}
- fuse_wait_on_page_writeback(inode, page->index);
+ fuse_wait_on_folio_writeback(inode, folio);
return VM_FAULT_LOCKED;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 05/11] fuse: use kiocb_modified in buffered write path
2024-08-27 20:45 [PATCH 00/11] fuse: convert to using folios and iomap Josef Bacik
` (3 preceding siblings ...)
2024-08-27 20:45 ` [PATCH 04/11] fuse: convert fuse_page_mkwrite " Josef Bacik
@ 2024-08-27 20:45 ` Josef Bacik
2024-08-27 20:45 ` [PATCH 06/11] fuse: use iomap for writeback cache buffered writes Josef Bacik
` (6 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 20:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
This combines the file_remove_privs() and file_update_time() call into
one call.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/fuse/file.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 3cc1917fd1b9..b259d4db0ff1 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1453,11 +1453,7 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
task_io_account_write(count);
- err = file_remove_privs(file);
- if (err)
- goto out;
-
- err = file_update_time(file);
+ err = kiocb_modified(iocb);
if (err)
goto out;
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 06/11] fuse: use iomap for writeback cache buffered writes
2024-08-27 20:45 [PATCH 00/11] fuse: convert to using folios and iomap Josef Bacik
` (4 preceding siblings ...)
2024-08-27 20:45 ` [PATCH 05/11] fuse: use kiocb_modified in buffered write path Josef Bacik
@ 2024-08-27 20:45 ` Josef Bacik
2024-08-28 5:16 ` Christoph Hellwig
2024-08-27 20:45 ` [PATCH 07/11] fuse: convert fuse_do_readpage to use folios Josef Bacik
` (5 subsequent siblings)
11 siblings, 1 reply; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 20:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
We're currently using the old ->write_begin()/->write_end() method of
doing buffered writes. This isn't a huge deal for fuse since we
basically just want to copy the pages and move on, but the iomap
infrastructure gives us access to having huge folios. Rework the
buffered write path when we have writeback cache to use the iomap
buffered write code, the ->get_folio() callback now handles the work
that we did in ->write_begin(), the rest of the work is handled inside
of iomap so we don't need a replacement for ->write_end.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/fuse/file.c | 154 +++++++++++++++++++++----------------------------
1 file changed, 66 insertions(+), 88 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index b259d4db0ff1..c61bc4396649 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -21,6 +21,7 @@
#include <linux/filelock.h>
#include <linux/splice.h>
#include <linux/task_io_accounting_ops.h>
+#include <linux/iomap.h>
static int fuse_send_open(struct fuse_mount *fm, u64 nodeid,
unsigned int open_flags, int opcode,
@@ -1419,6 +1420,63 @@ static void fuse_dio_unlock(struct kiocb *iocb, bool exclusive)
}
}
+static struct folio *fuse_iomap_get_folio(struct iomap_iter *iter,
+ loff_t pos, unsigned len)
+{
+ struct file *file = (struct file *)iter->private;
+ struct inode *inode = iter->inode;
+ struct folio *folio;
+ loff_t fsize;
+
+ folio = iomap_get_folio(iter, pos, len);
+ if (IS_ERR(folio))
+ return folio;
+
+ fuse_wait_on_folio_writeback(inode, folio);
+
+ if (folio_test_uptodate(folio))
+ return folio;
+
+ /*
+ * If we're going to write past EOF then avoid the read, but zero the
+ * whole thing and mark it uptodate so that if we get a short write we
+ * don't try to re-read this page, we just carry on.
+ */
+ fsize = i_size_read(inode);
+ if (fsize <= folio_pos(folio)) {
+ folio_zero_range(folio, 0, folio_size(folio));
+ } else {
+ int err = fuse_do_readpage(file, &folio->page);
+ if (err) {
+ folio_unlock(folio);
+ folio_put(folio);
+ return ERR_PTR(err);
+ }
+ }
+
+ return folio;
+}
+
+static const struct iomap_folio_ops fuse_iomap_folio_ops = {
+ .get_folio = fuse_iomap_get_folio,
+};
+
+static int fuse_iomap_begin_write(struct inode *inode, loff_t pos, loff_t length,
+ unsigned flags, struct iomap *iomap,
+ struct iomap *srcmap)
+{
+ iomap->type = IOMAP_DELALLOC;
+ iomap->addr = IOMAP_NULL_ADDR;
+ iomap->offset = pos;
+ iomap->length = length;
+ iomap->folio_ops = &fuse_iomap_folio_ops;
+ return 0;
+}
+
+static const struct iomap_ops fuse_iomap_write_ops = {
+ .iomap_begin = fuse_iomap_begin_write,
+};
+
static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct file *file = iocb->ki_filp;
@@ -1427,6 +1485,7 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
struct inode *inode = mapping->host;
ssize_t err, count;
struct fuse_conn *fc = get_fuse_conn(inode);
+ bool writethrough = (fc->writeback_cache == 0);
if (fc->writeback_cache) {
/* Update size (EOF optimization) and mode (SUID clearing) */
@@ -1437,14 +1496,10 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (fc->handle_killpriv_v2 &&
setattr_should_drop_suidgid(&nop_mnt_idmap,
- file_inode(file))) {
- goto writethrough;
- }
-
- return generic_file_write_iter(iocb, from);
+ file_inode(file)))
+ writethrough = true;
}
-writethrough:
inode_lock(inode);
err = count = generic_write_checks(iocb, from);
@@ -1463,8 +1518,12 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
goto out;
written = direct_write_fallback(iocb, from, written,
fuse_perform_write(iocb, from));
- } else {
+ } else if (writethrough) {
written = fuse_perform_write(iocb, from);
+ } else {
+ written = iomap_file_buffered_write(iocb, from,
+ &fuse_iomap_write_ops,
+ file);
}
out:
inode_unlock(inode);
@@ -2407,85 +2466,6 @@ static int fuse_writepages(struct address_space *mapping,
return err;
}
-/*
- * It's worthy to make sure that space is reserved on disk for the write,
- * but how to implement it without killing performance need more thinking.
- */
-static int fuse_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, struct page **pagep, void **fsdata)
-{
- pgoff_t index = pos >> PAGE_SHIFT;
- struct fuse_conn *fc = get_fuse_conn(file_inode(file));
- struct page *page;
- loff_t fsize;
- int err = -ENOMEM;
-
- WARN_ON(!fc->writeback_cache);
-
- page = grab_cache_page_write_begin(mapping, index);
- if (!page)
- goto error;
-
- fuse_wait_on_page_writeback(mapping->host, page->index);
-
- if (PageUptodate(page) || len == PAGE_SIZE)
- goto success;
- /*
- * Check if the start this page comes after the end of file, in which
- * case the readpage can be optimized away.
- */
- fsize = i_size_read(mapping->host);
- if (fsize <= (pos & PAGE_MASK)) {
- size_t off = pos & ~PAGE_MASK;
- if (off)
- zero_user_segment(page, 0, off);
- goto success;
- }
- err = fuse_do_readpage(file, page);
- if (err)
- goto cleanup;
-success:
- *pagep = page;
- return 0;
-
-cleanup:
- unlock_page(page);
- put_page(page);
-error:
- return err;
-}
-
-static int fuse_write_end(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned copied,
- struct page *page, void *fsdata)
-{
- struct inode *inode = page->mapping->host;
-
- /* Haven't copied anything? Skip zeroing, size extending, dirtying. */
- if (!copied)
- goto unlock;
-
- pos += copied;
- if (!PageUptodate(page)) {
- /* Zero any unwritten bytes at the end of the page */
- size_t endoff = pos & ~PAGE_MASK;
- if (endoff)
- zero_user_segment(page, endoff, PAGE_SIZE);
- SetPageUptodate(page);
- }
-
- if (pos > inode->i_size)
- i_size_write(inode, pos);
-
- set_page_dirty(page);
-
-unlock:
- unlock_page(page);
- put_page(page);
-
- return copied;
-}
-
static int fuse_launder_folio(struct folio *folio)
{
int err = 0;
@@ -3351,8 +3331,6 @@ static const struct address_space_operations fuse_file_aops = {
.migrate_folio = filemap_migrate_folio,
.bmap = fuse_bmap,
.direct_IO = fuse_direct_IO,
- .write_begin = fuse_write_begin,
- .write_end = fuse_write_end,
};
void fuse_init_file_inode(struct inode *inode, unsigned int flags)
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 07/11] fuse: convert fuse_do_readpage to use folios
2024-08-27 20:45 [PATCH 00/11] fuse: convert to using folios and iomap Josef Bacik
` (5 preceding siblings ...)
2024-08-27 20:45 ` [PATCH 06/11] fuse: use iomap for writeback cache buffered writes Josef Bacik
@ 2024-08-27 20:45 ` Josef Bacik
2024-08-27 20:45 ` [PATCH 08/11] fuse: convert fuse_writepage_need_send to take a folio Josef Bacik
` (4 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 20:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
Now that the buffered write path is using folios, convert
fuse_do_readpage() to take a folio instead of a page, update it to use
the appropriate folio helpers, and update the callers to pass in the
folio directly instead of a page.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/fuse/file.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index c61bc4396649..f06f0239427b 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -861,12 +861,13 @@ static void fuse_short_read(struct inode *inode, u64 attr_ver, size_t num_read,
}
}
-static int fuse_do_readpage(struct file *file, struct page *page)
+static int fuse_do_readpage(struct file *file, struct folio *folio)
{
- struct inode *inode = page->mapping->host;
+ struct inode *inode = folio->mapping->host;
struct fuse_mount *fm = get_fuse_mount(inode);
- loff_t pos = page_offset(page);
+ loff_t pos = folio_pos(folio);
struct fuse_page_desc desc = { .length = PAGE_SIZE };
+ struct page *page = &folio->page;
struct fuse_io_args ia = {
.ap.args.page_zeroing = true,
.ap.args.out_pages = true,
@@ -878,11 +879,10 @@ static int fuse_do_readpage(struct file *file, struct page *page)
u64 attr_ver;
/*
- * Page writeback can extend beyond the lifetime of the
- * page-cache page, so make sure we read a properly synced
- * page.
+ * Folio writeback can extend beyond the lifetime of the
+ * folio, so make sure we read a properly synced folio.
*/
- fuse_wait_on_page_writeback(inode, page->index);
+ fuse_wait_on_folio_writeback(inode, folio);
attr_ver = fuse_get_attr_version(fm->fc);
@@ -900,25 +900,24 @@ static int fuse_do_readpage(struct file *file, struct page *page)
if (res < desc.length)
fuse_short_read(inode, attr_ver, res, &ia.ap);
- SetPageUptodate(page);
+ folio_mark_uptodate(folio);
return 0;
}
static int fuse_read_folio(struct file *file, struct folio *folio)
{
- struct page *page = &folio->page;
- struct inode *inode = page->mapping->host;
+ struct inode *inode = folio->mapping->host;
int err;
err = -EIO;
if (fuse_is_bad(inode))
goto out;
- err = fuse_do_readpage(file, page);
+ err = fuse_do_readpage(file, folio);
fuse_invalidate_atime(inode);
out:
- unlock_page(page);
+ folio_unlock(folio);
return err;
}
@@ -1446,7 +1445,7 @@ static struct folio *fuse_iomap_get_folio(struct iomap_iter *iter,
if (fsize <= folio_pos(folio)) {
folio_zero_range(folio, 0, folio_size(folio));
} else {
- int err = fuse_do_readpage(file, &folio->page);
+ int err = fuse_do_readpage(file, folio);
if (err) {
folio_unlock(folio);
folio_put(folio);
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 08/11] fuse: convert fuse_writepage_need_send to take a folio
2024-08-27 20:45 [PATCH 00/11] fuse: convert to using folios and iomap Josef Bacik
` (6 preceding siblings ...)
2024-08-27 20:45 ` [PATCH 07/11] fuse: convert fuse_do_readpage to use folios Josef Bacik
@ 2024-08-27 20:45 ` Josef Bacik
2024-08-27 20:45 ` [PATCH 09/11] fuse: use the folio based vmstat helpers Josef Bacik
` (3 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 20:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
fuse_writepage_need_send is called by fuse_writepages_fill() which
already has a folio. Change fuse_writepage_need_send() to take a folio
instead, add a helper to check if the folio range is under writeback and
use this, as well as the appropriate folio helpers in the rest of the
function. Update fuse_writepage_need_send() to pass in the folio
directly.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/fuse/file.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index f06f0239427b..3ef6c2f58940 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -484,6 +484,13 @@ static void fuse_wait_on_page_writeback(struct inode *inode, pgoff_t index)
wait_event(fi->page_waitq, !fuse_page_is_writeback(inode, index));
}
+static inline bool fuse_folio_is_writeback(struct inode *inode,
+ struct folio *folio)
+{
+ return fuse_range_is_writeback(inode, folio_index(folio),
+ folio_next_index(folio) - 1);
+}
+
/*
* Wait for page writeback in the range to be completed. This will work for
* folio_size() > PAGE_SIZE, even tho we don't currently allow that.
@@ -2319,7 +2326,7 @@ static bool fuse_writepage_add(struct fuse_writepage_args *new_wpa,
return false;
}
-static bool fuse_writepage_need_send(struct fuse_conn *fc, struct page *page,
+static bool fuse_writepage_need_send(struct fuse_conn *fc, struct folio *folio,
struct fuse_args_pages *ap,
struct fuse_fill_wb_data *data)
{
@@ -2331,7 +2338,7 @@ static bool fuse_writepage_need_send(struct fuse_conn *fc, struct page *page,
* the pages are faulted with get_user_pages(), and then after the read
* completed.
*/
- if (fuse_page_is_writeback(data->inode, page->index))
+ if (fuse_folio_is_writeback(data->inode, folio))
return true;
/* Reached max pages */
@@ -2343,7 +2350,7 @@ static bool fuse_writepage_need_send(struct fuse_conn *fc, struct page *page,
return true;
/* Discontinuity */
- if (data->orig_pages[ap->num_pages - 1]->index + 1 != page->index)
+ if (data->orig_pages[ap->num_pages - 1]->index + 1 != folio_index(folio))
return true;
/* Need to grow the pages array? If so, did the expansion fail? */
@@ -2365,7 +2372,7 @@ static int fuse_writepages_fill(struct folio *folio,
struct folio *tmp_folio;
int err;
- if (wpa && fuse_writepage_need_send(fc, &folio->page, ap, data)) {
+ if (wpa && fuse_writepage_need_send(fc, folio, ap, data)) {
fuse_writepages_send(data);
data->wpa = NULL;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 09/11] fuse: use the folio based vmstat helpers
2024-08-27 20:45 [PATCH 00/11] fuse: convert to using folios and iomap Josef Bacik
` (7 preceding siblings ...)
2024-08-27 20:45 ` [PATCH 08/11] fuse: convert fuse_writepage_need_send to take a folio Josef Bacik
@ 2024-08-27 20:45 ` Josef Bacik
2024-08-27 22:05 ` Joanne Koong
2024-08-27 20:45 ` [PATCH 10/11] fuse: convert fuse_retrieve to use folios Josef Bacik
` (2 subsequent siblings)
11 siblings, 1 reply; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 20:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
In order to make it easier to switch to folios in the fuse_args_pages
update the places where we update the vmstat counters for writeback to
use the folio related helpers. On the inc side this is easy as we
already have the folio, on the dec side we have to page_folio() the
pages for now.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/fuse/file.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 3ef6c2f58940..e03b915d8229 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1853,12 +1853,12 @@ static void fuse_writepage_free(struct fuse_writepage_args *wpa)
kfree(wpa);
}
-static void fuse_writepage_finish_stat(struct inode *inode, struct page *page)
+static void fuse_writepage_finish_stat(struct inode *inode, struct folio *folio)
{
struct backing_dev_info *bdi = inode_to_bdi(inode);
dec_wb_stat(&bdi->wb, WB_WRITEBACK);
- dec_node_page_state(page, NR_WRITEBACK_TEMP);
+ node_stat_sub_folio(folio, NR_WRITEBACK_TEMP);
wb_writeout_inc(&bdi->wb);
}
@@ -1870,7 +1870,7 @@ static void fuse_writepage_finish(struct fuse_writepage_args *wpa)
int i;
for (i = 0; i < ap->num_pages; i++)
- fuse_writepage_finish_stat(inode, ap->pages[i]);
+ fuse_writepage_finish_stat(inode, page_folio(ap->pages[i]));
wake_up(&fi->page_waitq);
}
@@ -1925,7 +1925,8 @@ __acquires(fi->lock)
for (aux = wpa->next; aux; aux = next) {
next = aux->next;
aux->next = NULL;
- fuse_writepage_finish_stat(aux->inode, aux->ia.ap.pages[0]);
+ fuse_writepage_finish_stat(aux->inode,
+ page_folio(aux->ia.ap.pages[0]));
fuse_writepage_free(aux);
}
@@ -2145,7 +2146,7 @@ static void fuse_writepage_args_page_fill(struct fuse_writepage_args *wpa, struc
ap->descs[page_index].length = PAGE_SIZE;
inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK);
- inc_node_page_state(&tmp_folio->page, NR_WRITEBACK_TEMP);
+ node_stat_add_folio(tmp_folio, NR_WRITEBACK_TEMP);
}
static struct fuse_writepage_args *fuse_writepage_args_setup(struct folio *folio,
@@ -2319,7 +2320,8 @@ static bool fuse_writepage_add(struct fuse_writepage_args *new_wpa,
spin_unlock(&fi->lock);
if (tmp) {
- fuse_writepage_finish_stat(new_wpa->inode, new_ap->pages[0]);
+ fuse_writepage_finish_stat(new_wpa->inode,
+ page_folio(new_ap->pages[0]));
fuse_writepage_free(new_wpa);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 10/11] fuse: convert fuse_retrieve to use folios
2024-08-27 20:45 [PATCH 00/11] fuse: convert to using folios and iomap Josef Bacik
` (8 preceding siblings ...)
2024-08-27 20:45 ` [PATCH 09/11] fuse: use the folio based vmstat helpers Josef Bacik
@ 2024-08-27 20:45 ` Josef Bacik
2024-08-27 22:10 ` Joanne Koong
2024-08-27 20:45 ` [PATCH 11/11] fuse: convert fuse_notify_store " Josef Bacik
2024-08-27 21:36 ` [PATCH 00/11] fuse: convert to using folios and iomap Bernd Schubert
11 siblings, 1 reply; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 20:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
We're just looking for pages in a mapping, use a folio and the folio
lookup function directly instead of using the page helper.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/fuse/dev.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 7146038b2fe7..bcce75e07678 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1709,15 +1709,15 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
index = outarg->offset >> PAGE_SHIFT;
while (num && ap->num_pages < num_pages) {
- struct page *page;
+ struct folio *folio;
unsigned int this_num;
- page = find_get_page(mapping, index);
- if (!page)
+ folio = __filemap_get_folio(mapping, index, 0, 0);
+ if (IS_ERR(folio))
break;
this_num = min_t(unsigned, num, PAGE_SIZE - offset);
- ap->pages[ap->num_pages] = page;
+ ap->pages[ap->num_pages] = &folio->page;
ap->descs[ap->num_pages].offset = offset;
ap->descs[ap->num_pages].length = this_num;
ap->num_pages++;
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 11/11] fuse: convert fuse_notify_store to use folios
2024-08-27 20:45 [PATCH 00/11] fuse: convert to using folios and iomap Josef Bacik
` (9 preceding siblings ...)
2024-08-27 20:45 ` [PATCH 10/11] fuse: convert fuse_retrieve to use folios Josef Bacik
@ 2024-08-27 20:45 ` Josef Bacik
2024-08-27 21:36 ` [PATCH 00/11] fuse: convert to using folios and iomap Bernd Schubert
11 siblings, 0 replies; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 20:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
This function creates pages in an inode and copies data into them,
update the function to use a folio instead of a page, and use the
appropriate folio helpers.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
fs/fuse/dev.c | 30 +++++++++++++++++-------------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index bcce75e07678..eeb5cea4b7e4 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1607,24 +1607,28 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
num = outarg.size;
while (num) {
+ struct folio *folio;
struct page *page;
unsigned int this_num;
- err = -ENOMEM;
- page = find_or_create_page(mapping, index,
- mapping_gfp_mask(mapping));
- if (!page)
+ folio = __filemap_get_folio(mapping, index,
+ FGP_LOCK|FGP_ACCESSED|FGP_CREAT,
+ mapping_gfp_mask(mapping));
+ if (IS_ERR(folio)) {
+ err = PTR_ERR(folio);
goto out_iput;
-
- this_num = min_t(unsigned, num, PAGE_SIZE - offset);
- err = fuse_copy_page(cs, &page, offset, this_num, 0);
- if (!PageUptodate(page) && !err && offset == 0 &&
- (this_num == PAGE_SIZE || file_size == end)) {
- zero_user_segment(page, this_num, PAGE_SIZE);
- SetPageUptodate(page);
}
- unlock_page(page);
- put_page(page);
+
+ page = &folio->page;
+ this_num = min_t(unsigned, num, folio_size(folio) - offset);
+ err = fuse_copy_page(cs, &page, offset, this_num, 0);
+ if (!folio_test_uptodate(folio) && !err && offset == 0 &&
+ (this_num == folio_size(folio) || file_size == end)) {
+ folio_zero_range(folio, this_num, folio_size(folio));
+ folio_mark_uptodate(folio);
+ }
+ folio_unlock(folio);
+ folio_put(folio);
if (err)
goto out_iput;
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH 03/11] fuse: convert fuse_fill_write_pages to use folios
2024-08-27 20:45 ` [PATCH 03/11] fuse: convert fuse_fill_write_pages " Josef Bacik
@ 2024-08-27 21:30 ` Joanne Koong
2024-08-27 22:25 ` Josef Bacik
0 siblings, 1 reply; 23+ messages in thread
From: Joanne Koong @ 2024-08-27 21:30 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-fsdevel, amir73il, miklos, bschubert
On Tue, Aug 27, 2024 at 1:46 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> Convert this to grab the folio directly, and update all the helpers to
> use the folio related functions.
>
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> ---
> fs/fuse/file.c | 28 +++++++++++++++-------------
> 1 file changed, 15 insertions(+), 13 deletions(-)
>
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index 3621dbc17167..8cd3911446b6 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -1215,7 +1215,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
>
> do {
> size_t tmp;
> - struct page *page;
> + struct folio *folio;
> pgoff_t index = pos >> PAGE_SHIFT;
> size_t bytes = min_t(size_t, PAGE_SIZE - offset,
> iov_iter_count(ii));
> @@ -1227,25 +1227,27 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
> if (fault_in_iov_iter_readable(ii, bytes))
> break;
>
> - err = -ENOMEM;
> - page = grab_cache_page_write_begin(mapping, index);
> - if (!page)
> + folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,
> + mapping_gfp_mask(mapping));
> + if (!IS_ERR(folio)) {
I think you meant to put IS_ERR here instead of !IS_ERR?
> + err = PTR_ERR(folio);
> break;
> + }
>
> if (mapping_writably_mapped(mapping))
> - flush_dcache_page(page);
> + flush_dcache_folio(folio);
>
> - tmp = copy_page_from_iter_atomic(page, offset, bytes, ii);
> - flush_dcache_page(page);
> + tmp = copy_folio_from_iter_atomic(folio, offset, bytes, ii);
> + flush_dcache_folio(folio);
>
> if (!tmp) {
> - unlock_page(page);
> - put_page(page);
> + folio_unlock(folio);
> + folio_put(folio);
> goto again;
> }
>
> err = 0;
> - ap->pages[ap->num_pages] = page;
> + ap->pages[ap->num_pages] = &folio->page;
> ap->descs[ap->num_pages].length = tmp;
> ap->num_pages++;
>
> @@ -1257,10 +1259,10 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
>
> /* If we copied full page, mark it uptodate */
> if (tmp == PAGE_SIZE)
> - SetPageUptodate(page);
> + folio_mark_uptodate(folio);
>
> - if (PageUptodate(page)) {
> - unlock_page(page);
> + if (folio_test_uptodate(folio)) {
> + folio_unlock(folio);
> } else {
> ia->write.page_locked = true;
> break;
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 00/11] fuse: convert to using folios and iomap
2024-08-27 20:45 [PATCH 00/11] fuse: convert to using folios and iomap Josef Bacik
` (10 preceding siblings ...)
2024-08-27 20:45 ` [PATCH 11/11] fuse: convert fuse_notify_store " Josef Bacik
@ 2024-08-27 21:36 ` Bernd Schubert
2024-08-27 22:18 ` Josef Bacik
11 siblings, 1 reply; 23+ messages in thread
From: Bernd Schubert @ 2024-08-27 21:36 UTC (permalink / raw)
To: Josef Bacik, linux-fsdevel, amir73il, miklos, joannelkoong
Hi Josef,
On 8/27/24 22:45, Josef Bacik wrote:
> Hello,
>
> This is a prep series for my work to enable large folios on fuse. It has two
> dependencies, one is Joanne's writeback clean patches
>
> https://lore.kernel.org/linux-fsdevel/20240826211908.75190-1-joannelkoong@gmail.com/
>
> and an iomap patch to allow us to pass the file through the buffered write path
>
> https://lore.kernel.org/linux-fsdevel/7f55c7c32275004ba00cddf862d970e6e633f750.1724755651.git.josef@toxicpanda.com/
>
> I've run these through an fstests run with passthrough_hp --direct-io,
> everything looks good.
why with --direct-io? It is not exactly O_DIRECT, but also not that far
away - don't you want to stress read-ahead and page cache usage on write?
I typically run with/without --direct-io, but disable passthrough.
Thanks,
Bernd
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 01/11] fuse: convert readahead to use folios
2024-08-27 20:45 ` [PATCH 01/11] fuse: convert readahead to use folios Josef Bacik
@ 2024-08-27 21:46 ` Matthew Wilcox
2024-08-27 22:23 ` Josef Bacik
0 siblings, 1 reply; 23+ messages in thread
From: Matthew Wilcox @ 2024-08-27 21:46 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
On Tue, Aug 27, 2024 at 04:45:14PM -0400, Josef Bacik wrote:
>
> +/*
> + * Wait for page writeback in the range to be completed. This will work for
> + * folio_size() > PAGE_SIZE, even tho we don't currently allow that.
> + */
> +static void fuse_wait_on_folio_writeback(struct inode *inode,
> + struct folio *folio)
> +{
> + for (pgoff_t index = folio_index(folio);
> + index < folio_next_index(folio); index++)
> + fuse_wait_on_page_writeback(inode, index);
> +}
Would it be better to write this as:
struct fuse_inode *fi = get_fuse_inode(inode);
pgoff_t last = folio_next_index(folio) - 1;
wait_event(fi->page_waitq, !fuse_range_is_writeback(inode,
folio->index, last));
> @@ -1015,13 +1036,14 @@ static void fuse_readahead(struct readahead_control *rac)
> if (!ia)
> return;
> ap = &ia->ap;
> - nr_pages = __readahead_batch(rac, ap->pages, nr_pages);
> - for (i = 0; i < nr_pages; i++) {
> - fuse_wait_on_page_writeback(inode,
> - readahead_index(rac) + i);
> - ap->descs[i].length = PAGE_SIZE;
> +
> + while (nr_folios < nr_pages &&
> + (folio = readahead_folio(rac)) != NULL) {
> + fuse_wait_on_folio_writeback(inode, folio);
Oh. Even easier, we should hoist the whole thing to here. Before
this loop,
pgoff_t first = readahead_index(rac);
pgoff_t last = first + readahead_count(rac) - 1;
wait_event(fi->page_waitq, !fuse_range_is_writeback(inode,
first, last);
(I'm not quite sure how we might have pending writeback still when we're
doing readahead, but fuse is a funny creature and if somebody explains
why to me, I'll probably forget again)
> + ap->pages[i] = &folio->page;
> + ap->descs[i].length = folio_size(folio);
> + ap->num_pages++;
I do want to turn __readahead_batch into working on folios, but that
involves working on fuse & squashfs at the same time ... I see you
got rid of the readahead_page_batch() in btrfs recently; that'll help.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 02/11] fuse: convert fuse_send_write_pages to use folios
2024-08-27 20:45 ` [PATCH 02/11] fuse: convert fuse_send_write_pages " Josef Bacik
@ 2024-08-27 21:53 ` Matthew Wilcox
2024-08-27 22:24 ` Josef Bacik
0 siblings, 1 reply; 23+ messages in thread
From: Matthew Wilcox @ 2024-08-27 21:53 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
On Tue, Aug 27, 2024 at 04:45:15PM -0400, Josef Bacik wrote:
> for (i = 0; i < ap->num_pages; i++) {
> - struct page *page = ap->pages[i];
> + struct folio *folio = page_folio(ap->pages[i]);
>
> if (err) {
> - ClearPageUptodate(page);
> + folio_clear_uptodate(folio);
> } else {
> if (count >= PAGE_SIZE - offset)
> count -= PAGE_SIZE - offset;
I'd tend to adjust these to folio_size() while doing this function,
just so that I don't have to come back to it later.
Either way,
Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 09/11] fuse: use the folio based vmstat helpers
2024-08-27 20:45 ` [PATCH 09/11] fuse: use the folio based vmstat helpers Josef Bacik
@ 2024-08-27 22:05 ` Joanne Koong
0 siblings, 0 replies; 23+ messages in thread
From: Joanne Koong @ 2024-08-27 22:05 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-fsdevel, amir73il, miklos, bschubert
On Tue, Aug 27, 2024 at 1:46 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> In order to make it easier to switch to folios in the fuse_args_pages
> update the places where we update the vmstat counters for writeback to
> use the folio related helpers. On the inc side this is easy as we
> already have the folio, on the dec side we have to page_folio() the
> pages for now.
>
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
LGTM.
Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
> ---
> fs/fuse/file.c | 14 ++++++++------
> 1 file changed, 8 insertions(+), 6 deletions(-)
>
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index 3ef6c2f58940..e03b915d8229 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -1853,12 +1853,12 @@ static void fuse_writepage_free(struct fuse_writepage_args *wpa)
> kfree(wpa);
> }
>
> -static void fuse_writepage_finish_stat(struct inode *inode, struct page *page)
> +static void fuse_writepage_finish_stat(struct inode *inode, struct folio *folio)
> {
> struct backing_dev_info *bdi = inode_to_bdi(inode);
>
> dec_wb_stat(&bdi->wb, WB_WRITEBACK);
> - dec_node_page_state(page, NR_WRITEBACK_TEMP);
> + node_stat_sub_folio(folio, NR_WRITEBACK_TEMP);
> wb_writeout_inc(&bdi->wb);
> }
>
> @@ -1870,7 +1870,7 @@ static void fuse_writepage_finish(struct fuse_writepage_args *wpa)
> int i;
>
> for (i = 0; i < ap->num_pages; i++)
> - fuse_writepage_finish_stat(inode, ap->pages[i]);
> + fuse_writepage_finish_stat(inode, page_folio(ap->pages[i]));
>
> wake_up(&fi->page_waitq);
> }
> @@ -1925,7 +1925,8 @@ __acquires(fi->lock)
> for (aux = wpa->next; aux; aux = next) {
> next = aux->next;
> aux->next = NULL;
> - fuse_writepage_finish_stat(aux->inode, aux->ia.ap.pages[0]);
> + fuse_writepage_finish_stat(aux->inode,
> + page_folio(aux->ia.ap.pages[0]));
> fuse_writepage_free(aux);
> }
>
> @@ -2145,7 +2146,7 @@ static void fuse_writepage_args_page_fill(struct fuse_writepage_args *wpa, struc
> ap->descs[page_index].length = PAGE_SIZE;
>
> inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK);
> - inc_node_page_state(&tmp_folio->page, NR_WRITEBACK_TEMP);
> + node_stat_add_folio(tmp_folio, NR_WRITEBACK_TEMP);
> }
>
> static struct fuse_writepage_args *fuse_writepage_args_setup(struct folio *folio,
> @@ -2319,7 +2320,8 @@ static bool fuse_writepage_add(struct fuse_writepage_args *new_wpa,
> spin_unlock(&fi->lock);
>
> if (tmp) {
> - fuse_writepage_finish_stat(new_wpa->inode, new_ap->pages[0]);
> + fuse_writepage_finish_stat(new_wpa->inode,
> + page_folio(new_ap->pages[0]));
> fuse_writepage_free(new_wpa);
> }
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 10/11] fuse: convert fuse_retrieve to use folios
2024-08-27 20:45 ` [PATCH 10/11] fuse: convert fuse_retrieve to use folios Josef Bacik
@ 2024-08-27 22:10 ` Joanne Koong
0 siblings, 0 replies; 23+ messages in thread
From: Joanne Koong @ 2024-08-27 22:10 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-fsdevel, amir73il, miklos, bschubert
On Tue, Aug 27, 2024 at 1:46 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> We're just looking for pages in a mapping, use a folio and the folio
> lookup function directly instead of using the page helper.
>
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
LGTM
Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
> ---
> fs/fuse/dev.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 7146038b2fe7..bcce75e07678 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -1709,15 +1709,15 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
> index = outarg->offset >> PAGE_SHIFT;
>
> while (num && ap->num_pages < num_pages) {
> - struct page *page;
> + struct folio *folio;
> unsigned int this_num;
>
> - page = find_get_page(mapping, index);
> - if (!page)
> + folio = __filemap_get_folio(mapping, index, 0, 0);
> + if (IS_ERR(folio))
> break;
>
> this_num = min_t(unsigned, num, PAGE_SIZE - offset);
> - ap->pages[ap->num_pages] = page;
> + ap->pages[ap->num_pages] = &folio->page;
> ap->descs[ap->num_pages].offset = offset;
> ap->descs[ap->num_pages].length = this_num;
> ap->num_pages++;
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 00/11] fuse: convert to using folios and iomap
2024-08-27 21:36 ` [PATCH 00/11] fuse: convert to using folios and iomap Bernd Schubert
@ 2024-08-27 22:18 ` Josef Bacik
0 siblings, 0 replies; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 22:18 UTC (permalink / raw)
To: Bernd Schubert; +Cc: linux-fsdevel, amir73il, miklos, joannelkoong
On Tue, Aug 27, 2024 at 11:36:56PM +0200, Bernd Schubert wrote:
> Hi Josef,
>
> On 8/27/24 22:45, Josef Bacik wrote:
> > Hello,
> >
> > This is a prep series for my work to enable large folios on fuse. It has two
> > dependencies, one is Joanne's writeback clean patches
> >
> > https://lore.kernel.org/linux-fsdevel/20240826211908.75190-1-joannelkoong@gmail.com/
> >
> > and an iomap patch to allow us to pass the file through the buffered write path
> >
> > https://lore.kernel.org/linux-fsdevel/7f55c7c32275004ba00cddf862d970e6e633f750.1724755651.git.josef@toxicpanda.com/
> >
> > I've run these through an fstests run with passthrough_hp --direct-io,
> > everything looks good.
>
> why with --direct-io? It is not exactly O_DIRECT, but also not that far
> away - don't you want to stress read-ahead and page cache usage on write?
> I typically run with/without --direct-io, but disable passthrough.
>
I got distracted halfway through writing this email, I meant to write "with
passthrough_hp with and without --direct-io". I have to run with --direct-io
otherwise generic/097 hangs because of a fio bug (I really need to go fix that).
Thanks,
Josef
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 01/11] fuse: convert readahead to use folios
2024-08-27 21:46 ` Matthew Wilcox
@ 2024-08-27 22:23 ` Josef Bacik
0 siblings, 0 replies; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 22:23 UTC (permalink / raw)
To: Matthew Wilcox; +Cc: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
On Tue, Aug 27, 2024 at 10:46:57PM +0100, Matthew Wilcox wrote:
> On Tue, Aug 27, 2024 at 04:45:14PM -0400, Josef Bacik wrote:
> >
> > +/*
> > + * Wait for page writeback in the range to be completed. This will work for
> > + * folio_size() > PAGE_SIZE, even tho we don't currently allow that.
> > + */
> > +static void fuse_wait_on_folio_writeback(struct inode *inode,
> > + struct folio *folio)
> > +{
> > + for (pgoff_t index = folio_index(folio);
> > + index < folio_next_index(folio); index++)
> > + fuse_wait_on_page_writeback(inode, index);
> > +}
>
> Would it be better to write this as:
>
> struct fuse_inode *fi = get_fuse_inode(inode);
> pgoff_t last = folio_next_index(folio) - 1;
>
> wait_event(fi->page_waitq, !fuse_range_is_writeback(inode,
> folio->index, last));
>
> > @@ -1015,13 +1036,14 @@ static void fuse_readahead(struct readahead_control *rac)
> > if (!ia)
> > return;
> > ap = &ia->ap;
> > - nr_pages = __readahead_batch(rac, ap->pages, nr_pages);
> > - for (i = 0; i < nr_pages; i++) {
> > - fuse_wait_on_page_writeback(inode,
> > - readahead_index(rac) + i);
> > - ap->descs[i].length = PAGE_SIZE;
> > +
> > + while (nr_folios < nr_pages &&
> > + (folio = readahead_folio(rac)) != NULL) {
> > + fuse_wait_on_folio_writeback(inode, folio);
>
> Oh. Even easier, we should hoist the whole thing to here. Before
> this loop,
>
> pgoff_t first = readahead_index(rac);
> pgoff_t last = first + readahead_count(rac) - 1;
> wait_event(fi->page_waitq, !fuse_range_is_writeback(inode,
> first, last);
>
> (I'm not quite sure how we might have pending writeback still when we're
> doing readahead, but fuse is a funny creature and if somebody explains
> why to me, I'll probably forget again)
>
Ah good suggestion, I like this better. I didn't read carefully enough and
thought the waitqueue was on the writeback struct. I'll rework it in the
morning and re-send once the tests run again.
> > + ap->pages[i] = &folio->page;
> > + ap->descs[i].length = folio_size(folio);
> > + ap->num_pages++;
>
> I do want to turn __readahead_batch into working on folios, but that
> involves working on fuse & squashfs at the same time ... I see you
> got rid of the readahead_page_batch() in btrfs recently; that'll help.
Do you want me to tackle that since I'm messing around in this area anyway? My
only hesitation is we're limited to the 32 folios or whatever the pagevec count
is nowadays, and we may want to cycle through more. But I've just finished
eating dinner and haven't actually looked at anything yet. Thanks,
Josef
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 02/11] fuse: convert fuse_send_write_pages to use folios
2024-08-27 21:53 ` Matthew Wilcox
@ 2024-08-27 22:24 ` Josef Bacik
0 siblings, 0 replies; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 22:24 UTC (permalink / raw)
To: Matthew Wilcox; +Cc: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
On Tue, Aug 27, 2024 at 10:53:58PM +0100, Matthew Wilcox wrote:
> On Tue, Aug 27, 2024 at 04:45:15PM -0400, Josef Bacik wrote:
> > for (i = 0; i < ap->num_pages; i++) {
> > - struct page *page = ap->pages[i];
> > + struct folio *folio = page_folio(ap->pages[i]);
> >
> > if (err) {
> > - ClearPageUptodate(page);
> > + folio_clear_uptodate(folio);
> > } else {
> > if (count >= PAGE_SIZE - offset)
> > count -= PAGE_SIZE - offset;
>
> I'd tend to adjust these to folio_size() while doing this function,
> just so that I don't have to come back to it later.
>
> Either way,
>
> Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Same, I just glossed over this one because we weren't touching the folio
directly, I'll fix it up since I have to respin the series anyway. Thanks,
Josef
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 03/11] fuse: convert fuse_fill_write_pages to use folios
2024-08-27 21:30 ` Joanne Koong
@ 2024-08-27 22:25 ` Josef Bacik
0 siblings, 0 replies; 23+ messages in thread
From: Josef Bacik @ 2024-08-27 22:25 UTC (permalink / raw)
To: Joanne Koong; +Cc: linux-fsdevel, amir73il, miklos, bschubert
On Tue, Aug 27, 2024 at 02:30:49PM -0700, Joanne Koong wrote:
> On Tue, Aug 27, 2024 at 1:46 PM Josef Bacik <josef@toxicpanda.com> wrote:
> >
> > Convert this to grab the folio directly, and update all the helpers to
> > use the folio related functions.
> >
> > Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> > ---
> > fs/fuse/file.c | 28 +++++++++++++++-------------
> > 1 file changed, 15 insertions(+), 13 deletions(-)
> >
> > diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> > index 3621dbc17167..8cd3911446b6 100644
> > --- a/fs/fuse/file.c
> > +++ b/fs/fuse/file.c
> > @@ -1215,7 +1215,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
> >
> > do {
> > size_t tmp;
> > - struct page *page;
> > + struct folio *folio;
> > pgoff_t index = pos >> PAGE_SHIFT;
> > size_t bytes = min_t(size_t, PAGE_SIZE - offset,
> > iov_iter_count(ii));
> > @@ -1227,25 +1227,27 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
> > if (fault_in_iov_iter_readable(ii, bytes))
> > break;
> >
> > - err = -ENOMEM;
> > - page = grab_cache_page_write_begin(mapping, index);
> > - if (!page)
> > + folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,
> > + mapping_gfp_mask(mapping));
> > + if (!IS_ERR(folio)) {
>
> I think you meant to put IS_ERR here instead of !IS_ERR?
I definitely did, so now I have to go look at my fstests setup and figure out
why this didn't fall over. Nice catch, thanks,
Josef
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 06/11] fuse: use iomap for writeback cache buffered writes
2024-08-27 20:45 ` [PATCH 06/11] fuse: use iomap for writeback cache buffered writes Josef Bacik
@ 2024-08-28 5:16 ` Christoph Hellwig
0 siblings, 0 replies; 23+ messages in thread
From: Christoph Hellwig @ 2024-08-28 5:16 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-fsdevel, amir73il, miklos, joannelkoong, bschubert
On Tue, Aug 27, 2024 at 04:45:19PM -0400, Josef Bacik wrote:
> We're currently using the old ->write_begin()/->write_end() method of
> doing buffered writes. This isn't a huge deal for fuse since we
> basically just want to copy the pages and move on, but the iomap
> infrastructure gives us access to having huge folios. Rework the
> buffered write path when we have writeback cache to use the iomap
> buffered write code, the ->get_folio() callback now handles the work
> that we did in ->write_begin(), the rest of the work is handled inside
> of iomap so we don't need a replacement for ->write_end.
Fuse probably needs to select FS_IOMAP with this. And BLOCK as
well as buffered-io.o depends on it, but I suspect that is relatvely
easily fixable.
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2024-08-28 5:16 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-27 20:45 [PATCH 00/11] fuse: convert to using folios and iomap Josef Bacik
2024-08-27 20:45 ` [PATCH 01/11] fuse: convert readahead to use folios Josef Bacik
2024-08-27 21:46 ` Matthew Wilcox
2024-08-27 22:23 ` Josef Bacik
2024-08-27 20:45 ` [PATCH 02/11] fuse: convert fuse_send_write_pages " Josef Bacik
2024-08-27 21:53 ` Matthew Wilcox
2024-08-27 22:24 ` Josef Bacik
2024-08-27 20:45 ` [PATCH 03/11] fuse: convert fuse_fill_write_pages " Josef Bacik
2024-08-27 21:30 ` Joanne Koong
2024-08-27 22:25 ` Josef Bacik
2024-08-27 20:45 ` [PATCH 04/11] fuse: convert fuse_page_mkwrite " Josef Bacik
2024-08-27 20:45 ` [PATCH 05/11] fuse: use kiocb_modified in buffered write path Josef Bacik
2024-08-27 20:45 ` [PATCH 06/11] fuse: use iomap for writeback cache buffered writes Josef Bacik
2024-08-28 5:16 ` Christoph Hellwig
2024-08-27 20:45 ` [PATCH 07/11] fuse: convert fuse_do_readpage to use folios Josef Bacik
2024-08-27 20:45 ` [PATCH 08/11] fuse: convert fuse_writepage_need_send to take a folio Josef Bacik
2024-08-27 20:45 ` [PATCH 09/11] fuse: use the folio based vmstat helpers Josef Bacik
2024-08-27 22:05 ` Joanne Koong
2024-08-27 20:45 ` [PATCH 10/11] fuse: convert fuse_retrieve to use folios Josef Bacik
2024-08-27 22:10 ` Joanne Koong
2024-08-27 20:45 ` [PATCH 11/11] fuse: convert fuse_notify_store " Josef Bacik
2024-08-27 21:36 ` [PATCH 00/11] fuse: convert to using folios and iomap Bernd Schubert
2024-08-27 22:18 ` Josef Bacik
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).