linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/13] fuse: use folios instead of pages for requests
@ 2024-10-02 16:52 Joanne Koong
  2024-10-02 16:52 ` [PATCH 01/13] fuse: support folios in struct fuse_args_pages and fuse_copy_pages() Joanne Koong
                   ` (13 more replies)
  0 siblings, 14 replies; 20+ messages in thread
From: Joanne Koong @ 2024-10-02 16:52 UTC (permalink / raw)
  To: miklos, linux-fsdevel; +Cc: josef, bernd.schubert, willy, kernel-team

This patchset converts fuse requests to use folios instead of pages. Right
now, all folios in fuse are one page, but a subsequent patchset will be
enabling larger-size folios on fuse.

This patchset has no functional changes and have been run through fstests with
passthrough_hp.

This patchset is dependent on (and rebased on top of) Josef's folio conversions
patchset here:
https://lore.kernel.org/linux-fsdevel/cover.1727703714.git.josef@toxicpanda.com/

Joanne Koong (13):
  fuse: support folios in struct fuse_args_pages and fuse_copy_pages()
  fuse: add support in virtio for requests using folios
  fuse: convert cuse to use folios
  fuse: convert readlink to use folios
  fuse: convert readdir to use folios
  fuse: convert reads to use folios
  fuse: convert writes (non-writeback) to use folios
  fuse: convert ioctls to use folios
  fuse: convert retrieves to use folios
  fuse: convert writebacks to use folios
  mm/writeback: add folio_mark_dirty_lock()
  fuse: convert direct io to use folios
  fuse: remove pages for requests and exclusively use folios

 fs/fuse/cuse.c      |  31 ++---
 fs/fuse/dev.c       |  40 +++---
 fs/fuse/dir.c       |  28 ++---
 fs/fuse/file.c      | 291 +++++++++++++++++++++++---------------------
 fs/fuse/fuse_i.h    |  36 +++++-
 fs/fuse/ioctl.c     |  31 +++--
 fs/fuse/readdir.c   |  20 +--
 fs/fuse/virtio_fs.c |  57 +++++----
 include/linux/mm.h  |   1 +
 mm/page-writeback.c |  12 ++
 10 files changed, 303 insertions(+), 244 deletions(-)

-- 
2.43.5


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

* [PATCH 01/13] fuse: support folios in struct fuse_args_pages and fuse_copy_pages()
  2024-10-02 16:52 [PATCH 00/13] fuse: use folios instead of pages for requests Joanne Koong
@ 2024-10-02 16:52 ` Joanne Koong
  2024-10-18 19:48   ` Josef Bacik
  2024-10-02 16:52 ` [PATCH 02/13] fuse: add support in virtio for requests using folios Joanne Koong
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 20+ messages in thread
From: Joanne Koong @ 2024-10-02 16:52 UTC (permalink / raw)
  To: miklos, linux-fsdevel; +Cc: josef, bernd.schubert, willy, kernel-team

This adds support in struct fuse_args_pages and fuse_copy_pages() for
using folios instead of pages for transferring data. Both folios and
pages must be supported right now in struct fuse_args_pages and
fuse_copy_pages() until all request types have been converted to use
folios. Once all have been converted, then
struct fuse_args_pages and fuse_copy_pages() will only support folios.

Right now in fuse, all folios are one page (large folios are not yet
supported). As such, copying folio->page is sufficient for copying
the entire folio in fuse_copy_pages().

No functional changes.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/dev.c    | 36 ++++++++++++++++++++++++++++--------
 fs/fuse/fuse_i.h | 22 +++++++++++++++++++---
 2 files changed, 47 insertions(+), 11 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 7e4c5be45aec..cd9c5e0eefca 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1028,17 +1028,37 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
 	struct fuse_req *req = cs->req;
 	struct fuse_args_pages *ap = container_of(req->args, typeof(*ap), args);
 
+	if (ap->uses_folios) {
+		for (i = 0; i < ap->num_folios && (nbytes || zeroing); i++) {
+			int err;
+			unsigned int offset = ap->folio_descs[i].offset;
+			unsigned int count = min(nbytes, ap->folio_descs[i].length);
+			struct page *orig, *pagep;
 
-	for (i = 0; i < ap->num_pages && (nbytes || zeroing); i++) {
-		int err;
-		unsigned int offset = ap->descs[i].offset;
-		unsigned int count = min(nbytes, ap->descs[i].length);
+			orig = pagep = &ap->folios[i]->page;
 
-		err = fuse_copy_page(cs, &ap->pages[i], offset, count, zeroing);
-		if (err)
-			return err;
+			err = fuse_copy_page(cs, &pagep, offset, count, zeroing);
+			if (err)
+				return err;
+
+			nbytes -= count;
+
+			/* Check if the folio was replaced in the page cache */
+			if (pagep != orig)
+				ap->folios[i] = page_folio(pagep);
+		}
+	} else {
+		for (i = 0; i < ap->num_pages && (nbytes || zeroing); i++) {
+			int err;
+			unsigned int offset = ap->descs[i].offset;
+			unsigned int count = min(nbytes, ap->descs[i].length);
+
+			err = fuse_copy_page(cs, &ap->pages[i], offset, count, zeroing);
+			if (err)
+				return err;
 
-		nbytes -= count;
+			nbytes -= count;
+		}
 	}
 	return 0;
 }
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 7ff00bae4a84..dcc0ab4bea78 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -291,6 +291,12 @@ struct fuse_page_desc {
 	unsigned int offset;
 };
 
+/** FUSE folio descriptor */
+struct fuse_folio_desc {
+	unsigned int length;
+	unsigned int offset;
+};
+
 struct fuse_args {
 	uint64_t nodeid;
 	uint32_t opcode;
@@ -316,9 +322,19 @@ struct fuse_args {
 
 struct fuse_args_pages {
 	struct fuse_args args;
-	struct page **pages;
-	struct fuse_page_desc *descs;
-	unsigned int num_pages;
+	union {
+		struct {
+			struct page **pages;
+			struct fuse_page_desc *descs;
+			unsigned int num_pages;
+		};
+		struct {
+			struct folio **folios;
+			struct fuse_folio_desc *folio_descs;
+			unsigned int num_folios;
+		};
+	};
+	bool uses_folios;
 };
 
 struct fuse_release_args {
-- 
2.43.5


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

* [PATCH 02/13] fuse: add support in virtio for requests using folios
  2024-10-02 16:52 [PATCH 00/13] fuse: use folios instead of pages for requests Joanne Koong
  2024-10-02 16:52 ` [PATCH 01/13] fuse: support folios in struct fuse_args_pages and fuse_copy_pages() Joanne Koong
@ 2024-10-02 16:52 ` Joanne Koong
  2024-10-02 16:52 ` [PATCH 03/13] fuse: convert cuse to use folios Joanne Koong
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Joanne Koong @ 2024-10-02 16:52 UTC (permalink / raw)
  To: miklos, linux-fsdevel; +Cc: josef, bernd.schubert, willy, kernel-team

Until all requests have been converted to use folios instead of pages,
virtio will need to support both types. Once all requests have been
converted, then virtio will support just folios.

No functional changes.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/virtio_fs.c | 87 +++++++++++++++++++++++++++++----------------
 1 file changed, 56 insertions(+), 31 deletions(-)

diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c
index 6404a189e989..5e7262c93590 100644
--- a/fs/fuse/virtio_fs.c
+++ b/fs/fuse/virtio_fs.c
@@ -761,6 +761,7 @@ static void virtio_fs_request_complete(struct fuse_req *req,
 	struct fuse_args_pages *ap;
 	unsigned int len, i, thislen;
 	struct page *page;
+	struct folio *folio;
 
 	/*
 	 * TODO verify that server properly follows FUSE protocol
@@ -772,15 +773,29 @@ static void virtio_fs_request_complete(struct fuse_req *req,
 	if (args->out_pages && args->page_zeroing) {
 		len = args->out_args[args->out_numargs - 1].size;
 		ap = container_of(args, typeof(*ap), args);
-		for (i = 0; i < ap->num_pages; i++) {
-			thislen = ap->descs[i].length;
-			if (len < thislen) {
-				WARN_ON(ap->descs[i].offset);
-				page = ap->pages[i];
-				zero_user_segment(page, len, thislen);
-				len = 0;
-			} else {
-				len -= thislen;
+		if (ap->uses_folios) {
+			for (i = 0; i < ap->num_folios; i++) {
+				thislen = ap->folio_descs[i].length;
+				if (len < thislen) {
+					WARN_ON(ap->folio_descs[i].offset);
+					folio = ap->folios[i];
+					folio_zero_segment(folio, len, thislen);
+					len = 0;
+				} else {
+					len -= thislen;
+				}
+			}
+		} else {
+			for (i = 0; i < ap->num_pages; i++) {
+				thislen = ap->descs[i].length;
+				if (len < thislen) {
+					WARN_ON(ap->descs[i].offset);
+					page = ap->pages[i];
+					zero_user_segment(page, len, thislen);
+					len = 0;
+				} else {
+					len -= thislen;
+				}
 			}
 		}
 	}
@@ -1267,16 +1282,22 @@ static void virtio_fs_send_interrupt(struct fuse_iqueue *fiq, struct fuse_req *r
 }
 
 /* Count number of scatter-gather elements required */
-static unsigned int sg_count_fuse_pages(struct fuse_page_desc *page_descs,
-				       unsigned int num_pages,
-				       unsigned int total_len)
+static unsigned int sg_count_fuse_pages(struct fuse_args_pages *ap,
+					unsigned int total_len)
 {
 	unsigned int i;
 	unsigned int this_len;
 
-	for (i = 0; i < num_pages && total_len; i++) {
-		this_len =  min(page_descs[i].length, total_len);
-		total_len -= this_len;
+	if (ap->uses_folios) {
+		for (i = 0; i < ap->num_folios && total_len; i++) {
+			this_len =  min(ap->folio_descs[i].length, total_len);
+			total_len -= this_len;
+		}
+	} else {
+		for (i = 0; i < ap->num_pages && total_len; i++) {
+			this_len =  min(ap->descs[i].length, total_len);
+			total_len -= this_len;
+		}
 	}
 
 	return i;
@@ -1294,8 +1315,7 @@ static unsigned int sg_count_fuse_req(struct fuse_req *req)
 
 	if (args->in_pages) {
 		size = args->in_args[args->in_numargs - 1].size;
-		total_sgs += sg_count_fuse_pages(ap->descs, ap->num_pages,
-						 size);
+		total_sgs += sg_count_fuse_pages(ap, size);
 	}
 
 	if (!test_bit(FR_ISREPLY, &req->flags))
@@ -1308,28 +1328,35 @@ static unsigned int sg_count_fuse_req(struct fuse_req *req)
 
 	if (args->out_pages) {
 		size = args->out_args[args->out_numargs - 1].size;
-		total_sgs += sg_count_fuse_pages(ap->descs, ap->num_pages,
-						 size);
+		total_sgs += sg_count_fuse_pages(ap, size);
 	}
 
 	return total_sgs;
 }
 
-/* Add pages to scatter-gather list and return number of elements used */
+/* Add pages/folios to scatter-gather list and return number of elements used */
 static unsigned int sg_init_fuse_pages(struct scatterlist *sg,
-				       struct page **pages,
-				       struct fuse_page_desc *page_descs,
-				       unsigned int num_pages,
+				       struct fuse_args_pages *ap,
 				       unsigned int total_len)
 {
 	unsigned int i;
 	unsigned int this_len;
 
-	for (i = 0; i < num_pages && total_len; i++) {
-		sg_init_table(&sg[i], 1);
-		this_len =  min(page_descs[i].length, total_len);
-		sg_set_page(&sg[i], pages[i], this_len, page_descs[i].offset);
-		total_len -= this_len;
+	if (ap->uses_folios) {
+		for (i = 0; i < ap->num_folios && total_len; i++) {
+			sg_init_table(&sg[i], 1);
+			this_len =  min(ap->folio_descs[i].length, total_len);
+			sg_set_folio(&sg[i], ap->folios[i], this_len,
+				     ap->folio_descs[i].offset);
+			total_len -= this_len;
+		}
+	} else {
+		for (i = 0; i < ap->num_pages && total_len; i++) {
+			sg_init_table(&sg[i], 1);
+			this_len =  min(ap->descs[i].length, total_len);
+			sg_set_page(&sg[i], ap->pages[i], this_len, ap->descs[i].offset);
+			total_len -= this_len;
+		}
 	}
 
 	return i;
@@ -1353,9 +1380,7 @@ static unsigned int sg_init_fuse_args(struct scatterlist *sg,
 		sg_init_one(&sg[total_sgs++], argbuf, len);
 
 	if (argpages)
-		total_sgs += sg_init_fuse_pages(&sg[total_sgs],
-						ap->pages, ap->descs,
-						ap->num_pages,
+		total_sgs += sg_init_fuse_pages(&sg[total_sgs], ap,
 						args[numargs - 1].size);
 
 	if (len_used)
-- 
2.43.5


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

* [PATCH 03/13] fuse: convert cuse to use folios
  2024-10-02 16:52 [PATCH 00/13] fuse: use folios instead of pages for requests Joanne Koong
  2024-10-02 16:52 ` [PATCH 01/13] fuse: support folios in struct fuse_args_pages and fuse_copy_pages() Joanne Koong
  2024-10-02 16:52 ` [PATCH 02/13] fuse: add support in virtio for requests using folios Joanne Koong
@ 2024-10-02 16:52 ` Joanne Koong
  2024-10-02 16:52 ` [PATCH 04/13] fuse: convert readlink " Joanne Koong
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Joanne Koong @ 2024-10-02 16:52 UTC (permalink / raw)
  To: miklos, linux-fsdevel; +Cc: josef, bernd.schubert, willy, kernel-team

Convert cuse requests to use a folio instead of a page.

No functional changes.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/cuse.c | 32 +++++++++++++++++---------------
 1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
index 0b2da7b7e2ad..eed78e303139 100644
--- a/fs/fuse/cuse.c
+++ b/fs/fuse/cuse.c
@@ -303,8 +303,8 @@ struct cuse_init_args {
 	struct fuse_args_pages ap;
 	struct cuse_init_in in;
 	struct cuse_init_out out;
-	struct page *page;
-	struct fuse_page_desc desc;
+	struct folio *folio;
+	struct fuse_folio_desc desc;
 };
 
 /**
@@ -326,7 +326,7 @@ static void cuse_process_init_reply(struct fuse_mount *fm,
 	struct fuse_args_pages *ap = &ia->ap;
 	struct cuse_conn *cc = fc_to_cc(fc), *pos;
 	struct cuse_init_out *arg = &ia->out;
-	struct page *page = ap->pages[0];
+	struct folio *folio = ap->folios[0];
 	struct cuse_devinfo devinfo = { };
 	struct device *dev;
 	struct cdev *cdev;
@@ -343,7 +343,7 @@ static void cuse_process_init_reply(struct fuse_mount *fm,
 	/* parse init reply */
 	cc->unrestricted_ioctl = arg->flags & CUSE_UNRESTRICTED_IOCTL;
 
-	rc = cuse_parse_devinfo(page_address(page), ap->args.out_args[1].size,
+	rc = cuse_parse_devinfo(folio_address(folio), ap->args.out_args[1].size,
 				&devinfo);
 	if (rc)
 		goto err;
@@ -411,7 +411,7 @@ static void cuse_process_init_reply(struct fuse_mount *fm,
 	kobject_uevent(&dev->kobj, KOBJ_ADD);
 out:
 	kfree(ia);
-	__free_page(page);
+	folio_put(folio);
 	return;
 
 err_cdev:
@@ -429,7 +429,7 @@ static void cuse_process_init_reply(struct fuse_mount *fm,
 static int cuse_send_init(struct cuse_conn *cc)
 {
 	int rc;
-	struct page *page;
+	struct folio *folio;
 	struct fuse_mount *fm = &cc->fm;
 	struct cuse_init_args *ia;
 	struct fuse_args_pages *ap;
@@ -437,13 +437,14 @@ static int cuse_send_init(struct cuse_conn *cc)
 	BUILD_BUG_ON(CUSE_INIT_INFO_MAX > PAGE_SIZE);
 
 	rc = -ENOMEM;
-	page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-	if (!page)
+
+	folio = folio_alloc(GFP_KERNEL | __GFP_ZERO, 0);
+	if (!folio)
 		goto err;
 
 	ia = kzalloc(sizeof(*ia), GFP_KERNEL);
 	if (!ia)
-		goto err_free_page;
+		goto err_free_folio;
 
 	ap = &ia->ap;
 	ia->in.major = FUSE_KERNEL_VERSION;
@@ -459,18 +460,19 @@ static int cuse_send_init(struct cuse_conn *cc)
 	ap->args.out_args[1].size = CUSE_INIT_INFO_MAX;
 	ap->args.out_argvar = true;
 	ap->args.out_pages = true;
-	ap->num_pages = 1;
-	ap->pages = &ia->page;
-	ap->descs = &ia->desc;
-	ia->page = page;
+	ap->uses_folios = true;
+	ap->num_folios = 1;
+	ap->folios = &ia->folio;
+	ap->folio_descs = &ia->desc;
+	ia->folio = folio;
 	ia->desc.length = ap->args.out_args[1].size;
 	ap->args.end = cuse_process_init_reply;
 
 	rc = fuse_simple_background(fm, &ap->args, GFP_KERNEL);
 	if (rc) {
 		kfree(ia);
-err_free_page:
-		__free_page(page);
+err_free_folio:
+		folio_put(folio);
 	}
 err:
 	return rc;
-- 
2.43.5


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

* [PATCH 04/13] fuse: convert readlink to use folios
  2024-10-02 16:52 [PATCH 00/13] fuse: use folios instead of pages for requests Joanne Koong
                   ` (2 preceding siblings ...)
  2024-10-02 16:52 ` [PATCH 03/13] fuse: convert cuse to use folios Joanne Koong
@ 2024-10-02 16:52 ` Joanne Koong
  2024-10-02 16:52 ` [PATCH 05/13] fuse: convert readdir " Joanne Koong
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Joanne Koong @ 2024-10-02 16:52 UTC (permalink / raw)
  To: miklos, linux-fsdevel; +Cc: josef, bernd.schubert, willy, kernel-team

Convert readlink requests to use a folio instead of a page.

No functional changes.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/dir.c | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 54104dd48af7..a08c532068d0 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1585,14 +1585,15 @@ static int fuse_permission(struct mnt_idmap *idmap,
 	return err;
 }
 
-static int fuse_readlink_page(struct inode *inode, struct page *page)
+static int fuse_readlink_page(struct inode *inode, struct folio *folio)
 {
 	struct fuse_mount *fm = get_fuse_mount(inode);
-	struct fuse_page_desc desc = { .length = PAGE_SIZE - 1 };
+	struct fuse_folio_desc desc = { .length = PAGE_SIZE - 1 };
 	struct fuse_args_pages ap = {
-		.num_pages = 1,
-		.pages = &page,
-		.descs = &desc,
+		.uses_folios = true,
+		.num_folios = 1,
+		.folios = &folio,
+		.folio_descs = &desc,
 	};
 	char *link;
 	ssize_t res;
@@ -1614,7 +1615,7 @@ static int fuse_readlink_page(struct inode *inode, struct page *page)
 	if (WARN_ON(res >= PAGE_SIZE))
 		return -EIO;
 
-	link = page_address(page);
+	link = folio_address(folio);
 	link[res] = '\0';
 
 	return 0;
@@ -1624,7 +1625,7 @@ static const char *fuse_get_link(struct dentry *dentry, struct inode *inode,
 				 struct delayed_call *callback)
 {
 	struct fuse_conn *fc = get_fuse_conn(inode);
-	struct page *page;
+	struct folio *folio;
 	int err;
 
 	err = -EIO;
@@ -1638,20 +1639,20 @@ static const char *fuse_get_link(struct dentry *dentry, struct inode *inode,
 	if (!dentry)
 		goto out_err;
 
-	page = alloc_page(GFP_KERNEL);
+	folio = folio_alloc(GFP_KERNEL, 0);
 	err = -ENOMEM;
-	if (!page)
+	if (!folio)
 		goto out_err;
 
-	err = fuse_readlink_page(inode, page);
+	err = fuse_readlink_page(inode, folio);
 	if (err) {
-		__free_page(page);
+		folio_put(folio);
 		goto out_err;
 	}
 
-	set_delayed_call(callback, page_put_link, page);
+	set_delayed_call(callback, page_put_link, &folio->page);
 
-	return page_address(page);
+	return folio_address(folio);
 
 out_err:
 	return ERR_PTR(err);
@@ -2231,7 +2232,7 @@ void fuse_init_dir(struct inode *inode)
 
 static int fuse_symlink_read_folio(struct file *null, struct folio *folio)
 {
-	int err = fuse_readlink_page(folio->mapping->host, &folio->page);
+	int err = fuse_readlink_page(folio->mapping->host, folio);
 
 	if (!err)
 		folio_mark_uptodate(folio);
-- 
2.43.5


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

* [PATCH 05/13] fuse: convert readdir to use folios
  2024-10-02 16:52 [PATCH 00/13] fuse: use folios instead of pages for requests Joanne Koong
                   ` (3 preceding siblings ...)
  2024-10-02 16:52 ` [PATCH 04/13] fuse: convert readlink " Joanne Koong
@ 2024-10-02 16:52 ` Joanne Koong
  2024-10-02 16:52 ` [PATCH 06/13] fuse: convert reads " Joanne Koong
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Joanne Koong @ 2024-10-02 16:52 UTC (permalink / raw)
  To: miklos, linux-fsdevel; +Cc: josef, bernd.schubert, willy, kernel-team

Convert readdir requests to use a folio instead of a page.

No functional changes.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/readdir.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c
index 0377b6dc24c8..fd0eff1b9f2d 100644
--- a/fs/fuse/readdir.c
+++ b/fs/fuse/readdir.c
@@ -331,24 +331,25 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx)
 {
 	int plus;
 	ssize_t res;
-	struct page *page;
+	struct folio *folio;
 	struct inode *inode = file_inode(file);
 	struct fuse_mount *fm = get_fuse_mount(inode);
 	struct fuse_io_args ia = {};
 	struct fuse_args_pages *ap = &ia.ap;
-	struct fuse_page_desc desc = { .length = PAGE_SIZE };
+	struct fuse_folio_desc desc = { .length = PAGE_SIZE };
 	u64 attr_version = 0;
 	bool locked;
 
-	page = alloc_page(GFP_KERNEL);
-	if (!page)
+	folio = folio_alloc(GFP_KERNEL, 0);
+	if (!folio)
 		return -ENOMEM;
 
 	plus = fuse_use_readdirplus(inode, ctx);
 	ap->args.out_pages = true;
-	ap->num_pages = 1;
-	ap->pages = &page;
-	ap->descs = &desc;
+	ap->uses_folios = true;
+	ap->num_folios = 1;
+	ap->folios = &folio;
+	ap->folio_descs = &desc;
 	if (plus) {
 		attr_version = fuse_get_attr_version(fm->fc);
 		fuse_read_args_fill(&ia, file, ctx->pos, PAGE_SIZE,
@@ -367,15 +368,15 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx)
 			if (ff->open_flags & FOPEN_CACHE_DIR)
 				fuse_readdir_cache_end(file, ctx->pos);
 		} else if (plus) {
-			res = parse_dirplusfile(page_address(page), res,
+			res = parse_dirplusfile(folio_address(folio), res,
 						file, ctx, attr_version);
 		} else {
-			res = parse_dirfile(page_address(page), res, file,
+			res = parse_dirfile(folio_address(folio), res, file,
 					    ctx);
 		}
 	}
 
-	__free_page(page);
+	folio_put(folio);
 	fuse_invalidate_atime(inode);
 	return res;
 }
-- 
2.43.5


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

* [PATCH 06/13] fuse: convert reads to use folios
  2024-10-02 16:52 [PATCH 00/13] fuse: use folios instead of pages for requests Joanne Koong
                   ` (4 preceding siblings ...)
  2024-10-02 16:52 ` [PATCH 05/13] fuse: convert readdir " Joanne Koong
@ 2024-10-02 16:52 ` Joanne Koong
  2024-10-02 16:52 ` [PATCH 07/13] fuse: convert writes (non-writeback) " Joanne Koong
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Joanne Koong @ 2024-10-02 16:52 UTC (permalink / raw)
  To: miklos, linux-fsdevel; +Cc: josef, bernd.schubert, willy, kernel-team

Convert read requests to use folios instead of pages.

No functional changes.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/file.c   | 67 ++++++++++++++++++++++++++++++++----------------
 fs/fuse/fuse_i.h | 12 +++++++++
 2 files changed, 57 insertions(+), 22 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index dc701fa94c58..ad419fafbd5d 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -757,12 +757,37 @@ static struct fuse_io_args *fuse_io_alloc(struct fuse_io_priv *io,
 	return ia;
 }
 
+static struct fuse_io_args *fuse_io_folios_alloc(struct fuse_io_priv *io,
+						 unsigned int nfolios)
+{
+	struct fuse_io_args *ia;
+
+	ia = kzalloc(sizeof(*ia), GFP_KERNEL);
+	if (ia) {
+		ia->io = io;
+		ia->ap.uses_folios = true;
+		ia->ap.folios = fuse_folios_alloc(nfolios, GFP_KERNEL,
+						  &ia->ap.folio_descs);
+		if (!ia->ap.folios) {
+			kfree(ia);
+			ia = NULL;
+		}
+	}
+	return ia;
+}
+
 static void fuse_io_free(struct fuse_io_args *ia)
 {
 	kfree(ia->ap.pages);
 	kfree(ia);
 }
 
+static void fuse_io_folios_free(struct fuse_io_args *ia)
+{
+	kfree(ia->ap.folios);
+	kfree(ia);
+}
+
 static void fuse_aio_complete_req(struct fuse_mount *fm, struct fuse_args *args,
 				  int err)
 {
@@ -858,7 +883,7 @@ static void fuse_short_read(struct inode *inode, u64 attr_ver, size_t num_read,
 	 * reached the client fs yet.  So the hole is not present there.
 	 */
 	if (!fc->writeback_cache) {
-		loff_t pos = page_offset(ap->pages[0]) + num_read;
+		loff_t pos = folio_pos(ap->folios[0]) + num_read;
 		fuse_read_update_size(inode, pos, attr_ver);
 	}
 }
@@ -868,14 +893,14 @@ static int fuse_do_readfolio(struct file *file, struct folio *folio)
 	struct inode *inode = folio->mapping->host;
 	struct fuse_mount *fm = get_fuse_mount(inode);
 	loff_t pos = folio_pos(folio);
-	struct fuse_page_desc desc = { .length = PAGE_SIZE };
-	struct page *page = &folio->page;
+	struct fuse_folio_desc desc = { .length = PAGE_SIZE };
 	struct fuse_io_args ia = {
 		.ap.args.page_zeroing = true,
 		.ap.args.out_pages = true,
-		.ap.num_pages = 1,
-		.ap.pages = &page,
-		.ap.descs = &desc,
+		.ap.uses_folios = true,
+		.ap.num_folios = 1,
+		.ap.folios = &folio,
+		.ap.folio_descs = &desc,
 	};
 	ssize_t res;
 	u64 attr_ver;
@@ -934,8 +959,8 @@ static void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args,
 	size_t num_read = args->out_args[0].size;
 	struct address_space *mapping = NULL;
 
-	for (i = 0; mapping == NULL && i < ap->num_pages; i++)
-		mapping = ap->pages[i]->mapping;
+	for (i = 0; mapping == NULL && i < ap->num_folios; i++)
+		mapping = ap->folios[i]->mapping;
 
 	if (mapping) {
 		struct inode *inode = mapping->host;
@@ -949,15 +974,12 @@ static void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args,
 		fuse_invalidate_atime(inode);
 	}
 
-	for (i = 0; i < ap->num_pages; i++) {
-		struct folio *folio = page_folio(ap->pages[i]);
-
-		folio_end_read(folio, !err);
-	}
+	for (i = 0; i < ap->num_folios; i++)
+		folio_end_read(ap->folios[i], !err);
 	if (ia->ff)
 		fuse_file_put(ia->ff, false);
 
-	fuse_io_free(ia);
+	fuse_io_folios_free(ia);
 }
 
 static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file)
@@ -965,8 +987,9 @@ static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file)
 	struct fuse_file *ff = file->private_data;
 	struct fuse_mount *fm = ff->fm;
 	struct fuse_args_pages *ap = &ia->ap;
-	loff_t pos = page_offset(ap->pages[0]);
-	size_t count = ap->num_pages << PAGE_SHIFT;
+	loff_t pos = folio_pos(ap->folios[0]);
+	/* Currently, all folios in FUSE are one page */
+	size_t count = ap->num_folios << PAGE_SHIFT;
 	ssize_t res;
 	int err;
 
@@ -977,7 +1000,7 @@ static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file)
 	/* Don't overflow end offset */
 	if (pos + (count - 1) == LLONG_MAX) {
 		count--;
-		ap->descs[ap->num_pages - 1].length--;
+		ap->folio_descs[ap->num_folios - 1].length--;
 	}
 	WARN_ON((loff_t) (pos + count) < 0);
 
@@ -1038,16 +1061,16 @@ static void fuse_readahead(struct readahead_control *rac)
 			 */
 			break;
 
-		ia = fuse_io_alloc(NULL, cur_pages);
+		ia = fuse_io_folios_alloc(NULL, cur_pages);
 		if (!ia)
 			return;
 		ap = &ia->ap;
 
-		while (ap->num_pages < cur_pages &&
+		while (ap->num_folios < 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->folios[ap->num_folios] = folio;
+			ap->folio_descs[ap->num_folios].length = folio_size(folio);
+			ap->num_folios++;
 		}
 		fuse_send_readpages(ia, rac->file);
 		nr_pages -= cur_pages;
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index dcc0ab4bea78..2533313502de 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1023,6 +1023,18 @@ static inline struct page **fuse_pages_alloc(unsigned int npages, gfp_t flags,
 	return pages;
 }
 
+static inline struct folio **fuse_folios_alloc(unsigned int nfolios, gfp_t flags,
+					       struct fuse_folio_desc **desc)
+{
+	struct folio **folios;
+
+	folios = kzalloc(nfolios * (sizeof(struct folio *) +
+				    sizeof(struct fuse_folio_desc)), flags);
+	*desc = (void *) (folios + nfolios);
+
+	return folios;
+}
+
 static inline void fuse_page_descs_length_init(struct fuse_page_desc *descs,
 					       unsigned int index,
 					       unsigned int nr_pages)
-- 
2.43.5


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

* [PATCH 07/13] fuse: convert writes (non-writeback) to use folios
  2024-10-02 16:52 [PATCH 00/13] fuse: use folios instead of pages for requests Joanne Koong
                   ` (5 preceding siblings ...)
  2024-10-02 16:52 ` [PATCH 06/13] fuse: convert reads " Joanne Koong
@ 2024-10-02 16:52 ` Joanne Koong
  2024-10-02 16:52 ` [PATCH 08/13] fuse: convert ioctls " Joanne Koong
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Joanne Koong @ 2024-10-02 16:52 UTC (permalink / raw)
  To: miklos, linux-fsdevel; +Cc: josef, bernd.schubert, willy, kernel-team

Convert non-writeback write requests to use folios instead of pages.

No functional changes.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/file.c   | 49 ++++++++++++++++++++++++------------------------
 fs/fuse/fuse_i.h |  2 +-
 2 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index ad419fafbd5d..0f01b4fa324c 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1190,8 +1190,8 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia,
 	bool short_write;
 	int err;
 
-	for (i = 0; i < ap->num_pages; i++)
-		fuse_wait_on_page_writeback(inode, ap->pages[i]->index);
+	for (i = 0; i < ap->num_folios; i++)
+		fuse_wait_on_folio_writeback(inode, ap->folios[i]);
 
 	fuse_write_args_fill(ia, ff, pos, count);
 	ia->write.in.flags = fuse_write_flags(iocb);
@@ -1203,10 +1203,10 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia,
 		err = -EIO;
 
 	short_write = ia->write.out.size < count;
-	offset = ap->descs[0].offset;
+	offset = ap->folio_descs[0].offset;
 	count = ia->write.out.size;
-	for (i = 0; i < ap->num_pages; i++) {
-		struct folio *folio = page_folio(ap->pages[i]);
+	for (i = 0; i < ap->num_folios; i++) {
+		struct folio *folio = ap->folios[i];
 
 		if (err) {
 			folio_clear_uptodate(folio);
@@ -1220,7 +1220,7 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia,
 			}
 			offset = 0;
 		}
-		if (ia->write.page_locked && (i == ap->num_pages - 1))
+		if (ia->write.folio_locked && (i == ap->num_folios - 1))
 			folio_unlock(folio);
 		folio_put(folio);
 	}
@@ -1228,10 +1228,10 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia,
 	return err;
 }
 
-static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
-				     struct address_space *mapping,
-				     struct iov_iter *ii, loff_t pos,
-				     unsigned int max_pages)
+static ssize_t fuse_fill_write_folios(struct fuse_io_args *ia,
+				      struct address_space *mapping,
+				      struct iov_iter *ii, loff_t pos,
+				      unsigned int max_folios)
 {
 	struct fuse_args_pages *ap = &ia->ap;
 	struct fuse_conn *fc = get_fuse_conn(mapping->host);
@@ -1240,7 +1240,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
 	int err;
 
 	ap->args.in_pages = true;
-	ap->descs[0].offset = offset;
+	ap->folio_descs[0].offset = offset;
 
 	do {
 		size_t tmp;
@@ -1276,9 +1276,9 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
 		}
 
 		err = 0;
-		ap->pages[ap->num_pages] = &folio->page;
-		ap->descs[ap->num_pages].length = tmp;
-		ap->num_pages++;
+		ap->folios[ap->num_folios] = folio;
+		ap->folio_descs[ap->num_folios].length = tmp;
+		ap->num_folios++;
 
 		count += tmp;
 		pos += tmp;
@@ -1293,19 +1293,19 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
 		if (folio_test_uptodate(folio)) {
 			folio_unlock(folio);
 		} else {
-			ia->write.page_locked = true;
+			ia->write.folio_locked = true;
 			break;
 		}
 		if (!fc->big_writes)
 			break;
 	} while (iov_iter_count(ii) && count < fc->max_write &&
-		 ap->num_pages < max_pages && offset == 0);
+		 ap->num_folios < max_folios && offset == 0);
 
 	return count > 0 ? count : err;
 }
 
-static inline unsigned int fuse_wr_pages(loff_t pos, size_t len,
-				     unsigned int max_pages)
+static inline unsigned int fuse_wr_folios(loff_t pos, size_t len,
+					  unsigned int max_pages)
 {
 	return min_t(unsigned int,
 		     ((pos + len - 1) >> PAGE_SHIFT) -
@@ -1330,16 +1330,17 @@ static ssize_t fuse_perform_write(struct kiocb *iocb, struct iov_iter *ii)
 		ssize_t count;
 		struct fuse_io_args ia = {};
 		struct fuse_args_pages *ap = &ia.ap;
-		unsigned int nr_pages = fuse_wr_pages(pos, iov_iter_count(ii),
-						      fc->max_pages);
+		unsigned int nr_folios = fuse_wr_folios(pos, iov_iter_count(ii),
+							fc->max_pages);
 
-		ap->pages = fuse_pages_alloc(nr_pages, GFP_KERNEL, &ap->descs);
-		if (!ap->pages) {
+		ap->uses_folios = true;
+		ap->folios = fuse_folios_alloc(nr_folios, GFP_KERNEL, &ap->folio_descs);
+		if (!ap->folios) {
 			err = -ENOMEM;
 			break;
 		}
 
-		count = fuse_fill_write_pages(&ia, mapping, ii, pos, nr_pages);
+		count = fuse_fill_write_folios(&ia, mapping, ii, pos, nr_folios);
 		if (count <= 0) {
 			err = count;
 		} else {
@@ -1356,7 +1357,7 @@ static ssize_t fuse_perform_write(struct kiocb *iocb, struct iov_iter *ii)
 					err = -EIO;
 			}
 		}
-		kfree(ap->pages);
+		kfree(ap->folios);
 	} while (!err && iov_iter_count(ii));
 
 	fuse_write_update_attr(inode, pos, res);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 2533313502de..52492c9bb264 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1090,7 +1090,7 @@ struct fuse_io_args {
 		struct {
 			struct fuse_write_in in;
 			struct fuse_write_out out;
-			bool page_locked;
+			bool folio_locked;
 		} write;
 	};
 	struct fuse_args_pages ap;
-- 
2.43.5


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

* [PATCH 08/13] fuse: convert ioctls to use folios
  2024-10-02 16:52 [PATCH 00/13] fuse: use folios instead of pages for requests Joanne Koong
                   ` (6 preceding siblings ...)
  2024-10-02 16:52 ` [PATCH 07/13] fuse: convert writes (non-writeback) " Joanne Koong
@ 2024-10-02 16:52 ` Joanne Koong
  2024-10-02 16:52 ` [PATCH 09/13] fuse: convert retrieves " Joanne Koong
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Joanne Koong @ 2024-10-02 16:52 UTC (permalink / raw)
  To: miklos, linux-fsdevel; +Cc: josef, bernd.schubert, willy, kernel-team

Convert ioctl requests to use folios instead of pages.

No functional changes.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/fuse_i.h | 10 ++++++++++
 fs/fuse/ioctl.c  | 32 ++++++++++++++++----------------
 2 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 52492c9bb264..d9fa12aee07d 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1045,6 +1045,16 @@ static inline void fuse_page_descs_length_init(struct fuse_page_desc *descs,
 		descs[i].length = PAGE_SIZE - descs[i].offset;
 }
 
+static inline void fuse_folio_descs_length_init(struct fuse_folio_desc *descs,
+						unsigned int index,
+						unsigned int nr_folios)
+{
+	int i;
+
+	for (i = index; i < index + nr_folios; i++)
+		descs[i].length = PAGE_SIZE - descs[i].offset;
+}
+
 static inline void fuse_sync_bucket_dec(struct fuse_sync_bucket *bucket)
 {
 	/* Need RCU protection to prevent use after free after the decrement */
diff --git a/fs/fuse/ioctl.c b/fs/fuse/ioctl.c
index a6c8ee551635..1c77d8a27950 100644
--- a/fs/fuse/ioctl.c
+++ b/fs/fuse/ioctl.c
@@ -251,12 +251,12 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
 	BUILD_BUG_ON(sizeof(struct fuse_ioctl_iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE);
 
 	err = -ENOMEM;
-	ap.pages = fuse_pages_alloc(fm->fc->max_pages, GFP_KERNEL, &ap.descs);
+	ap.folios = fuse_folios_alloc(fm->fc->max_pages, GFP_KERNEL, &ap.folio_descs);
 	iov_page = (struct iovec *) __get_free_page(GFP_KERNEL);
-	if (!ap.pages || !iov_page)
+	if (!ap.folios || !iov_page)
 		goto out;
 
-	fuse_page_descs_length_init(ap.descs, 0, fm->fc->max_pages);
+	fuse_folio_descs_length_init(ap.folio_descs, 0, fm->fc->max_pages);
 
 	/*
 	 * If restricted, initialize IO parameters as encoded in @cmd.
@@ -306,14 +306,14 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
 	err = -ENOMEM;
 	if (max_pages > fm->fc->max_pages)
 		goto out;
-	while (ap.num_pages < max_pages) {
-		ap.pages[ap.num_pages] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
-		if (!ap.pages[ap.num_pages])
+	ap.uses_folios = true;
+	while (ap.num_folios < max_pages) {
+		ap.folios[ap.num_folios] = folio_alloc(GFP_KERNEL | __GFP_HIGHMEM, 0);
+		if (!ap.folios[ap.num_folios])
 			goto out;
-		ap.num_pages++;
+		ap.num_folios++;
 	}
 
-
 	/* okay, let's send it to the client */
 	ap.args.opcode = FUSE_IOCTL;
 	ap.args.nodeid = ff->nodeid;
@@ -327,8 +327,8 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
 
 		err = -EFAULT;
 		iov_iter_init(&ii, ITER_SOURCE, in_iov, in_iovs, in_size);
-		for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_pages); i++) {
-			c = copy_page_from_iter(ap.pages[i], 0, PAGE_SIZE, &ii);
+		for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_folios); i++) {
+			c = copy_folio_from_iter(ap.folios[i], 0, PAGE_SIZE, &ii);
 			if (c != PAGE_SIZE && iov_iter_count(&ii))
 				goto out;
 		}
@@ -366,7 +366,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
 		    in_iovs + out_iovs > FUSE_IOCTL_MAX_IOV)
 			goto out;
 
-		vaddr = kmap_local_page(ap.pages[0]);
+		vaddr = kmap_local_folio(ap.folios[0], 0);
 		err = fuse_copy_ioctl_iovec(fm->fc, iov_page, vaddr,
 					    transferred, in_iovs + out_iovs,
 					    (flags & FUSE_IOCTL_COMPAT) != 0);
@@ -394,17 +394,17 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
 
 	err = -EFAULT;
 	iov_iter_init(&ii, ITER_DEST, out_iov, out_iovs, transferred);
-	for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_pages); i++) {
-		c = copy_page_to_iter(ap.pages[i], 0, PAGE_SIZE, &ii);
+	for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_folios); i++) {
+		c = copy_folio_to_iter(ap.folios[i], 0, PAGE_SIZE, &ii);
 		if (c != PAGE_SIZE && iov_iter_count(&ii))
 			goto out;
 	}
 	err = 0;
  out:
 	free_page((unsigned long) iov_page);
-	while (ap.num_pages)
-		__free_page(ap.pages[--ap.num_pages]);
-	kfree(ap.pages);
+	while (ap.num_folios)
+		folio_put(ap.folios[--ap.num_folios]);
+	kfree(ap.folios);
 
 	return err ? err : outarg.result;
 }
-- 
2.43.5


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

* [PATCH 09/13] fuse: convert retrieves to use folios
  2024-10-02 16:52 [PATCH 00/13] fuse: use folios instead of pages for requests Joanne Koong
                   ` (7 preceding siblings ...)
  2024-10-02 16:52 ` [PATCH 08/13] fuse: convert ioctls " Joanne Koong
@ 2024-10-02 16:52 ` Joanne Koong
  2024-10-02 16:52 ` [PATCH 10/13] fuse: convert writebacks " Joanne Koong
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Joanne Koong @ 2024-10-02 16:52 UTC (permalink / raw)
  To: miklos, linux-fsdevel; +Cc: josef, bernd.schubert, willy, kernel-team

Convert retrieve requests to use folios instead of pages.

No functional changes.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/dev.c | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index cd9c5e0eefca..2f59af6a8c22 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1727,7 +1727,7 @@ static void fuse_retrieve_end(struct fuse_mount *fm, struct fuse_args *args,
 	struct fuse_retrieve_args *ra =
 		container_of(args, typeof(*ra), ap.args);
 
-	release_pages(ra->ap.pages, ra->ap.num_pages);
+	release_pages(ra->ap.folios, ra->ap.num_folios);
 	kfree(ra);
 }
 
@@ -1741,7 +1741,7 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
 	unsigned int num;
 	unsigned int offset;
 	size_t total_len = 0;
-	unsigned int num_pages;
+	unsigned int num_folios;
 	struct fuse_conn *fc = fm->fc;
 	struct fuse_retrieve_args *ra;
 	size_t args_size = sizeof(*ra);
@@ -1757,18 +1757,19 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
 	else if (outarg->offset + num > file_size)
 		num = file_size - outarg->offset;
 
-	num_pages = (num + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
-	num_pages = min(num_pages, fc->max_pages);
+	num_folios = (num + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	num_folios = min(num_folios, fc->max_pages);
 
-	args_size += num_pages * (sizeof(ap->pages[0]) + sizeof(ap->descs[0]));
+	args_size += num_folios * (sizeof(ap->folios[0]) + sizeof(ap->folio_descs[0]));
 
 	ra = kzalloc(args_size, GFP_KERNEL);
 	if (!ra)
 		return -ENOMEM;
 
 	ap = &ra->ap;
-	ap->pages = (void *) (ra + 1);
-	ap->descs = (void *) (ap->pages + num_pages);
+	ap->folios = (void *) (ra + 1);
+	ap->folio_descs = (void *) (ap->folios + num_folios);
+	ap->uses_folios = true;
 
 	args = &ap->args;
 	args->nodeid = outarg->nodeid;
@@ -1779,7 +1780,7 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
 
 	index = outarg->offset >> PAGE_SHIFT;
 
-	while (num && ap->num_pages < num_pages) {
+	while (num && ap->num_folios < num_folios) {
 		struct folio *folio;
 		unsigned int this_num;
 
@@ -1788,10 +1789,10 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
 			break;
 
 		this_num = min_t(unsigned, num, PAGE_SIZE - offset);
-		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++;
+		ap->folios[ap->num_folios] = folio;
+		ap->folio_descs[ap->num_folios].offset = offset;
+		ap->folio_descs[ap->num_folios].length = this_num;
+		ap->num_folios++;
 
 		offset = 0;
 		num -= this_num;
-- 
2.43.5


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

* [PATCH 10/13] fuse: convert writebacks to use folios
  2024-10-02 16:52 [PATCH 00/13] fuse: use folios instead of pages for requests Joanne Koong
                   ` (8 preceding siblings ...)
  2024-10-02 16:52 ` [PATCH 09/13] fuse: convert retrieves " Joanne Koong
@ 2024-10-02 16:52 ` Joanne Koong
  2024-10-02 16:52 ` [PATCH 11/13] mm/writeback: add folio_mark_dirty_lock() Joanne Koong
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Joanne Koong @ 2024-10-02 16:52 UTC (permalink / raw)
  To: miklos, linux-fsdevel; +Cc: josef, bernd.schubert, willy, kernel-team

Convert writeback requests to use folios instead of pages.

No functional changes.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/file.c | 125 +++++++++++++++++++++++++------------------------
 1 file changed, 63 insertions(+), 62 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 0f01b4fa324c..1fa870fb3cc4 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -436,7 +436,7 @@ static struct fuse_writepage_args *fuse_find_writeback(struct fuse_inode *fi,
 		wpa = rb_entry(n, struct fuse_writepage_args, writepages_entry);
 		WARN_ON(get_fuse_inode(wpa->inode) != fi);
 		curr_index = wpa->ia.write.in.offset >> PAGE_SHIFT;
-		if (idx_from >= curr_index + wpa->ia.ap.num_pages)
+		if (idx_from >= curr_index + wpa->ia.ap.num_folios)
 			n = n->rb_right;
 		else if (idx_to < curr_index)
 			n = n->rb_left;
@@ -1810,12 +1810,12 @@ static void fuse_writepage_free(struct fuse_writepage_args *wpa)
 	if (wpa->bucket)
 		fuse_sync_bucket_dec(wpa->bucket);
 
-	for (i = 0; i < ap->num_pages; i++)
-		__free_page(ap->pages[i]);
+	for (i = 0; i < ap->num_folios; i++)
+		folio_put(ap->folios[i]);
 
 	fuse_file_put(wpa->ia.ff, false);
 
-	kfree(ap->pages);
+	kfree(ap->folios);
 	kfree(wpa);
 }
 
@@ -1835,8 +1835,8 @@ static void fuse_writepage_finish(struct fuse_writepage_args *wpa)
 	struct fuse_inode *fi = get_fuse_inode(inode);
 	int i;
 
-	for (i = 0; i < ap->num_pages; i++)
-		fuse_writepage_finish_stat(inode, page_folio(ap->pages[i]));
+	for (i = 0; i < ap->num_folios; i++)
+		fuse_writepage_finish_stat(inode, ap->folios[i]);
 
 	wake_up(&fi->page_waitq);
 }
@@ -1851,7 +1851,7 @@ __acquires(fi->lock)
 	struct fuse_inode *fi = get_fuse_inode(wpa->inode);
 	struct fuse_write_in *inarg = &wpa->ia.write.in;
 	struct fuse_args *args = &wpa->ia.ap.args;
-	__u64 data_size = wpa->ia.ap.num_pages * PAGE_SIZE;
+	__u64 data_size = wpa->ia.ap.num_folios * PAGE_SIZE;
 	int err;
 
 	fi->writectr++;
@@ -1892,7 +1892,7 @@ __acquires(fi->lock)
 		next = aux->next;
 		aux->next = NULL;
 		fuse_writepage_finish_stat(aux->inode,
-					   page_folio(aux->ia.ap.pages[0]));
+					   aux->ia.ap.folios[0]);
 		fuse_writepage_free(aux);
 	}
 
@@ -1927,11 +1927,11 @@ static struct fuse_writepage_args *fuse_insert_writeback(struct rb_root *root,
 						struct fuse_writepage_args *wpa)
 {
 	pgoff_t idx_from = wpa->ia.write.in.offset >> PAGE_SHIFT;
-	pgoff_t idx_to = idx_from + wpa->ia.ap.num_pages - 1;
+	pgoff_t idx_to = idx_from + wpa->ia.ap.num_folios - 1;
 	struct rb_node **p = &root->rb_node;
 	struct rb_node  *parent = NULL;
 
-	WARN_ON(!wpa->ia.ap.num_pages);
+	WARN_ON(!wpa->ia.ap.num_folios);
 	while (*p) {
 		struct fuse_writepage_args *curr;
 		pgoff_t curr_index;
@@ -1942,7 +1942,7 @@ static struct fuse_writepage_args *fuse_insert_writeback(struct rb_root *root,
 		WARN_ON(curr->inode != wpa->inode);
 		curr_index = curr->ia.write.in.offset >> PAGE_SHIFT;
 
-		if (idx_from >= curr_index + curr->ia.ap.num_pages)
+		if (idx_from >= curr_index + curr->ia.ap.num_folios)
 			p = &(*p)->rb_right;
 		else if (idx_to < curr_index)
 			p = &(*p)->rb_left;
@@ -2074,9 +2074,10 @@ static struct fuse_writepage_args *fuse_writepage_args_alloc(void)
 	wpa = kzalloc(sizeof(*wpa), GFP_NOFS);
 	if (wpa) {
 		ap = &wpa->ia.ap;
-		ap->num_pages = 0;
-		ap->pages = fuse_pages_alloc(1, GFP_NOFS, &ap->descs);
-		if (!ap->pages) {
+		ap->num_folios = 0;
+		ap->uses_folios = true;
+		ap->folios = fuse_folios_alloc(1, GFP_NOFS, &ap->folio_descs);
+		if (!ap->folios) {
 			kfree(wpa);
 			wpa = NULL;
 		}
@@ -2100,16 +2101,16 @@ static void fuse_writepage_add_to_bucket(struct fuse_conn *fc,
 }
 
 static void fuse_writepage_args_page_fill(struct fuse_writepage_args *wpa, struct folio *folio,
-					  struct folio *tmp_folio, uint32_t page_index)
+					  struct folio *tmp_folio, uint32_t folio_index)
 {
 	struct inode *inode = folio->mapping->host;
 	struct fuse_args_pages *ap = &wpa->ia.ap;
 
 	folio_copy(tmp_folio, folio);
 
-	ap->pages[page_index] = &tmp_folio->page;
-	ap->descs[page_index].offset = 0;
-	ap->descs[page_index].length = PAGE_SIZE;
+	ap->folios[folio_index] = tmp_folio;
+	ap->folio_descs[folio_index].offset = 0;
+	ap->folio_descs[folio_index].length = PAGE_SIZE;
 
 	inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK);
 	node_stat_add_folio(tmp_folio, NR_WRITEBACK_TEMP);
@@ -2166,7 +2167,7 @@ static int fuse_writepage_locked(struct folio *folio)
 		goto err_writepage_args;
 
 	ap = &wpa->ia.ap;
-	ap->num_pages = 1;
+	ap->num_folios = 1;
 
 	folio_start_writeback(folio);
 	fuse_writepage_args_page_fill(wpa, folio, tmp_folio, 0);
@@ -2194,32 +2195,32 @@ struct fuse_fill_wb_data {
 	struct fuse_writepage_args *wpa;
 	struct fuse_file *ff;
 	struct inode *inode;
-	struct page **orig_pages;
-	unsigned int max_pages;
+	struct folio **orig_folios;
+	unsigned int max_folios;
 };
 
 static bool fuse_pages_realloc(struct fuse_fill_wb_data *data)
 {
 	struct fuse_args_pages *ap = &data->wpa->ia.ap;
 	struct fuse_conn *fc = get_fuse_conn(data->inode);
-	struct page **pages;
-	struct fuse_page_desc *descs;
-	unsigned int npages = min_t(unsigned int,
-				    max_t(unsigned int, data->max_pages * 2,
-					  FUSE_DEFAULT_MAX_PAGES_PER_REQ),
+	struct folio **folios;
+	struct fuse_folio_desc *descs;
+	unsigned int nfolios = min_t(unsigned int,
+				     max_t(unsigned int, data->max_folios * 2,
+					   FUSE_DEFAULT_MAX_PAGES_PER_REQ),
 				    fc->max_pages);
-	WARN_ON(npages <= data->max_pages);
+	WARN_ON(nfolios <= data->max_folios);
 
-	pages = fuse_pages_alloc(npages, GFP_NOFS, &descs);
-	if (!pages)
+	folios = fuse_folios_alloc(nfolios, GFP_NOFS, &descs);
+	if (!folios)
 		return false;
 
-	memcpy(pages, ap->pages, sizeof(struct page *) * ap->num_pages);
-	memcpy(descs, ap->descs, sizeof(struct fuse_page_desc) * ap->num_pages);
-	kfree(ap->pages);
-	ap->pages = pages;
-	ap->descs = descs;
-	data->max_pages = npages;
+	memcpy(folios, ap->folios, sizeof(struct folio *) * ap->num_folios);
+	memcpy(descs, ap->folio_descs, sizeof(struct fuse_folio_desc) * ap->num_folios);
+	kfree(ap->folios);
+	ap->folios = folios;
+	ap->folio_descs = descs;
+	data->max_folios = nfolios;
 
 	return true;
 }
@@ -2229,7 +2230,7 @@ static void fuse_writepages_send(struct fuse_fill_wb_data *data)
 	struct fuse_writepage_args *wpa = data->wpa;
 	struct inode *inode = data->inode;
 	struct fuse_inode *fi = get_fuse_inode(inode);
-	int num_pages = wpa->ia.ap.num_pages;
+	int num_folios = wpa->ia.ap.num_folios;
 	int i;
 
 	spin_lock(&fi->lock);
@@ -2237,8 +2238,8 @@ static void fuse_writepages_send(struct fuse_fill_wb_data *data)
 	fuse_flush_writepages(inode);
 	spin_unlock(&fi->lock);
 
-	for (i = 0; i < num_pages; i++)
-		end_page_writeback(data->orig_pages[i]);
+	for (i = 0; i < num_folios; i++)
+		folio_end_writeback(data->orig_folios[i]);
 }
 
 /*
@@ -2249,15 +2250,15 @@ static void fuse_writepages_send(struct fuse_fill_wb_data *data)
  * swapping the new temp page with the old one.
  */
 static bool fuse_writepage_add(struct fuse_writepage_args *new_wpa,
-			       struct page *page)
+			       struct folio *folio)
 {
 	struct fuse_inode *fi = get_fuse_inode(new_wpa->inode);
 	struct fuse_writepage_args *tmp;
 	struct fuse_writepage_args *old_wpa;
 	struct fuse_args_pages *new_ap = &new_wpa->ia.ap;
 
-	WARN_ON(new_ap->num_pages != 0);
-	new_ap->num_pages = 1;
+	WARN_ON(new_ap->num_folios != 0);
+	new_ap->num_folios = 1;
 
 	spin_lock(&fi->lock);
 	old_wpa = fuse_insert_writeback(&fi->writepages, new_wpa);
@@ -2271,9 +2272,9 @@ static bool fuse_writepage_add(struct fuse_writepage_args *new_wpa,
 
 		WARN_ON(tmp->inode != new_wpa->inode);
 		curr_index = tmp->ia.write.in.offset >> PAGE_SHIFT;
-		if (curr_index == page->index) {
-			WARN_ON(tmp->ia.ap.num_pages != 1);
-			swap(tmp->ia.ap.pages[0], new_ap->pages[0]);
+		if (curr_index == folio->index) {
+			WARN_ON(tmp->ia.ap.num_folios != 1);
+			swap(tmp->ia.ap.folios[0], new_ap->folios[0]);
 			break;
 		}
 	}
@@ -2287,7 +2288,7 @@ static bool fuse_writepage_add(struct fuse_writepage_args *new_wpa,
 
 	if (tmp) {
 		fuse_writepage_finish_stat(new_wpa->inode,
-					   page_folio(new_ap->pages[0]));
+					   folio);
 		fuse_writepage_free(new_wpa);
 	}
 
@@ -2298,7 +2299,7 @@ static bool fuse_writepage_need_send(struct fuse_conn *fc, struct folio *folio,
 				     struct fuse_args_pages *ap,
 				     struct fuse_fill_wb_data *data)
 {
-	WARN_ON(!ap->num_pages);
+	WARN_ON(!ap->num_folios);
 
 	/*
 	 * Being under writeback is unlikely but possible.  For example direct
@@ -2310,19 +2311,19 @@ static bool fuse_writepage_need_send(struct fuse_conn *fc, struct folio *folio,
 		return true;
 
 	/* Reached max pages */
-	if (ap->num_pages == fc->max_pages)
+	if (ap->num_folios == fc->max_pages)
 		return true;
 
 	/* Reached max write bytes */
-	if ((ap->num_pages + 1) * PAGE_SIZE > fc->max_write)
+	if ((ap->num_folios + 1) * PAGE_SIZE > fc->max_write)
 		return true;
 
 	/* Discontinuity */
-	if (data->orig_pages[ap->num_pages - 1]->index + 1 != folio_index(folio))
+	if (data->orig_folios[ap->num_folios - 1]->index + 1 != folio_index(folio))
 		return true;
 
 	/* Need to grow the pages array?  If so, did the expansion fail? */
-	if (ap->num_pages == data->max_pages && !fuse_pages_realloc(data))
+	if (ap->num_folios == data->max_folios && !fuse_pages_realloc(data))
 		return true;
 
 	return false;
@@ -2359,7 +2360,7 @@ static int fuse_writepages_fill(struct folio *folio,
 	 * This is ensured by holding the page lock in page_mkwrite() while
 	 * checking fuse_page_is_writeback().  We already hold the page lock
 	 * since clear_page_dirty_for_io() and keep it held until we add the
-	 * request to the fi->writepages list and increment ap->num_pages.
+	 * request to the fi->writepages list and increment ap->num_folios.
 	 * After this fuse_page_is_writeback() will indicate that the page is
 	 * under writeback, so we can release the page lock.
 	 */
@@ -2371,13 +2372,13 @@ static int fuse_writepages_fill(struct folio *folio,
 			goto out_unlock;
 		}
 		fuse_file_get(wpa->ia.ff);
-		data->max_pages = 1;
+		data->max_folios = 1;
 		ap = &wpa->ia.ap;
 	}
 	folio_start_writeback(folio);
 
-	fuse_writepage_args_page_fill(wpa, folio, tmp_folio, ap->num_pages);
-	data->orig_pages[ap->num_pages] = &folio->page;
+	fuse_writepage_args_page_fill(wpa, folio, tmp_folio, ap->num_folios);
+	data->orig_folios[ap->num_folios] = folio;
 
 	err = 0;
 	if (data->wpa) {
@@ -2386,9 +2387,9 @@ static int fuse_writepages_fill(struct folio *folio,
 		 * fuse_page_is_writeback().
 		 */
 		spin_lock(&fi->lock);
-		ap->num_pages++;
+		ap->num_folios++;
 		spin_unlock(&fi->lock);
-	} else if (fuse_writepage_add(wpa, &folio->page)) {
+	} else if (fuse_writepage_add(wpa, folio)) {
 		data->wpa = wpa;
 	} else {
 		folio_end_writeback(folio);
@@ -2422,19 +2423,19 @@ static int fuse_writepages(struct address_space *mapping,
 		return -EIO;
 
 	err = -ENOMEM;
-	data.orig_pages = kcalloc(fc->max_pages,
-				  sizeof(struct page *),
-				  GFP_NOFS);
-	if (!data.orig_pages)
+	data.orig_folios = kcalloc(fc->max_pages,
+				   sizeof(struct folio *),
+				   GFP_NOFS);
+	if (!data.orig_folios)
 		goto out;
 
 	err = write_cache_pages(mapping, wbc, fuse_writepages_fill, &data);
 	if (data.wpa) {
-		WARN_ON(!data.wpa->ia.ap.num_pages);
+		WARN_ON(!data.wpa->ia.ap.num_folios);
 		fuse_writepages_send(&data);
 	}
 
-	kfree(data.orig_pages);
+	kfree(data.orig_folios);
 out:
 	fuse_file_put(data.ff, false);
 	return err;
-- 
2.43.5


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

* [PATCH 11/13] mm/writeback: add folio_mark_dirty_lock()
  2024-10-02 16:52 [PATCH 00/13] fuse: use folios instead of pages for requests Joanne Koong
                   ` (9 preceding siblings ...)
  2024-10-02 16:52 ` [PATCH 10/13] fuse: convert writebacks " Joanne Koong
@ 2024-10-02 16:52 ` Joanne Koong
  2024-10-18 20:01   ` Josef Bacik
  2024-10-02 16:52 ` [PATCH 12/13] fuse: convert direct io to use folios Joanne Koong
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 20+ messages in thread
From: Joanne Koong @ 2024-10-02 16:52 UTC (permalink / raw)
  To: miklos, linux-fsdevel; +Cc: josef, bernd.schubert, willy, kernel-team

Add a new convenience helper folio_mark_dirty_lock() that grabs the
folio lock before calling folio_mark_dirty().

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 include/linux/mm.h  |  1 +
 mm/page-writeback.c | 12 ++++++++++++
 2 files changed, 13 insertions(+)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index ecf63d2b0582..446d7096c48f 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2539,6 +2539,7 @@ struct kvec;
 struct page *get_dump_page(unsigned long addr);
 
 bool folio_mark_dirty(struct folio *folio);
+bool folio_mark_dirty_lock(struct folio *folio);
 bool set_page_dirty(struct page *page);
 int set_page_dirty_lock(struct page *page);
 
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index fcd4c1439cb9..9b1c95dd219c 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -2913,6 +2913,18 @@ bool folio_mark_dirty(struct folio *folio)
 }
 EXPORT_SYMBOL(folio_mark_dirty);
 
+bool folio_mark_dirty_lock(struct folio *folio)
+{
+	bool ret;
+
+	folio_lock(folio);
+	ret = folio_mark_dirty(folio);
+	folio_unlock(folio);
+
+	return ret;
+}
+EXPORT_SYMBOL(folio_mark_dirty_lock);
+
 /*
  * set_page_dirty() is racy if the caller has no reference against
  * page->mapping->host, and if the page is unlocked.  This is because another
-- 
2.43.5


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

* [PATCH 12/13] fuse: convert direct io to use folios
  2024-10-02 16:52 [PATCH 00/13] fuse: use folios instead of pages for requests Joanne Koong
                   ` (10 preceding siblings ...)
  2024-10-02 16:52 ` [PATCH 11/13] mm/writeback: add folio_mark_dirty_lock() Joanne Koong
@ 2024-10-02 16:52 ` Joanne Koong
  2024-10-18 20:02   ` Josef Bacik
  2024-10-02 16:52 ` [PATCH 13/13] fuse: remove pages for requests and exclusively " Joanne Koong
  2024-10-18 20:07 ` [PATCH 00/13] fuse: use folios instead of pages for requests Josef Bacik
  13 siblings, 1 reply; 20+ messages in thread
From: Joanne Koong @ 2024-10-02 16:52 UTC (permalink / raw)
  To: miklos, linux-fsdevel; +Cc: josef, bernd.schubert, willy, kernel-team

Convert direct io requests to use folios instead of pages.

No functional changes.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/file.c | 88 ++++++++++++++++++++++----------------------------
 1 file changed, 38 insertions(+), 50 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 1fa870fb3cc4..38ed9026f286 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -665,11 +665,11 @@ static void fuse_release_user_pages(struct fuse_args_pages *ap,
 {
 	unsigned int i;
 
-	for (i = 0; i < ap->num_pages; i++) {
+	for (i = 0; i < ap->num_folios; i++) {
 		if (should_dirty)
-			set_page_dirty_lock(ap->pages[i]);
+			folio_mark_dirty_lock(ap->folios[i]);
 		if (ap->args.is_pinned)
-			unpin_user_page(ap->pages[i]);
+			unpin_folio(ap->folios[i]);
 	}
 }
 
@@ -739,24 +739,6 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
 	kref_put(&io->refcnt, fuse_io_release);
 }
 
-static struct fuse_io_args *fuse_io_alloc(struct fuse_io_priv *io,
-					  unsigned int npages)
-{
-	struct fuse_io_args *ia;
-
-	ia = kzalloc(sizeof(*ia), GFP_KERNEL);
-	if (ia) {
-		ia->io = io;
-		ia->ap.pages = fuse_pages_alloc(npages, GFP_KERNEL,
-						&ia->ap.descs);
-		if (!ia->ap.pages) {
-			kfree(ia);
-			ia = NULL;
-		}
-	}
-	return ia;
-}
-
 static struct fuse_io_args *fuse_io_folios_alloc(struct fuse_io_priv *io,
 						 unsigned int nfolios)
 {
@@ -776,12 +758,6 @@ static struct fuse_io_args *fuse_io_folios_alloc(struct fuse_io_priv *io,
 	return ia;
 }
 
-static void fuse_io_free(struct fuse_io_args *ia)
-{
-	kfree(ia->ap.pages);
-	kfree(ia);
-}
-
 static void fuse_io_folios_free(struct fuse_io_args *ia)
 {
 	kfree(ia->ap.folios);
@@ -814,7 +790,7 @@ static void fuse_aio_complete_req(struct fuse_mount *fm, struct fuse_args *args,
 	}
 
 	fuse_aio_complete(io, err, pos);
-	fuse_io_free(ia);
+	fuse_io_folios_free(ia);
 }
 
 static ssize_t fuse_async_req_send(struct fuse_mount *fm,
@@ -1518,10 +1494,11 @@ static inline size_t fuse_get_frag_size(const struct iov_iter *ii,
 
 static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
 			       size_t *nbytesp, int write,
-			       unsigned int max_pages)
+			       unsigned int max_folios)
 {
 	size_t nbytes = 0;  /* # bytes already packed in req */
 	ssize_t ret = 0;
+	ssize_t i = 0;
 
 	/* Special case for kernel I/O: can copy directly into the buffer */
 	if (iov_iter_is_kvec(ii)) {
@@ -1538,15 +1515,23 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
 		return 0;
 	}
 
-	while (nbytes < *nbytesp && ap->num_pages < max_pages) {
-		unsigned npages;
+	/*
+	 * Until there is support for iov_iter_extract_folios(), we have to
+	 * manually extract pages using iov_iter_extract_pages() and then
+	 * copy that to a folios array.
+	 */
+	struct page **pages = kzalloc((max_folios - ap->num_folios) * sizeof(struct page *),
+				      GFP_KERNEL);
+	if (!pages)
+		return -ENOMEM;
+
+	while (nbytes < *nbytesp && ap->num_folios < max_folios) {
+		unsigned nfolios;
 		size_t start;
-		struct page **pt_pages;
 
-		pt_pages = &ap->pages[ap->num_pages];
-		ret = iov_iter_extract_pages(ii, &pt_pages,
+		ret = iov_iter_extract_pages(ii, &pages,
 					     *nbytesp - nbytes,
-					     max_pages - ap->num_pages,
+					     max_folios - ap->num_folios,
 					     0, &start);
 		if (ret < 0)
 			break;
@@ -1554,15 +1539,18 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
 		nbytes += ret;
 
 		ret += start;
-		npages = DIV_ROUND_UP(ret, PAGE_SIZE);
+		nfolios = DIV_ROUND_UP(ret, PAGE_SIZE);
 
-		ap->descs[ap->num_pages].offset = start;
-		fuse_page_descs_length_init(ap->descs, ap->num_pages, npages);
+		ap->folio_descs[ap->num_folios].offset = start;
+		fuse_folio_descs_length_init(ap->folio_descs, ap->num_folios, nfolios);
+		for (i = 0; i < nfolios; i++)
+			ap->folios[i + ap->num_folios] = page_folio(pages[i]);
 
-		ap->num_pages += npages;
-		ap->descs[ap->num_pages - 1].length -=
+		ap->num_folios += nfolios;
+		ap->folio_descs[ap->num_folios - 1].length -=
 			(PAGE_SIZE - ret) & (PAGE_SIZE - 1);
 	}
+	kfree(pages);
 
 	ap->args.is_pinned = iov_iter_extract_will_pin(ii);
 	ap->args.user_pages = true;
@@ -1594,18 +1582,18 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
 	ssize_t res = 0;
 	int err = 0;
 	struct fuse_io_args *ia;
-	unsigned int max_pages;
+	unsigned int max_folios;
 	bool fopen_direct_io = ff->open_flags & FOPEN_DIRECT_IO;
 
-	max_pages = iov_iter_npages(iter, fc->max_pages);
-	ia = fuse_io_alloc(io, max_pages);
+	max_folios = iov_iter_npages(iter, fc->max_pages);
+	ia = fuse_io_folios_alloc(io, max_folios);
 	if (!ia)
 		return -ENOMEM;
 
 	if (fopen_direct_io && fc->direct_io_allow_mmap) {
 		res = filemap_write_and_wait_range(mapping, pos, pos + count - 1);
 		if (res) {
-			fuse_io_free(ia);
+			fuse_io_folios_free(ia);
 			return res;
 		}
 	}
@@ -1620,7 +1608,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
 	if (fopen_direct_io && write) {
 		res = invalidate_inode_pages2_range(mapping, idx_from, idx_to);
 		if (res) {
-			fuse_io_free(ia);
+			fuse_io_folios_free(ia);
 			return res;
 		}
 	}
@@ -1632,7 +1620,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
 		size_t nbytes = min(count, nmax);
 
 		err = fuse_get_user_pages(&ia->ap, iter, &nbytes, write,
-					  max_pages);
+					  max_folios);
 		if (err && !nbytes)
 			break;
 
@@ -1647,7 +1635,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
 
 		if (!io->async || nres < 0) {
 			fuse_release_user_pages(&ia->ap, io->should_dirty);
-			fuse_io_free(ia);
+			fuse_io_folios_free(ia);
 		}
 		ia = NULL;
 		if (nres < 0) {
@@ -1665,14 +1653,14 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
 			break;
 		}
 		if (count) {
-			max_pages = iov_iter_npages(iter, fc->max_pages);
-			ia = fuse_io_alloc(io, max_pages);
+			max_folios = iov_iter_npages(iter, fc->max_pages);
+			ia = fuse_io_folios_alloc(io, max_folios);
 			if (!ia)
 				break;
 		}
 	}
 	if (ia)
-		fuse_io_free(ia);
+		fuse_io_folios_free(ia);
 	if (res > 0)
 		*ppos = pos;
 
-- 
2.43.5


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

* [PATCH 13/13] fuse: remove pages for requests and exclusively use folios
  2024-10-02 16:52 [PATCH 00/13] fuse: use folios instead of pages for requests Joanne Koong
                   ` (11 preceding siblings ...)
  2024-10-02 16:52 ` [PATCH 12/13] fuse: convert direct io to use folios Joanne Koong
@ 2024-10-02 16:52 ` Joanne Koong
  2024-10-18 20:07 ` [PATCH 00/13] fuse: use folios instead of pages for requests Josef Bacik
  13 siblings, 0 replies; 20+ messages in thread
From: Joanne Koong @ 2024-10-02 16:52 UTC (permalink / raw)
  To: miklos, linux-fsdevel; +Cc: josef, bernd.schubert, willy, kernel-team

All fuse requests use folios instead of pages for transferring data.
Remove pages from the requests and exclusively use folios.

No functional changes.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/cuse.c      |  1 -
 fs/fuse/dev.c       | 41 +++++++-------------
 fs/fuse/dir.c       |  1 -
 fs/fuse/file.c      |  4 --
 fs/fuse/fuse_i.h    | 16 ++------
 fs/fuse/ioctl.c     |  1 -
 fs/fuse/readdir.c   |  1 -
 fs/fuse/virtio_fs.c | 94 +++++++++++++++++----------------------------
 8 files changed, 52 insertions(+), 107 deletions(-)

diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
index eed78e303139..ef9fb30b9bdc 100644
--- a/fs/fuse/cuse.c
+++ b/fs/fuse/cuse.c
@@ -460,7 +460,6 @@ static int cuse_send_init(struct cuse_conn *cc)
 	ap->args.out_args[1].size = CUSE_INIT_INFO_MAX;
 	ap->args.out_argvar = true;
 	ap->args.out_pages = true;
-	ap->uses_folios = true;
 	ap->num_folios = 1;
 	ap->folios = &ia->folio;
 	ap->folio_descs = &ia->desc;
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 2f59af6a8c22..00390a0cd010 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1028,37 +1028,23 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
 	struct fuse_req *req = cs->req;
 	struct fuse_args_pages *ap = container_of(req->args, typeof(*ap), args);
 
-	if (ap->uses_folios) {
-		for (i = 0; i < ap->num_folios && (nbytes || zeroing); i++) {
-			int err;
-			unsigned int offset = ap->folio_descs[i].offset;
-			unsigned int count = min(nbytes, ap->folio_descs[i].length);
-			struct page *orig, *pagep;
+	for (i = 0; i < ap->num_folios && (nbytes || zeroing); i++) {
+		int err;
+		unsigned int offset = ap->folio_descs[i].offset;
+		unsigned int count = min(nbytes, ap->folio_descs[i].length);
+		struct page *orig, *pagep;
 
-			orig = pagep = &ap->folios[i]->page;
+		orig = pagep = &ap->folios[i]->page;
 
-			err = fuse_copy_page(cs, &pagep, offset, count, zeroing);
-			if (err)
-				return err;
-
-			nbytes -= count;
-
-			/* Check if the folio was replaced in the page cache */
-			if (pagep != orig)
-				ap->folios[i] = page_folio(pagep);
-		}
-	} else {
-		for (i = 0; i < ap->num_pages && (nbytes || zeroing); i++) {
-			int err;
-			unsigned int offset = ap->descs[i].offset;
-			unsigned int count = min(nbytes, ap->descs[i].length);
+		err = fuse_copy_page(cs, &pagep, offset, count, zeroing);
+		if (err)
+			return err;
 
-			err = fuse_copy_page(cs, &ap->pages[i], offset, count, zeroing);
-			if (err)
-				return err;
+		nbytes -= count;
 
-			nbytes -= count;
-		}
+		/* Check if the folio was replaced in the page cache */
+		if (pagep != orig)
+			ap->folios[i] = page_folio(pagep);
 	}
 	return 0;
 }
@@ -1769,7 +1755,6 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
 	ap = &ra->ap;
 	ap->folios = (void *) (ra + 1);
 	ap->folio_descs = (void *) (ap->folios + num_folios);
-	ap->uses_folios = true;
 
 	args = &ap->args;
 	args->nodeid = outarg->nodeid;
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index a08c532068d0..2661f0cab349 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1590,7 +1590,6 @@ static int fuse_readlink_page(struct inode *inode, struct folio *folio)
 	struct fuse_mount *fm = get_fuse_mount(inode);
 	struct fuse_folio_desc desc = { .length = PAGE_SIZE - 1 };
 	struct fuse_args_pages ap = {
-		.uses_folios = true,
 		.num_folios = 1,
 		.folios = &folio,
 		.folio_descs = &desc,
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 38ed9026f286..2bc860bd3ca3 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -747,7 +747,6 @@ static struct fuse_io_args *fuse_io_folios_alloc(struct fuse_io_priv *io,
 	ia = kzalloc(sizeof(*ia), GFP_KERNEL);
 	if (ia) {
 		ia->io = io;
-		ia->ap.uses_folios = true;
 		ia->ap.folios = fuse_folios_alloc(nfolios, GFP_KERNEL,
 						  &ia->ap.folio_descs);
 		if (!ia->ap.folios) {
@@ -873,7 +872,6 @@ static int fuse_do_readfolio(struct file *file, struct folio *folio)
 	struct fuse_io_args ia = {
 		.ap.args.page_zeroing = true,
 		.ap.args.out_pages = true,
-		.ap.uses_folios = true,
 		.ap.num_folios = 1,
 		.ap.folios = &folio,
 		.ap.folio_descs = &desc,
@@ -1309,7 +1307,6 @@ static ssize_t fuse_perform_write(struct kiocb *iocb, struct iov_iter *ii)
 		unsigned int nr_folios = fuse_wr_folios(pos, iov_iter_count(ii),
 							fc->max_pages);
 
-		ap->uses_folios = true;
 		ap->folios = fuse_folios_alloc(nr_folios, GFP_KERNEL, &ap->folio_descs);
 		if (!ap->folios) {
 			err = -ENOMEM;
@@ -2063,7 +2060,6 @@ static struct fuse_writepage_args *fuse_writepage_args_alloc(void)
 	if (wpa) {
 		ap = &wpa->ia.ap;
 		ap->num_folios = 0;
-		ap->uses_folios = true;
 		ap->folios = fuse_folios_alloc(1, GFP_NOFS, &ap->folio_descs);
 		if (!ap->folios) {
 			kfree(wpa);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index d9fa12aee07d..60c76f8afb9e 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -322,19 +322,9 @@ struct fuse_args {
 
 struct fuse_args_pages {
 	struct fuse_args args;
-	union {
-		struct {
-			struct page **pages;
-			struct fuse_page_desc *descs;
-			unsigned int num_pages;
-		};
-		struct {
-			struct folio **folios;
-			struct fuse_folio_desc *folio_descs;
-			unsigned int num_folios;
-		};
-	};
-	bool uses_folios;
+	struct folio **folios;
+	unsigned int num_folios;
+	struct fuse_folio_desc *folio_descs;
 };
 
 struct fuse_release_args {
diff --git a/fs/fuse/ioctl.c b/fs/fuse/ioctl.c
index 1c77d8a27950..28138c838d49 100644
--- a/fs/fuse/ioctl.c
+++ b/fs/fuse/ioctl.c
@@ -306,7 +306,6 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
 	err = -ENOMEM;
 	if (max_pages > fm->fc->max_pages)
 		goto out;
-	ap.uses_folios = true;
 	while (ap.num_folios < max_pages) {
 		ap.folios[ap.num_folios] = folio_alloc(GFP_KERNEL | __GFP_HIGHMEM, 0);
 		if (!ap.folios[ap.num_folios])
diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c
index fd0eff1b9f2d..aeb5ea534c96 100644
--- a/fs/fuse/readdir.c
+++ b/fs/fuse/readdir.c
@@ -346,7 +346,6 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx)
 
 	plus = fuse_use_readdirplus(inode, ctx);
 	ap->args.out_pages = true;
-	ap->uses_folios = true;
 	ap->num_folios = 1;
 	ap->folios = &folio;
 	ap->folio_descs = &desc;
diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c
index 5e7262c93590..9c09ee22caaa 100644
--- a/fs/fuse/virtio_fs.c
+++ b/fs/fuse/virtio_fs.c
@@ -773,29 +773,15 @@ static void virtio_fs_request_complete(struct fuse_req *req,
 	if (args->out_pages && args->page_zeroing) {
 		len = args->out_args[args->out_numargs - 1].size;
 		ap = container_of(args, typeof(*ap), args);
-		if (ap->uses_folios) {
-			for (i = 0; i < ap->num_folios; i++) {
-				thislen = ap->folio_descs[i].length;
-				if (len < thislen) {
-					WARN_ON(ap->folio_descs[i].offset);
-					folio = ap->folios[i];
-					folio_zero_segment(folio, len, thislen);
-					len = 0;
-				} else {
-					len -= thislen;
-				}
-			}
-		} else {
-			for (i = 0; i < ap->num_pages; i++) {
-				thislen = ap->descs[i].length;
-				if (len < thislen) {
-					WARN_ON(ap->descs[i].offset);
-					page = ap->pages[i];
-					zero_user_segment(page, len, thislen);
-					len = 0;
-				} else {
-					len -= thislen;
-				}
+		for (i = 0; i < ap->num_folios; i++) {
+			thislen = ap->folio_descs[i].length;
+			if (len < thislen) {
+				WARN_ON(ap->folio_descs[i].offset);
+				folio = ap->folios[i];
+				folio_zero_segment(folio, len, thislen);
+				len = 0;
+			} else {
+				len -= thislen;
 			}
 		}
 	}
@@ -1282,22 +1268,16 @@ static void virtio_fs_send_interrupt(struct fuse_iqueue *fiq, struct fuse_req *r
 }
 
 /* Count number of scatter-gather elements required */
-static unsigned int sg_count_fuse_pages(struct fuse_args_pages *ap,
-					unsigned int total_len)
+static unsigned int sg_count_fuse_folios(struct fuse_folio_desc *folio_descs,
+					 unsigned int num_folios,
+					 unsigned int total_len)
 {
 	unsigned int i;
 	unsigned int this_len;
 
-	if (ap->uses_folios) {
-		for (i = 0; i < ap->num_folios && total_len; i++) {
-			this_len =  min(ap->folio_descs[i].length, total_len);
-			total_len -= this_len;
-		}
-	} else {
-		for (i = 0; i < ap->num_pages && total_len; i++) {
-			this_len =  min(ap->descs[i].length, total_len);
-			total_len -= this_len;
-		}
+	for (i = 0; i < num_folios && total_len; i++) {
+		this_len =  min(folio_descs[i].length, total_len);
+		total_len -= this_len;
 	}
 
 	return i;
@@ -1315,7 +1295,8 @@ static unsigned int sg_count_fuse_req(struct fuse_req *req)
 
 	if (args->in_pages) {
 		size = args->in_args[args->in_numargs - 1].size;
-		total_sgs += sg_count_fuse_pages(ap, size);
+		total_sgs += sg_count_fuse_folios(ap->folio_descs, ap->num_folios,
+						  size);
 	}
 
 	if (!test_bit(FR_ISREPLY, &req->flags))
@@ -1328,35 +1309,29 @@ static unsigned int sg_count_fuse_req(struct fuse_req *req)
 
 	if (args->out_pages) {
 		size = args->out_args[args->out_numargs - 1].size;
-		total_sgs += sg_count_fuse_pages(ap, size);
+		total_sgs += sg_count_fuse_folios(ap->folio_descs, ap->num_folios,
+						  size);
 	}
 
 	return total_sgs;
 }
 
-/* Add pages/folios to scatter-gather list and return number of elements used */
-static unsigned int sg_init_fuse_pages(struct scatterlist *sg,
-				       struct fuse_args_pages *ap,
-				       unsigned int total_len)
+/* Add folios to scatter-gather list and return number of elements used */
+static unsigned int sg_init_fuse_folios(struct scatterlist *sg,
+					struct folio **folios,
+					struct fuse_folio_desc *folio_descs,
+					unsigned int num_folios,
+				        unsigned int total_len)
 {
 	unsigned int i;
 	unsigned int this_len;
 
-	if (ap->uses_folios) {
-		for (i = 0; i < ap->num_folios && total_len; i++) {
-			sg_init_table(&sg[i], 1);
-			this_len =  min(ap->folio_descs[i].length, total_len);
-			sg_set_folio(&sg[i], ap->folios[i], this_len,
-				     ap->folio_descs[i].offset);
-			total_len -= this_len;
-		}
-	} else {
-		for (i = 0; i < ap->num_pages && total_len; i++) {
-			sg_init_table(&sg[i], 1);
-			this_len =  min(ap->descs[i].length, total_len);
-			sg_set_page(&sg[i], ap->pages[i], this_len, ap->descs[i].offset);
-			total_len -= this_len;
-		}
+	for (i = 0; i < num_folios && total_len; i++) {
+		sg_init_table(&sg[i], 1);
+		this_len =  min(folio_descs[i].length, total_len);
+		sg_set_folio(&sg[i], folios[i], this_len,
+			     folio_descs[i].offset);
+		total_len -= this_len;
 	}
 
 	return i;
@@ -1380,8 +1355,11 @@ static unsigned int sg_init_fuse_args(struct scatterlist *sg,
 		sg_init_one(&sg[total_sgs++], argbuf, len);
 
 	if (argpages)
-		total_sgs += sg_init_fuse_pages(&sg[total_sgs], ap,
-						args[numargs - 1].size);
+		total_sgs += sg_init_fuse_folios(&sg[total_sgs],
+						 ap->folios,
+						 ap->folio_descs,
+						 ap->num_folios,
+						 args[numargs - 1].size);
 
 	if (len_used)
 		*len_used = len;
-- 
2.43.5


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

* Re: [PATCH 01/13] fuse: support folios in struct fuse_args_pages and fuse_copy_pages()
  2024-10-02 16:52 ` [PATCH 01/13] fuse: support folios in struct fuse_args_pages and fuse_copy_pages() Joanne Koong
@ 2024-10-18 19:48   ` Josef Bacik
  0 siblings, 0 replies; 20+ messages in thread
From: Josef Bacik @ 2024-10-18 19:48 UTC (permalink / raw)
  To: Joanne Koong; +Cc: miklos, linux-fsdevel, bernd.schubert, willy, kernel-team

On Wed, Oct 02, 2024 at 09:52:41AM -0700, Joanne Koong wrote:
> This adds support in struct fuse_args_pages and fuse_copy_pages() for
> using folios instead of pages for transferring data. Both folios and
> pages must be supported right now in struct fuse_args_pages and
> fuse_copy_pages() until all request types have been converted to use
> folios. Once all have been converted, then
> struct fuse_args_pages and fuse_copy_pages() will only support folios.
> 
> Right now in fuse, all folios are one page (large folios are not yet
> supported). As such, copying folio->page is sufficient for copying
> the entire folio in fuse_copy_pages().
> 
> No functional changes.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> ---
>  fs/fuse/dev.c    | 36 ++++++++++++++++++++++++++++--------
>  fs/fuse/fuse_i.h | 22 +++++++++++++++++++---
>  2 files changed, 47 insertions(+), 11 deletions(-)
> 
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 7e4c5be45aec..cd9c5e0eefca 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -1028,17 +1028,37 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
>  	struct fuse_req *req = cs->req;
>  	struct fuse_args_pages *ap = container_of(req->args, typeof(*ap), args);
>  
> +	if (ap->uses_folios) {
> +		for (i = 0; i < ap->num_folios && (nbytes || zeroing); i++) {
> +			int err;
> +			unsigned int offset = ap->folio_descs[i].offset;
> +			unsigned int count = min(nbytes, ap->folio_descs[i].length);
> +			struct page *orig, *pagep;
>  
> -	for (i = 0; i < ap->num_pages && (nbytes || zeroing); i++) {
> -		int err;
> -		unsigned int offset = ap->descs[i].offset;
> -		unsigned int count = min(nbytes, ap->descs[i].length);
> +			orig = pagep = &ap->folios[i]->page;
>  
> -		err = fuse_copy_page(cs, &ap->pages[i], offset, count, zeroing);
> -		if (err)
> -			return err;
> +			err = fuse_copy_page(cs, &pagep, offset, count, zeroing);
> +			if (err)
> +				return err;
> +
> +			nbytes -= count;
> +
> +			/* Check if the folio was replaced in the page cache */

This comment confused me, I think it would be better to say something like

/*
 * fuse_copy_page may have moved a page from a pipe instead of copying into our
 * given page, so update the folios if it was replaced.
 */

Or something like that.  Thanks,

Josef

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

* Re: [PATCH 11/13] mm/writeback: add folio_mark_dirty_lock()
  2024-10-02 16:52 ` [PATCH 11/13] mm/writeback: add folio_mark_dirty_lock() Joanne Koong
@ 2024-10-18 20:01   ` Josef Bacik
  2024-10-22 18:05     ` Joanne Koong
  0 siblings, 1 reply; 20+ messages in thread
From: Josef Bacik @ 2024-10-18 20:01 UTC (permalink / raw)
  To: Joanne Koong; +Cc: miklos, linux-fsdevel, bernd.schubert, willy, kernel-team

On Wed, Oct 02, 2024 at 09:52:51AM -0700, Joanne Koong wrote:
> Add a new convenience helper folio_mark_dirty_lock() that grabs the
> folio lock before calling folio_mark_dirty().
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> ---
>  include/linux/mm.h  |  1 +
>  mm/page-writeback.c | 12 ++++++++++++
>  2 files changed, 13 insertions(+)
> 
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index ecf63d2b0582..446d7096c48f 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -2539,6 +2539,7 @@ struct kvec;
>  struct page *get_dump_page(unsigned long addr);
>  
>  bool folio_mark_dirty(struct folio *folio);
> +bool folio_mark_dirty_lock(struct folio *folio);
>  bool set_page_dirty(struct page *page);
>  int set_page_dirty_lock(struct page *page);
>  
> diff --git a/mm/page-writeback.c b/mm/page-writeback.c
> index fcd4c1439cb9..9b1c95dd219c 100644
> --- a/mm/page-writeback.c
> +++ b/mm/page-writeback.c
> @@ -2913,6 +2913,18 @@ bool folio_mark_dirty(struct folio *folio)
>  }
>  EXPORT_SYMBOL(folio_mark_dirty);
>  

I think you should include the comment description from set_page_dirty_lock() as
well here, generally good to keep documentation consistent.  Thanks,

Josef

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

* Re: [PATCH 12/13] fuse: convert direct io to use folios
  2024-10-02 16:52 ` [PATCH 12/13] fuse: convert direct io to use folios Joanne Koong
@ 2024-10-18 20:02   ` Josef Bacik
  2024-10-21 22:02     ` Joanne Koong
  0 siblings, 1 reply; 20+ messages in thread
From: Josef Bacik @ 2024-10-18 20:02 UTC (permalink / raw)
  To: Joanne Koong; +Cc: miklos, linux-fsdevel, bernd.schubert, willy, kernel-team

On Wed, Oct 02, 2024 at 09:52:52AM -0700, Joanne Koong wrote:
> Convert direct io requests to use folios instead of pages.
> 
> No functional changes.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> ---
>  fs/fuse/file.c | 88 ++++++++++++++++++++++----------------------------
>  1 file changed, 38 insertions(+), 50 deletions(-)
> 
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index 1fa870fb3cc4..38ed9026f286 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -665,11 +665,11 @@ static void fuse_release_user_pages(struct fuse_args_pages *ap,
>  {
>  	unsigned int i;
>  
> -	for (i = 0; i < ap->num_pages; i++) {
> +	for (i = 0; i < ap->num_folios; i++) {
>  		if (should_dirty)
> -			set_page_dirty_lock(ap->pages[i]);
> +			folio_mark_dirty_lock(ap->folios[i]);
>  		if (ap->args.is_pinned)
> -			unpin_user_page(ap->pages[i]);
> +			unpin_folio(ap->folios[i]);
>  	}
>  }
>  
> @@ -739,24 +739,6 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
>  	kref_put(&io->refcnt, fuse_io_release);
>  }
>  
> -static struct fuse_io_args *fuse_io_alloc(struct fuse_io_priv *io,
> -					  unsigned int npages)
> -{
> -	struct fuse_io_args *ia;
> -
> -	ia = kzalloc(sizeof(*ia), GFP_KERNEL);
> -	if (ia) {
> -		ia->io = io;
> -		ia->ap.pages = fuse_pages_alloc(npages, GFP_KERNEL,
> -						&ia->ap.descs);
> -		if (!ia->ap.pages) {
> -			kfree(ia);
> -			ia = NULL;
> -		}
> -	}
> -	return ia;
> -}
> -
>  static struct fuse_io_args *fuse_io_folios_alloc(struct fuse_io_priv *io,
>  						 unsigned int nfolios)
>  {
> @@ -776,12 +758,6 @@ static struct fuse_io_args *fuse_io_folios_alloc(struct fuse_io_priv *io,
>  	return ia;
>  }
>  
> -static void fuse_io_free(struct fuse_io_args *ia)
> -{
> -	kfree(ia->ap.pages);
> -	kfree(ia);
> -}
> -
>  static void fuse_io_folios_free(struct fuse_io_args *ia)
>  {
>  	kfree(ia->ap.folios);
> @@ -814,7 +790,7 @@ static void fuse_aio_complete_req(struct fuse_mount *fm, struct fuse_args *args,
>  	}
>  
>  	fuse_aio_complete(io, err, pos);
> -	fuse_io_free(ia);
> +	fuse_io_folios_free(ia);
>  }
>  
>  static ssize_t fuse_async_req_send(struct fuse_mount *fm,
> @@ -1518,10 +1494,11 @@ static inline size_t fuse_get_frag_size(const struct iov_iter *ii,
>  
>  static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
>  			       size_t *nbytesp, int write,
> -			       unsigned int max_pages)
> +			       unsigned int max_folios)
>  {
>  	size_t nbytes = 0;  /* # bytes already packed in req */
>  	ssize_t ret = 0;
> +	ssize_t i = 0;
>  
>  	/* Special case for kernel I/O: can copy directly into the buffer */
>  	if (iov_iter_is_kvec(ii)) {
> @@ -1538,15 +1515,23 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
>  		return 0;
>  	}
>  
> -	while (nbytes < *nbytesp && ap->num_pages < max_pages) {
> -		unsigned npages;
> +	/*
> +	 * Until there is support for iov_iter_extract_folios(), we have to
> +	 * manually extract pages using iov_iter_extract_pages() and then
> +	 * copy that to a folios array.
> +	 */
> +	struct page **pages = kzalloc((max_folios - ap->num_folios) * sizeof(struct page *),
> +				      GFP_KERNEL);
> +	if (!pages)
> +		return -ENOMEM;
> +
> +	while (nbytes < *nbytesp && ap->num_folios < max_folios) {
> +		unsigned nfolios;
>  		size_t start;
> -		struct page **pt_pages;
>  
> -		pt_pages = &ap->pages[ap->num_pages];
> -		ret = iov_iter_extract_pages(ii, &pt_pages,
> +		ret = iov_iter_extract_pages(ii, &pages,
>  					     *nbytesp - nbytes,
> -					     max_pages - ap->num_pages,
> +					     max_folios - ap->num_folios,
>  					     0, &start);
>  		if (ret < 0)
>  			break;
> @@ -1554,15 +1539,18 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
>  		nbytes += ret;
>  
>  		ret += start;
> -		npages = DIV_ROUND_UP(ret, PAGE_SIZE);
> +		nfolios = DIV_ROUND_UP(ret, PAGE_SIZE);
>  
> -		ap->descs[ap->num_pages].offset = start;
> -		fuse_page_descs_length_init(ap->descs, ap->num_pages, npages);
> +		ap->folio_descs[ap->num_folios].offset = start;
> +		fuse_folio_descs_length_init(ap->folio_descs, ap->num_folios, nfolios);

With this conversion fuse_page_descs_length_init now has no users, so I'd add a
followup patch at the end of the series to remove it.  Thanks,

Josef

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

* Re: [PATCH 00/13] fuse: use folios instead of pages for requests
  2024-10-02 16:52 [PATCH 00/13] fuse: use folios instead of pages for requests Joanne Koong
                   ` (12 preceding siblings ...)
  2024-10-02 16:52 ` [PATCH 13/13] fuse: remove pages for requests and exclusively " Joanne Koong
@ 2024-10-18 20:07 ` Josef Bacik
  13 siblings, 0 replies; 20+ messages in thread
From: Josef Bacik @ 2024-10-18 20:07 UTC (permalink / raw)
  To: Joanne Koong; +Cc: miklos, linux-fsdevel, bernd.schubert, willy, kernel-team

On Wed, Oct 02, 2024 at 09:52:40AM -0700, Joanne Koong wrote:
> This patchset converts fuse requests to use folios instead of pages. Right
> now, all folios in fuse are one page, but a subsequent patchset will be
> enabling larger-size folios on fuse.
> 
> This patchset has no functional changes and have been run through fstests with
> passthrough_hp.
> 
> This patchset is dependent on (and rebased on top of) Josef's folio conversions
> patchset here:
> https://lore.kernel.org/linux-fsdevel/cover.1727703714.git.josef@toxicpanda.com/

This is a really good example of how to do a big conversion, it was really easy
to review.  Address the few nits and rebase and then you can add

Reviewed-by: Josef Bacik <josef@toxicpanda.com>

Thanks,

Josef

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

* Re: [PATCH 12/13] fuse: convert direct io to use folios
  2024-10-18 20:02   ` Josef Bacik
@ 2024-10-21 22:02     ` Joanne Koong
  0 siblings, 0 replies; 20+ messages in thread
From: Joanne Koong @ 2024-10-21 22:02 UTC (permalink / raw)
  To: Josef Bacik; +Cc: miklos, linux-fsdevel, bernd.schubert, willy, kernel-team

On Fri, Oct 18, 2024 at 1:02 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> On Wed, Oct 02, 2024 at 09:52:52AM -0700, Joanne Koong wrote:
> > Convert direct io requests to use folios instead of pages.
> >
> > No functional changes.
> >
> > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > ---
> >  fs/fuse/file.c | 88 ++++++++++++++++++++++----------------------------
> >  1 file changed, 38 insertions(+), 50 deletions(-)
> >
> > diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> > index 1fa870fb3cc4..38ed9026f286 100644
> > --- a/fs/fuse/file.c
> > +++ b/fs/fuse/file.c
> > @@ -665,11 +665,11 @@ static void fuse_release_user_pages(struct fuse_args_pages *ap,
> >  {
> >       unsigned int i;
> >
> > -     for (i = 0; i < ap->num_pages; i++) {
> > +     for (i = 0; i < ap->num_folios; i++) {
> >               if (should_dirty)
> > -                     set_page_dirty_lock(ap->pages[i]);
> > +                     folio_mark_dirty_lock(ap->folios[i]);
> >               if (ap->args.is_pinned)
> > -                     unpin_user_page(ap->pages[i]);
> > +                     unpin_folio(ap->folios[i]);
> >       }
> >  }
> >
> > @@ -739,24 +739,6 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
> >       kref_put(&io->refcnt, fuse_io_release);
> >  }
> >
> > -static struct fuse_io_args *fuse_io_alloc(struct fuse_io_priv *io,
> > -                                       unsigned int npages)
> > -{
> > -     struct fuse_io_args *ia;
> > -
> > -     ia = kzalloc(sizeof(*ia), GFP_KERNEL);
> > -     if (ia) {
> > -             ia->io = io;
> > -             ia->ap.pages = fuse_pages_alloc(npages, GFP_KERNEL,
> > -                                             &ia->ap.descs);
> > -             if (!ia->ap.pages) {
> > -                     kfree(ia);
> > -                     ia = NULL;
> > -             }
> > -     }
> > -     return ia;
> > -}
> > -
> >  static struct fuse_io_args *fuse_io_folios_alloc(struct fuse_io_priv *io,
> >                                                unsigned int nfolios)
> >  {
> > @@ -776,12 +758,6 @@ static struct fuse_io_args *fuse_io_folios_alloc(struct fuse_io_priv *io,
> >       return ia;
> >  }
> >
> > -static void fuse_io_free(struct fuse_io_args *ia)
> > -{
> > -     kfree(ia->ap.pages);
> > -     kfree(ia);
> > -}
> > -
> >  static void fuse_io_folios_free(struct fuse_io_args *ia)
> >  {
> >       kfree(ia->ap.folios);
> > @@ -814,7 +790,7 @@ static void fuse_aio_complete_req(struct fuse_mount *fm, struct fuse_args *args,
> >       }
> >
> >       fuse_aio_complete(io, err, pos);
> > -     fuse_io_free(ia);
> > +     fuse_io_folios_free(ia);
> >  }
> >
> >  static ssize_t fuse_async_req_send(struct fuse_mount *fm,
> > @@ -1518,10 +1494,11 @@ static inline size_t fuse_get_frag_size(const struct iov_iter *ii,
> >
> >  static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
> >                              size_t *nbytesp, int write,
> > -                            unsigned int max_pages)
> > +                            unsigned int max_folios)
> >  {
> >       size_t nbytes = 0;  /* # bytes already packed in req */
> >       ssize_t ret = 0;
> > +     ssize_t i = 0;
> >
> >       /* Special case for kernel I/O: can copy directly into the buffer */
> >       if (iov_iter_is_kvec(ii)) {
> > @@ -1538,15 +1515,23 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
> >               return 0;
> >       }
> >
> > -     while (nbytes < *nbytesp && ap->num_pages < max_pages) {
> > -             unsigned npages;
> > +     /*
> > +      * Until there is support for iov_iter_extract_folios(), we have to
> > +      * manually extract pages using iov_iter_extract_pages() and then
> > +      * copy that to a folios array.
> > +      */
> > +     struct page **pages = kzalloc((max_folios - ap->num_folios) * sizeof(struct page *),
> > +                                   GFP_KERNEL);
> > +     if (!pages)
> > +             return -ENOMEM;
> > +
> > +     while (nbytes < *nbytesp && ap->num_folios < max_folios) {
> > +             unsigned nfolios;
> >               size_t start;
> > -             struct page **pt_pages;
> >
> > -             pt_pages = &ap->pages[ap->num_pages];
> > -             ret = iov_iter_extract_pages(ii, &pt_pages,
> > +             ret = iov_iter_extract_pages(ii, &pages,
> >                                            *nbytesp - nbytes,
> > -                                          max_pages - ap->num_pages,
> > +                                          max_folios - ap->num_folios,
> >                                            0, &start);
> >               if (ret < 0)
> >                       break;
> > @@ -1554,15 +1539,18 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
> >               nbytes += ret;
> >
> >               ret += start;
> > -             npages = DIV_ROUND_UP(ret, PAGE_SIZE);
> > +             nfolios = DIV_ROUND_UP(ret, PAGE_SIZE);
> >
> > -             ap->descs[ap->num_pages].offset = start;
> > -             fuse_page_descs_length_init(ap->descs, ap->num_pages, npages);
> > +             ap->folio_descs[ap->num_folios].offset = start;
> > +             fuse_folio_descs_length_init(ap->folio_descs, ap->num_folios, nfolios);
>
> With this conversion fuse_page_descs_length_init now has no users, so I'd add a
> followup patch at the end of the series to remove it.  Thanks,

Great catch. Thanks for reviewing these patches. I agree with your
other comments as well and will make sure to address those for v2.

Thanks,
Joanne
>
> Josef

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

* Re: [PATCH 11/13] mm/writeback: add folio_mark_dirty_lock()
  2024-10-18 20:01   ` Josef Bacik
@ 2024-10-22 18:05     ` Joanne Koong
  0 siblings, 0 replies; 20+ messages in thread
From: Joanne Koong @ 2024-10-22 18:05 UTC (permalink / raw)
  To: Josef Bacik; +Cc: miklos, linux-fsdevel, bernd.schubert, willy, kernel-team

On Fri, Oct 18, 2024 at 1:01 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> On Wed, Oct 02, 2024 at 09:52:51AM -0700, Joanne Koong wrote:
> > Add a new convenience helper folio_mark_dirty_lock() that grabs the
> > folio lock before calling folio_mark_dirty().
> >
> > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > ---
> >  include/linux/mm.h  |  1 +
> >  mm/page-writeback.c | 12 ++++++++++++
> >  2 files changed, 13 insertions(+)
> >
> > diff --git a/include/linux/mm.h b/include/linux/mm.h
> > index ecf63d2b0582..446d7096c48f 100644
> > --- a/include/linux/mm.h
> > +++ b/include/linux/mm.h
> > @@ -2539,6 +2539,7 @@ struct kvec;
> >  struct page *get_dump_page(unsigned long addr);
> >
> >  bool folio_mark_dirty(struct folio *folio);
> > +bool folio_mark_dirty_lock(struct folio *folio);
> >  bool set_page_dirty(struct page *page);
> >  int set_page_dirty_lock(struct page *page);
> >
> > diff --git a/mm/page-writeback.c b/mm/page-writeback.c
> > index fcd4c1439cb9..9b1c95dd219c 100644
> > --- a/mm/page-writeback.c
> > +++ b/mm/page-writeback.c
> > @@ -2913,6 +2913,18 @@ bool folio_mark_dirty(struct folio *folio)
> >  }
> >  EXPORT_SYMBOL(folio_mark_dirty);
> >
>
> I think you should include the comment description from set_page_dirty_lock() as
> well here, generally good to keep documentation consistent.  Thanks,

Looking at this some more, for v2 I am going to replace
set_page_dirty_lock() to be a wrapper around folio_mark_dirty_lock(),
eg something like

+int set_page_dirty_lock(struct page *page)
+{
+       return folio_mark_dirty_lock(page_folio(page));
+}
+EXPORT_SYMBOL(set_page_dirty_lock);

so that we have one source of truth for the logic. I'll remove your
Reviewed-by for this patch in v2 in case you have disagreements on the
newer v2 implementation.


Thanks,
Joanne

>
> Josef

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

end of thread, other threads:[~2024-10-22 18:06 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-02 16:52 [PATCH 00/13] fuse: use folios instead of pages for requests Joanne Koong
2024-10-02 16:52 ` [PATCH 01/13] fuse: support folios in struct fuse_args_pages and fuse_copy_pages() Joanne Koong
2024-10-18 19:48   ` Josef Bacik
2024-10-02 16:52 ` [PATCH 02/13] fuse: add support in virtio for requests using folios Joanne Koong
2024-10-02 16:52 ` [PATCH 03/13] fuse: convert cuse to use folios Joanne Koong
2024-10-02 16:52 ` [PATCH 04/13] fuse: convert readlink " Joanne Koong
2024-10-02 16:52 ` [PATCH 05/13] fuse: convert readdir " Joanne Koong
2024-10-02 16:52 ` [PATCH 06/13] fuse: convert reads " Joanne Koong
2024-10-02 16:52 ` [PATCH 07/13] fuse: convert writes (non-writeback) " Joanne Koong
2024-10-02 16:52 ` [PATCH 08/13] fuse: convert ioctls " Joanne Koong
2024-10-02 16:52 ` [PATCH 09/13] fuse: convert retrieves " Joanne Koong
2024-10-02 16:52 ` [PATCH 10/13] fuse: convert writebacks " Joanne Koong
2024-10-02 16:52 ` [PATCH 11/13] mm/writeback: add folio_mark_dirty_lock() Joanne Koong
2024-10-18 20:01   ` Josef Bacik
2024-10-22 18:05     ` Joanne Koong
2024-10-02 16:52 ` [PATCH 12/13] fuse: convert direct io to use folios Joanne Koong
2024-10-18 20:02   ` Josef Bacik
2024-10-21 22:02     ` Joanne Koong
2024-10-02 16:52 ` [PATCH 13/13] fuse: remove pages for requests and exclusively " Joanne Koong
2024-10-18 20:07 ` [PATCH 00/13] fuse: use folios instead of pages for requests Josef Bacik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).