Commit fcee216b authored by Max Reitz's avatar Max Reitz Committed by Miklos Szeredi

fuse: split fuse_mount off of fuse_conn

We want to allow submounts for the same fuse_conn, but with different
superblocks so that each of the submounts has its own device ID.  To do
so, we need to split all mount-specific information off of fuse_conn
into a new fuse_mount structure, so that multiple mounts can share a
single fuse_conn.

We need to take care only to perform connection-level actions once (i.e.
when the fuse_conn and thus the first fuse_mount are established, or
when the last fuse_mount and thus the fuse_conn are destroyed).  For
example, fuse_sb_destroy() must invoke fuse_send_destroy() until the
last superblock is released.

To do so, we keep track of which fuse_mount is the root mount and
perform all fuse_conn-level actions only when this fuse_mount is
involved.
Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
Reviewed-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 8f622e94
...@@ -164,6 +164,7 @@ static ssize_t fuse_conn_congestion_threshold_write(struct file *file, ...@@ -164,6 +164,7 @@ static ssize_t fuse_conn_congestion_threshold_write(struct file *file,
{ {
unsigned val; unsigned val;
struct fuse_conn *fc; struct fuse_conn *fc;
struct fuse_mount *fm;
ssize_t ret; ssize_t ret;
ret = fuse_conn_limit_write(file, buf, count, ppos, &val, ret = fuse_conn_limit_write(file, buf, count, ppos, &val,
...@@ -174,18 +175,27 @@ static ssize_t fuse_conn_congestion_threshold_write(struct file *file, ...@@ -174,18 +175,27 @@ static ssize_t fuse_conn_congestion_threshold_write(struct file *file,
if (!fc) if (!fc)
goto out; goto out;
down_read(&fc->killsb);
spin_lock(&fc->bg_lock); spin_lock(&fc->bg_lock);
fc->congestion_threshold = val; fc->congestion_threshold = val;
if (fc->sb) {
/*
* Get any fuse_mount belonging to this fuse_conn; s_bdi is
* shared between all of them
*/
if (!list_empty(&fc->mounts)) {
fm = list_first_entry(&fc->mounts, struct fuse_mount, fc_entry);
if (fc->num_background < fc->congestion_threshold) { if (fc->num_background < fc->congestion_threshold) {
clear_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC); clear_bdi_congested(fm->sb->s_bdi, BLK_RW_SYNC);
clear_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC); clear_bdi_congested(fm->sb->s_bdi, BLK_RW_ASYNC);
} else { } else {
set_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC); set_bdi_congested(fm->sb->s_bdi, BLK_RW_SYNC);
set_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC); set_bdi_congested(fm->sb->s_bdi, BLK_RW_ASYNC);
} }
} }
spin_unlock(&fc->bg_lock); spin_unlock(&fc->bg_lock);
up_read(&fc->killsb);
fuse_conn_put(fc); fuse_conn_put(fc);
out: out:
return ret; return ret;
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
struct cuse_conn { struct cuse_conn {
struct list_head list; /* linked on cuse_conntbl */ struct list_head list; /* linked on cuse_conntbl */
struct fuse_mount fm; /* Dummy mount referencing fc */
struct fuse_conn fc; /* fuse connection */ struct fuse_conn fc; /* fuse connection */
struct cdev *cdev; /* associated character device */ struct cdev *cdev; /* associated character device */
struct device *dev; /* device representing @cdev */ struct device *dev; /* device representing @cdev */
...@@ -134,7 +135,7 @@ static int cuse_open(struct inode *inode, struct file *file) ...@@ -134,7 +135,7 @@ static int cuse_open(struct inode *inode, struct file *file)
* Generic permission check is already done against the chrdev * Generic permission check is already done against the chrdev
* file, proceed to open. * file, proceed to open.
*/ */
rc = fuse_do_open(&cc->fc, 0, file, 0); rc = fuse_do_open(&cc->fm, 0, file, 0);
if (rc) if (rc)
fuse_conn_put(&cc->fc); fuse_conn_put(&cc->fc);
return rc; return rc;
...@@ -143,10 +144,10 @@ static int cuse_open(struct inode *inode, struct file *file) ...@@ -143,10 +144,10 @@ static int cuse_open(struct inode *inode, struct file *file)
static int cuse_release(struct inode *inode, struct file *file) static int cuse_release(struct inode *inode, struct file *file)
{ {
struct fuse_file *ff = file->private_data; struct fuse_file *ff = file->private_data;
struct fuse_conn *fc = ff->fc; struct fuse_mount *fm = ff->fm;
fuse_sync_release(NULL, ff, file->f_flags); fuse_sync_release(NULL, ff, file->f_flags);
fuse_conn_put(fc); fuse_conn_put(fm->fc);
return 0; return 0;
} }
...@@ -155,7 +156,7 @@ static long cuse_file_ioctl(struct file *file, unsigned int cmd, ...@@ -155,7 +156,7 @@ static long cuse_file_ioctl(struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
struct fuse_file *ff = file->private_data; struct fuse_file *ff = file->private_data;
struct cuse_conn *cc = fc_to_cc(ff->fc); struct cuse_conn *cc = fc_to_cc(ff->fm->fc);
unsigned int flags = 0; unsigned int flags = 0;
if (cc->unrestricted_ioctl) if (cc->unrestricted_ioctl)
...@@ -168,7 +169,7 @@ static long cuse_file_compat_ioctl(struct file *file, unsigned int cmd, ...@@ -168,7 +169,7 @@ static long cuse_file_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
struct fuse_file *ff = file->private_data; struct fuse_file *ff = file->private_data;
struct cuse_conn *cc = fc_to_cc(ff->fc); struct cuse_conn *cc = fc_to_cc(ff->fm->fc);
unsigned int flags = FUSE_IOCTL_COMPAT; unsigned int flags = FUSE_IOCTL_COMPAT;
if (cc->unrestricted_ioctl) if (cc->unrestricted_ioctl)
...@@ -313,9 +314,10 @@ struct cuse_init_args { ...@@ -313,9 +314,10 @@ struct cuse_init_args {
* required data structures for it. Please read the comment at the * required data structures for it. Please read the comment at the
* top of this file for high level overview. * top of this file for high level overview.
*/ */
static void cuse_process_init_reply(struct fuse_conn *fc, static void cuse_process_init_reply(struct fuse_mount *fm,
struct fuse_args *args, int error) struct fuse_args *args, int error)
{ {
struct fuse_conn *fc = fm->fc;
struct cuse_init_args *ia = container_of(args, typeof(*ia), ap.args); struct cuse_init_args *ia = container_of(args, typeof(*ia), ap.args);
struct fuse_args_pages *ap = &ia->ap; struct fuse_args_pages *ap = &ia->ap;
struct cuse_conn *cc = fc_to_cc(fc), *pos; struct cuse_conn *cc = fc_to_cc(fc), *pos;
...@@ -424,7 +426,7 @@ static int cuse_send_init(struct cuse_conn *cc) ...@@ -424,7 +426,7 @@ static int cuse_send_init(struct cuse_conn *cc)
{ {
int rc; int rc;
struct page *page; struct page *page;
struct fuse_conn *fc = &cc->fc; struct fuse_mount *fm = &cc->fm;
struct cuse_init_args *ia; struct cuse_init_args *ia;
struct fuse_args_pages *ap; struct fuse_args_pages *ap;
...@@ -460,7 +462,7 @@ static int cuse_send_init(struct cuse_conn *cc) ...@@ -460,7 +462,7 @@ static int cuse_send_init(struct cuse_conn *cc)
ia->desc.length = ap->args.out_args[1].size; ia->desc.length = ap->args.out_args[1].size;
ap->args.end = cuse_process_init_reply; ap->args.end = cuse_process_init_reply;
rc = fuse_simple_background(fc, &ap->args, GFP_KERNEL); rc = fuse_simple_background(fm, &ap->args, GFP_KERNEL);
if (rc) { if (rc) {
kfree(ia); kfree(ia);
err_free_page: err_free_page:
...@@ -506,7 +508,8 @@ static int cuse_channel_open(struct inode *inode, struct file *file) ...@@ -506,7 +508,8 @@ static int cuse_channel_open(struct inode *inode, struct file *file)
* Limit the cuse channel to requests that can * Limit the cuse channel to requests that can
* be represented in file->f_cred->user_ns. * be represented in file->f_cred->user_ns.
*/ */
fuse_conn_init(&cc->fc, file->f_cred->user_ns, &fuse_dev_fiq_ops, NULL); fuse_conn_init(&cc->fc, &cc->fm, file->f_cred->user_ns,
&fuse_dev_fiq_ops, NULL);
fud = fuse_dev_alloc_install(&cc->fc); fud = fuse_dev_alloc_install(&cc->fc);
if (!fud) { if (!fud) {
......
...@@ -182,8 +182,8 @@ static int fuse_setup_one_mapping(struct inode *inode, unsigned long start_idx, ...@@ -182,8 +182,8 @@ static int fuse_setup_one_mapping(struct inode *inode, unsigned long start_idx,
struct fuse_dax_mapping *dmap, bool writable, struct fuse_dax_mapping *dmap, bool writable,
bool upgrade) bool upgrade)
{ {
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_mount *fm = get_fuse_mount(inode);
struct fuse_conn_dax *fcd = fc->dax; struct fuse_conn_dax *fcd = fm->fc->dax;
struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_inode *fi = get_fuse_inode(inode);
struct fuse_setupmapping_in inarg; struct fuse_setupmapping_in inarg;
loff_t offset = start_idx << FUSE_DAX_SHIFT; loff_t offset = start_idx << FUSE_DAX_SHIFT;
...@@ -206,7 +206,7 @@ static int fuse_setup_one_mapping(struct inode *inode, unsigned long start_idx, ...@@ -206,7 +206,7 @@ static int fuse_setup_one_mapping(struct inode *inode, unsigned long start_idx,
args.in_numargs = 1; args.in_numargs = 1;
args.in_args[0].size = sizeof(inarg); args.in_args[0].size = sizeof(inarg);
args.in_args[0].value = &inarg; args.in_args[0].value = &inarg;
err = fuse_simple_request(fc, &args); err = fuse_simple_request(fm, &args);
if (err < 0) if (err < 0)
return err; return err;
dmap->writable = writable; dmap->writable = writable;
...@@ -234,7 +234,7 @@ static int fuse_send_removemapping(struct inode *inode, ...@@ -234,7 +234,7 @@ static int fuse_send_removemapping(struct inode *inode,
struct fuse_removemapping_one *remove_one) struct fuse_removemapping_one *remove_one)
{ {
struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_inode *fi = get_fuse_inode(inode);
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_mount *fm = get_fuse_mount(inode);
FUSE_ARGS(args); FUSE_ARGS(args);
args.opcode = FUSE_REMOVEMAPPING; args.opcode = FUSE_REMOVEMAPPING;
...@@ -244,7 +244,7 @@ static int fuse_send_removemapping(struct inode *inode, ...@@ -244,7 +244,7 @@ static int fuse_send_removemapping(struct inode *inode,
args.in_args[0].value = inargp; args.in_args[0].value = inargp;
args.in_args[1].size = inargp->count * sizeof(*remove_one); args.in_args[1].size = inargp->count * sizeof(*remove_one);
args.in_args[1].value = remove_one; args.in_args[1].value = remove_one;
return fuse_simple_request(fc, &args); return fuse_simple_request(fm, &args);
} }
static int dmap_removemapping_list(struct inode *inode, unsigned int num, static int dmap_removemapping_list(struct inode *inode, unsigned int num,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -175,12 +175,13 @@ enum { ...@@ -175,12 +175,13 @@ enum {
}; };
struct fuse_conn; struct fuse_conn;
struct fuse_mount;
struct fuse_release_args; struct fuse_release_args;
/** FUSE specific file data */ /** FUSE specific file data */
struct fuse_file { struct fuse_file {
/** Fuse connection for this file */ /** Fuse connection for this file */
struct fuse_conn *fc; struct fuse_mount *fm;
/* Argument space reserved for release */ /* Argument space reserved for release */
struct fuse_release_args *release_args; struct fuse_release_args *release_args;
...@@ -266,7 +267,7 @@ struct fuse_args { ...@@ -266,7 +267,7 @@ struct fuse_args {
bool may_block:1; bool may_block:1;
struct fuse_in_arg in_args[3]; struct fuse_in_arg in_args[3];
struct fuse_arg out_args[2]; struct fuse_arg out_args[2];
void (*end)(struct fuse_conn *fc, struct fuse_args *args, int error); void (*end)(struct fuse_mount *fm, struct fuse_args *args, int error);
}; };
struct fuse_args_pages { struct fuse_args_pages {
...@@ -375,8 +376,8 @@ struct fuse_req { ...@@ -375,8 +376,8 @@ struct fuse_req {
void *argbuf; void *argbuf;
#endif #endif
/** fuse_conn this request belongs to */ /** fuse_mount this request belongs to */
struct fuse_conn *fc; struct fuse_mount *fm;
}; };
struct fuse_iqueue; struct fuse_iqueue;
...@@ -515,9 +516,9 @@ struct fuse_fs_context { ...@@ -515,9 +516,9 @@ struct fuse_fs_context {
/** /**
* A Fuse connection. * A Fuse connection.
* *
* This structure is created, when the filesystem is mounted, and is * This structure is created, when the root filesystem is mounted, and
* destroyed, when the client device is closed and the filesystem is * is destroyed, when the client device is closed and the last
* unmounted. * fuse_mount is destroyed.
*/ */
struct fuse_conn { struct fuse_conn {
/** Lock protecting accessess to members of this structure */ /** Lock protecting accessess to members of this structure */
...@@ -747,10 +748,10 @@ struct fuse_conn { ...@@ -747,10 +748,10 @@ struct fuse_conn {
/** Negotiated minor version */ /** Negotiated minor version */
unsigned minor; unsigned minor;
/** Entry on the fuse_conn_list */ /** Entry on the fuse_mount_list */
struct list_head entry; struct list_head entry;
/** Device ID from super block */ /** Device ID from the root super block */
dev_t dev; dev_t dev;
/** Dentries in the control filesystem */ /** Dentries in the control filesystem */
...@@ -768,10 +769,10 @@ struct fuse_conn { ...@@ -768,10 +769,10 @@ struct fuse_conn {
/** Called on final put */ /** Called on final put */
void (*release)(struct fuse_conn *); void (*release)(struct fuse_conn *);
/** Super block for this connection. */ /**
struct super_block *sb; * Read/write semaphore to hold when accessing the sb of any
* fuse_mount belonging to this connection
/** Read/write semaphore to hold when accessing sb. */ */
struct rw_semaphore killsb; struct rw_semaphore killsb;
/** List of device instances belonging to this connection */ /** List of device instances belonging to this connection */
...@@ -781,16 +782,57 @@ struct fuse_conn { ...@@ -781,16 +782,57 @@ struct fuse_conn {
/* Dax specific conn data, non-NULL if DAX is enabled */ /* Dax specific conn data, non-NULL if DAX is enabled */
struct fuse_conn_dax *dax; struct fuse_conn_dax *dax;
#endif #endif
/** List of filesystems using this connection */
struct list_head mounts;
}; };
static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) /*
* Represents a mounted filesystem, potentially a submount.
*
* This object allows sharing a fuse_conn between separate mounts to
* allow submounts with dedicated superblocks and thus separate device
* IDs.
*/
struct fuse_mount {
/* Underlying (potentially shared) connection to the FUSE server */
struct fuse_conn *fc;
/* Refcount */
refcount_t count;
/*
* Super block for this connection (fc->killsb must be held when
* accessing this).
*/
struct super_block *sb;
/* Entry on fc->mounts */
struct list_head fc_entry;
};
static inline struct fuse_mount *get_fuse_mount_super(struct super_block *sb)
{ {
return sb->s_fs_info; return sb->s_fs_info;
} }
static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
{
struct fuse_mount *fm = get_fuse_mount_super(sb);
return fm ? fm->fc : NULL;
}
static inline struct fuse_mount *get_fuse_mount(struct inode *inode)
{
return get_fuse_mount_super(inode->i_sb);
}
static inline struct fuse_conn *get_fuse_conn(struct inode *inode) static inline struct fuse_conn *get_fuse_conn(struct inode *inode)
{ {
return get_fuse_conn_super(inode->i_sb); struct fuse_mount *fm = get_fuse_mount(inode);
return fm ? fm->fc : NULL;
} }
static inline struct fuse_inode *get_fuse_inode(struct inode *inode) static inline struct fuse_inode *get_fuse_inode(struct inode *inode)
...@@ -819,11 +861,6 @@ extern const struct file_operations fuse_dev_operations; ...@@ -819,11 +861,6 @@ extern const struct file_operations fuse_dev_operations;
extern const struct dentry_operations fuse_dentry_operations; extern const struct dentry_operations fuse_dentry_operations;
extern const struct dentry_operations fuse_root_dentry_operations; extern const struct dentry_operations fuse_root_dentry_operations;
/**
* Inode to nodeid comparison.
*/
int fuse_inode_eq(struct inode *inode, void *_nodeidp);
/** /**
* Get a filled in inode * Get a filled in inode
*/ */
...@@ -874,7 +911,7 @@ void fuse_read_args_fill(struct fuse_io_args *ia, struct file *file, loff_t pos, ...@@ -874,7 +911,7 @@ void fuse_read_args_fill(struct fuse_io_args *ia, struct file *file, loff_t pos,
*/ */
int fuse_open_common(struct inode *inode, struct file *file, bool isdir); int fuse_open_common(struct inode *inode, struct file *file, bool isdir);
struct fuse_file *fuse_file_alloc(struct fuse_conn *fc); struct fuse_file *fuse_file_alloc(struct fuse_mount *fm);
void fuse_file_free(struct fuse_file *ff); void fuse_file_free(struct fuse_file *ff);
void fuse_finish_open(struct inode *inode, struct file *file); void fuse_finish_open(struct inode *inode, struct file *file);
...@@ -942,8 +979,8 @@ void __exit fuse_ctl_cleanup(void); ...@@ -942,8 +979,8 @@ void __exit fuse_ctl_cleanup(void);
/** /**
* Simple request sending that does request allocation and freeing * Simple request sending that does request allocation and freeing
*/ */
ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args); ssize_t fuse_simple_request(struct fuse_mount *fm, struct fuse_args *args);
int fuse_simple_background(struct fuse_conn *fc, struct fuse_args *args, int fuse_simple_background(struct fuse_mount *fm, struct fuse_args *args,
gfp_t gfp_flags); gfp_t gfp_flags);
/** /**
...@@ -975,7 +1012,8 @@ struct fuse_conn *fuse_conn_get(struct fuse_conn *fc); ...@@ -975,7 +1012,8 @@ struct fuse_conn *fuse_conn_get(struct fuse_conn *fc);
/** /**
* Initialize fuse_conn * Initialize fuse_conn
*/ */
void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns, void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm,
struct user_namespace *user_ns,
const struct fuse_iqueue_ops *fiq_ops, void *fiq_priv); const struct fuse_iqueue_ops *fiq_ops, void *fiq_priv);
/** /**
...@@ -983,11 +1021,21 @@ void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns, ...@@ -983,11 +1021,21 @@ void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns,
*/ */
void fuse_conn_put(struct fuse_conn *fc); void fuse_conn_put(struct fuse_conn *fc);
/**
* Acquire reference to fuse_mount
*/
struct fuse_mount *fuse_mount_get(struct fuse_mount *fm);
/**
* Release reference to fuse_mount
*/
void fuse_mount_put(struct fuse_mount *fm);
struct fuse_dev *fuse_dev_alloc_install(struct fuse_conn *fc); struct fuse_dev *fuse_dev_alloc_install(struct fuse_conn *fc);
struct fuse_dev *fuse_dev_alloc(void); struct fuse_dev *fuse_dev_alloc(void);
void fuse_dev_install(struct fuse_dev *fud, struct fuse_conn *fc); void fuse_dev_install(struct fuse_dev *fud, struct fuse_conn *fc);
void fuse_dev_free(struct fuse_dev *fud); void fuse_dev_free(struct fuse_dev *fud);
void fuse_send_init(struct fuse_conn *fc); void fuse_send_init(struct fuse_mount *fm);
/** /**
* Fill in superblock and initialize fuse connection * Fill in superblock and initialize fuse connection
...@@ -996,12 +1044,18 @@ void fuse_send_init(struct fuse_conn *fc); ...@@ -996,12 +1044,18 @@ void fuse_send_init(struct fuse_conn *fc);
*/ */
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);
/**
* Disassociate fuse connection from superblock and kill the superblock /*
* Remove the mount from the connection
* *
* Calls kill_anon_super(), do not use with bdev mounts. * Returns whether this was the last mount
*/
bool fuse_mount_remove(struct fuse_mount *fm);
/*
* Shut down the connection (possibly sending DESTROY request).
*/ */
void fuse_kill_sb_anon(struct super_block *sb); void fuse_conn_destroy(struct fuse_mount *fm);
/** /**
* Add connection to control filesystem * Add connection to control filesystem
...@@ -1036,10 +1090,20 @@ void fuse_flush_writepages(struct inode *inode); ...@@ -1036,10 +1090,20 @@ void fuse_flush_writepages(struct inode *inode);
void fuse_set_nowrite(struct inode *inode); void fuse_set_nowrite(struct inode *inode);
void fuse_release_nowrite(struct inode *inode); void fuse_release_nowrite(struct inode *inode);
/**
* Scan all fuse_mounts belonging to fc to find the first where
* ilookup5() returns a result. Return that result and the
* respective fuse_mount in *fm (unless fm is NULL).
*
* The caller must hold fc->killsb.
*/
struct inode *fuse_ilookup(struct fuse_conn *fc, u64 nodeid,
struct fuse_mount **fm);
/** /**
* File-system tells the kernel to invalidate cache for the given node id. * File-system tells the kernel to invalidate cache for the given node id.
*/ */
int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid, int fuse_reverse_inval_inode(struct fuse_conn *fc, u64 nodeid,
loff_t offset, loff_t len); loff_t offset, loff_t len);
/** /**
...@@ -1052,10 +1116,10 @@ int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid, ...@@ -1052,10 +1116,10 @@ int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid,
* - is a file or oan empty directory * - is a file or oan empty directory
* then the dentry is unhashed (d_delete()). * then the dentry is unhashed (d_delete()).
*/ */
int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
u64 child_nodeid, struct qstr *name); u64 child_nodeid, struct qstr *name);
int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file,
bool isdir); bool isdir);
/** /**
......
This diff is collapsed.
...@@ -252,7 +252,7 @@ static int fuse_direntplus_link(struct file *file, ...@@ -252,7 +252,7 @@ static int fuse_direntplus_link(struct file *file,
static void fuse_force_forget(struct file *file, u64 nodeid) static void fuse_force_forget(struct file *file, u64 nodeid)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_mount *fm = get_fuse_mount(inode);
struct fuse_forget_in inarg; struct fuse_forget_in inarg;
FUSE_ARGS(args); FUSE_ARGS(args);
...@@ -266,7 +266,7 @@ static void fuse_force_forget(struct file *file, u64 nodeid) ...@@ -266,7 +266,7 @@ static void fuse_force_forget(struct file *file, u64 nodeid)
args.force = true; args.force = true;
args.noreply = true; args.noreply = true;
fuse_simple_request(fc, &args); fuse_simple_request(fm, &args);
/* ignore errors */ /* ignore errors */
} }
...@@ -320,7 +320,7 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx) ...@@ -320,7 +320,7 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx)
ssize_t res; ssize_t res;
struct page *page; struct page *page;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_mount *fm = get_fuse_mount(inode);
struct fuse_io_args ia = {}; struct fuse_io_args ia = {};
struct fuse_args_pages *ap = &ia.ap; struct fuse_args_pages *ap = &ia.ap;
struct fuse_page_desc desc = { .length = PAGE_SIZE }; struct fuse_page_desc desc = { .length = PAGE_SIZE };
...@@ -337,7 +337,7 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx) ...@@ -337,7 +337,7 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx)
ap->pages = &page; ap->pages = &page;
ap->descs = &desc; ap->descs = &desc;
if (plus) { if (plus) {
attr_version = fuse_get_attr_version(fc); attr_version = fuse_get_attr_version(fm->fc);
fuse_read_args_fill(&ia, file, ctx->pos, PAGE_SIZE, fuse_read_args_fill(&ia, file, ctx->pos, PAGE_SIZE,
FUSE_READDIRPLUS); FUSE_READDIRPLUS);
} else { } else {
...@@ -345,7 +345,7 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx) ...@@ -345,7 +345,7 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx)
FUSE_READDIR); FUSE_READDIR);
} }
locked = fuse_lock_inode(inode); locked = fuse_lock_inode(inode);
res = fuse_simple_request(fc, &ap->args); res = fuse_simple_request(fm, &ap->args);
fuse_unlock_inode(inode, locked); fuse_unlock_inode(inode, locked);
if (res >= 0) { if (res >= 0) {
if (!res) { if (!res) {
......
...@@ -1270,7 +1270,8 @@ static inline void virtio_fs_ctx_set_defaults(struct fuse_fs_context *ctx) ...@@ -1270,7 +1270,8 @@ static inline void virtio_fs_ctx_set_defaults(struct fuse_fs_context *ctx)
static int virtio_fs_fill_super(struct super_block *sb, struct fs_context *fsc) static int virtio_fs_fill_super(struct super_block *sb, struct fs_context *fsc)
{ {
struct fuse_conn *fc = get_fuse_conn_super(sb); struct fuse_mount *fm = get_fuse_mount_super(sb);
struct fuse_conn *fc = fm->fc;
struct virtio_fs *fs = fc->iq.priv; struct virtio_fs *fs = fc->iq.priv;
struct fuse_fs_context *ctx = fsc->fs_private; struct fuse_fs_context *ctx = fsc->fs_private;
unsigned int i; unsigned int i;
...@@ -1315,7 +1316,7 @@ static int virtio_fs_fill_super(struct super_block *sb, struct fs_context *fsc) ...@@ -1315,7 +1316,7 @@ static int virtio_fs_fill_super(struct super_block *sb, struct fs_context *fsc)
/* Previous unmount will stop all queues. Start these again */ /* Previous unmount will stop all queues. Start these again */
virtio_fs_start_all_queues(fs); virtio_fs_start_all_queues(fs);
fuse_send_init(fc); fuse_send_init(fm);
mutex_unlock(&virtio_fs_mutex); mutex_unlock(&virtio_fs_mutex);
return 0; return 0;
...@@ -1326,21 +1327,14 @@ static int virtio_fs_fill_super(struct super_block *sb, struct fs_context *fsc) ...@@ -1326,21 +1327,14 @@ static int virtio_fs_fill_super(struct super_block *sb, struct fs_context *fsc)
return err; return err;
} }
static void virtio_kill_sb(struct super_block *sb) static void virtio_fs_conn_destroy(struct fuse_mount *fm)
{ {
struct fuse_conn *fc = get_fuse_conn_super(sb); struct fuse_conn *fc = fm->fc;
struct virtio_fs *vfs; struct virtio_fs *vfs = fc->iq.priv;
struct virtio_fs_vq *fsvq; struct virtio_fs_vq *fsvq = &vfs->vqs[VQ_HIPRIO];
/* If mount failed, we can still be called without any fc */
if (!fc)
return fuse_kill_sb_anon(sb);
vfs = fc->iq.priv;
fsvq = &vfs->vqs[VQ_HIPRIO];
/* Stop dax worker. Soon evict_inodes() will be called which will /* Stop dax worker. Soon evict_inodes() will be called which
* free all memory ranges belonging to all inodes. * will free all memory ranges belonging to all inodes.
*/ */
if (IS_ENABLED(CONFIG_FUSE_DAX)) if (IS_ENABLED(CONFIG_FUSE_DAX))
fuse_dax_cancel_work(fc); fuse_dax_cancel_work(fc);
...@@ -1351,9 +1345,9 @@ static void virtio_kill_sb(struct super_block *sb) ...@@ -1351,9 +1345,9 @@ static void virtio_kill_sb(struct super_block *sb)
spin_unlock(&fsvq->lock); spin_unlock(&fsvq->lock);
virtio_fs_drain_all_queues(vfs); virtio_fs_drain_all_queues(vfs);
fuse_kill_sb_anon(sb); fuse_conn_destroy(fm);
/* fuse_kill_sb_anon() must have sent destroy. Stop all queues /* fuse_conn_destroy() must have sent destroy. Stop all queues
* and drain one more time and free fuse devices. Freeing fuse * and drain one more time and free fuse devices. Freeing fuse
* devices will drop their reference on fuse_conn and that in * devices will drop their reference on fuse_conn and that in
* turn will drop its reference on virtio_fs object. * turn will drop its reference on virtio_fs object.
...@@ -1363,12 +1357,27 @@ static void virtio_kill_sb(struct super_block *sb) ...@@ -1363,12 +1357,27 @@ static void virtio_kill_sb(struct super_block *sb)
virtio_fs_free_devs(vfs); virtio_fs_free_devs(vfs);
} }
static void virtio_kill_sb(struct super_block *sb)
{
struct fuse_mount *fm = get_fuse_mount_super(sb);
bool last;
/* If mount failed, we can still be called without any fc */
if (fm) {
last = fuse_mount_remove(fm);
if (last)
virtio_fs_conn_destroy(fm);
}
kill_anon_super(sb);
}
static int virtio_fs_test_super(struct super_block *sb, static int virtio_fs_test_super(struct super_block *sb,
struct fs_context *fsc) struct fs_context *fsc)
{ {
struct fuse_conn *fc = fsc->s_fs_info; struct fuse_mount *fsc_fm = fsc->s_fs_info;
struct fuse_mount *sb_fm = get_fuse_mount_super(sb);
return fc->iq.priv == get_fuse_conn_super(sb)->iq.priv; return fsc_fm->fc->iq.priv == sb_fm->fc->iq.priv;
} }
static int virtio_fs_set_super(struct super_block *sb, static int virtio_fs_set_super(struct super_block *sb,
...@@ -1378,7 +1387,7 @@ static int virtio_fs_set_super(struct super_block *sb, ...@@ -1378,7 +1387,7 @@ static int virtio_fs_set_super(struct super_block *sb,
err = get_anon_bdev(&sb->s_dev); err = get_anon_bdev(&sb->s_dev);
if (!err) if (!err)
fuse_conn_get(fsc->s_fs_info); fuse_mount_get(fsc->s_fs_info);
return err; return err;
} }
...@@ -1388,6 +1397,7 @@ static int virtio_fs_get_tree(struct fs_context *fsc) ...@@ -1388,6 +1397,7 @@ static int virtio_fs_get_tree(struct fs_context *fsc)
struct virtio_fs *fs; struct virtio_fs *fs;
struct super_block *sb; struct super_block *sb;
struct fuse_conn *fc; struct fuse_conn *fc;
struct fuse_mount *fm;
int err; int err;
/* This gets a reference on virtio_fs object. This ptr gets installed /* This gets a reference on virtio_fs object. This ptr gets installed
...@@ -1408,14 +1418,23 @@ static int virtio_fs_get_tree(struct fs_context *fsc) ...@@ -1408,14 +1418,23 @@ static int virtio_fs_get_tree(struct fs_context *fsc)
return -ENOMEM; return -ENOMEM;
} }
fuse_conn_init(fc, get_user_ns(current_user_ns()), &virtio_fs_fiq_ops, fm = kzalloc(sizeof(struct fuse_mount), GFP_KERNEL);
fs); if (!fm) {
mutex_lock(&virtio_fs_mutex);
virtio_fs_put(fs);
mutex_unlock(&virtio_fs_mutex);
kfree(fc);
return -ENOMEM;
}
fuse_conn_init(fc, fm, get_user_ns(current_user_ns()),
&virtio_fs_fiq_ops, fs);
fc->release = fuse_free_conn; fc->release = fuse_free_conn;
fc->delete_stale = true; fc->delete_stale = true;
fsc->s_fs_info = fc; fsc->s_fs_info = fm;
sb = sget_fc(fsc, virtio_fs_test_super, virtio_fs_set_super); sb = sget_fc(fsc, virtio_fs_test_super, virtio_fs_set_super);
fuse_conn_put(fc); fuse_mount_put(fm);
if (IS_ERR(sb)) if (IS_ERR(sb))
return PTR_ERR(sb); return PTR_ERR(sb);
......
...@@ -14,12 +14,12 @@ ...@@ -14,12 +14,12 @@
int fuse_setxattr(struct inode *inode, const char *name, const void *value, int fuse_setxattr(struct inode *inode, const char *name, const void *value,
size_t size, int flags) size_t size, int flags)
{ {
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_mount *fm = get_fuse_mount(inode);
FUSE_ARGS(args); FUSE_ARGS(args);
struct fuse_setxattr_in inarg; struct fuse_setxattr_in inarg;
int err; int err;
if (fc->no_setxattr) if (fm->fc->no_setxattr)
return -EOPNOTSUPP; return -EOPNOTSUPP;
memset(&inarg, 0, sizeof(inarg)); memset(&inarg, 0, sizeof(inarg));
...@@ -34,9 +34,9 @@ int fuse_setxattr(struct inode *inode, const char *name, const void *value, ...@@ -34,9 +34,9 @@ int fuse_setxattr(struct inode *inode, const char *name, const void *value,
args.in_args[1].value = name; args.in_args[1].value = name;
args.in_args[2].size = size; args.in_args[2].size = size;
args.in_args[2].value = value; args.in_args[2].value = value;
err = fuse_simple_request(fc, &args); err = fuse_simple_request(fm, &args);
if (err == -ENOSYS) { if (err == -ENOSYS) {
fc->no_setxattr = 1; fm->fc->no_setxattr = 1;
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
} }
if (!err) { if (!err) {
...@@ -49,13 +49,13 @@ int fuse_setxattr(struct inode *inode, const char *name, const void *value, ...@@ -49,13 +49,13 @@ int fuse_setxattr(struct inode *inode, const char *name, const void *value,
ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value, ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value,
size_t size) size_t size)
{ {
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_mount *fm = get_fuse_mount(inode);
FUSE_ARGS(args); FUSE_ARGS(args);
struct fuse_getxattr_in inarg; struct fuse_getxattr_in inarg;
struct fuse_getxattr_out outarg; struct fuse_getxattr_out outarg;
ssize_t ret; ssize_t ret;
if (fc->no_getxattr) if (fm->fc->no_getxattr)
return -EOPNOTSUPP; return -EOPNOTSUPP;
memset(&inarg, 0, sizeof(inarg)); memset(&inarg, 0, sizeof(inarg));
...@@ -77,11 +77,11 @@ ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value, ...@@ -77,11 +77,11 @@ ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value,
args.out_args[0].size = sizeof(outarg); args.out_args[0].size = sizeof(outarg);
args.out_args[0].value = &outarg; args.out_args[0].value = &outarg;
} }
ret = fuse_simple_request(fc, &args); ret = fuse_simple_request(fm, &args);
if (!ret && !size) if (!ret && !size)
ret = min_t(ssize_t, outarg.size, XATTR_SIZE_MAX); ret = min_t(ssize_t, outarg.size, XATTR_SIZE_MAX);
if (ret == -ENOSYS) { if (ret == -ENOSYS) {
fc->no_getxattr = 1; fm->fc->no_getxattr = 1;
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
} }
return ret; return ret;
...@@ -107,16 +107,16 @@ static int fuse_verify_xattr_list(char *list, size_t size) ...@@ -107,16 +107,16 @@ static int fuse_verify_xattr_list(char *list, size_t size)
ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
{ {
struct inode *inode = d_inode(entry); struct inode *inode = d_inode(entry);
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_mount *fm = get_fuse_mount(inode);
FUSE_ARGS(args); FUSE_ARGS(args);
struct fuse_getxattr_in inarg; struct fuse_getxattr_in inarg;
struct fuse_getxattr_out outarg; struct fuse_getxattr_out outarg;
ssize_t ret; ssize_t ret;
if (!fuse_allow_current_process(fc)) if (!fuse_allow_current_process(fm->fc))
return -EACCES; return -EACCES;
if (fc->no_listxattr) if (fm->fc->no_listxattr)
return -EOPNOTSUPP; return -EOPNOTSUPP;
memset(&inarg, 0, sizeof(inarg)); memset(&inarg, 0, sizeof(inarg));
...@@ -136,13 +136,13 @@ ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) ...@@ -136,13 +136,13 @@ ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
args.out_args[0].size = sizeof(outarg); args.out_args[0].size = sizeof(outarg);
args.out_args[0].value = &outarg; args.out_args[0].value = &outarg;
} }
ret = fuse_simple_request(fc, &args); ret = fuse_simple_request(fm, &args);
if (!ret && !size) if (!ret && !size)
ret = min_t(ssize_t, outarg.size, XATTR_LIST_MAX); ret = min_t(ssize_t, outarg.size, XATTR_LIST_MAX);
if (ret > 0 && size) if (ret > 0 && size)
ret = fuse_verify_xattr_list(list, ret); ret = fuse_verify_xattr_list(list, ret);
if (ret == -ENOSYS) { if (ret == -ENOSYS) {
fc->no_listxattr = 1; fm->fc->no_listxattr = 1;
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
} }
return ret; return ret;
...@@ -150,11 +150,11 @@ ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) ...@@ -150,11 +150,11 @@ ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
int fuse_removexattr(struct inode *inode, const char *name) int fuse_removexattr(struct inode *inode, const char *name)
{ {
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_mount *fm = get_fuse_mount(inode);
FUSE_ARGS(args); FUSE_ARGS(args);
int err; int err;
if (fc->no_removexattr) if (fm->fc->no_removexattr)
return -EOPNOTSUPP; return -EOPNOTSUPP;
args.opcode = FUSE_REMOVEXATTR; args.opcode = FUSE_REMOVEXATTR;
...@@ -162,9 +162,9 @@ int fuse_removexattr(struct inode *inode, const char *name) ...@@ -162,9 +162,9 @@ int fuse_removexattr(struct inode *inode, const char *name)
args.in_numargs = 1; args.in_numargs = 1;
args.in_args[0].size = strlen(name) + 1; args.in_args[0].size = strlen(name) + 1;
args.in_args[0].value = name; args.in_args[0].value = name;
err = fuse_simple_request(fc, &args); err = fuse_simple_request(fm, &args);
if (err == -ENOSYS) { if (err == -ENOSYS) {
fc->no_removexattr = 1; fm->fc->no_removexattr = 1;
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
} }
if (!err) { if (!err) {
......
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