linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/10] fuse: folio conversions
@ 2024-09-27 20:44 Josef Bacik
  2024-09-27 20:44 ` [PATCH v3 01/10] fuse: convert readahead to use folios Josef Bacik
                   ` (9 more replies)
  0 siblings, 10 replies; 21+ messages in thread
From: Josef Bacik @ 2024-09-27 20:44 UTC (permalink / raw)
  To: linux-fsdevel, amir73il, miklos, kernel-team

v2: https://lore.kernel.org/linux-fsdevel/cover.1724879414.git.josef@toxicpanda.com/
v1: https://lore.kernel.org/linux-fsdevel/cover.1724791233.git.josef@toxicpanda.com/

v2->v3:
- Discussions with Willy at Plumbers helped clarify expectations around large
  folio usage, he had already converted the generic_perform_write to deal with
  large folios, so I dropped the iomap conversion since it's a bit overkill for
  FUSE's buffered use case.
- Rebased onto linus + fuse/for-next.  I had to combine the branches because
  fuse/for-next is behind linus and there are fixes from Jann and Willy that
  aren't in the FUSE tree.
- Pushed a new GH branch since I had to combine everything
  https://github.com/josefbacik/linux/tree/fuse-folio-prep

v1->v2:
- Fixed my fstests setup to use --nopassthrough so my code actually got tested
  this time.
- Fixed a bug where we double put on the folio in readpages, because previous
  behavior was the reference was maintained until the endio, but
  readahead_folio() drops the reference on the folio, so we need to not call put
  in the endio anymore.
- Fixed the IS_ERR inversion pointed out by Joanne.
- Made the various adjustments pointed out by Willy.
- Updated the Kconfig per hch's suggestion.
- Pushed to my GH tree since there are dependencies to make it easier to see
  what the code is https://github.com/josefbacik/linux/tree/fuse-iomap

--- Original email ---
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 (10):
  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: 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 | 163 ++++++++++++++++++++++++++++---------------------
 2 files changed, 116 insertions(+), 85 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v3 01/10] fuse: convert readahead to use folios
  2024-09-27 20:44 [PATCH v3 00/10] fuse: folio conversions Josef Bacik
@ 2024-09-27 20:44 ` Josef Bacik
  2024-09-27 22:22   ` Joanne Koong
  2024-09-27 20:44 ` [PATCH v3 02/10] fuse: convert fuse_send_write_pages " Josef Bacik
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 21+ messages in thread
From: Josef Bacik @ 2024-09-27 20:44 UTC (permalink / raw)
  To: linux-fsdevel, amir73il, miklos, kernel-team

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 | 43 ++++++++++++++++++++++++++++---------------
 1 file changed, 28 insertions(+), 15 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index f33fbce86ae0..132528cde745 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -938,7 +938,6 @@ static void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args,
 		struct folio *folio = page_folio(ap->pages[i]);
 
 		folio_end_read(folio, !err);
-		folio_put(folio);
 	}
 	if (ia->ff)
 		fuse_file_put(ia->ff, false);
@@ -985,18 +984,36 @@ static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file)
 static void fuse_readahead(struct readahead_control *rac)
 {
 	struct inode *inode = rac->mapping->host;
+	struct fuse_inode *fi = get_fuse_inode(inode);
 	struct fuse_conn *fc = get_fuse_conn(inode);
-	unsigned int i, max_pages, nr_pages = 0;
+	unsigned int max_pages, nr_pages;
+	pgoff_t first = readahead_index(rac);
+	pgoff_t last = first + readahead_count(rac) - 1;
 
 	if (fuse_is_bad(inode))
 		return;
 
+	wait_event(fi->page_waitq, !fuse_range_is_writeback(inode, first, last));
+
 	max_pages = min_t(unsigned int, fc->max_pages,
 			fc->max_read / PAGE_SIZE);
 
-	for (;;) {
+	/*
+	 * This is only accurate the first time through, since readahead_folio()
+	 * doesn't update readahead_count() from the previous folio until the
+	 * next call.  Grab nr_pages here so we know how many pages we're going
+	 * to have to process.  This means that we will exit here with
+	 * readahead_count() == folio_nr_pages(last_folio), but we will have
+	 * consumed all of the folios, and read_pages() will call
+	 * readahead_folio() again which will clean up the rac.
+	 */
+	nr_pages = readahead_count(rac);
+
+	while (nr_pages) {
 		struct fuse_io_args *ia;
 		struct fuse_args_pages *ap;
+		struct folio *folio;
+		unsigned cur_pages = min(max_pages, nr_pages);
 
 		if (fc->num_background >= fc->congestion_threshold &&
 		    rac->ra->async_size >= readahead_count(rac))
@@ -1006,23 +1023,19 @@ static void fuse_readahead(struct readahead_control *rac)
 			 */
 			break;
 
-		nr_pages = readahead_count(rac) - nr_pages;
-		if (nr_pages > max_pages)
-			nr_pages = max_pages;
-		if (nr_pages == 0)
-			break;
-		ia = fuse_io_alloc(NULL, nr_pages);
+		ia = fuse_io_alloc(NULL, cur_pages);
 		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 (ap->num_pages < cur_pages &&
+		       (folio = readahead_folio(rac)) != NULL) {
+			ap->pages[ap->num_pages] = &folio->page;
+			ap->descs[ap->num_pages].length = folio_size(folio);
+			ap->num_pages++;
 		}
-		ap->num_pages = nr_pages;
 		fuse_send_readpages(ia, rac->file);
+		nr_pages -= cur_pages;
 	}
 }
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 02/10] fuse: convert fuse_send_write_pages to use folios
  2024-09-27 20:44 [PATCH v3 00/10] fuse: folio conversions Josef Bacik
  2024-09-27 20:44 ` [PATCH v3 01/10] fuse: convert readahead to use folios Josef Bacik
@ 2024-09-27 20:44 ` Josef Bacik
  2024-09-27 22:24   ` Joanne Koong
  2024-09-27 20:44 ` [PATCH v3 03/10] fuse: convert fuse_fill_write_pages " Josef Bacik
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 21+ messages in thread
From: Josef Bacik @ 2024-09-27 20:44 UTC (permalink / raw)
  To: linux-fsdevel, amir73il, miklos, kernel-team; +Cc: Matthew Wilcox

Convert this to grab the folio from the fuse_args_pages and use the
appropriate folio related functions.

Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 fs/fuse/file.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 132528cde745..17ac2de61cdb 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1168,23 +1168,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;
+			if (count >= folio_size(folio) - offset)
+				count -= folio_size(folio) - 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] 21+ messages in thread

* [PATCH v3 03/10] fuse: convert fuse_fill_write_pages to use folios
  2024-09-27 20:44 [PATCH v3 00/10] fuse: folio conversions Josef Bacik
  2024-09-27 20:44 ` [PATCH v3 01/10] fuse: convert readahead to use folios Josef Bacik
  2024-09-27 20:44 ` [PATCH v3 02/10] fuse: convert fuse_send_write_pages " Josef Bacik
@ 2024-09-27 20:44 ` Josef Bacik
  2024-09-27 22:36   ` Joanne Koong
  2024-09-27 20:44 ` [PATCH v3 04/10] fuse: convert fuse_page_mkwrite " Josef Bacik
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 21+ messages in thread
From: Josef Bacik @ 2024-09-27 20:44 UTC (permalink / raw)
  To: linux-fsdevel, amir73il, miklos, kernel-team

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 17ac2de61cdb..1f7fe5416139 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1206,7 +1206,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));
@@ -1218,25 +1218,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++;
 
@@ -1248,10 +1250,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] 21+ messages in thread

* [PATCH v3 04/10] fuse: convert fuse_page_mkwrite to use folios
  2024-09-27 20:44 [PATCH v3 00/10] fuse: folio conversions Josef Bacik
                   ` (2 preceding siblings ...)
  2024-09-27 20:44 ` [PATCH v3 03/10] fuse: convert fuse_fill_write_pages " Josef Bacik
@ 2024-09-27 20:44 ` Josef Bacik
  2024-09-27 22:42   ` Joanne Koong
  2024-09-27 20:44 ` [PATCH v3 05/10] fuse: use kiocb_modified in buffered write path Josef Bacik
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 21+ messages in thread
From: Josef Bacik @ 2024-09-27 20:44 UTC (permalink / raw)
  To: linux-fsdevel, amir73il, miklos, kernel-team

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 | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 1f7fe5416139..c8a5fa579615 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -483,6 +483,16 @@ 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 void fuse_wait_on_folio_writeback(struct inode *inode,
+					 struct folio *folio)
+{
+	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(folio), last));
+}
+
 /*
  * Wait for all pending writepages on the inode to finish.
  *
@@ -2527,17 +2537,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] 21+ messages in thread

* [PATCH v3 05/10] fuse: use kiocb_modified in buffered write path
  2024-09-27 20:44 [PATCH v3 00/10] fuse: folio conversions Josef Bacik
                   ` (3 preceding siblings ...)
  2024-09-27 20:44 ` [PATCH v3 04/10] fuse: convert fuse_page_mkwrite " Josef Bacik
@ 2024-09-27 20:44 ` Josef Bacik
  2024-09-27 20:44 ` [PATCH v3 06/10] fuse: convert fuse_do_readpage to use folios Josef Bacik
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 21+ messages in thread
From: Josef Bacik @ 2024-09-27 20:44 UTC (permalink / raw)
  To: linux-fsdevel, amir73il, miklos, kernel-team

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 c8a5fa579615..2af9ec67a8e7 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1455,11 +1455,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] 21+ messages in thread

* [PATCH v3 06/10] fuse: convert fuse_do_readpage to use folios
  2024-09-27 20:44 [PATCH v3 00/10] fuse: folio conversions Josef Bacik
                   ` (4 preceding siblings ...)
  2024-09-27 20:44 ` [PATCH v3 05/10] fuse: use kiocb_modified in buffered write path Josef Bacik
@ 2024-09-27 20:44 ` Josef Bacik
  2024-09-27 22:51   ` Joanne Koong
  2024-09-27 20:44 ` [PATCH v3 07/10] fuse: convert fuse_writepage_need_send to take a folio Josef Bacik
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 21+ messages in thread
From: Josef Bacik @ 2024-09-27 20:44 UTC (permalink / raw)
  To: linux-fsdevel, amir73il, miklos, kernel-team

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 2af9ec67a8e7..8a4621939d3b 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -858,12 +858,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,
@@ -875,11 +876,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);
 
@@ -897,25 +897,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;
 }
 
@@ -2444,7 +2443,7 @@ static int fuse_write_begin(struct file *file, struct address_space *mapping,
 			folio_zero_segment(folio, 0, off);
 		goto success;
 	}
-	err = fuse_do_readpage(file, &folio->page);
+	err = fuse_do_readpage(file, folio);
 	if (err)
 		goto cleanup;
 success:
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 07/10] fuse: convert fuse_writepage_need_send to take a folio
  2024-09-27 20:44 [PATCH v3 00/10] fuse: folio conversions Josef Bacik
                   ` (5 preceding siblings ...)
  2024-09-27 20:44 ` [PATCH v3 06/10] fuse: convert fuse_do_readpage to use folios Josef Bacik
@ 2024-09-27 20:44 ` Josef Bacik
  2024-09-27 22:55   ` Joanne Koong
  2024-09-27 20:44 ` [PATCH v3 08/10] fuse: use the folio based vmstat helpers Josef Bacik
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 21+ messages in thread
From: Josef Bacik @ 2024-09-27 20:44 UTC (permalink / raw)
  To: linux-fsdevel, amir73il, miklos, kernel-team

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 | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 8a4621939d3b..e02093fe539a 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -483,14 +483,19 @@ 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)
+{
+	pgoff_t last = folio_next_index(folio) - 1;
+	return fuse_range_is_writeback(inode, folio_index(folio), last);
+}
+
 static void fuse_wait_on_folio_writeback(struct inode *inode,
 					 struct folio *folio)
 {
 	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(folio), last));
+	wait_event(fi->page_waitq, !fuse_folio_is_writeback(inode, folio));
 }
 
 /*
@@ -2262,7 +2267,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)
 {
@@ -2274,7 +2279,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 */
@@ -2286,7 +2291,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? */
@@ -2308,7 +2313,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] 21+ messages in thread

* [PATCH v3 08/10] fuse: use the folio based vmstat helpers
  2024-09-27 20:44 [PATCH v3 00/10] fuse: folio conversions Josef Bacik
                   ` (6 preceding siblings ...)
  2024-09-27 20:44 ` [PATCH v3 07/10] fuse: convert fuse_writepage_need_send to take a folio Josef Bacik
@ 2024-09-27 20:44 ` Josef Bacik
  2024-09-27 20:45 ` [PATCH v3 09/10] fuse: convert fuse_retrieve to use folios Josef Bacik
  2024-09-27 20:45 ` [PATCH v3 10/10] fuse: convert fuse_notify_store " Josef Bacik
  9 siblings, 0 replies; 21+ messages in thread
From: Josef Bacik @ 2024-09-27 20:44 UTC (permalink / raw)
  To: linux-fsdevel, amir73il, miklos, kernel-team; +Cc: Joanne Koong

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.

Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
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 e02093fe539a..4c6eb724212d 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1794,12 +1794,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);
 }
 
@@ -1811,7 +1811,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);
 }
@@ -1866,7 +1866,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);
 	}
 
@@ -2086,7 +2087,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,
@@ -2260,7 +2261,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] 21+ messages in thread

* [PATCH v3 09/10] fuse: convert fuse_retrieve to use folios
  2024-09-27 20:44 [PATCH v3 00/10] fuse: folio conversions Josef Bacik
                   ` (7 preceding siblings ...)
  2024-09-27 20:44 ` [PATCH v3 08/10] fuse: use the folio based vmstat helpers Josef Bacik
@ 2024-09-27 20:45 ` Josef Bacik
  2024-09-27 22:59   ` Joanne Koong
  2024-09-27 20:45 ` [PATCH v3 10/10] fuse: convert fuse_notify_store " Josef Bacik
  9 siblings, 1 reply; 21+ messages in thread
From: Josef Bacik @ 2024-09-27 20:45 UTC (permalink / raw)
  To: linux-fsdevel, amir73il, miklos, kernel-team; +Cc: Joanne Koong

We're just looking for pages in a mapping, use a folio and the folio
lookup function directly instead of using the page helper.

Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
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 1f64ae6d7a69..4c58113eb6a1 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1756,15 +1756,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] 21+ messages in thread

* [PATCH v3 10/10] fuse: convert fuse_notify_store to use folios
  2024-09-27 20:44 [PATCH v3 00/10] fuse: folio conversions Josef Bacik
                   ` (8 preceding siblings ...)
  2024-09-27 20:45 ` [PATCH v3 09/10] fuse: convert fuse_retrieve to use folios Josef Bacik
@ 2024-09-27 20:45 ` Josef Bacik
  2024-09-27 23:08   ` Joanne Koong
  9 siblings, 1 reply; 21+ messages in thread
From: Josef Bacik @ 2024-09-27 20:45 UTC (permalink / raw)
  To: linux-fsdevel, amir73il, miklos, kernel-team

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 4c58113eb6a1..5b011c8fa9d6 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1654,24 +1654,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] 21+ messages in thread

* Re: [PATCH v3 01/10] fuse: convert readahead to use folios
  2024-09-27 20:44 ` [PATCH v3 01/10] fuse: convert readahead to use folios Josef Bacik
@ 2024-09-27 22:22   ` Joanne Koong
  2024-09-30 13:33     ` Josef Bacik
  0 siblings, 1 reply; 21+ messages in thread
From: Joanne Koong @ 2024-09-27 22:22 UTC (permalink / raw)
  To: Josef Bacik; +Cc: linux-fsdevel, amir73il, miklos, kernel-team

On Fri, Sep 27, 2024 at 1:45 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> 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 | 43 ++++++++++++++++++++++++++++---------------
>  1 file changed, 28 insertions(+), 15 deletions(-)
>
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index f33fbce86ae0..132528cde745 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -938,7 +938,6 @@ static void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args,
>                 struct folio *folio = page_folio(ap->pages[i]);
>
>                 folio_end_read(folio, !err);
> -               folio_put(folio);
>         }
>         if (ia->ff)
>                 fuse_file_put(ia->ff, false);
> @@ -985,18 +984,36 @@ static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file)
>  static void fuse_readahead(struct readahead_control *rac)
>  {
>         struct inode *inode = rac->mapping->host;
> +       struct fuse_inode *fi = get_fuse_inode(inode);
>         struct fuse_conn *fc = get_fuse_conn(inode);
> -       unsigned int i, max_pages, nr_pages = 0;
> +       unsigned int max_pages, nr_pages;
> +       pgoff_t first = readahead_index(rac);
> +       pgoff_t last = first + readahead_count(rac) - 1;
>
>         if (fuse_is_bad(inode))
>                 return;
>
> +       wait_event(fi->page_waitq, !fuse_range_is_writeback(inode, first, last));

Should this line be moved to after we check the readahead count? eg

nr_pages = readahead_count(rac);
if (!nr_pages)
    return;
wait_event(fi->page_waitq, !fuse_range_is_writeback(inode, first, last));

Otherwise I think in that case you mentioned where read_pages() calls
into readahead_folio() after it's consumed the last folio, we end up
calling this wait_event

> +
>         max_pages = min_t(unsigned int, fc->max_pages,
>                         fc->max_read / PAGE_SIZE);
>
> -       for (;;) {
> +       /*
> +        * This is only accurate the first time through, since readahead_folio()
> +        * doesn't update readahead_count() from the previous folio until the
> +        * next call.  Grab nr_pages here so we know how many pages we're going
> +        * to have to process.  This means that we will exit here with
> +        * readahead_count() == folio_nr_pages(last_folio), but we will have
> +        * consumed all of the folios, and read_pages() will call
> +        * readahead_folio() again which will clean up the rac.
> +        */
> +       nr_pages = readahead_count(rac);
> +
> +       while (nr_pages) {
>                 struct fuse_io_args *ia;
>                 struct fuse_args_pages *ap;
> +               struct folio *folio;
> +               unsigned cur_pages = min(max_pages, nr_pages);
>
>                 if (fc->num_background >= fc->congestion_threshold &&
>                     rac->ra->async_size >= readahead_count(rac))
> @@ -1006,23 +1023,19 @@ static void fuse_readahead(struct readahead_control *rac)
>                          */
>                         break;
>
> -               nr_pages = readahead_count(rac) - nr_pages;
> -               if (nr_pages > max_pages)
> -                       nr_pages = max_pages;
> -               if (nr_pages == 0)
> -                       break;
> -               ia = fuse_io_alloc(NULL, nr_pages);
> +               ia = fuse_io_alloc(NULL, cur_pages);
>                 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 (ap->num_pages < cur_pages &&
> +                      (folio = readahead_folio(rac)) != NULL) {
> +                       ap->pages[ap->num_pages] = &folio->page;
> +                       ap->descs[ap->num_pages].length = folio_size(folio);
> +                       ap->num_pages++;
>                 }
> -               ap->num_pages = nr_pages;
>                 fuse_send_readpages(ia, rac->file);
> +               nr_pages -= cur_pages;
>         }
>  }
>
> --
> 2.43.0
>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 02/10] fuse: convert fuse_send_write_pages to use folios
  2024-09-27 20:44 ` [PATCH v3 02/10] fuse: convert fuse_send_write_pages " Josef Bacik
@ 2024-09-27 22:24   ` Joanne Koong
  0 siblings, 0 replies; 21+ messages in thread
From: Joanne Koong @ 2024-09-27 22:24 UTC (permalink / raw)
  To: Josef Bacik; +Cc: linux-fsdevel, amir73il, miklos, kernel-team, Matthew Wilcox

On Fri, Sep 27, 2024 at 1:46 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> Convert this to grab the folio from the fuse_args_pages and use the
> appropriate folio related functions.
>
> Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>

Reviewed-by: Joanne Koong <joannelkoong@gmail.com>

> ---
>  fs/fuse/file.c | 14 +++++++-------
>  1 file changed, 7 insertions(+), 7 deletions(-)
>
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index 132528cde745..17ac2de61cdb 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -1168,23 +1168,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;
> +                       if (count >= folio_size(folio) - offset)
> +                               count -= folio_size(folio) - 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	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 03/10] fuse: convert fuse_fill_write_pages to use folios
  2024-09-27 20:44 ` [PATCH v3 03/10] fuse: convert fuse_fill_write_pages " Josef Bacik
@ 2024-09-27 22:36   ` Joanne Koong
  0 siblings, 0 replies; 21+ messages in thread
From: Joanne Koong @ 2024-09-27 22:36 UTC (permalink / raw)
  To: Josef Bacik; +Cc: linux-fsdevel, amir73il, miklos, kernel-team

On Fri, Sep 27, 2024 at 1:45 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>

Reviewed-by: Joanne Koong <joannelkoong@gmail.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 17ac2de61cdb..1f7fe5416139 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -1206,7 +1206,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));
> @@ -1218,25 +1218,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++;
>
> @@ -1248,10 +1250,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] 21+ messages in thread

* Re: [PATCH v3 04/10] fuse: convert fuse_page_mkwrite to use folios
  2024-09-27 20:44 ` [PATCH v3 04/10] fuse: convert fuse_page_mkwrite " Josef Bacik
@ 2024-09-27 22:42   ` Joanne Koong
  0 siblings, 0 replies; 21+ messages in thread
From: Joanne Koong @ 2024-09-27 22:42 UTC (permalink / raw)
  To: Josef Bacik; +Cc: linux-fsdevel, amir73il, miklos, kernel-team

On Fri, Sep 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>

Reviewed-by: Joanne Koong <joannelkoong@gmail.com>

> ---
>  fs/fuse/file.c | 20 +++++++++++++++-----
>  1 file changed, 15 insertions(+), 5 deletions(-)
>
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index 1f7fe5416139..c8a5fa579615 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -483,6 +483,16 @@ 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 void fuse_wait_on_folio_writeback(struct inode *inode,
> +                                        struct folio *folio)
> +{
> +       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(folio), last));
> +}
> +
>  /*
>   * Wait for all pending writepages on the inode to finish.
>   *
> @@ -2527,17 +2537,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	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 06/10] fuse: convert fuse_do_readpage to use folios
  2024-09-27 20:44 ` [PATCH v3 06/10] fuse: convert fuse_do_readpage to use folios Josef Bacik
@ 2024-09-27 22:51   ` Joanne Koong
  2024-09-30 13:39     ` Josef Bacik
  0 siblings, 1 reply; 21+ messages in thread
From: Joanne Koong @ 2024-09-27 22:51 UTC (permalink / raw)
  To: Josef Bacik; +Cc: linux-fsdevel, amir73il, miklos, kernel-team

On Fri, Sep 27, 2024 at 1:54 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> 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 2af9ec67a8e7..8a4621939d3b 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -858,12 +858,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)

Should we also rename this to fuse_do_readfolio instead of fuse_do_readpage?

>  {
> -       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,
> @@ -875,11 +876,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.

Is this comment true that folio writeback can extend beyond the
lifetime of the folio? Or is it that folio writeback can extend beyond
the lifetime of the folio in the page cache?

>          */
> -       fuse_wait_on_page_writeback(inode, page->index);
> +       fuse_wait_on_folio_writeback(inode, folio);
>
>         attr_ver = fuse_get_attr_version(fm->fc);
>
> @@ -897,25 +897,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;
>  }
>
> @@ -2444,7 +2443,7 @@ static int fuse_write_begin(struct file *file, struct address_space *mapping,
>                         folio_zero_segment(folio, 0, off);
>                 goto success;
>         }
> -       err = fuse_do_readpage(file, &folio->page);
> +       err = fuse_do_readpage(file, folio);
>         if (err)
>                 goto cleanup;
>  success:
> --
> 2.43.0
>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 07/10] fuse: convert fuse_writepage_need_send to take a folio
  2024-09-27 20:44 ` [PATCH v3 07/10] fuse: convert fuse_writepage_need_send to take a folio Josef Bacik
@ 2024-09-27 22:55   ` Joanne Koong
  0 siblings, 0 replies; 21+ messages in thread
From: Joanne Koong @ 2024-09-27 22:55 UTC (permalink / raw)
  To: Josef Bacik; +Cc: linux-fsdevel, amir73il, miklos, kernel-team

On Fri, Sep 27, 2024 at 1:54 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> 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>

Reviewed-by: Joanne Koong <joannelkoong@gmail.com>


> ---
>  fs/fuse/file.c | 19 ++++++++++++-------
>  1 file changed, 12 insertions(+), 7 deletions(-)
>
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index 8a4621939d3b..e02093fe539a 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -483,14 +483,19 @@ 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)
> +{
> +       pgoff_t last = folio_next_index(folio) - 1;
> +       return fuse_range_is_writeback(inode, folio_index(folio), last);
> +}
> +
>  static void fuse_wait_on_folio_writeback(struct inode *inode,
>                                          struct folio *folio)
>  {
>         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(folio), last));
> +       wait_event(fi->page_waitq, !fuse_folio_is_writeback(inode, folio));
>  }
>
>  /*
> @@ -2262,7 +2267,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)
>  {
> @@ -2274,7 +2279,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 */
> @@ -2286,7 +2291,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? */
> @@ -2308,7 +2313,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	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 09/10] fuse: convert fuse_retrieve to use folios
  2024-09-27 20:45 ` [PATCH v3 09/10] fuse: convert fuse_retrieve to use folios Josef Bacik
@ 2024-09-27 22:59   ` Joanne Koong
  0 siblings, 0 replies; 21+ messages in thread
From: Joanne Koong @ 2024-09-27 22:59 UTC (permalink / raw)
  To: Josef Bacik; +Cc: linux-fsdevel, amir73il, miklos, kernel-team

On Fri, Sep 27, 2024 at 1:45 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.
>
> Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
> 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 1f64ae6d7a69..4c58113eb6a1 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -1756,15 +1756,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);

I think you can also just use "filemap_get_folio(mapping, index);" here

> +               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] 21+ messages in thread

* Re: [PATCH v3 10/10] fuse: convert fuse_notify_store to use folios
  2024-09-27 20:45 ` [PATCH v3 10/10] fuse: convert fuse_notify_store " Josef Bacik
@ 2024-09-27 23:08   ` Joanne Koong
  0 siblings, 0 replies; 21+ messages in thread
From: Joanne Koong @ 2024-09-27 23:08 UTC (permalink / raw)
  To: Josef Bacik; +Cc: linux-fsdevel, amir73il, miklos, kernel-team

On Fri, Sep 27, 2024 at 1:46 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> 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>

Reviewed-by: Joanne Koong <joannelkoong@gmail.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 4c58113eb6a1..5b011c8fa9d6 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -1654,24 +1654,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	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 01/10] fuse: convert readahead to use folios
  2024-09-27 22:22   ` Joanne Koong
@ 2024-09-30 13:33     ` Josef Bacik
  0 siblings, 0 replies; 21+ messages in thread
From: Josef Bacik @ 2024-09-30 13:33 UTC (permalink / raw)
  To: Joanne Koong; +Cc: linux-fsdevel, amir73il, miklos, kernel-team

On Fri, Sep 27, 2024 at 03:22:25PM -0700, Joanne Koong wrote:
> On Fri, Sep 27, 2024 at 1:45 PM Josef Bacik <josef@toxicpanda.com> wrote:
> >
> > 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 | 43 ++++++++++++++++++++++++++++---------------
> >  1 file changed, 28 insertions(+), 15 deletions(-)
> >
> > diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> > index f33fbce86ae0..132528cde745 100644
> > --- a/fs/fuse/file.c
> > +++ b/fs/fuse/file.c
> > @@ -938,7 +938,6 @@ static void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args,
> >                 struct folio *folio = page_folio(ap->pages[i]);
> >
> >                 folio_end_read(folio, !err);
> > -               folio_put(folio);
> >         }
> >         if (ia->ff)
> >                 fuse_file_put(ia->ff, false);
> > @@ -985,18 +984,36 @@ static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file)
> >  static void fuse_readahead(struct readahead_control *rac)
> >  {
> >         struct inode *inode = rac->mapping->host;
> > +       struct fuse_inode *fi = get_fuse_inode(inode);
> >         struct fuse_conn *fc = get_fuse_conn(inode);
> > -       unsigned int i, max_pages, nr_pages = 0;
> > +       unsigned int max_pages, nr_pages;
> > +       pgoff_t first = readahead_index(rac);
> > +       pgoff_t last = first + readahead_count(rac) - 1;
> >
> >         if (fuse_is_bad(inode))
> >                 return;
> >
> > +       wait_event(fi->page_waitq, !fuse_range_is_writeback(inode, first, last));
> 
> Should this line be moved to after we check the readahead count? eg
> 
> nr_pages = readahead_count(rac);
> if (!nr_pages)
>     return;
> wait_event(fi->page_waitq, !fuse_range_is_writeback(inode, first, last));
> 
> Otherwise I think in that case you mentioned where read_pages() calls
> into readahead_folio() after it's consumed the last folio, we end up
> calling this wait_event

The first bit of read_pages covers this for us

static void read_pages(struct readahead_control *rac)
{
        const struct address_space_operations *aops = rac->mapping->a_ops;
        struct folio *folio;
        struct blk_plug plug;

        if (!readahead_count(rac))
                return;

We don't get ->readahead called unless there's pages to read.  Thanks,

Josef

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 06/10] fuse: convert fuse_do_readpage to use folios
  2024-09-27 22:51   ` Joanne Koong
@ 2024-09-30 13:39     ` Josef Bacik
  0 siblings, 0 replies; 21+ messages in thread
From: Josef Bacik @ 2024-09-30 13:39 UTC (permalink / raw)
  To: Joanne Koong; +Cc: linux-fsdevel, amir73il, miklos, kernel-team

On Fri, Sep 27, 2024 at 03:51:17PM -0700, Joanne Koong wrote:
> On Fri, Sep 27, 2024 at 1:54 PM Josef Bacik <josef@toxicpanda.com> wrote:
> >
> > 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 2af9ec67a8e7..8a4621939d3b 100644
> > --- a/fs/fuse/file.c
> > +++ b/fs/fuse/file.c
> > @@ -858,12 +858,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)
> 
> Should we also rename this to fuse_do_readfolio instead of fuse_do_readpage?
> 
> >  {
> > -       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,
> > @@ -875,11 +876,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.
> 
> Is this comment true that folio writeback can extend beyond the
> lifetime of the folio? Or is it that folio writeback can extend beyond
> the lifetime of the folio in the page cache?

This is true today because of the temporary pages.  We can have writebackout for
the range of the folio outstanding because the temporary pages can still be in
flight and we might have reclaimed the folio that existed for that given range.
Once you delete the temporary pages thing the comment will no longer be correct.
I'll update the comment to be more clear, thanks,

Josef

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2024-09-30 13:39 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-27 20:44 [PATCH v3 00/10] fuse: folio conversions Josef Bacik
2024-09-27 20:44 ` [PATCH v3 01/10] fuse: convert readahead to use folios Josef Bacik
2024-09-27 22:22   ` Joanne Koong
2024-09-30 13:33     ` Josef Bacik
2024-09-27 20:44 ` [PATCH v3 02/10] fuse: convert fuse_send_write_pages " Josef Bacik
2024-09-27 22:24   ` Joanne Koong
2024-09-27 20:44 ` [PATCH v3 03/10] fuse: convert fuse_fill_write_pages " Josef Bacik
2024-09-27 22:36   ` Joanne Koong
2024-09-27 20:44 ` [PATCH v3 04/10] fuse: convert fuse_page_mkwrite " Josef Bacik
2024-09-27 22:42   ` Joanne Koong
2024-09-27 20:44 ` [PATCH v3 05/10] fuse: use kiocb_modified in buffered write path Josef Bacik
2024-09-27 20:44 ` [PATCH v3 06/10] fuse: convert fuse_do_readpage to use folios Josef Bacik
2024-09-27 22:51   ` Joanne Koong
2024-09-30 13:39     ` Josef Bacik
2024-09-27 20:44 ` [PATCH v3 07/10] fuse: convert fuse_writepage_need_send to take a folio Josef Bacik
2024-09-27 22:55   ` Joanne Koong
2024-09-27 20:44 ` [PATCH v3 08/10] fuse: use the folio based vmstat helpers Josef Bacik
2024-09-27 20:45 ` [PATCH v3 09/10] fuse: convert fuse_retrieve to use folios Josef Bacik
2024-09-27 22:59   ` Joanne Koong
2024-09-27 20:45 ` [PATCH v3 10/10] fuse: convert fuse_notify_store " Josef Bacik
2024-09-27 23:08   ` Joanne Koong

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).