* [PATCH v4 01/10] fuse: convert readahead to use folios
2024-09-30 13:45 [PATCH v4 00/10] fuse: folio conversions Josef Bacik
@ 2024-09-30 13:45 ` Josef Bacik
2024-09-30 13:45 ` [PATCH v4 02/10] fuse: convert fuse_send_write_pages " Josef Bacik
` (9 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2024-09-30 13:45 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] 14+ messages in thread
* [PATCH v4 02/10] fuse: convert fuse_send_write_pages to use folios
2024-09-30 13:45 [PATCH v4 00/10] fuse: folio conversions Josef Bacik
2024-09-30 13:45 ` [PATCH v4 01/10] fuse: convert readahead to use folios Josef Bacik
@ 2024-09-30 13:45 ` Josef Bacik
2024-09-30 13:45 ` [PATCH v4 03/10] fuse: convert fuse_fill_write_pages " Josef Bacik
` (8 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2024-09-30 13:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, kernel-team; +Cc: Matthew Wilcox, Joanne Koong
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>
Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
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] 14+ messages in thread
* [PATCH v4 03/10] fuse: convert fuse_fill_write_pages to use folios
2024-09-30 13:45 [PATCH v4 00/10] fuse: folio conversions Josef Bacik
2024-09-30 13:45 ` [PATCH v4 01/10] fuse: convert readahead to use folios Josef Bacik
2024-09-30 13:45 ` [PATCH v4 02/10] fuse: convert fuse_send_write_pages " Josef Bacik
@ 2024-09-30 13:45 ` Josef Bacik
2024-09-30 13:45 ` [PATCH v4 04/10] fuse: convert fuse_page_mkwrite " Josef Bacik
` (7 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2024-09-30 13:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, kernel-team; +Cc: Joanne Koong
Convert this to grab the folio directly, and update all the helpers to
use the folio related functions.
Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
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] 14+ messages in thread
* [PATCH v4 04/10] fuse: convert fuse_page_mkwrite to use folios
2024-09-30 13:45 [PATCH v4 00/10] fuse: folio conversions Josef Bacik
` (2 preceding siblings ...)
2024-09-30 13:45 ` [PATCH v4 03/10] fuse: convert fuse_fill_write_pages " Josef Bacik
@ 2024-09-30 13:45 ` Josef Bacik
2024-09-30 13:45 ` [PATCH v4 05/10] fuse: use kiocb_modified in buffered write path Josef Bacik
` (6 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2024-09-30 13:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, kernel-team; +Cc: Joanne Koong
Convert this to grab the folio directly, and update all the helpers to
use the folio related functions.
Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
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] 14+ messages in thread
* [PATCH v4 05/10] fuse: use kiocb_modified in buffered write path
2024-09-30 13:45 [PATCH v4 00/10] fuse: folio conversions Josef Bacik
` (3 preceding siblings ...)
2024-09-30 13:45 ` [PATCH v4 04/10] fuse: convert fuse_page_mkwrite " Josef Bacik
@ 2024-09-30 13:45 ` Josef Bacik
2024-09-30 13:45 ` [PATCH v4 06/10] fuse: convert fuse_do_readpage to use folios Josef Bacik
` (5 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2024-09-30 13:45 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] 14+ messages in thread
* [PATCH v4 06/10] fuse: convert fuse_do_readpage to use folios
2024-09-30 13:45 [PATCH v4 00/10] fuse: folio conversions Josef Bacik
` (4 preceding siblings ...)
2024-09-30 13:45 ` [PATCH v4 05/10] fuse: use kiocb_modified in buffered write path Josef Bacik
@ 2024-09-30 13:45 ` Josef Bacik
2024-10-01 16:54 ` Joanne Koong
2024-09-30 13:45 ` [PATCH v4 07/10] fuse: convert fuse_writepage_need_send to take a folio Josef Bacik
` (4 subsequent siblings)
10 siblings, 1 reply; 14+ messages in thread
From: Josef Bacik @ 2024-09-30 13:45 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 | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 2af9ec67a8e7..45667c40de7a 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_readfolio(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,11 @@ 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.
+ * With the temporary pages that are used to complete writeback, we can
+ * have writeback that extends 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 +898,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_readfolio(file, folio);
fuse_invalidate_atime(inode);
out:
- unlock_page(page);
+ folio_unlock(folio);
return err;
}
@@ -2444,7 +2444,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_readfolio(file, folio);
if (err)
goto cleanup;
success:
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v4 06/10] fuse: convert fuse_do_readpage to use folios
2024-09-30 13:45 ` [PATCH v4 06/10] fuse: convert fuse_do_readpage to use folios Josef Bacik
@ 2024-10-01 16:54 ` Joanne Koong
2024-10-01 20:19 ` Josef Bacik
0 siblings, 1 reply; 14+ messages in thread
From: Joanne Koong @ 2024-10-01 16:54 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-fsdevel, amir73il, miklos, kernel-team
On Mon, Sep 30, 2024 at 6:46 AM 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>
Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
> ---
> fs/fuse/file.c | 26 +++++++++++++-------------
> 1 file changed, 13 insertions(+), 13 deletions(-)
>
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index 2af9ec67a8e7..45667c40de7a 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_readfolio(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,11 @@ 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.
> + * With the temporary pages that are used to complete writeback, we can
> + * have writeback that extends 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 +898,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_readfolio(file, folio);
> fuse_invalidate_atime(inode);
> out:
> - unlock_page(page);
> + folio_unlock(folio);
> return err;
> }
>
> @@ -2444,7 +2444,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_readfolio(file, folio);
I'm on top of Miklos' for-next tree but I'm seeing this patch unable
to apply cleanly. On the top of the tree, I see the original line as:
err = fuse_do_readpage(file, page);
Is there another patch/patchset this stack is based on top of?
Thanks,
Joanne
> if (err)
> goto cleanup;
> success:
> --
> 2.43.0
>
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v4 06/10] fuse: convert fuse_do_readpage to use folios
2024-10-01 16:54 ` Joanne Koong
@ 2024-10-01 20:19 ` Josef Bacik
0 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2024-10-01 20:19 UTC (permalink / raw)
To: Joanne Koong; +Cc: linux-fsdevel, amir73il, miklos, kernel-team
On Tue, Oct 01, 2024 at 09:54:51AM -0700, Joanne Koong wrote:
> On Mon, Sep 30, 2024 at 6:46 AM 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>
>
> Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
>
> > ---
> > fs/fuse/file.c | 26 +++++++++++++-------------
> > 1 file changed, 13 insertions(+), 13 deletions(-)
> >
> > diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> > index 2af9ec67a8e7..45667c40de7a 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_readfolio(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,11 @@ 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.
> > + * With the temporary pages that are used to complete writeback, we can
> > + * have writeback that extends 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 +898,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_readfolio(file, folio);
> > fuse_invalidate_atime(inode);
> > out:
> > - unlock_page(page);
> > + folio_unlock(folio);
> > return err;
> > }
> >
> > @@ -2444,7 +2444,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_readfolio(file, folio);
>
> I'm on top of Miklos' for-next tree but I'm seeing this patch unable
> to apply cleanly. On the top of the tree, I see the original line as:
>
> err = fuse_do_readpage(file, page);
>
> Is there another patch/patchset this stack is based on top of?
Yeah Willy had a folio conversion that's in Linus's tree but is newer than
Miklos's base for his tree. Thanks,
Josef
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v4 07/10] fuse: convert fuse_writepage_need_send to take a folio
2024-09-30 13:45 [PATCH v4 00/10] fuse: folio conversions Josef Bacik
` (5 preceding siblings ...)
2024-09-30 13:45 ` [PATCH v4 06/10] fuse: convert fuse_do_readpage to use folios Josef Bacik
@ 2024-09-30 13:45 ` Josef Bacik
2024-09-30 13:45 ` [PATCH v4 08/10] fuse: use the folio based vmstat helpers Josef Bacik
` (3 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2024-09-30 13:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, kernel-team; +Cc: Joanne Koong
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.
Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
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 45667c40de7a..33f98cd27e09 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));
}
/*
@@ -2263,7 +2268,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)
{
@@ -2275,7 +2280,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 */
@@ -2287,7 +2292,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? */
@@ -2309,7 +2314,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] 14+ messages in thread
* [PATCH v4 08/10] fuse: use the folio based vmstat helpers
2024-09-30 13:45 [PATCH v4 00/10] fuse: folio conversions Josef Bacik
` (6 preceding siblings ...)
2024-09-30 13:45 ` [PATCH v4 07/10] fuse: convert fuse_writepage_need_send to take a folio Josef Bacik
@ 2024-09-30 13:45 ` Josef Bacik
2024-09-30 13:45 ` [PATCH v4 09/10] fuse: convert fuse_retrieve to use folios Josef Bacik
` (2 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2024-09-30 13:45 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 33f98cd27e09..dc701fa94c58 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1795,12 +1795,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);
}
@@ -1812,7 +1812,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);
}
@@ -1867,7 +1867,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);
}
@@ -2087,7 +2088,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,
@@ -2261,7 +2262,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] 14+ messages in thread
* [PATCH v4 09/10] fuse: convert fuse_retrieve to use folios
2024-09-30 13:45 [PATCH v4 00/10] fuse: folio conversions Josef Bacik
` (7 preceding siblings ...)
2024-09-30 13:45 ` [PATCH v4 08/10] fuse: use the folio based vmstat helpers Josef Bacik
@ 2024-09-30 13:45 ` Josef Bacik
2024-09-30 13:45 ` [PATCH v4 10/10] fuse: convert fuse_notify_store " Josef Bacik
2024-10-18 9:59 ` [PATCH v4 00/10] fuse: folio conversions Miklos Szeredi
10 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2024-09-30 13: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..a332cb799967 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);
+ 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] 14+ messages in thread
* [PATCH v4 10/10] fuse: convert fuse_notify_store to use folios
2024-09-30 13:45 [PATCH v4 00/10] fuse: folio conversions Josef Bacik
` (8 preceding siblings ...)
2024-09-30 13:45 ` [PATCH v4 09/10] fuse: convert fuse_retrieve to use folios Josef Bacik
@ 2024-09-30 13:45 ` Josef Bacik
2024-10-18 9:59 ` [PATCH v4 00/10] fuse: folio conversions Miklos Szeredi
10 siblings, 0 replies; 14+ messages in thread
From: Josef Bacik @ 2024-09-30 13:45 UTC (permalink / raw)
To: linux-fsdevel, amir73il, miklos, kernel-team; +Cc: Joanne Koong
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.
Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
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 a332cb799967..7e4c5be45aec 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] 14+ messages in thread
* Re: [PATCH v4 00/10] fuse: folio conversions
2024-09-30 13:45 [PATCH v4 00/10] fuse: folio conversions Josef Bacik
` (9 preceding siblings ...)
2024-09-30 13:45 ` [PATCH v4 10/10] fuse: convert fuse_notify_store " Josef Bacik
@ 2024-10-18 9:59 ` Miklos Szeredi
10 siblings, 0 replies; 14+ messages in thread
From: Miklos Szeredi @ 2024-10-18 9:59 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-fsdevel, amir73il, kernel-team
On Mon, 30 Sept 2024 at 15:45, Josef Bacik <josef@toxicpanda.com> wrote:
> 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
Applied with minor modifications. Now in fuse.git/for-next
Thanks,
Miklos
^ permalink raw reply [flat|nested] 14+ messages in thread