Commit 8e4f3e15 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'fuse-update-5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

Pull fuse updates from Miklos Szeredi:

 - Fixes for virtiofs submounts

 - Misc fixes and cleanups

* tag 'fuse-update-5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  virtiofs: Fix spelling mistakes
  fuse: use DIV_ROUND_UP helper macro for calculations
  fuse: fix illegal access to inode with reused nodeid
  fuse: allow fallocate(FALLOC_FL_ZERO_RANGE)
  fuse: Make fuse_fill_super_submount() static
  fuse: Switch to fc_mount() for submounts
  fuse: Call vfs_get_tree() for submounts
  fuse: add dedicated filesystem context ops for submounts
  virtiofs: propagate sync() to file server
  fuse: reject internal errno
  fuse: check connected before queueing on fpq->io
  fuse: ignore PG_workingset after stealing
  fuse: Fix infinite loop in sget_fc()
  fuse: Fix crash if superblock of submount gets killed early
  fuse: Fix crash in fuse_dentry_automount() error path
parents 729437e3 c4e0cd4e
...@@ -213,7 +213,7 @@ static int fuse_setup_one_mapping(struct inode *inode, unsigned long start_idx, ...@@ -213,7 +213,7 @@ static int fuse_setup_one_mapping(struct inode *inode, unsigned long start_idx,
dmap->writable = writable; dmap->writable = writable;
if (!upgrade) { if (!upgrade) {
/* /*
* We don't take a refernce on inode. inode is valid right now * We don't take a reference on inode. inode is valid right now
* and when inode is going away, cleanup logic should first * and when inode is going away, cleanup logic should first
* cleanup dmap entries. * cleanup dmap entries.
*/ */
...@@ -622,7 +622,7 @@ static int fuse_iomap_begin(struct inode *inode, loff_t pos, loff_t length, ...@@ -622,7 +622,7 @@ static int fuse_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
} }
/* /*
* If read beyond end of file happnes, fs code seems to return * If read beyond end of file happens, fs code seems to return
* it as hole * it as hole
*/ */
iomap_hole: iomap_hole:
...@@ -1207,7 +1207,7 @@ static void fuse_dax_free_mem_worker(struct work_struct *work) ...@@ -1207,7 +1207,7 @@ static void fuse_dax_free_mem_worker(struct work_struct *work)
ret); ret);
} }
/* If number of free ranges are still below threhold, requeue */ /* If number of free ranges are still below threshold, requeue */
kick_dmap_free_worker(fcd, 1); kick_dmap_free_worker(fcd, 1);
} }
......
...@@ -91,7 +91,7 @@ static void fuse_drop_waiting(struct fuse_conn *fc) ...@@ -91,7 +91,7 @@ static void fuse_drop_waiting(struct fuse_conn *fc)
{ {
/* /*
* lockess check of fc->connected is okay, because atomic_dec_and_test() * lockess check of fc->connected is okay, because atomic_dec_and_test()
* provides a memory barrier mached with the one in fuse_wait_aborted() * provides a memory barrier matched with the one in fuse_wait_aborted()
* to ensure no wake-up is missed. * to ensure no wake-up is missed.
*/ */
if (atomic_dec_and_test(&fc->num_waiting) && if (atomic_dec_and_test(&fc->num_waiting) &&
...@@ -783,6 +783,7 @@ static int fuse_check_page(struct page *page) ...@@ -783,6 +783,7 @@ static int fuse_check_page(struct page *page)
1 << PG_uptodate | 1 << PG_uptodate |
1 << PG_lru | 1 << PG_lru |
1 << PG_active | 1 << PG_active |
1 << PG_workingset |
1 << PG_reclaim | 1 << PG_reclaim |
1 << PG_waiters))) { 1 << PG_waiters))) {
dump_page(page, "fuse: trying to steal weird page"); dump_page(page, "fuse: trying to steal weird page");
...@@ -1271,6 +1272,15 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, ...@@ -1271,6 +1272,15 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
goto restart; goto restart;
} }
spin_lock(&fpq->lock); spin_lock(&fpq->lock);
/*
* Must not put request on fpq->io queue after having been shut down by
* fuse_abort_conn()
*/
if (!fpq->connected) {
req->out.h.error = err = -ECONNABORTED;
goto out_end;
}
list_add(&req->list, &fpq->io); list_add(&req->list, &fpq->io);
spin_unlock(&fpq->lock); spin_unlock(&fpq->lock);
cs->req = req; cs->req = req;
...@@ -1857,7 +1867,7 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, ...@@ -1857,7 +1867,7 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
} }
err = -EINVAL; err = -EINVAL;
if (oh.error <= -1000 || oh.error > 0) if (oh.error <= -512 || oh.error > 0)
goto copy_finish; goto copy_finish;
spin_lock(&fpq->lock); spin_lock(&fpq->lock);
......
...@@ -252,7 +252,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) ...@@ -252,7 +252,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
if (ret == -ENOMEM) if (ret == -ENOMEM)
goto out; goto out;
if (ret || fuse_invalid_attr(&outarg.attr) || if (ret || fuse_invalid_attr(&outarg.attr) ||
inode_wrong_type(inode, outarg.attr.mode)) fuse_stale_inode(inode, outarg.generation, &outarg.attr))
goto invalid; goto invalid;
forget_all_cached_acls(inode); forget_all_cached_acls(inode);
...@@ -309,68 +309,23 @@ static int fuse_dentry_delete(const struct dentry *dentry) ...@@ -309,68 +309,23 @@ static int fuse_dentry_delete(const struct dentry *dentry)
static struct vfsmount *fuse_dentry_automount(struct path *path) static struct vfsmount *fuse_dentry_automount(struct path *path)
{ {
struct fs_context *fsc; struct fs_context *fsc;
struct fuse_mount *parent_fm = get_fuse_mount_super(path->mnt->mnt_sb);
struct fuse_conn *fc = parent_fm->fc;
struct fuse_mount *fm;
struct vfsmount *mnt; struct vfsmount *mnt;
struct fuse_inode *mp_fi = get_fuse_inode(d_inode(path->dentry)); struct fuse_inode *mp_fi = get_fuse_inode(d_inode(path->dentry));
struct super_block *sb;
int err;
fsc = fs_context_for_submount(path->mnt->mnt_sb->s_type, path->dentry); fsc = fs_context_for_submount(path->mnt->mnt_sb->s_type, path->dentry);
if (IS_ERR(fsc)) { if (IS_ERR(fsc))
err = PTR_ERR(fsc); return ERR_CAST(fsc);
goto out;
}
err = -ENOMEM;
fm = kzalloc(sizeof(struct fuse_mount), GFP_KERNEL);
if (!fm)
goto out_put_fsc;
fsc->s_fs_info = fm;
sb = sget_fc(fsc, NULL, set_anon_super_fc);
if (IS_ERR(sb)) {
err = PTR_ERR(sb);
kfree(fm);
goto out_put_fsc;
}
fm->fc = fuse_conn_get(fc);
/* Initialize superblock, making @mp_fi its root */
err = fuse_fill_super_submount(sb, mp_fi);
if (err)
goto out_put_sb;
sb->s_flags |= SB_ACTIVE; /* Pass the FUSE inode of the mount for fuse_get_tree_submount() */
fsc->root = dget(sb->s_root); fsc->fs_private = mp_fi;
/* We are done configuring the superblock, so unlock it */
up_write(&sb->s_umount);
down_write(&fc->killsb);
list_add_tail(&fm->fc_entry, &fc->mounts);
up_write(&fc->killsb);
/* Create the submount */ /* Create the submount */
mnt = vfs_create_mount(fsc); mnt = fc_mount(fsc);
if (IS_ERR(mnt)) { if (!IS_ERR(mnt))
err = PTR_ERR(mnt);
goto out_put_fsc;
}
mntget(mnt); mntget(mnt);
put_fs_context(fsc);
return mnt;
out_put_sb:
/*
* Only jump here when fsc->root is NULL and sb is still locked
* (otherwise put_fs_context() will put the superblock)
*/
deactivate_locked_super(sb);
out_put_fsc:
put_fs_context(fsc); put_fs_context(fsc);
out: return mnt;
return ERR_PTR(err);
} }
const struct dentry_operations fuse_dentry_operations = { const struct dentry_operations fuse_dentry_operations = {
......
...@@ -645,7 +645,7 @@ static ssize_t fuse_get_res_by_io(struct fuse_io_priv *io) ...@@ -645,7 +645,7 @@ static ssize_t fuse_get_res_by_io(struct fuse_io_priv *io)
* == bytes_transferred or rw == WRITE, the caller sets 'pos' to -1. * == bytes_transferred or rw == WRITE, the caller sets 'pos' to -1.
* *
* An example: * An example:
* User requested DIO read of 64K. It was splitted into two 32K fuse requests, * User requested DIO read of 64K. It was split into two 32K fuse requests,
* both submitted asynchronously. The first of them was ACKed by userspace as * both submitted asynchronously. The first of them was ACKed by userspace as
* fully completed (req->out.args[0].size == 32K) resulting in pos == -1. The * fully completed (req->out.args[0].size == 32K) resulting in pos == -1. The
* second request was ACKed as short, e.g. only 1K was read, resulting in * second request was ACKed as short, e.g. only 1K was read, resulting in
...@@ -1403,7 +1403,7 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii, ...@@ -1403,7 +1403,7 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
nbytes += ret; nbytes += ret;
ret += start; ret += start;
npages = (ret + PAGE_SIZE - 1) / PAGE_SIZE; npages = DIV_ROUND_UP(ret, PAGE_SIZE);
ap->descs[ap->num_pages].offset = start; ap->descs[ap->num_pages].offset = start;
fuse_page_descs_length_init(ap->descs, ap->num_pages, npages); fuse_page_descs_length_init(ap->descs, ap->num_pages, npages);
...@@ -2905,11 +2905,13 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, ...@@ -2905,11 +2905,13 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
}; };
int err; int err;
bool lock_inode = !(mode & FALLOC_FL_KEEP_SIZE) || bool lock_inode = !(mode & FALLOC_FL_KEEP_SIZE) ||
(mode & FALLOC_FL_PUNCH_HOLE); (mode & (FALLOC_FL_PUNCH_HOLE |
FALLOC_FL_ZERO_RANGE));
bool block_faults = FUSE_IS_DAX(inode) && lock_inode; bool block_faults = FUSE_IS_DAX(inode) && lock_inode;
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
FALLOC_FL_ZERO_RANGE))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (fm->fc->no_fallocate) if (fm->fc->no_fallocate)
...@@ -2924,7 +2926,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, ...@@ -2924,7 +2926,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
goto out; goto out;
} }
if (mode & FALLOC_FL_PUNCH_HOLE) { if (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) {
loff_t endbyte = offset + length - 1; loff_t endbyte = offset + length - 1;
err = fuse_writeback_range(inode, offset, endbyte); err = fuse_writeback_range(inode, offset, endbyte);
...@@ -2964,7 +2966,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, ...@@ -2964,7 +2966,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
file_update_time(file); file_update_time(file);
} }
if (mode & FALLOC_FL_PUNCH_HOLE) if (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE))
truncate_pagecache_range(inode, offset, offset + length - 1); truncate_pagecache_range(inode, offset, offset + length - 1);
fuse_invalidate_attr(inode); fuse_invalidate_attr(inode);
......
...@@ -761,6 +761,9 @@ struct fuse_conn { ...@@ -761,6 +761,9 @@ struct fuse_conn {
/* Auto-mount submounts announced by the server */ /* Auto-mount submounts announced by the server */
unsigned int auto_submounts:1; unsigned int auto_submounts:1;
/* Propagate syncfs() to server */
unsigned int sync_fs:1;
/** The number of requests waiting for completion */ /** The number of requests waiting for completion */
atomic_t num_waiting; atomic_t num_waiting;
...@@ -867,6 +870,13 @@ static inline u64 fuse_get_attr_version(struct fuse_conn *fc) ...@@ -867,6 +870,13 @@ static inline u64 fuse_get_attr_version(struct fuse_conn *fc)
return atomic64_read(&fc->attr_version); return atomic64_read(&fc->attr_version);
} }
static inline bool fuse_stale_inode(const struct inode *inode, int generation,
struct fuse_attr *attr)
{
return inode->i_generation != generation ||
inode_wrong_type(inode, attr->mode);
}
static inline void fuse_make_bad(struct inode *inode) static inline void fuse_make_bad(struct inode *inode)
{ {
remove_inode_hash(inode); remove_inode_hash(inode);
...@@ -1081,15 +1091,6 @@ void fuse_send_init(struct fuse_mount *fm); ...@@ -1081,15 +1091,6 @@ void fuse_send_init(struct fuse_mount *fm);
*/ */
int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx); int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx);
/*
* Fill in superblock for submounts
* @sb: partially-initialized superblock to fill in
* @parent_fi: The fuse_inode of the parent filesystem where this submount is
* mounted
*/
int fuse_fill_super_submount(struct super_block *sb,
struct fuse_inode *parent_fi);
/* /*
* Remove the mount from the connection * Remove the mount from the connection
* *
...@@ -1097,6 +1098,11 @@ int fuse_fill_super_submount(struct super_block *sb, ...@@ -1097,6 +1098,11 @@ int fuse_fill_super_submount(struct super_block *sb,
*/ */
bool fuse_mount_remove(struct fuse_mount *fm); bool fuse_mount_remove(struct fuse_mount *fm);
/*
* Setup context ops for submounts
*/
int fuse_init_fs_context_submount(struct fs_context *fsc);
/* /*
* Shut down the connection (possibly sending DESTROY request). * Shut down the connection (possibly sending DESTROY request).
*/ */
......
...@@ -350,8 +350,8 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid, ...@@ -350,8 +350,8 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
inode->i_generation = generation; inode->i_generation = generation;
fuse_init_inode(inode, attr); fuse_init_inode(inode, attr);
unlock_new_inode(inode); unlock_new_inode(inode);
} else if (inode_wrong_type(inode, attr->mode)) { } else if (fuse_stale_inode(inode, generation, attr)) {
/* Inode has changed type, any I/O on the old should fail */ /* nodeid was reused, any I/O on the old inode should fail */
fuse_make_bad(inode); fuse_make_bad(inode);
iput(inode); iput(inode);
goto retry; goto retry;
...@@ -506,6 +506,45 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -506,6 +506,45 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
return err; return err;
} }
static int fuse_sync_fs(struct super_block *sb, int wait)
{
struct fuse_mount *fm = get_fuse_mount_super(sb);
struct fuse_conn *fc = fm->fc;
struct fuse_syncfs_in inarg;
FUSE_ARGS(args);
int err;
/*
* Userspace cannot handle the wait == 0 case. Avoid a
* gratuitous roundtrip.
*/
if (!wait)
return 0;
/* The filesystem is being unmounted. Nothing to do. */
if (!sb->s_root)
return 0;
if (!fc->sync_fs)
return 0;
memset(&inarg, 0, sizeof(inarg));
args.in_numargs = 1;
args.in_args[0].size = sizeof(inarg);
args.in_args[0].value = &inarg;
args.opcode = FUSE_SYNCFS;
args.nodeid = get_node_id(sb->s_root->d_inode);
args.out_numargs = 0;
err = fuse_simple_request(fm, &args);
if (err == -ENOSYS) {
fc->sync_fs = 0;
err = 0;
}
return err;
}
enum { enum {
OPT_SOURCE, OPT_SOURCE,
OPT_SUBTYPE, OPT_SUBTYPE,
...@@ -909,6 +948,7 @@ static const struct super_operations fuse_super_operations = { ...@@ -909,6 +948,7 @@ static const struct super_operations fuse_super_operations = {
.put_super = fuse_put_super, .put_super = fuse_put_super,
.umount_begin = fuse_umount_begin, .umount_begin = fuse_umount_begin,
.statfs = fuse_statfs, .statfs = fuse_statfs,
.sync_fs = fuse_sync_fs,
.show_options = fuse_show_options, .show_options = fuse_show_options,
}; };
...@@ -1275,7 +1315,7 @@ static void fuse_sb_defaults(struct super_block *sb) ...@@ -1275,7 +1315,7 @@ static void fuse_sb_defaults(struct super_block *sb)
sb->s_xattr = fuse_no_acl_xattr_handlers; sb->s_xattr = fuse_no_acl_xattr_handlers;
} }
int fuse_fill_super_submount(struct super_block *sb, static int fuse_fill_super_submount(struct super_block *sb,
struct fuse_inode *parent_fi) struct fuse_inode *parent_fi)
{ {
struct fuse_mount *fm = get_fuse_mount_super(sb); struct fuse_mount *fm = get_fuse_mount_super(sb);
...@@ -1313,6 +1353,58 @@ int fuse_fill_super_submount(struct super_block *sb, ...@@ -1313,6 +1353,58 @@ int fuse_fill_super_submount(struct super_block *sb,
return 0; return 0;
} }
/* Filesystem context private data holds the FUSE inode of the mount point */
static int fuse_get_tree_submount(struct fs_context *fsc)
{
struct fuse_mount *fm;
struct fuse_inode *mp_fi = fsc->fs_private;
struct fuse_conn *fc = get_fuse_conn(&mp_fi->inode);
struct super_block *sb;
int err;
fm = kzalloc(sizeof(struct fuse_mount), GFP_KERNEL);
if (!fm)
return -ENOMEM;
fsc->s_fs_info = fm;
sb = sget_fc(fsc, NULL, set_anon_super_fc);
if (IS_ERR(sb)) {
kfree(fm);
return PTR_ERR(sb);
}
fm->fc = fuse_conn_get(fc);
/* Initialize superblock, making @mp_fi its root */
err = fuse_fill_super_submount(sb, mp_fi);
if (err) {
fuse_conn_put(fc);
kfree(fm);
sb->s_fs_info = NULL;
deactivate_locked_super(sb);
return err;
}
down_write(&fc->killsb);
list_add_tail(&fm->fc_entry, &fc->mounts);
up_write(&fc->killsb);
sb->s_flags |= SB_ACTIVE;
fsc->root = dget(sb->s_root);
return 0;
}
static const struct fs_context_operations fuse_context_submount_ops = {
.get_tree = fuse_get_tree_submount,
};
int fuse_init_fs_context_submount(struct fs_context *fsc)
{
fsc->ops = &fuse_context_submount_ops;
return 0;
}
EXPORT_SYMBOL_GPL(fuse_init_fs_context_submount);
int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
{ {
struct fuse_dev *fud = NULL; struct fuse_dev *fud = NULL;
......
...@@ -200,9 +200,12 @@ static int fuse_direntplus_link(struct file *file, ...@@ -200,9 +200,12 @@ static int fuse_direntplus_link(struct file *file,
if (!d_in_lookup(dentry)) { if (!d_in_lookup(dentry)) {
struct fuse_inode *fi; struct fuse_inode *fi;
inode = d_inode(dentry); inode = d_inode(dentry);
if (inode && get_node_id(inode) != o->nodeid)
inode = NULL;
if (!inode || if (!inode ||
get_node_id(inode) != o->nodeid || fuse_stale_inode(inode, o->generation, &o->attr)) {
inode_wrong_type(inode, o->attr.mode)) { if (inode)
fuse_make_bad(inode);
d_invalidate(dentry); d_invalidate(dentry);
dput(dentry); dput(dentry);
goto retry; goto retry;
......
...@@ -1447,6 +1447,7 @@ static int virtio_fs_get_tree(struct fs_context *fsc) ...@@ -1447,6 +1447,7 @@ static int virtio_fs_get_tree(struct fs_context *fsc)
fc->release = fuse_free_conn; fc->release = fuse_free_conn;
fc->delete_stale = true; fc->delete_stale = true;
fc->auto_submounts = true; fc->auto_submounts = true;
fc->sync_fs = true;
/* Tell FUSE to split requests that exceed the virtqueue's size */ /* Tell FUSE to split requests that exceed the virtqueue's size */
fc->max_pages_limit = min_t(unsigned int, fc->max_pages_limit, fc->max_pages_limit = min_t(unsigned int, fc->max_pages_limit,
...@@ -1496,6 +1497,9 @@ static int virtio_fs_init_fs_context(struct fs_context *fsc) ...@@ -1496,6 +1497,9 @@ static int virtio_fs_init_fs_context(struct fs_context *fsc)
{ {
struct fuse_fs_context *ctx; struct fuse_fs_context *ctx;
if (fsc->purpose == FS_CONTEXT_FOR_SUBMOUNT)
return fuse_init_fs_context_submount(fsc);
ctx = kzalloc(sizeof(struct fuse_fs_context), GFP_KERNEL); ctx = kzalloc(sizeof(struct fuse_fs_context), GFP_KERNEL);
if (!ctx) if (!ctx)
return -ENOMEM; return -ENOMEM;
......
...@@ -181,6 +181,9 @@ ...@@ -181,6 +181,9 @@
* - add FUSE_OPEN_KILL_SUIDGID * - add FUSE_OPEN_KILL_SUIDGID
* - extend fuse_setxattr_in, add FUSE_SETXATTR_EXT * - extend fuse_setxattr_in, add FUSE_SETXATTR_EXT
* - add FUSE_SETXATTR_ACL_KILL_SGID * - add FUSE_SETXATTR_ACL_KILL_SGID
*
* 7.34
* - add FUSE_SYNCFS
*/ */
#ifndef _LINUX_FUSE_H #ifndef _LINUX_FUSE_H
...@@ -216,7 +219,7 @@ ...@@ -216,7 +219,7 @@
#define FUSE_KERNEL_VERSION 7 #define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */ /** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 33 #define FUSE_KERNEL_MINOR_VERSION 34
/** The node ID of the root inode */ /** The node ID of the root inode */
#define FUSE_ROOT_ID 1 #define FUSE_ROOT_ID 1
...@@ -509,6 +512,7 @@ enum fuse_opcode { ...@@ -509,6 +512,7 @@ enum fuse_opcode {
FUSE_COPY_FILE_RANGE = 47, FUSE_COPY_FILE_RANGE = 47,
FUSE_SETUPMAPPING = 48, FUSE_SETUPMAPPING = 48,
FUSE_REMOVEMAPPING = 49, FUSE_REMOVEMAPPING = 49,
FUSE_SYNCFS = 50,
/* CUSE specific operations */ /* CUSE specific operations */
CUSE_INIT = 4096, CUSE_INIT = 4096,
...@@ -971,4 +975,8 @@ struct fuse_removemapping_one { ...@@ -971,4 +975,8 @@ struct fuse_removemapping_one {
#define FUSE_REMOVEMAPPING_MAX_ENTRY \ #define FUSE_REMOVEMAPPING_MAX_ENTRY \
(PAGE_SIZE / sizeof(struct fuse_removemapping_one)) (PAGE_SIZE / sizeof(struct fuse_removemapping_one))
struct fuse_syncfs_in {
uint64_t padding;
};
#endif /* _LINUX_FUSE_H */ #endif /* _LINUX_FUSE_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment