public inbox for linux-fsdevel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/12] fuse: support large folios
@ 2024-11-09  0:12 Joanne Koong
  2024-11-09  0:12 ` [PATCH 01/12] fuse: support copying " Joanne Koong
                   ` (12 more replies)
  0 siblings, 13 replies; 32+ messages in thread
From: Joanne Koong @ 2024-11-09  0:12 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

This patchset adds support for folios larger than one page size in FUSE.

This patchset is rebased on top of the (unmerged) patchset that removes temp
folios in writeback [1]. (There is also a version of this patchset that is
independent from that change, but that version has two additional patches
needed to account for temp folios and temp folio copying, which may require
some debate to get the API right for as these two patches add generic
(non-FUSE) helpers. For simplicity's sake for now, I sent out this patchset
version rebased on top of the patchset that removes temp pages)

This patchset was tested by running it through fstests on passthrough_hp.

[1] https://lore.kernel.org/linux-fsdevel/20241107235614.3637221-1-joannelkoong@gmail.com/

Joanne Koong (12):
  fuse: support copying large folios
  fuse: support large folios for retrieves
  fuse: refactor fuse_fill_write_pages()
  fuse: support large folios for non-writeback writes
  fuse: support large folios for folio reads
  fuse: support large folios for symlinks
  fuse: support large folios for stores
  fuse: support large folios for queued writes
  fuse: support large folios for readahead
  fuse: support large folios for direct io
  fuse: support large folios for writeback
  fuse: enable large folios

 fs/fuse/dev.c  | 131 +++++++++++++++++++++++-----------------------
 fs/fuse/dir.c  |   8 +--
 fs/fuse/file.c | 138 +++++++++++++++++++++++++++++++------------------
 3 files changed, 159 insertions(+), 118 deletions(-)

-- 
2.43.5


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

* [PATCH 01/12] fuse: support copying large folios
  2024-11-09  0:12 [PATCH 00/12] fuse: support large folios Joanne Koong
@ 2024-11-09  0:12 ` Joanne Koong
  2024-11-21 22:27   ` Josef Bacik
  2024-11-09  0:12 ` [PATCH 02/12] fuse: support large folios for retrieves Joanne Koong
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 32+ messages in thread
From: Joanne Koong @ 2024-11-09  0:12 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

Currently, all folios associated with fuse are one page size. As part of
the work to enable large folios, this commit adds support for copying
to/from folios larger than one page size.

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

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 29fc61a072ba..9914cc1243f4 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -703,7 +703,7 @@ struct fuse_copy_state {
 	struct page *pg;
 	unsigned len;
 	unsigned offset;
-	unsigned move_pages:1;
+	unsigned move_folios:1;
 };
 
 static void fuse_copy_init(struct fuse_copy_state *cs, int write,
@@ -836,10 +836,10 @@ static int fuse_check_folio(struct folio *folio)
 	return 0;
 }
 
-static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
+static int fuse_try_move_folio(struct fuse_copy_state *cs, struct folio **foliop)
 {
 	int err;
-	struct folio *oldfolio = page_folio(*pagep);
+	struct folio *oldfolio = *foliop;
 	struct folio *newfolio;
 	struct pipe_buffer *buf = cs->pipebufs;
 
@@ -860,7 +860,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
 	cs->pipebufs++;
 	cs->nr_segs--;
 
-	if (cs->len != PAGE_SIZE)
+	if (cs->len != folio_size(oldfolio))
 		goto out_fallback;
 
 	if (!pipe_buf_try_steal(cs->pipe, buf))
@@ -906,7 +906,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
 	if (test_bit(FR_ABORTED, &cs->req->flags))
 		err = -ENOENT;
 	else
-		*pagep = &newfolio->page;
+		*foliop = newfolio;
 	spin_unlock(&cs->req->waitq.lock);
 
 	if (err) {
@@ -939,8 +939,8 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
 	goto out_put_old;
 }
 
-static int fuse_ref_page(struct fuse_copy_state *cs, struct page *page,
-			 unsigned offset, unsigned count)
+static int fuse_ref_folio(struct fuse_copy_state *cs, struct folio *folio,
+			  unsigned offset, unsigned count)
 {
 	struct pipe_buffer *buf;
 	int err;
@@ -948,17 +948,17 @@ static int fuse_ref_page(struct fuse_copy_state *cs, struct page *page,
 	if (cs->nr_segs >= cs->pipe->max_usage)
 		return -EIO;
 
-	get_page(page);
+	folio_get(folio);
 	err = unlock_request(cs->req);
 	if (err) {
-		put_page(page);
+		folio_put(folio);
 		return err;
 	}
 
 	fuse_copy_finish(cs);
 
 	buf = cs->pipebufs;
-	buf->page = page;
+	buf->page = &folio->page;
 	buf->offset = offset;
 	buf->len = count;
 
@@ -970,20 +970,24 @@ static int fuse_ref_page(struct fuse_copy_state *cs, struct page *page,
 }
 
 /*
- * Copy a page in the request to/from the userspace buffer.  Must be
+ * Copy a folio in the request to/from the userspace buffer.  Must be
  * done atomically
  */
-static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
-			  unsigned offset, unsigned count, int zeroing)
+static int fuse_copy_folio(struct fuse_copy_state *cs, struct folio **foliop,
+			   unsigned offset, unsigned count, int zeroing)
 {
 	int err;
-	struct page *page = *pagep;
+	struct folio *folio = *foliop;
+	size_t size = folio_size(folio);
 
-	if (page && zeroing && count < PAGE_SIZE)
-		clear_highpage(page);
+	if (folio && zeroing && count < size) {
+		void *kaddr = kmap_local_folio(folio, 0);
+		memset(kaddr, 0, size);
+		kunmap_local(kaddr);
+	}
 
 	while (count) {
-		if (cs->write && cs->pipebufs && page) {
+		if (cs->write && cs->pipebufs && folio) {
 			/*
 			 * Can't control lifetime of pipe buffers, so always
 			 * copy user pages.
@@ -993,12 +997,12 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
 				if (err)
 					return err;
 			} else {
-				return fuse_ref_page(cs, page, offset, count);
+				return fuse_ref_folio(cs, folio, offset, count);
 			}
 		} else if (!cs->len) {
-			if (cs->move_pages && page &&
-			    offset == 0 && count == PAGE_SIZE) {
-				err = fuse_try_move_page(cs, pagep);
+			if (cs->move_folios && folio &&
+			    offset == 0 && count == folio_size(folio)) {
+				err = fuse_try_move_folio(cs, foliop);
 				if (err <= 0)
 					return err;
 			} else {
@@ -1007,22 +1011,22 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
 					return err;
 			}
 		}
-		if (page) {
-			void *mapaddr = kmap_local_page(page);
-			void *buf = mapaddr + offset;
+		if (folio) {
+			void *mapaddr = kmap_local_folio(folio, offset);
+			void *buf = mapaddr;
 			offset += fuse_copy_do(cs, &buf, &count);
 			kunmap_local(mapaddr);
 		} else
 			offset += fuse_copy_do(cs, NULL, &count);
 	}
-	if (page && !cs->write)
-		flush_dcache_page(page);
+	if (folio && !cs->write)
+		flush_dcache_folio(folio);
 	return 0;
 }
 
-/* Copy pages in the request to/from userspace buffer */
-static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
-			   int zeroing)
+/* Copy folios in the request to/from userspace buffer */
+static int fuse_copy_folios(struct fuse_copy_state *cs, unsigned nbytes,
+			    int zeroing)
 {
 	unsigned i;
 	struct fuse_req *req = cs->req;
@@ -1032,23 +1036,12 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
 		int err;
 		unsigned int offset = ap->descs[i].offset;
 		unsigned int count = min(nbytes, ap->descs[i].length);
-		struct page *orig, *pagep;
-
-		orig = pagep = &ap->folios[i]->page;
 
-		err = fuse_copy_page(cs, &pagep, offset, count, zeroing);
+		err = fuse_copy_folio(cs, &ap->folios[i], offset, count, zeroing);
 		if (err)
 			return err;
 
 		nbytes -= count;
-
-		/*
-		 *  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.
-		 */
-		if (pagep != orig)
-			ap->folios[i] = page_folio(pagep);
 	}
 	return 0;
 }
@@ -1078,7 +1071,7 @@ static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs,
 	for (i = 0; !err && i < numargs; i++)  {
 		struct fuse_arg *arg = &args[i];
 		if (i == numargs - 1 && argpages)
-			err = fuse_copy_pages(cs, arg->size, zeroing);
+			err = fuse_copy_folios(cs, arg->size, zeroing);
 		else
 			err = fuse_copy_one(cs, arg->value, arg->size);
 	}
@@ -1665,7 +1658,6 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
 	num = outarg.size;
 	while (num) {
 		struct folio *folio;
-		struct page *page;
 		unsigned int this_num;
 
 		folio = filemap_grab_folio(mapping, index);
@@ -1673,9 +1665,8 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
 		if (IS_ERR(folio))
 			goto out_iput;
 
-		page = &folio->page;
 		this_num = min_t(unsigned, num, folio_size(folio) - offset);
-		err = fuse_copy_page(cs, &page, offset, this_num, 0);
+		err = fuse_copy_folio(cs, &folio, offset, this_num, 0);
 		if (!folio_test_uptodate(folio) && !err && offset == 0 &&
 		    (this_num == folio_size(folio) || file_size == end)) {
 			folio_zero_segment(folio, this_num, folio_size(folio));
@@ -1902,8 +1893,8 @@ static int fuse_notify_resend(struct fuse_conn *fc)
 static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
 		       unsigned int size, struct fuse_copy_state *cs)
 {
-	/* Don't try to move pages (yet) */
-	cs->move_pages = 0;
+	/* Don't try to move folios (yet) */
+	cs->move_folios = 0;
 
 	switch (code) {
 	case FUSE_NOTIFY_POLL:
@@ -2044,7 +2035,7 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
 	spin_unlock(&fpq->lock);
 	cs->req = req;
 	if (!req->args->page_replace)
-		cs->move_pages = 0;
+		cs->move_folios = 0;
 
 	if (oh.error)
 		err = nbytes != sizeof(oh) ? -EINVAL : 0;
@@ -2163,7 +2154,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
 	cs.pipe = pipe;
 
 	if (flags & SPLICE_F_MOVE)
-		cs.move_pages = 1;
+		cs.move_folios = 1;
 
 	ret = fuse_dev_do_write(fud, &cs, len);
 
-- 
2.43.5


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

* [PATCH 02/12] fuse: support large folios for retrieves
  2024-11-09  0:12 [PATCH 00/12] fuse: support large folios Joanne Koong
  2024-11-09  0:12 ` [PATCH 01/12] fuse: support copying " Joanne Koong
@ 2024-11-09  0:12 ` Joanne Koong
  2024-11-21 22:28   ` Josef Bacik
  2024-11-09  0:12 ` [PATCH 03/12] fuse: refactor fuse_fill_write_pages() Joanne Koong
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 32+ messages in thread
From: Joanne Koong @ 2024-11-09  0:12 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

Add support for folios larger than one page size for retrieves.

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

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 9914cc1243f4..5be666af3ebe 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1719,7 +1719,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, cur_pages = 0;
+	unsigned int num_pages;
 	struct fuse_conn *fc = fm->fc;
 	struct fuse_retrieve_args *ra;
 	size_t args_size = sizeof(*ra);
@@ -1737,6 +1737,7 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
 
 	num_pages = (num + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	num_pages = min(num_pages, fc->max_pages);
+	num = min(num, num_pages << PAGE_SHIFT);
 
 	args_size += num_pages * (sizeof(ap->folios[0]) + sizeof(ap->descs[0]));
 
@@ -1757,25 +1758,29 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
 
 	index = outarg->offset >> PAGE_SHIFT;
 
-	while (num && cur_pages < num_pages) {
+	while (num) {
 		struct folio *folio;
-		unsigned int this_num;
+		unsigned int folio_offset;
+		unsigned int nr_bytes;
+		unsigned int nr_pages;
 
 		folio = filemap_get_folio(mapping, index);
 		if (IS_ERR(folio))
 			break;
 
-		this_num = min_t(unsigned, num, PAGE_SIZE - offset);
+		folio_offset = ((index - folio->index) << PAGE_SHIFT) + offset;
+		nr_bytes = min(folio_size(folio) - folio_offset, num);
+		nr_pages = (offset + nr_bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
 		ap->folios[ap->num_folios] = folio;
-		ap->descs[ap->num_folios].offset = offset;
-		ap->descs[ap->num_folios].length = this_num;
+		ap->descs[ap->num_folios].offset = folio_offset;
+		ap->descs[ap->num_folios].length = nr_bytes;
 		ap->num_folios++;
-		cur_pages++;
 
 		offset = 0;
-		num -= this_num;
-		total_len += this_num;
-		index++;
+		num -= nr_bytes;
+		total_len += nr_bytes;
+		index += nr_pages;
 	}
 	ra->inarg.offset = outarg->offset;
 	ra->inarg.size = total_len;
-- 
2.43.5


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

* [PATCH 03/12] fuse: refactor fuse_fill_write_pages()
  2024-11-09  0:12 [PATCH 00/12] fuse: support large folios Joanne Koong
  2024-11-09  0:12 ` [PATCH 01/12] fuse: support copying " Joanne Koong
  2024-11-09  0:12 ` [PATCH 02/12] fuse: support large folios for retrieves Joanne Koong
@ 2024-11-09  0:12 ` Joanne Koong
  2024-11-21 22:28   ` Josef Bacik
  2024-11-09  0:12 ` [PATCH 04/12] fuse: support large folios for non-writeback writes Joanne Koong
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 32+ messages in thread
From: Joanne Koong @ 2024-11-09  0:12 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

Refactor the logic in fuse_fill_write_pages() for copying out write
data. This will make the future change for supporting large folios for
writes easier. No functional changes.

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

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index f8719d8c56ca..a89fdc55a40b 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1138,21 +1138,21 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
 	struct fuse_args_pages *ap = &ia->ap;
 	struct fuse_conn *fc = get_fuse_conn(mapping->host);
 	unsigned offset = pos & (PAGE_SIZE - 1);
-	unsigned int nr_pages = 0;
 	size_t count = 0;
+	unsigned int num;
 	int err;
 
+	num = min(iov_iter_count(ii), fc->max_write);
+	num = min(num, max_pages << PAGE_SHIFT);
+
 	ap->args.in_pages = true;
 	ap->descs[0].offset = offset;
 
-	do {
+	while (num) {
 		size_t tmp;
 		struct folio *folio;
 		pgoff_t index = pos >> PAGE_SHIFT;
-		size_t bytes = min_t(size_t, PAGE_SIZE - offset,
-				     iov_iter_count(ii));
-
-		bytes = min_t(size_t, bytes, fc->max_write - count);
+		unsigned int bytes = min(PAGE_SIZE - offset, num);
 
  again:
 		err = -EFAULT;
@@ -1182,10 +1182,10 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
 		ap->folios[ap->num_folios] = folio;
 		ap->descs[ap->num_folios].length = tmp;
 		ap->num_folios++;
-		nr_pages++;
 
 		count += tmp;
 		pos += tmp;
+		num -= tmp;
 		offset += tmp;
 		if (offset == PAGE_SIZE)
 			offset = 0;
@@ -1202,8 +1202,9 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
 		}
 		if (!fc->big_writes)
 			break;
-	} while (iov_iter_count(ii) && count < fc->max_write &&
-		 nr_pages < max_pages && offset == 0);
+		if (offset != 0)
+			break;
+	}
 
 	return count > 0 ? count : err;
 }
-- 
2.43.5


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

* [PATCH 04/12] fuse: support large folios for non-writeback writes
  2024-11-09  0:12 [PATCH 00/12] fuse: support large folios Joanne Koong
                   ` (2 preceding siblings ...)
  2024-11-09  0:12 ` [PATCH 03/12] fuse: refactor fuse_fill_write_pages() Joanne Koong
@ 2024-11-09  0:12 ` Joanne Koong
  2024-11-12 17:32   ` Joanne Koong
  2024-11-21 22:32   ` Josef Bacik
  2024-11-09  0:12 ` [PATCH 05/12] fuse: support large folios for folio reads Joanne Koong
                   ` (8 subsequent siblings)
  12 siblings, 2 replies; 32+ messages in thread
From: Joanne Koong @ 2024-11-09  0:12 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

Add support for folios larger than one page size for non-writeback
writes.

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

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index a89fdc55a40b..6ee23ab9b7f2 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1146,19 +1146,15 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
 	num = min(num, max_pages << PAGE_SHIFT);
 
 	ap->args.in_pages = true;
-	ap->descs[0].offset = offset;
 
 	while (num) {
 		size_t tmp;
 		struct folio *folio;
 		pgoff_t index = pos >> PAGE_SHIFT;
-		unsigned int bytes = min(PAGE_SIZE - offset, num);
-
- again:
-		err = -EFAULT;
-		if (fault_in_iov_iter_readable(ii, bytes))
-			break;
+		unsigned int bytes;
+		unsigned int folio_offset;
 
+	again:
 		folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,
 					    mapping_gfp_mask(mapping));
 		if (IS_ERR(folio)) {
@@ -1166,10 +1162,20 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
 			break;
 		}
 
+		folio_offset = ((index - folio->index) << PAGE_SHIFT) + offset;
+		bytes = min(folio_size(folio) - folio_offset, num);
+
+		err = -EFAULT;
+		if (fault_in_iov_iter_readable(ii, bytes)) {
+			folio_unlock(folio);
+			folio_put(folio);
+			break;
+		}
+
 		if (mapping_writably_mapped(mapping))
 			flush_dcache_folio(folio);
 
-		tmp = copy_folio_from_iter_atomic(folio, offset, bytes, ii);
+		tmp = copy_folio_from_iter_atomic(folio, folio_offset, bytes, ii);
 		flush_dcache_folio(folio);
 
 		if (!tmp) {
@@ -1180,6 +1186,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
 
 		err = 0;
 		ap->folios[ap->num_folios] = folio;
+		ap->descs[ap->num_folios].offset = folio_offset;
 		ap->descs[ap->num_folios].length = tmp;
 		ap->num_folios++;
 
@@ -1187,11 +1194,11 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
 		pos += tmp;
 		num -= tmp;
 		offset += tmp;
-		if (offset == PAGE_SIZE)
+		if (offset == folio_size(folio))
 			offset = 0;
 
-		/* If we copied full page, mark it uptodate */
-		if (tmp == PAGE_SIZE)
+		/* If we copied full folio, mark it uptodate */
+		if (tmp == folio_size(folio))
 			folio_mark_uptodate(folio);
 
 		if (folio_test_uptodate(folio)) {
-- 
2.43.5


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

* [PATCH 05/12] fuse: support large folios for folio reads
  2024-11-09  0:12 [PATCH 00/12] fuse: support large folios Joanne Koong
                   ` (3 preceding siblings ...)
  2024-11-09  0:12 ` [PATCH 04/12] fuse: support large folios for non-writeback writes Joanne Koong
@ 2024-11-09  0:12 ` Joanne Koong
  2024-11-22 14:42   ` Josef Bacik
  2024-11-09  0:12 ` [PATCH 06/12] fuse: support large folios for symlinks Joanne Koong
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 32+ messages in thread
From: Joanne Koong @ 2024-11-09  0:12 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

Add support for folios larger than one page size for folio reads into
the page cache.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/file.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 6ee23ab9b7f2..399bc8898cc4 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -797,7 +797,7 @@ 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_folio_desc desc = { .length = PAGE_SIZE };
+	struct fuse_folio_desc desc = { .length = folio_size(folio) };
 	struct fuse_io_args ia = {
 		.ap.args.page_zeroing = true,
 		.ap.args.out_pages = true,
-- 
2.43.5


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

* [PATCH 06/12] fuse: support large folios for symlinks
  2024-11-09  0:12 [PATCH 00/12] fuse: support large folios Joanne Koong
                   ` (4 preceding siblings ...)
  2024-11-09  0:12 ` [PATCH 05/12] fuse: support large folios for folio reads Joanne Koong
@ 2024-11-09  0:12 ` Joanne Koong
  2024-11-22 14:43   ` Josef Bacik
  2024-11-09  0:12 ` [PATCH 07/12] fuse: support large folios for stores Joanne Koong
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 32+ messages in thread
From: Joanne Koong @ 2024-11-09  0:12 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

Support large folios for symlinks and change the name from
fuse_getlink_page() to fuse_getlink_folio().

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

diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index b8a4608e31af..37c1e194909b 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1585,10 +1585,10 @@ static int fuse_permission(struct mnt_idmap *idmap,
 	return err;
 }
 
-static int fuse_readlink_page(struct inode *inode, struct folio *folio)
+static int fuse_readlink_folio(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_folio_desc desc = { .length = folio_size(folio) - 1 };
 	struct fuse_args_pages ap = {
 		.num_folios = 1,
 		.folios = &folio,
@@ -1643,7 +1643,7 @@ static const char *fuse_get_link(struct dentry *dentry, struct inode *inode,
 	if (!folio)
 		goto out_err;
 
-	err = fuse_readlink_page(inode, folio);
+	err = fuse_readlink_folio(inode, folio);
 	if (err) {
 		folio_put(folio);
 		goto out_err;
@@ -2231,7 +2231,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);
+	int err = fuse_readlink_folio(folio->mapping->host, folio);
 
 	if (!err)
 		folio_mark_uptodate(folio);
-- 
2.43.5


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

* [PATCH 07/12] fuse: support large folios for stores
  2024-11-09  0:12 [PATCH 00/12] fuse: support large folios Joanne Koong
                   ` (5 preceding siblings ...)
  2024-11-09  0:12 ` [PATCH 06/12] fuse: support large folios for symlinks Joanne Koong
@ 2024-11-09  0:12 ` Joanne Koong
  2024-11-22 14:45   ` Josef Bacik
  2024-11-09  0:12 ` [PATCH 08/12] fuse: support large folios for queued writes Joanne Koong
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 32+ messages in thread
From: Joanne Koong @ 2024-11-09  0:12 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

Add support for folios larger than one page size for stores.
Also change variable naming from "this_num" to "nr_bytes".

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

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 5be666af3ebe..df9138f33c47 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1658,18 +1658,23 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
 	num = outarg.size;
 	while (num) {
 		struct folio *folio;
-		unsigned int this_num;
+		unsigned int folio_offset;
+		unsigned int nr_bytes;
+		unsigned int nr_pages;
 
 		folio = filemap_grab_folio(mapping, index);
 		err = PTR_ERR(folio);
 		if (IS_ERR(folio))
 			goto out_iput;
 
-		this_num = min_t(unsigned, num, folio_size(folio) - offset);
-		err = fuse_copy_folio(cs, &folio, offset, this_num, 0);
+		folio_offset = ((index - folio->index) << PAGE_SHIFT) + offset;
+		nr_bytes = min_t(unsigned, num, folio_size(folio) - folio_offset);
+		nr_pages = (offset + nr_bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+		err = fuse_copy_folio(cs, &folio, folio_offset, nr_bytes, 0);
 		if (!folio_test_uptodate(folio) && !err && offset == 0 &&
-		    (this_num == folio_size(folio) || file_size == end)) {
-			folio_zero_segment(folio, this_num, folio_size(folio));
+		    (nr_bytes == folio_size(folio) || file_size == end)) {
+			folio_zero_segment(folio, nr_bytes, folio_size(folio));
 			folio_mark_uptodate(folio);
 		}
 		folio_unlock(folio);
@@ -1678,9 +1683,9 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
 		if (err)
 			goto out_iput;
 
-		num -= this_num;
+		num -= nr_bytes;
 		offset = 0;
-		index++;
+		index += nr_pages;
 	}
 
 	err = 0;
-- 
2.43.5


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

* [PATCH 08/12] fuse: support large folios for queued writes
  2024-11-09  0:12 [PATCH 00/12] fuse: support large folios Joanne Koong
                   ` (6 preceding siblings ...)
  2024-11-09  0:12 ` [PATCH 07/12] fuse: support large folios for stores Joanne Koong
@ 2024-11-09  0:12 ` Joanne Koong
  2024-11-22 14:45   ` Josef Bacik
  2024-11-09  0:12 ` [PATCH 09/12] fuse: support large folios for readahead Joanne Koong
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 32+ messages in thread
From: Joanne Koong @ 2024-11-09  0:12 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

Add support for folios larger than one page size for queued writes.

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

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 399bc8898cc4..44a65bdfe8fb 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1793,11 +1793,14 @@ __releases(fi->lock)
 __acquires(fi->lock)
 {
 	struct fuse_inode *fi = get_fuse_inode(wpa->inode);
+	struct fuse_args_pages *ap = &wpa->ia.ap;
 	struct fuse_write_in *inarg = &wpa->ia.write.in;
-	struct fuse_args *args = &wpa->ia.ap.args;
-	/* Currently, all folios in FUSE are one page */
-	__u64 data_size = wpa->ia.ap.num_folios * PAGE_SIZE;
-	int err;
+	struct fuse_args *args = &ap->args;
+	__u64 data_size = 0;
+	int err, i;
+
+	for (i = 0; i < ap->num_folios; i++)
+		data_size += ap->descs[i].length;
 
 	fi->writectr++;
 	if (inarg->offset + data_size <= size) {
-- 
2.43.5


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

* [PATCH 09/12] fuse: support large folios for readahead
  2024-11-09  0:12 [PATCH 00/12] fuse: support large folios Joanne Koong
                   ` (7 preceding siblings ...)
  2024-11-09  0:12 ` [PATCH 08/12] fuse: support large folios for queued writes Joanne Koong
@ 2024-11-09  0:12 ` Joanne Koong
  2024-11-22 14:47   ` Josef Bacik
  2024-11-09  0:12 ` [PATCH 10/12] fuse: support large folios for direct io Joanne Koong
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 32+ messages in thread
From: Joanne Koong @ 2024-11-09  0:12 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

Add support for folios larger than one page size for readahead.

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

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 44a65bdfe8fb..255c7f2f2ed4 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -885,14 +885,13 @@ static void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args,
 	fuse_io_free(ia);
 }
 
-static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file)
+static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file,
+				unsigned int count)
 {
 	struct fuse_file *ff = file->private_data;
 	struct fuse_mount *fm = ff->fm;
 	struct fuse_args_pages *ap = &ia->ap;
 	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;
 
@@ -929,6 +928,7 @@ static void fuse_readahead(struct readahead_control *rac)
 	unsigned int max_pages, nr_pages;
 	loff_t first = readahead_pos(rac);
 	loff_t last = first + readahead_length(rac) - 1;
+	struct folio *folio = NULL;
 
 	if (fuse_is_bad(inode))
 		return;
@@ -952,8 +952,8 @@ static void fuse_readahead(struct readahead_control *rac)
 	while (nr_pages) {
 		struct fuse_io_args *ia;
 		struct fuse_args_pages *ap;
-		struct folio *folio;
 		unsigned cur_pages = min(max_pages, nr_pages);
+		unsigned int pages = 0;
 
 		if (fc->num_background >= fc->congestion_threshold &&
 		    rac->ra->async_size >= readahead_count(rac))
@@ -968,14 +968,24 @@ static void fuse_readahead(struct readahead_control *rac)
 			return;
 		ap = &ia->ap;
 
-		while (ap->num_folios < cur_pages) {
-			folio = readahead_folio(rac);
+		while (pages < cur_pages) {
+			unsigned int folio_pages;
+
+			if (!folio)
+				folio = readahead_folio(rac);
+
+			folio_pages = folio_nr_pages(folio);
+			if (folio_pages > cur_pages - pages)
+				break;
+
 			ap->folios[ap->num_folios] = folio;
-			ap->descs[ap->num_folios].length = folio_size(folio);
+			ap->descs[ap->num_folios].length = folio_pages << PAGE_SHIFT;
 			ap->num_folios++;
+			pages += folio_pages;
+			folio = NULL;
 		}
-		fuse_send_readpages(ia, rac->file);
-		nr_pages -= cur_pages;
+		fuse_send_readpages(ia, rac->file, pages << PAGE_SHIFT);
+		nr_pages -= pages;
 	}
 }
 
-- 
2.43.5


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

* [PATCH 10/12] fuse: support large folios for direct io
  2024-11-09  0:12 [PATCH 00/12] fuse: support large folios Joanne Koong
                   ` (8 preceding siblings ...)
  2024-11-09  0:12 ` [PATCH 09/12] fuse: support large folios for readahead Joanne Koong
@ 2024-11-09  0:12 ` Joanne Koong
  2024-11-22 14:49   ` Josef Bacik
  2024-11-09  0:12 ` [PATCH 11/12] fuse: support large folios for writeback Joanne Koong
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 32+ messages in thread
From: Joanne Koong @ 2024-11-09  0:12 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

Add support for folios larger than one page size for direct io.

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

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 255c7f2f2ed4..54e2b58df82f 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1484,7 +1484,8 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
 		return -ENOMEM;
 
 	while (nbytes < *nbytesp && nr_pages < max_pages) {
-		unsigned nfolios, i;
+		unsigned npages;
+		unsigned i = 0;
 		size_t start;
 
 		ret = iov_iter_extract_pages(ii, &pages,
@@ -1496,19 +1497,28 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
 
 		nbytes += ret;
 
-		ret += start;
-		/* Currently, all folios in FUSE are one page */
-		nfolios = DIV_ROUND_UP(ret, PAGE_SIZE);
+		npages = DIV_ROUND_UP(ret + start, PAGE_SIZE);
 
-		ap->descs[ap->num_folios].offset = start;
-		fuse_folio_descs_length_init(ap->descs, ap->num_folios, nfolios);
-		for (i = 0; i < nfolios; i++)
-			ap->folios[i + ap->num_folios] = page_folio(pages[i]);
+		while (ret && i < npages) {
+			struct folio *folio;
+			unsigned int folio_offset;
+			unsigned int len;
 
-		ap->num_folios += nfolios;
-		ap->descs[ap->num_folios - 1].length -=
-			(PAGE_SIZE - ret) & (PAGE_SIZE - 1);
-		nr_pages += nfolios;
+			folio = page_folio(pages[i]);
+			folio_offset = ((size_t)folio_page_idx(folio, pages[i]) <<
+				       PAGE_SHIFT) + start;
+			len = min_t(ssize_t, ret, folio_size(folio) - folio_offset);
+
+			ap->folios[ap->num_folios] = folio;
+			ap->descs[ap->num_folios].offset = folio_offset;
+			ap->descs[ap->num_folios].length = len;
+			ap->num_folios++;
+
+			ret -= len;
+			i += DIV_ROUND_UP(start + len, PAGE_SIZE);
+			start = 0;
+		}
+		nr_pages += npages;
 	}
 	kfree(pages);
 
-- 
2.43.5


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

* [PATCH 11/12] fuse: support large folios for writeback
  2024-11-09  0:12 [PATCH 00/12] fuse: support large folios Joanne Koong
                   ` (9 preceding siblings ...)
  2024-11-09  0:12 ` [PATCH 10/12] fuse: support large folios for direct io Joanne Koong
@ 2024-11-09  0:12 ` Joanne Koong
  2024-11-22 14:50   ` Josef Bacik
  2024-11-09  0:12 ` [PATCH 12/12] fuse: enable large folios Joanne Koong
  2024-11-09  0:22 ` [PATCH 00/12] fuse: support " Joanne Koong
  12 siblings, 1 reply; 32+ messages in thread
From: Joanne Koong @ 2024-11-09  0:12 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

Add support for folios larger than one page size for writeback.

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

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 54e2b58df82f..a542f16d5a69 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1993,7 +1993,7 @@ static void fuse_writepage_args_page_fill(struct fuse_writepage_args *wpa, struc
 	folio_get(folio);
 	ap->folios[folio_index] = folio;
 	ap->descs[folio_index].offset = 0;
-	ap->descs[folio_index].length = PAGE_SIZE;
+	ap->descs[folio_index].length = folio_size(folio);
 
 	inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK);
 	node_stat_add_folio(folio, NR_WRITEBACK);
@@ -2068,6 +2068,7 @@ struct fuse_fill_wb_data {
 	struct fuse_file *ff;
 	struct inode *inode;
 	unsigned int max_folios;
+	unsigned int nr_pages;
 };
 
 static bool fuse_pages_realloc(struct fuse_fill_wb_data *data)
@@ -2115,15 +2116,15 @@ static bool fuse_writepage_need_send(struct fuse_conn *fc, struct folio *folio,
 	WARN_ON(!ap->num_folios);
 
 	/* Reached max pages */
-	if (ap->num_folios == fc->max_pages)
+	if (data->nr_pages + folio_nr_pages(folio) > fc->max_pages)
 		return true;
 
 	/* Reached max write bytes */
-	if ((ap->num_folios + 1) * PAGE_SIZE > fc->max_write)
+	if ((data->nr_pages * PAGE_SIZE) + folio_size(folio) > fc->max_write)
 		return true;
 
 	/* Discontinuity */
-	if (ap->folios[ap->num_folios - 1]->index + 1 != folio_index(folio))
+	if (folio_next_index(ap->folios[ap->num_folios - 1]) != folio_index(folio))
 		return true;
 
 	/* Need to grow the pages array?  If so, did the expansion fail? */
@@ -2154,6 +2155,7 @@ static int fuse_writepages_fill(struct folio *folio,
 	if (wpa && fuse_writepage_need_send(fc, folio, ap, data)) {
 		fuse_writepages_send(data);
 		data->wpa = NULL;
+		data->nr_pages = 0;
 	}
 
 	if (data->wpa == NULL) {
@@ -2168,6 +2170,7 @@ static int fuse_writepages_fill(struct folio *folio,
 	folio_start_writeback(folio);
 
 	fuse_writepage_args_page_fill(wpa, folio, ap->num_folios);
+	data->nr_pages += folio_nr_pages(folio);
 
 	err = 0;
 	ap->num_folios++;
@@ -2198,6 +2201,7 @@ static int fuse_writepages(struct address_space *mapping,
 	data.inode = inode;
 	data.wpa = NULL;
 	data.ff = NULL;
+	data.nr_pages = 0;
 
 	err = write_cache_pages(mapping, wbc, fuse_writepages_fill, &data);
 	if (data.wpa) {
-- 
2.43.5


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

* [PATCH 12/12] fuse: enable large folios
  2024-11-09  0:12 [PATCH 00/12] fuse: support large folios Joanne Koong
                   ` (10 preceding siblings ...)
  2024-11-09  0:12 ` [PATCH 11/12] fuse: support large folios for writeback Joanne Koong
@ 2024-11-09  0:12 ` Joanne Koong
  2024-11-22 14:51   ` Josef Bacik
  2024-11-09  0:22 ` [PATCH 00/12] fuse: support " Joanne Koong
  12 siblings, 1 reply; 32+ messages in thread
From: Joanne Koong @ 2024-11-09  0:12 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

Enable folios larger than one page size.

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

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index a542f16d5a69..20fe3dff8904 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -3166,12 +3166,17 @@ void fuse_init_file_inode(struct inode *inode, unsigned int flags)
 {
 	struct fuse_inode *fi = get_fuse_inode(inode);
 	struct fuse_conn *fc = get_fuse_conn(inode);
+	unsigned int max_pages, max_order;
 
 	inode->i_fop = &fuse_file_operations;
 	inode->i_data.a_ops = &fuse_file_aops;
 	if (fc->writeback_cache)
 		mapping_set_writeback_may_block(&inode->i_data);
 
+	max_pages = min(fc->max_write >> PAGE_SHIFT, fc->max_pages);
+	max_order = ilog2(max_pages);
+	mapping_set_folio_order_range(inode->i_mapping, 0, max_order);
+
 	INIT_LIST_HEAD(&fi->write_files);
 	INIT_LIST_HEAD(&fi->queued_writes);
 	fi->writectr = 0;
-- 
2.43.5


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

* Re: [PATCH 00/12] fuse: support large folios
  2024-11-09  0:12 [PATCH 00/12] fuse: support large folios Joanne Koong
                   ` (11 preceding siblings ...)
  2024-11-09  0:12 ` [PATCH 12/12] fuse: enable large folios Joanne Koong
@ 2024-11-09  0:22 ` Joanne Koong
  2024-11-09  0:32   ` Bernd Schubert
  2024-11-13 18:58   ` Joanne Koong
  12 siblings, 2 replies; 32+ messages in thread
From: Joanne Koong @ 2024-11-09  0:22 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

On Fri, Nov 8, 2024 at 4:13 PM Joanne Koong <joannelkoong@gmail.com> wrote:
>
> This patchset adds support for folios larger than one page size in FUSE.
>
> This patchset is rebased on top of the (unmerged) patchset that removes temp
> folios in writeback [1]. (There is also a version of this patchset that is
> independent from that change, but that version has two additional patches
> needed to account for temp folios and temp folio copying, which may require
> some debate to get the API right for as these two patches add generic
> (non-FUSE) helpers. For simplicity's sake for now, I sent out this patchset
> version rebased on top of the patchset that removes temp pages)
>
> This patchset was tested by running it through fstests on passthrough_hp.

Will be updating this thread with some fio benchmark results early next week.

>
> [1] https://lore.kernel.org/linux-fsdevel/20241107235614.3637221-1-joannelkoong@gmail.com/
>
> Joanne Koong (12):
>   fuse: support copying large folios
>   fuse: support large folios for retrieves
>   fuse: refactor fuse_fill_write_pages()
>   fuse: support large folios for non-writeback writes
>   fuse: support large folios for folio reads
>   fuse: support large folios for symlinks
>   fuse: support large folios for stores
>   fuse: support large folios for queued writes
>   fuse: support large folios for readahead
>   fuse: support large folios for direct io
>   fuse: support large folios for writeback
>   fuse: enable large folios
>
>  fs/fuse/dev.c  | 131 +++++++++++++++++++++++-----------------------
>  fs/fuse/dir.c  |   8 +--
>  fs/fuse/file.c | 138 +++++++++++++++++++++++++++++++------------------
>  3 files changed, 159 insertions(+), 118 deletions(-)
>
> --
> 2.43.5
>

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

* Re: [PATCH 00/12] fuse: support large folios
  2024-11-09  0:22 ` [PATCH 00/12] fuse: support " Joanne Koong
@ 2024-11-09  0:32   ` Bernd Schubert
  2024-11-11 17:44     ` Joanne Koong
  2024-11-13 18:58   ` Joanne Koong
  1 sibling, 1 reply; 32+ messages in thread
From: Bernd Schubert @ 2024-11-09  0:32 UTC (permalink / raw)
  To: Joanne Koong, miklos, linux-fsdevel
  Cc: josef, jefflexu, willy, shakeel.butt, kernel-team

Hi Joanne,

thanks a lot for working on this!

On 11/9/24 01:22, Joanne Koong wrote:
> On Fri, Nov 8, 2024 at 4:13 PM Joanne Koong <joannelkoong@gmail.com> wrote:
>>
>> This patchset adds support for folios larger than one page size in FUSE.
>>
>> This patchset is rebased on top of the (unmerged) patchset that removes temp
>> folios in writeback [1]. (There is also a version of this patchset that is
>> independent from that change, but that version has two additional patches
>> needed to account for temp folios and temp folio copying, which may require
>> some debate to get the API right for as these two patches add generic
>> (non-FUSE) helpers. For simplicity's sake for now, I sent out this patchset
>> version rebased on top of the patchset that removes temp pages)
>>
>> This patchset was tested by running it through fstests on passthrough_hp.
> 
> Will be updating this thread with some fio benchmark results early next week.

I will try to find some time over the weekend to improve this patch 

https://github.com/libfuse/libfuse/pull/807/commits/e83789cc6e83ca42ccc9899c4f7f8c69f31cbff9

It basically should give you the fuse interface speed, without being IO bound.



Best,
Bernd

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

* Re: [PATCH 00/12] fuse: support large folios
  2024-11-09  0:32   ` Bernd Schubert
@ 2024-11-11 17:44     ` Joanne Koong
  0 siblings, 0 replies; 32+ messages in thread
From: Joanne Koong @ 2024-11-11 17:44 UTC (permalink / raw)
  To: Bernd Schubert
  Cc: miklos, linux-fsdevel, josef, jefflexu, willy, shakeel.butt,
	kernel-team

On Fri, Nov 8, 2024 at 4:32 PM Bernd Schubert
<bernd.schubert@fastmail.fm> wrote:
>
> Hi Joanne,
>
> thanks a lot for working on this!
>
> On 11/9/24 01:22, Joanne Koong wrote:
> > On Fri, Nov 8, 2024 at 4:13 PM Joanne Koong <joannelkoong@gmail.com> wrote:
> >>
> >> This patchset adds support for folios larger than one page size in FUSE.
> >>
> >> This patchset is rebased on top of the (unmerged) patchset that removes temp
> >> folios in writeback [1]. (There is also a version of this patchset that is
> >> independent from that change, but that version has two additional patches
> >> needed to account for temp folios and temp folio copying, which may require
> >> some debate to get the API right for as these two patches add generic
> >> (non-FUSE) helpers. For simplicity's sake for now, I sent out this patchset
> >> version rebased on top of the patchset that removes temp pages)
> >>
> >> This patchset was tested by running it through fstests on passthrough_hp.
> >
> > Will be updating this thread with some fio benchmark results early next week.
>
> I will try to find some time over the weekend to improve this patch
>
> https://github.com/libfuse/libfuse/pull/807/commits/e83789cc6e83ca42ccc9899c4f7f8c69f31cbff9
>
> It basically should give you the fuse interface speed, without being IO bound.

Thank you, Bernd! I will use your current patch in the meantime to get
some preliminary numbers.

>
>
>
> Best,
> Bernd

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

* Re: [PATCH 04/12] fuse: support large folios for non-writeback writes
  2024-11-09  0:12 ` [PATCH 04/12] fuse: support large folios for non-writeback writes Joanne Koong
@ 2024-11-12 17:32   ` Joanne Koong
  2024-11-13 18:41     ` Joanne Koong
  2024-11-21 22:32   ` Josef Bacik
  1 sibling, 1 reply; 32+ messages in thread
From: Joanne Koong @ 2024-11-12 17:32 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

On Fri, Nov 8, 2024 at 4:13 PM Joanne Koong <joannelkoong@gmail.com> wrote:
>
> Add support for folios larger than one page size for non-writeback

I'll change this naming from "non-writeback" to "writethrough"

> writes.
>
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> ---
>  fs/fuse/file.c | 29 ++++++++++++++++++-----------
>  1 file changed, 18 insertions(+), 11 deletions(-)
>
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index a89fdc55a40b..6ee23ab9b7f2 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -1146,19 +1146,15 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
>         num = min(num, max_pages << PAGE_SHIFT);
>
>         ap->args.in_pages = true;
> -       ap->descs[0].offset = offset;
>
>         while (num) {
>                 size_t tmp;
>                 struct folio *folio;
>                 pgoff_t index = pos >> PAGE_SHIFT;
> -               unsigned int bytes = min(PAGE_SIZE - offset, num);
> -
> - again:
> -               err = -EFAULT;
> -               if (fault_in_iov_iter_readable(ii, bytes))
> -                       break;
> +               unsigned int bytes;
> +               unsigned int folio_offset;
>
> +       again:
>                 folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,
>                                             mapping_gfp_mask(mapping));

This __filemap_get_folio() call (and the one in fuse_write_begin() as
well) needs to also set the order on the fgf flag to enable large
folios, else all folios returned will be order 0.

I'll fix this in v2.

>                 if (IS_ERR(folio)) {
> @@ -1166,10 +1162,20 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
>                         break;
>                 }
>
> +               folio_offset = ((index - folio->index) << PAGE_SHIFT) + offset;
> +               bytes = min(folio_size(folio) - folio_offset, num);
> +
> +               err = -EFAULT;
> +               if (fault_in_iov_iter_readable(ii, bytes)) {
> +                       folio_unlock(folio);
> +                       folio_put(folio);
> +                       break;
> +               }
> +
>                 if (mapping_writably_mapped(mapping))
>                         flush_dcache_folio(folio);
>
> -               tmp = copy_folio_from_iter_atomic(folio, offset, bytes, ii);
> +               tmp = copy_folio_from_iter_atomic(folio, folio_offset, bytes, ii);
>                 flush_dcache_folio(folio);
>
>                 if (!tmp) {
> @@ -1180,6 +1186,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
>
>                 err = 0;
>                 ap->folios[ap->num_folios] = folio;
> +               ap->descs[ap->num_folios].offset = folio_offset;
>                 ap->descs[ap->num_folios].length = tmp;
>                 ap->num_folios++;
>
> @@ -1187,11 +1194,11 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
>                 pos += tmp;
>                 num -= tmp;
>                 offset += tmp;
> -               if (offset == PAGE_SIZE)
> +               if (offset == folio_size(folio))
>                         offset = 0;
>
> -               /* If we copied full page, mark it uptodate */
> -               if (tmp == PAGE_SIZE)
> +               /* If we copied full folio, mark it uptodate */
> +               if (tmp == folio_size(folio))
>                         folio_mark_uptodate(folio);
>
>                 if (folio_test_uptodate(folio)) {
> --
> 2.43.5
>

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

* Re: [PATCH 04/12] fuse: support large folios for non-writeback writes
  2024-11-12 17:32   ` Joanne Koong
@ 2024-11-13 18:41     ` Joanne Koong
  0 siblings, 0 replies; 32+ messages in thread
From: Joanne Koong @ 2024-11-13 18:41 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

On Tue, Nov 12, 2024 at 9:32 AM Joanne Koong <joannelkoong@gmail.com> wrote:
>
> On Fri, Nov 8, 2024 at 4:13 PM Joanne Koong <joannelkoong@gmail.com> wrote:
> >
> > Add support for folios larger than one page size for non-writeback
>
> I'll change this naming from "non-writeback" to "writethrough"
>
> > writes.
> >
> > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > ---
> >  fs/fuse/file.c | 29 ++++++++++++++++++-----------
> >  1 file changed, 18 insertions(+), 11 deletions(-)
> >
> > diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> > index a89fdc55a40b..6ee23ab9b7f2 100644
> > --- a/fs/fuse/file.c
> > +++ b/fs/fuse/file.c
> > @@ -1146,19 +1146,15 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
> >         num = min(num, max_pages << PAGE_SHIFT);
> >
> >         ap->args.in_pages = true;
> > -       ap->descs[0].offset = offset;
> >
> >         while (num) {
> >                 size_t tmp;
> >                 struct folio *folio;
> >                 pgoff_t index = pos >> PAGE_SHIFT;
> > -               unsigned int bytes = min(PAGE_SIZE - offset, num);
> > -
> > - again:
> > -               err = -EFAULT;
> > -               if (fault_in_iov_iter_readable(ii, bytes))
> > -                       break;
> > +               unsigned int bytes;
> > +               unsigned int folio_offset;
> >
> > +       again:
> >                 folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,
> >                                             mapping_gfp_mask(mapping));
>
> This __filemap_get_folio() call (and the one in fuse_write_begin() as
> well) needs to also set the order on the fgf flag to enable large
> folios, else all folios returned will be order 0.
>
> I'll fix this in v2.

Ran some benchmarks and trying to get the largest folios possible from
__filemap_get_folio() is an over-optimization and slows down writes
significantly. I'll leave this as is for v2, and we could look into
optimizing this in the future.

>
> >                 if (IS_ERR(folio)) {
> > @@ -1166,10 +1162,20 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
> >                         break;
> >                 }
> >
> > +               folio_offset = ((index - folio->index) << PAGE_SHIFT) + offset;
> > +               bytes = min(folio_size(folio) - folio_offset, num);
> > +
> > +               err = -EFAULT;
> > +               if (fault_in_iov_iter_readable(ii, bytes)) {
> > +                       folio_unlock(folio);
> > +                       folio_put(folio);
> > +                       break;
> > +               }
> > +
> >                 if (mapping_writably_mapped(mapping))
> >                         flush_dcache_folio(folio);
> >
> > -               tmp = copy_folio_from_iter_atomic(folio, offset, bytes, ii);
> > +               tmp = copy_folio_from_iter_atomic(folio, folio_offset, bytes, ii);
> >                 flush_dcache_folio(folio);
> >
> >                 if (!tmp) {
> > @@ -1180,6 +1186,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
> >
> >                 err = 0;
> >                 ap->folios[ap->num_folios] = folio;
> > +               ap->descs[ap->num_folios].offset = folio_offset;
> >                 ap->descs[ap->num_folios].length = tmp;
> >                 ap->num_folios++;
> >
> > @@ -1187,11 +1194,11 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
> >                 pos += tmp;
> >                 num -= tmp;
> >                 offset += tmp;
> > -               if (offset == PAGE_SIZE)
> > +               if (offset == folio_size(folio))
> >                         offset = 0;
> >
> > -               /* If we copied full page, mark it uptodate */
> > -               if (tmp == PAGE_SIZE)
> > +               /* If we copied full folio, mark it uptodate */
> > +               if (tmp == folio_size(folio))
> >                         folio_mark_uptodate(folio);
> >
> >                 if (folio_test_uptodate(folio)) {
> > --
> > 2.43.5
> >

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

* Re: [PATCH 00/12] fuse: support large folios
  2024-11-09  0:22 ` [PATCH 00/12] fuse: support " Joanne Koong
  2024-11-09  0:32   ` Bernd Schubert
@ 2024-11-13 18:58   ` Joanne Koong
  1 sibling, 0 replies; 32+ messages in thread
From: Joanne Koong @ 2024-11-13 18:58 UTC (permalink / raw)
  To: miklos, linux-fsdevel
  Cc: josef, bernd.schubert, jefflexu, willy, shakeel.butt, kernel-team

On Fri, Nov 8, 2024 at 4:22 PM Joanne Koong <joannelkoong@gmail.com> wrote:
>
> On Fri, Nov 8, 2024 at 4:13 PM Joanne Koong <joannelkoong@gmail.com> wrote:
> >
> > This patchset adds support for folios larger than one page size in FUSE.
> >
> > This patchset is rebased on top of the (unmerged) patchset that removes temp
> > folios in writeback [1]. (There is also a version of this patchset that is
> > independent from that change, but that version has two additional patches
> > needed to account for temp folios and temp folio copying, which may require
> > some debate to get the API right for as these two patches add generic
> > (non-FUSE) helpers. For simplicity's sake for now, I sent out this patchset
> > version rebased on top of the patchset that removes temp pages)
> >
> > This patchset was tested by running it through fstests on passthrough_hp.
>
> Will be updating this thread with some fio benchmark results early next week.
>

For reads I'm seeing about a ~45% increase in throughput.

This is the setup I used:

-- Set up server --
 ./libfuse/build/example/passthrough_hp --bypass-rw=1 ~/libfuse
~/mounts/fuse/ --nopassthrough
(using libfuse patched with Bernd's passthrough_hp benchmark pr
https://github.com/libfuse/libfuse/pull/807)

-- Run fio --
 fio --name=read --ioengine=sync --rw=read --bs=1M --size=1G
--numjobs=2 --ramp_time=30 --group_reporting=1
--directory=mounts/fuse/

I tested on 2 machines and saw the following:
Machine 1:
    No large folios:     ~4400 MiB/s
    Large folios:         ~7100 MiB/s

Machine 2:
    No large folios:     ~3700 MiB/s
    Large folios:         ~6400 MiB/s

I also did see variability (on both ends) between runs and threw away outliers.


For writes, we're still sending out one page folios (see thread on the
4th patch in this series [1]), so there is no difference. Benchmarks
showed that trying to get the largest folios possible from
__filemap_get_folio() is an over-optimization and ends up being
significantly more expensive. I think it'd probably be an improvement
if we set some reasonably sized order to the __filemap_get_folio()
call (order 2?), but that can be optimized in the future in another
patchset.

[1] https://lore.kernel.org/linux-fsdevel/CAJnrk1aPVwNmv2uxYLwtdwGqe=QUROUXmZc8BiLAV=uqrnCrrw@mail.gmail.com/

> >
> > [1] https://lore.kernel.org/linux-fsdevel/20241107235614.3637221-1-joannelkoong@gmail.com/
> >
> > Joanne Koong (12):
> >   fuse: support copying large folios
> >   fuse: support large folios for retrieves
> >   fuse: refactor fuse_fill_write_pages()
> >   fuse: support large folios for non-writeback writes
> >   fuse: support large folios for folio reads
> >   fuse: support large folios for symlinks
> >   fuse: support large folios for stores
> >   fuse: support large folios for queued writes
> >   fuse: support large folios for readahead
> >   fuse: support large folios for direct io
> >   fuse: support large folios for writeback
> >   fuse: enable large folios
> >
> >  fs/fuse/dev.c  | 131 +++++++++++++++++++++++-----------------------
> >  fs/fuse/dir.c  |   8 +--
> >  fs/fuse/file.c | 138 +++++++++++++++++++++++++++++++------------------
> >  3 files changed, 159 insertions(+), 118 deletions(-)
> >
> > --
> > 2.43.5
> >

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

* Re: [PATCH 01/12] fuse: support copying large folios
  2024-11-09  0:12 ` [PATCH 01/12] fuse: support copying " Joanne Koong
@ 2024-11-21 22:27   ` Josef Bacik
  0 siblings, 0 replies; 32+ messages in thread
From: Josef Bacik @ 2024-11-21 22:27 UTC (permalink / raw)
  To: Joanne Koong
  Cc: miklos, linux-fsdevel, bernd.schubert, jefflexu, willy,
	shakeel.butt, kernel-team

On Fri, Nov 08, 2024 at 04:12:47PM -0800, Joanne Koong wrote:
> Currently, all folios associated with fuse are one page size. As part of
> the work to enable large folios, this commit adds support for copying
> to/from folios larger than one page size.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> ---
>  fs/fuse/dev.c | 89 +++++++++++++++++++++++----------------------------
>  1 file changed, 40 insertions(+), 49 deletions(-)
> 
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 29fc61a072ba..9914cc1243f4 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -703,7 +703,7 @@ struct fuse_copy_state {
>  	struct page *pg;
>  	unsigned len;
>  	unsigned offset;
> -	unsigned move_pages:1;
> +	unsigned move_folios:1;
>  };
>  
>  static void fuse_copy_init(struct fuse_copy_state *cs, int write,
> @@ -836,10 +836,10 @@ static int fuse_check_folio(struct folio *folio)
>  	return 0;
>  }
>  
> -static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
> +static int fuse_try_move_folio(struct fuse_copy_state *cs, struct folio **foliop)
>  {
>  	int err;
> -	struct folio *oldfolio = page_folio(*pagep);
> +	struct folio *oldfolio = *foliop;
>  	struct folio *newfolio;
>  	struct pipe_buffer *buf = cs->pipebufs;
>  
> @@ -860,7 +860,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
>  	cs->pipebufs++;
>  	cs->nr_segs--;
>  
> -	if (cs->len != PAGE_SIZE)
> +	if (cs->len != folio_size(oldfolio))
>  		goto out_fallback;
>  
>  	if (!pipe_buf_try_steal(cs->pipe, buf))
> @@ -906,7 +906,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
>  	if (test_bit(FR_ABORTED, &cs->req->flags))
>  		err = -ENOENT;
>  	else
> -		*pagep = &newfolio->page;
> +		*foliop = newfolio;
>  	spin_unlock(&cs->req->waitq.lock);
>  
>  	if (err) {
> @@ -939,8 +939,8 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
>  	goto out_put_old;
>  }
>  
> -static int fuse_ref_page(struct fuse_copy_state *cs, struct page *page,
> -			 unsigned offset, unsigned count)
> +static int fuse_ref_folio(struct fuse_copy_state *cs, struct folio *folio,
> +			  unsigned offset, unsigned count)
>  {
>  	struct pipe_buffer *buf;
>  	int err;
> @@ -948,17 +948,17 @@ static int fuse_ref_page(struct fuse_copy_state *cs, struct page *page,
>  	if (cs->nr_segs >= cs->pipe->max_usage)
>  		return -EIO;
>  
> -	get_page(page);
> +	folio_get(folio);
>  	err = unlock_request(cs->req);
>  	if (err) {
> -		put_page(page);
> +		folio_put(folio);
>  		return err;
>  	}
>  
>  	fuse_copy_finish(cs);
>  
>  	buf = cs->pipebufs;
> -	buf->page = page;
> +	buf->page = &folio->page;
>  	buf->offset = offset;
>  	buf->len = count;
>  
> @@ -970,20 +970,24 @@ static int fuse_ref_page(struct fuse_copy_state *cs, struct page *page,
>  }
>  
>  /*
> - * Copy a page in the request to/from the userspace buffer.  Must be
> + * Copy a folio in the request to/from the userspace buffer.  Must be
>   * done atomically
>   */
> -static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
> -			  unsigned offset, unsigned count, int zeroing)
> +static int fuse_copy_folio(struct fuse_copy_state *cs, struct folio **foliop,
> +			   unsigned offset, unsigned count, int zeroing)
>  {
>  	int err;
> -	struct page *page = *pagep;
> +	struct folio *folio = *foliop;
> +	size_t size = folio_size(folio);
>  
> -	if (page && zeroing && count < PAGE_SIZE)
> -		clear_highpage(page);
> +	if (folio && zeroing && count < size) {
> +		void *kaddr = kmap_local_folio(folio, 0);
> +		memset(kaddr, 0, size);
> +		kunmap_local(kaddr);

There's a folio_zero_range() that can be used here instead of this, but be sure
you get it right, I definitely did it wrong recently and I think Jan had to fix
my mistake.  Thanks,

Josef

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

* Re: [PATCH 02/12] fuse: support large folios for retrieves
  2024-11-09  0:12 ` [PATCH 02/12] fuse: support large folios for retrieves Joanne Koong
@ 2024-11-21 22:28   ` Josef Bacik
  0 siblings, 0 replies; 32+ messages in thread
From: Josef Bacik @ 2024-11-21 22:28 UTC (permalink / raw)
  To: Joanne Koong
  Cc: miklos, linux-fsdevel, bernd.schubert, jefflexu, willy,
	shakeel.butt, kernel-team

On Fri, Nov 08, 2024 at 04:12:48PM -0800, Joanne Koong wrote:
> Add support for folios larger than one page size for retrieves.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>

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

Thanks,

Josef

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

* Re: [PATCH 03/12] fuse: refactor fuse_fill_write_pages()
  2024-11-09  0:12 ` [PATCH 03/12] fuse: refactor fuse_fill_write_pages() Joanne Koong
@ 2024-11-21 22:28   ` Josef Bacik
  0 siblings, 0 replies; 32+ messages in thread
From: Josef Bacik @ 2024-11-21 22:28 UTC (permalink / raw)
  To: Joanne Koong
  Cc: miklos, linux-fsdevel, bernd.schubert, jefflexu, willy,
	shakeel.butt, kernel-team

On Fri, Nov 08, 2024 at 04:12:49PM -0800, Joanne Koong wrote:
> Refactor the logic in fuse_fill_write_pages() for copying out write
> data. This will make the future change for supporting large folios for
> writes easier. No functional changes.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>

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

Thanks,

Josef

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

* Re: [PATCH 04/12] fuse: support large folios for non-writeback writes
  2024-11-09  0:12 ` [PATCH 04/12] fuse: support large folios for non-writeback writes Joanne Koong
  2024-11-12 17:32   ` Joanne Koong
@ 2024-11-21 22:32   ` Josef Bacik
  1 sibling, 0 replies; 32+ messages in thread
From: Josef Bacik @ 2024-11-21 22:32 UTC (permalink / raw)
  To: Joanne Koong
  Cc: miklos, linux-fsdevel, bernd.schubert, jefflexu, willy,
	shakeel.butt, kernel-team

On Fri, Nov 08, 2024 at 04:12:50PM -0800, Joanne Koong wrote:
> Add support for folios larger than one page size for non-writeback
> writes.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> ---
>  fs/fuse/file.c | 29 ++++++++++++++++++-----------
>  1 file changed, 18 insertions(+), 11 deletions(-)
> 
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index a89fdc55a40b..6ee23ab9b7f2 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -1146,19 +1146,15 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
>  	num = min(num, max_pages << PAGE_SHIFT);
>  
>  	ap->args.in_pages = true;
> -	ap->descs[0].offset = offset;
>  
>  	while (num) {
>  		size_t tmp;
>  		struct folio *folio;
>  		pgoff_t index = pos >> PAGE_SHIFT;
> -		unsigned int bytes = min(PAGE_SIZE - offset, num);
> -
> - again:
> -		err = -EFAULT;
> -		if (fault_in_iov_iter_readable(ii, bytes))
> -			break;
> +		unsigned int bytes;
> +		unsigned int folio_offset;
>  
> +	again:
>  		folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,
>  					    mapping_gfp_mask(mapping));
>  		if (IS_ERR(folio)) {
> @@ -1166,10 +1162,20 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
>  			break;
>  		}
>  
> +		folio_offset = ((index - folio->index) << PAGE_SHIFT) + offset;
> +		bytes = min(folio_size(folio) - folio_offset, num);
> +
> +		err = -EFAULT;
> +		if (fault_in_iov_iter_readable(ii, bytes)) {
> +			folio_unlock(folio);
> +			folio_put(folio);
> +			break;
> +		}

This is a deadlock potentially.  mmap the file, then buffered write to it with
the mmaped region and you will deadlock because fault_in_iov_iter_readable()
will try to lock the folio to submit the read, and you're already holding the
lock from the __filemap_get_folio() call.

If you look at iomap_write_iter it does a the fault_in_iov_iter_readable() call
before getting the folio, and it just uses the mapping_max_folio_size() value to
fault in larger chunks for whatever folio we manage to grab.  Thanks,

Josef

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

* Re: [PATCH 05/12] fuse: support large folios for folio reads
  2024-11-09  0:12 ` [PATCH 05/12] fuse: support large folios for folio reads Joanne Koong
@ 2024-11-22 14:42   ` Josef Bacik
  0 siblings, 0 replies; 32+ messages in thread
From: Josef Bacik @ 2024-11-22 14:42 UTC (permalink / raw)
  To: Joanne Koong
  Cc: miklos, linux-fsdevel, bernd.schubert, jefflexu, willy,
	shakeel.butt, kernel-team

On Fri, Nov 08, 2024 at 04:12:51PM -0800, Joanne Koong wrote:
> Add support for folios larger than one page size for folio reads into
> the page cache.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>

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

Thanks,

Josef

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

* Re: [PATCH 06/12] fuse: support large folios for symlinks
  2024-11-09  0:12 ` [PATCH 06/12] fuse: support large folios for symlinks Joanne Koong
@ 2024-11-22 14:43   ` Josef Bacik
  0 siblings, 0 replies; 32+ messages in thread
From: Josef Bacik @ 2024-11-22 14:43 UTC (permalink / raw)
  To: Joanne Koong
  Cc: miklos, linux-fsdevel, bernd.schubert, jefflexu, willy,
	shakeel.butt, kernel-team

On Fri, Nov 08, 2024 at 04:12:52PM -0800, Joanne Koong wrote:
> Support large folios for symlinks and change the name from
> fuse_getlink_page() to fuse_getlink_folio().
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>

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

Thanks,

Josef

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

* Re: [PATCH 07/12] fuse: support large folios for stores
  2024-11-09  0:12 ` [PATCH 07/12] fuse: support large folios for stores Joanne Koong
@ 2024-11-22 14:45   ` Josef Bacik
  0 siblings, 0 replies; 32+ messages in thread
From: Josef Bacik @ 2024-11-22 14:45 UTC (permalink / raw)
  To: Joanne Koong
  Cc: miklos, linux-fsdevel, bernd.schubert, jefflexu, willy,
	shakeel.butt, kernel-team

On Fri, Nov 08, 2024 at 04:12:53PM -0800, Joanne Koong wrote:
> Add support for folios larger than one page size for stores.
> Also change variable naming from "this_num" to "nr_bytes".
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>

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

Thanks,

Josef

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

* Re: [PATCH 08/12] fuse: support large folios for queued writes
  2024-11-09  0:12 ` [PATCH 08/12] fuse: support large folios for queued writes Joanne Koong
@ 2024-11-22 14:45   ` Josef Bacik
  0 siblings, 0 replies; 32+ messages in thread
From: Josef Bacik @ 2024-11-22 14:45 UTC (permalink / raw)
  To: Joanne Koong
  Cc: miklos, linux-fsdevel, bernd.schubert, jefflexu, willy,
	shakeel.butt, kernel-team

On Fri, Nov 08, 2024 at 04:12:54PM -0800, Joanne Koong wrote:
> Add support for folios larger than one page size for queued writes.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>

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

Thanks,

Josef

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

* Re: [PATCH 09/12] fuse: support large folios for readahead
  2024-11-09  0:12 ` [PATCH 09/12] fuse: support large folios for readahead Joanne Koong
@ 2024-11-22 14:47   ` Josef Bacik
  2024-11-25 19:23     ` Joanne Koong
  0 siblings, 1 reply; 32+ messages in thread
From: Josef Bacik @ 2024-11-22 14:47 UTC (permalink / raw)
  To: Joanne Koong
  Cc: miklos, linux-fsdevel, bernd.schubert, jefflexu, willy,
	shakeel.butt, kernel-team

On Fri, Nov 08, 2024 at 04:12:55PM -0800, Joanne Koong wrote:
> Add support for folios larger than one page size for readahead.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> ---
>  fs/fuse/file.c | 28 +++++++++++++++++++---------
>  1 file changed, 19 insertions(+), 9 deletions(-)
> 
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index 44a65bdfe8fb..255c7f2f2ed4 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -885,14 +885,13 @@ static void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args,
>  	fuse_io_free(ia);
>  }
>  
> -static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file)
> +static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file,
> +				unsigned int count)
>  {
>  	struct fuse_file *ff = file->private_data;
>  	struct fuse_mount *fm = ff->fm;
>  	struct fuse_args_pages *ap = &ia->ap;
>  	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;
>  
> @@ -929,6 +928,7 @@ static void fuse_readahead(struct readahead_control *rac)
>  	unsigned int max_pages, nr_pages;
>  	loff_t first = readahead_pos(rac);
>  	loff_t last = first + readahead_length(rac) - 1;
> +	struct folio *folio = NULL;
>  
>  	if (fuse_is_bad(inode))
>  		return;
> @@ -952,8 +952,8 @@ static void fuse_readahead(struct readahead_control *rac)
>  	while (nr_pages) {
>  		struct fuse_io_args *ia;
>  		struct fuse_args_pages *ap;
> -		struct folio *folio;
>  		unsigned cur_pages = min(max_pages, nr_pages);
> +		unsigned int pages = 0;
>  
>  		if (fc->num_background >= fc->congestion_threshold &&
>  		    rac->ra->async_size >= readahead_count(rac))
> @@ -968,14 +968,24 @@ static void fuse_readahead(struct readahead_control *rac)
>  			return;
>  		ap = &ia->ap;
>  
> -		while (ap->num_folios < cur_pages) {
> -			folio = readahead_folio(rac);
> +		while (pages < cur_pages) {
> +			unsigned int folio_pages;
> +
> +			if (!folio)
> +				folio = readahead_folio(rac);
> +
> +			folio_pages = folio_nr_pages(folio);
> +			if (folio_pages > cur_pages - pages)
> +				break;
> +
>  			ap->folios[ap->num_folios] = folio;
> -			ap->descs[ap->num_folios].length = folio_size(folio);
> +			ap->descs[ap->num_folios].length = folio_pages << PAGE_SHIFT;

Why change this?  Aren't these equivalent?  Thanks,

Josef

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

* Re: [PATCH 10/12] fuse: support large folios for direct io
  2024-11-09  0:12 ` [PATCH 10/12] fuse: support large folios for direct io Joanne Koong
@ 2024-11-22 14:49   ` Josef Bacik
  0 siblings, 0 replies; 32+ messages in thread
From: Josef Bacik @ 2024-11-22 14:49 UTC (permalink / raw)
  To: Joanne Koong
  Cc: miklos, linux-fsdevel, bernd.schubert, jefflexu, willy,
	shakeel.butt, kernel-team

On Fri, Nov 08, 2024 at 04:12:56PM -0800, Joanne Koong wrote:
> Add support for folios larger than one page size for direct io.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>

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

Thanks,

Josef

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

* Re: [PATCH 11/12] fuse: support large folios for writeback
  2024-11-09  0:12 ` [PATCH 11/12] fuse: support large folios for writeback Joanne Koong
@ 2024-11-22 14:50   ` Josef Bacik
  0 siblings, 0 replies; 32+ messages in thread
From: Josef Bacik @ 2024-11-22 14:50 UTC (permalink / raw)
  To: Joanne Koong
  Cc: miklos, linux-fsdevel, bernd.schubert, jefflexu, willy,
	shakeel.butt, kernel-team

On Fri, Nov 08, 2024 at 04:12:57PM -0800, Joanne Koong wrote:
> Add support for folios larger than one page size for writeback.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>

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

Thanks,

Josef

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

* Re: [PATCH 12/12] fuse: enable large folios
  2024-11-09  0:12 ` [PATCH 12/12] fuse: enable large folios Joanne Koong
@ 2024-11-22 14:51   ` Josef Bacik
  0 siblings, 0 replies; 32+ messages in thread
From: Josef Bacik @ 2024-11-22 14:51 UTC (permalink / raw)
  To: Joanne Koong
  Cc: miklos, linux-fsdevel, bernd.schubert, jefflexu, willy,
	shakeel.butt, kernel-team

On Fri, Nov 08, 2024 at 04:12:58PM -0800, Joanne Koong wrote:
> Enable folios larger than one page size.
> 
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>

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

Thanks,

Josef

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

* Re: [PATCH 09/12] fuse: support large folios for readahead
  2024-11-22 14:47   ` Josef Bacik
@ 2024-11-25 19:23     ` Joanne Koong
  0 siblings, 0 replies; 32+ messages in thread
From: Joanne Koong @ 2024-11-25 19:23 UTC (permalink / raw)
  To: Josef Bacik
  Cc: miklos, linux-fsdevel, bernd.schubert, jefflexu, willy,
	shakeel.butt, kernel-team

On Fri, Nov 22, 2024 at 6:47 AM Josef Bacik <josef@toxicpanda.com> wrote:
>
> On Fri, Nov 08, 2024 at 04:12:55PM -0800, Joanne Koong wrote:
> > Add support for folios larger than one page size for readahead.
> >
> > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > ---
> >  fs/fuse/file.c | 28 +++++++++++++++++++---------
> >  1 file changed, 19 insertions(+), 9 deletions(-)
> >
> > diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> > index 44a65bdfe8fb..255c7f2f2ed4 100644
> > --- a/fs/fuse/file.c
> > +++ b/fs/fuse/file.c
> > @@ -885,14 +885,13 @@ static void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args,
> >       fuse_io_free(ia);
> >  }
> >
> > -static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file)
> > +static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file,
> > +                             unsigned int count)
> >  {
> >       struct fuse_file *ff = file->private_data;
> >       struct fuse_mount *fm = ff->fm;
> >       struct fuse_args_pages *ap = &ia->ap;
> >       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;
> >
> > @@ -929,6 +928,7 @@ static void fuse_readahead(struct readahead_control *rac)
> >       unsigned int max_pages, nr_pages;
> >       loff_t first = readahead_pos(rac);
> >       loff_t last = first + readahead_length(rac) - 1;
> > +     struct folio *folio = NULL;
> >
> >       if (fuse_is_bad(inode))
> >               return;
> > @@ -952,8 +952,8 @@ static void fuse_readahead(struct readahead_control *rac)
> >       while (nr_pages) {
> >               struct fuse_io_args *ia;
> >               struct fuse_args_pages *ap;
> > -             struct folio *folio;
> >               unsigned cur_pages = min(max_pages, nr_pages);
> > +             unsigned int pages = 0;
> >
> >               if (fc->num_background >= fc->congestion_threshold &&
> >                   rac->ra->async_size >= readahead_count(rac))
> > @@ -968,14 +968,24 @@ static void fuse_readahead(struct readahead_control *rac)
> >                       return;
> >               ap = &ia->ap;
> >
> > -             while (ap->num_folios < cur_pages) {
> > -                     folio = readahead_folio(rac);
> > +             while (pages < cur_pages) {
> > +                     unsigned int folio_pages;
> > +
> > +                     if (!folio)
> > +                             folio = readahead_folio(rac);
> > +
> > +                     folio_pages = folio_nr_pages(folio);
> > +                     if (folio_pages > cur_pages - pages)
> > +                             break;
> > +
> >                       ap->folios[ap->num_folios] = folio;
> > -                     ap->descs[ap->num_folios].length = folio_size(folio);
> > +                     ap->descs[ap->num_folios].length = folio_pages << PAGE_SHIFT;
>
> Why change this?  Aren't these equivalent?  Thanks,

Yes, these are equivalent. Don't know why I modified this, thanks for
noting. I'll change this back to the original line for v2.


Thanks,
Joanne
>
> Josef

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

end of thread, other threads:[~2024-11-25 19:23 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-09  0:12 [PATCH 00/12] fuse: support large folios Joanne Koong
2024-11-09  0:12 ` [PATCH 01/12] fuse: support copying " Joanne Koong
2024-11-21 22:27   ` Josef Bacik
2024-11-09  0:12 ` [PATCH 02/12] fuse: support large folios for retrieves Joanne Koong
2024-11-21 22:28   ` Josef Bacik
2024-11-09  0:12 ` [PATCH 03/12] fuse: refactor fuse_fill_write_pages() Joanne Koong
2024-11-21 22:28   ` Josef Bacik
2024-11-09  0:12 ` [PATCH 04/12] fuse: support large folios for non-writeback writes Joanne Koong
2024-11-12 17:32   ` Joanne Koong
2024-11-13 18:41     ` Joanne Koong
2024-11-21 22:32   ` Josef Bacik
2024-11-09  0:12 ` [PATCH 05/12] fuse: support large folios for folio reads Joanne Koong
2024-11-22 14:42   ` Josef Bacik
2024-11-09  0:12 ` [PATCH 06/12] fuse: support large folios for symlinks Joanne Koong
2024-11-22 14:43   ` Josef Bacik
2024-11-09  0:12 ` [PATCH 07/12] fuse: support large folios for stores Joanne Koong
2024-11-22 14:45   ` Josef Bacik
2024-11-09  0:12 ` [PATCH 08/12] fuse: support large folios for queued writes Joanne Koong
2024-11-22 14:45   ` Josef Bacik
2024-11-09  0:12 ` [PATCH 09/12] fuse: support large folios for readahead Joanne Koong
2024-11-22 14:47   ` Josef Bacik
2024-11-25 19:23     ` Joanne Koong
2024-11-09  0:12 ` [PATCH 10/12] fuse: support large folios for direct io Joanne Koong
2024-11-22 14:49   ` Josef Bacik
2024-11-09  0:12 ` [PATCH 11/12] fuse: support large folios for writeback Joanne Koong
2024-11-22 14:50   ` Josef Bacik
2024-11-09  0:12 ` [PATCH 12/12] fuse: enable large folios Joanne Koong
2024-11-22 14:51   ` Josef Bacik
2024-11-09  0:22 ` [PATCH 00/12] fuse: support " Joanne Koong
2024-11-09  0:32   ` Bernd Schubert
2024-11-11 17:44     ` Joanne Koong
2024-11-13 18:58   ` Joanne Koong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox