Skip to content

Commit

Permalink
Merge tag 'fuse-update-6.13' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/git/mszeredi/fuse

Pull fuse updates from Miklos Szeredi:

 - Add page -> folio conversions (Joanne Koong, Josef Bacik)

 - Allow max size of fuse requests to be configurable with a sysctl
   (Joanne Koong)

 - Allow FOPEN_DIRECT_IO to take advantage of async code path (yangyun)

 - Fix large kernel reads (like a module load) in virtio_fs (Hou Tao)

 - Fix attribute inconsistency in case readdirplus (and plain lookup in
   corner cases) is racing with inode eviction (Zhang Tianci)

 - Fix a WARN_ON triggered by virtio_fs (Asahi Lina)

* tag 'fuse-update-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: (30 commits)
  virtiofs: dax: remove ->writepages() callback
  fuse: check attributes staleness on fuse_iget()
  fuse: remove pages for requests and exclusively use folios
  fuse: convert direct io to use folios
  mm/writeback: add folio_mark_dirty_lock()
  fuse: convert writebacks to use folios
  fuse: convert retrieves to use folios
  fuse: convert ioctls to use folios
  fuse: convert writes (non-writeback) to use folios
  fuse: convert reads to use folios
  fuse: convert readdir to use folios
  fuse: convert readlink to use folios
  fuse: convert cuse to use folios
  fuse: add support in virtio for requests using folios
  fuse: support folios in struct fuse_args_pages and fuse_copy_pages()
  fuse: convert fuse_notify_store to use folios
  fuse: convert fuse_retrieve to use folios
  fuse: use the folio based vmstat helpers
  fuse: convert fuse_writepage_need_send to take a folio
  fuse: convert fuse_do_readpage to use folios
  ...
  • Loading branch information
torvalds committed Nov 26, 2024
2 parents ff2a7a0 + d1dfb5f commit fb527fc
Show file tree
Hide file tree
Showing 16 changed files with 578 additions and 374 deletions.
10 changes: 10 additions & 0 deletions Documentation/admin-guide/sysctl/fs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -337,3 +337,13 @@ Each "watch" costs roughly 90 bytes on a 32-bit kernel, and roughly 160 bytes
on a 64-bit one.
The current default value for ``max_user_watches`` is 4% of the
available low memory, divided by the "watch" cost in bytes.

5. /proc/sys/fs/fuse - Configuration options for FUSE filesystems
=====================================================================

This directory contains the following configuration options for FUSE
filesystems:

``/proc/sys/fs/fuse/max_pages_limit`` is a read/write file for
setting/getting the maximum number of pages that can be used for servicing
requests in FUSE.
1 change: 1 addition & 0 deletions fs/fuse/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ fuse-y := dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o ioctl.o
fuse-y += iomode.o
fuse-$(CONFIG_FUSE_DAX) += dax.o
fuse-$(CONFIG_FUSE_PASSTHROUGH) += passthrough.o
fuse-$(CONFIG_SYSCTL) += sysctl.o

virtiofs-y := virtio_fs.o
29 changes: 15 additions & 14 deletions fs/fuse/cuse.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

/**
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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:
Expand All @@ -429,21 +429,22 @@ 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;

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;
Expand All @@ -459,18 +460,18 @@ 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->num_folios = 1;
ap->folios = &ia->folio;
ap->descs = &ia->desc;
ia->page = page;
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;
Expand Down
11 changes: 0 additions & 11 deletions fs/fuse/dax.c
Original file line number Diff line number Diff line change
Expand Up @@ -774,16 +774,6 @@ ssize_t fuse_dax_write_iter(struct kiocb *iocb, struct iov_iter *from)
return ret;
}

static int fuse_dax_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{

struct inode *inode = mapping->host;
struct fuse_conn *fc = get_fuse_conn(inode);

return dax_writeback_mapping_range(mapping, fc->dax->dev, wbc);
}

static vm_fault_t __fuse_dax_fault(struct vm_fault *vmf, unsigned int order,
bool write)
{
Expand Down Expand Up @@ -1323,7 +1313,6 @@ bool fuse_dax_inode_alloc(struct super_block *sb, struct fuse_inode *fi)
}

static const struct address_space_operations fuse_dax_file_aops = {
.writepages = fuse_dax_writepages,
.direct_IO = noop_direct_IO,
.dirty_folio = noop_dirty_folio,
};
Expand Down
66 changes: 39 additions & 27 deletions fs/fuse/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1028,17 +1028,27 @@ 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);


for (i = 0; i < ap->num_pages && (nbytes || zeroing); i++) {
for (i = 0; i < ap->num_folios && (nbytes || zeroing); i++) {
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, &ap->pages[i], offset, count, zeroing);
err = fuse_copy_page(cs, &pagep, 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;
}
Expand Down Expand Up @@ -1654,24 +1664,25 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,

num = outarg.size;
while (num) {
struct folio *folio;
struct page *page;
unsigned int this_num;

err = -ENOMEM;
page = find_or_create_page(mapping, index,
mapping_gfp_mask(mapping));
if (!page)
folio = filemap_grab_folio(mapping, index);
err = PTR_ERR(folio);
if (IS_ERR(folio))
goto out_iput;

this_num = min_t(unsigned, num, PAGE_SIZE - offset);
page = &folio->page;
this_num = min_t(unsigned, num, folio_size(folio) - offset);
err = fuse_copy_page(cs, &page, offset, this_num, 0);
if (!PageUptodate(page) && !err && offset == 0 &&
(this_num == PAGE_SIZE || file_size == end)) {
zero_user_segment(page, this_num, PAGE_SIZE);
SetPageUptodate(page);
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));
folio_mark_uptodate(folio);
}
unlock_page(page);
put_page(page);
folio_unlock(folio);
folio_put(folio);

if (err)
goto out_iput;
Expand Down Expand Up @@ -1703,7 +1714,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);
}

Expand All @@ -1717,7 +1728,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_pages, cur_pages = 0;
struct fuse_conn *fc = fm->fc;
struct fuse_retrieve_args *ra;
size_t args_size = sizeof(*ra);
Expand All @@ -1736,15 +1747,15 @@ 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);

args_size += num_pages * (sizeof(ap->pages[0]) + sizeof(ap->descs[0]));
args_size += num_pages * (sizeof(ap->folios[0]) + sizeof(ap->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->descs = (void *) (ap->folios + num_pages);

args = &ap->args;
args->nodeid = outarg->nodeid;
Expand All @@ -1755,19 +1766,20 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,

index = outarg->offset >> PAGE_SHIFT;

while (num && ap->num_pages < num_pages) {
struct page *page;
while (num && cur_pages < num_pages) {
struct folio *folio;
unsigned int this_num;

page = find_get_page(mapping, index);
if (!page)
folio = filemap_get_folio(mapping, index);
if (IS_ERR(folio))
break;

this_num = min_t(unsigned, num, PAGE_SIZE - offset);
ap->pages[ap->num_pages] = page;
ap->descs[ap->num_pages].offset = offset;
ap->descs[ap->num_pages].length = this_num;
ap->num_pages++;
ap->folios[ap->num_folios] = folio;
ap->descs[ap->num_folios].offset = offset;
ap->descs[ap->num_folios].length = this_num;
ap->num_folios++;
cur_pages++;

offset = 0;
num -= this_num;
Expand Down
37 changes: 19 additions & 18 deletions fs/fuse/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
struct fuse_mount *fm = get_fuse_mount_super(sb);
FUSE_ARGS(args);
struct fuse_forget_link *forget;
u64 attr_version;
u64 attr_version, evict_ctr;
int err;

*inode = NULL;
Expand All @@ -381,6 +381,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
goto out;

attr_version = fuse_get_attr_version(fm->fc);
evict_ctr = fuse_get_evict_ctr(fm->fc);

fuse_lookup_init(fm->fc, &args, nodeid, name, outarg);
err = fuse_simple_request(fm, &args);
Expand All @@ -398,7 +399,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name

*inode = fuse_iget(sb, outarg->nodeid, outarg->generation,
&outarg->attr, ATTR_TIMEOUT(outarg),
attr_version);
attr_version, evict_ctr);
err = -ENOMEM;
if (!*inode) {
fuse_queue_forget(fm->fc, forget, outarg->nodeid, 1);
Expand Down Expand Up @@ -691,7 +692,7 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir,
ff->nodeid = outentry.nodeid;
ff->open_flags = outopenp->open_flags;
inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
&outentry.attr, ATTR_TIMEOUT(&outentry), 0);
&outentry.attr, ATTR_TIMEOUT(&outentry), 0, 0);
if (!inode) {
flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
fuse_sync_release(NULL, ff, flags);
Expand Down Expand Up @@ -822,7 +823,7 @@ static int create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm,
goto out_put_forget_req;

inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
&outarg.attr, ATTR_TIMEOUT(&outarg), 0);
&outarg.attr, ATTR_TIMEOUT(&outarg), 0, 0);
if (!inode) {
fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1);
return -ENOMEM;
Expand Down Expand Up @@ -1585,13 +1586,13 @@ 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,
.num_folios = 1,
.folios = &folio,
.descs = &desc,
};
char *link;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -2028,7 +2029,7 @@ int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry,

fuse_change_attributes_common(inode, &outarg.attr, NULL,
ATTR_TIMEOUT(&outarg),
fuse_get_cache_mask(inode));
fuse_get_cache_mask(inode), 0);
oldsize = inode->i_size;
/* see the comment in fuse_change_attributes() */
if (!is_wb || is_truncate)
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit fb527fc

Please sign in to comment.