Re: [PATCH v5 01/11] fuse: support copying large folios

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 4/26/25 02:08, 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@xxxxxxxxx>
> Reviewed-by: Jeff Layton <jlayton@xxxxxxxxxx>

Reviewed-by: Bernd Schubert <bschubert@xxxxxxx>

> ---
>  fs/fuse/dev.c        | 84 +++++++++++++++++++-------------------------
>  fs/fuse/fuse_dev_i.h |  2 +-
>  2 files changed, 37 insertions(+), 49 deletions(-)
> 
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 155bb6aeaef5..7b0e3a394480 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -955,10 +955,10 @@ static int fuse_check_folio(struct folio *folio)
>   * folio that was originally in @pagep will lose a reference and the new
>   * folio returned in @pagep will carry a reference.
>   */
> -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;
>  
> @@ -979,7 +979,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))
> @@ -1025,7 +1025,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) {
> @@ -1058,8 +1058,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;
> @@ -1067,17 +1067,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;
>  
> @@ -1089,20 +1089,21 @@ 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)
> +		folio_zero_range(folio, 0, size);
>  
>  	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.
> @@ -1112,12 +1113,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 {
> @@ -1126,22 +1127,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;
> @@ -1151,23 +1152,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;
>  }
> @@ -1197,7 +1187,7 @@ 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);
>  	}
> @@ -1786,7 +1776,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);
> @@ -1794,9 +1783,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));
> @@ -2037,8 +2025,8 @@ static int fuse_notify_inc_epoch(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 = false;
> +	/* Don't try to move folios (yet) */
> +	cs->move_folios = false;
>  
>  	switch (code) {
>  	case FUSE_NOTIFY_POLL:
> @@ -2189,7 +2177,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 = false;
> +		cs->move_folios = false;
>  
>  	if (oh.error)
>  		err = nbytes != sizeof(oh) ? -EINVAL : 0;
> @@ -2307,7 +2295,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
>  	cs.pipe = pipe;
>  
>  	if (flags & SPLICE_F_MOVE)
> -		cs.move_pages = true;
> +		cs.move_folios = true;
>  
>  	ret = fuse_dev_do_write(fud, &cs, len);
>  
> diff --git a/fs/fuse/fuse_dev_i.h b/fs/fuse/fuse_dev_i.h
> index db136e045925..5a9bd771a319 100644
> --- a/fs/fuse/fuse_dev_i.h
> +++ b/fs/fuse/fuse_dev_i.h
> @@ -30,7 +30,7 @@ struct fuse_copy_state {
>  	unsigned int len;
>  	unsigned int offset;
>  	bool write:1;
> -	bool move_pages:1;
> +	bool move_folios:1;
>  	bool is_uring:1;
>  	struct {
>  		unsigned int copied_sz; /* copied size into the user buffer */





[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux