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,
{
unsigned val;
struct fuse_conn *fc;
struct fuse_mount *fm;
ssize_t ret;
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,
if (!fc)
goto out;
down_read(&fc->killsb);
spin_lock(&fc->bg_lock);
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) {
clear_bdi_congested(fc->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_SYNC);
clear_bdi_congested(fm->sb->s_bdi, BLK_RW_ASYNC);
} else {
set_bdi_congested(fc->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_SYNC);
set_bdi_congested(fm->sb->s_bdi, BLK_RW_ASYNC);
}
}
spin_unlock(&fc->bg_lock);
up_read(&fc->killsb);
fuse_conn_put(fc);
out:
return ret;
......
......@@ -57,6 +57,7 @@
struct cuse_conn {
struct list_head list; /* linked on cuse_conntbl */
struct fuse_mount fm; /* Dummy mount referencing fc */
struct fuse_conn fc; /* fuse connection */
struct cdev *cdev; /* associated character device */
struct device *dev; /* device representing @cdev */
......@@ -134,7 +135,7 @@ static int cuse_open(struct inode *inode, struct file *file)
* Generic permission check is already done against the chrdev
* file, proceed to open.
*/
rc = fuse_do_open(&cc->fc, 0, file, 0);
rc = fuse_do_open(&cc->fm, 0, file, 0);
if (rc)
fuse_conn_put(&cc->fc);
return rc;
......@@ -143,10 +144,10 @@ static int cuse_open(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_conn *fc = ff->fc;
struct fuse_mount *fm = ff->fm;
fuse_sync_release(NULL, ff, file->f_flags);
fuse_conn_put(fc);
fuse_conn_put(fm->fc);
return 0;
}
......@@ -155,7 +156,7 @@ static long cuse_file_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
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;
if (cc->unrestricted_ioctl)
......@@ -168,7 +169,7 @@ static long cuse_file_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
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;
if (cc->unrestricted_ioctl)
......@@ -313,9 +314,10 @@ struct cuse_init_args {
* required data structures for it. Please read the comment at the
* 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_conn *fc = fm->fc;
struct cuse_init_args *ia = container_of(args, typeof(*ia), ap.args);
struct fuse_args_pages *ap = &ia->ap;
struct cuse_conn *cc = fc_to_cc(fc), *pos;
......@@ -424,7 +426,7 @@ static int cuse_send_init(struct cuse_conn *cc)
{
int rc;
struct page *page;
struct fuse_conn *fc = &cc->fc;
struct fuse_mount *fm = &cc->fm;
struct cuse_init_args *ia;
struct fuse_args_pages *ap;
......@@ -460,7 +462,7 @@ static int cuse_send_init(struct cuse_conn *cc)
ia->desc.length = ap->args.out_args[1].size;
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) {
kfree(ia);
err_free_page:
......@@ -506,7 +508,8 @@ static int cuse_channel_open(struct inode *inode, struct file *file)
* Limit the cuse channel to requests that can
* 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);
if (!fud) {
......
......@@ -182,8 +182,8 @@ static int fuse_setup_one_mapping(struct inode *inode, unsigned long start_idx,
struct fuse_dax_mapping *dmap, bool writable,
bool upgrade)
{
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_conn_dax *fcd = fc->dax;
struct fuse_mount *fm = get_fuse_mount(inode);
struct fuse_conn_dax *fcd = fm->fc->dax;
struct fuse_inode *fi = get_fuse_inode(inode);
struct fuse_setupmapping_in inarg;
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,
args.in_numargs = 1;
args.in_args[0].size = sizeof(inarg);
args.in_args[0].value = &inarg;
err = fuse_simple_request(fc, &args);
err = fuse_simple_request(fm, &args);
if (err < 0)
return err;
dmap->writable = writable;
......@@ -234,7 +234,7 @@ static int fuse_send_removemapping(struct inode *inode,
struct fuse_removemapping_one *remove_one)
{
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);
args.opcode = FUSE_REMOVEMAPPING;
......@@ -244,7 +244,7 @@ static int fuse_send_removemapping(struct inode *inode,
args.in_args[0].value = inargp;
args.in_args[1].size = inargp->count * sizeof(*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,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -175,12 +175,13 @@ enum {
};
struct fuse_conn;
struct fuse_mount;
struct fuse_release_args;
/** FUSE specific file data */
struct fuse_file {
/** Fuse connection for this file */
struct fuse_conn *fc;
struct fuse_mount *fm;
/* Argument space reserved for release */
struct fuse_release_args *release_args;
......@@ -266,7 +267,7 @@ struct fuse_args {
bool may_block:1;
struct fuse_in_arg in_args[3];
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 {
......@@ -375,8 +376,8 @@ struct fuse_req {
void *argbuf;
#endif
/** fuse_conn this request belongs to */
struct fuse_conn *fc;
/** fuse_mount this request belongs to */
struct fuse_mount *fm;
};
struct fuse_iqueue;
......@@ -515,9 +516,9 @@ struct fuse_fs_context {
/**
* A Fuse connection.
*
* This structure is created, when the filesystem is mounted, and is
* destroyed, when the client device is closed and the filesystem is
* unmounted.
* This structure is created, when the root filesystem is mounted, and
* is destroyed, when the client device is closed and the last
* fuse_mount is destroyed.
*/
struct fuse_conn {
/** Lock protecting accessess to members of this structure */
......@@ -747,10 +748,10 @@ struct fuse_conn {
/** Negotiated minor version */
unsigned minor;
/** Entry on the fuse_conn_list */
/** Entry on the fuse_mount_list */
struct list_head entry;
/** Device ID from super block */
/** Device ID from the root super block */
dev_t dev;
/** Dentries in the control filesystem */
......@@ -768,10 +769,10 @@ struct fuse_conn {
/** Called on final put */
void (*release)(struct fuse_conn *);
/** Super block for this connection. */
struct super_block *sb;
/** Read/write semaphore to hold when accessing sb. */
/**
* Read/write semaphore to hold when accessing the sb of any
* fuse_mount belonging to this connection
*/
struct rw_semaphore killsb;
/** List of device instances belonging to this connection */
......@@ -781,16 +782,57 @@ struct fuse_conn {
/* Dax specific conn data, non-NULL if DAX is enabled */
struct fuse_conn_dax *dax;
#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;
}
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)
{
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)
......@@ -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_root_dentry_operations;
/**
* Inode to nodeid comparison.
*/
int fuse_inode_eq(struct inode *inode, void *_nodeidp);
/**
* 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,
*/
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_finish_open(struct inode *inode, struct file *file);
......@@ -942,8 +979,8 @@ void __exit fuse_ctl_cleanup(void);
/**
* Simple request sending that does request allocation and freeing
*/
ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args);
int fuse_simple_background(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_mount *fm, struct fuse_args *args,
gfp_t gfp_flags);
/**
......@@ -975,7 +1012,8 @@ struct fuse_conn *fuse_conn_get(struct fuse_conn *fc);
/**
* 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);
/**
......@@ -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);
/**
* 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(void);
void fuse_dev_install(struct fuse_dev *fud, struct fuse_conn *fc);
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
......@@ -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);
/**
* 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
......@@ -1036,10 +1090,20 @@ void fuse_flush_writepages(struct inode *inode);
void fuse_set_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.
*/
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);
/**
......@@ -1052,10 +1116,10 @@ int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid,
* - is a file or oan empty directory
* 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);
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);
/**
......
This diff is collapsed.
......@@ -252,7 +252,7 @@ static int fuse_direntplus_link(struct file *file,
static void fuse_force_forget(struct file *file, u64 nodeid)
{
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;
FUSE_ARGS(args);
......@@ -266,7 +266,7 @@ static void fuse_force_forget(struct file *file, u64 nodeid)
args.force = true;
args.noreply = true;
fuse_simple_request(fc, &args);
fuse_simple_request(fm, &args);
/* ignore errors */
}
......@@ -320,7 +320,7 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx)
ssize_t res;
struct page *page;
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_args_pages *ap = &ia.ap;
struct fuse_page_desc desc = { .length = PAGE_SIZE };
......@@ -337,7 +337,7 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx)
ap->pages = &page;
ap->descs = &desc;
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_READDIRPLUS);
} else {
......@@ -345,7 +345,7 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx)
FUSE_READDIR);
}
locked = fuse_lock_inode(inode);
res = fuse_simple_request(fc, &ap->args);
res = fuse_simple_request(fm, &ap->args);
fuse_unlock_inode(inode, locked);
if (res >= 0) {
if (!res) {
......
......@@ -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)
{
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 fuse_fs_context *ctx = fsc->fs_private;
unsigned int i;
......@@ -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 */
virtio_fs_start_all_queues(fs);
fuse_send_init(fc);
fuse_send_init(fm);
mutex_unlock(&virtio_fs_mutex);
return 0;
......@@ -1326,21 +1327,14 @@ static int virtio_fs_fill_super(struct super_block *sb, struct fs_context *fsc)
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 virtio_fs *vfs;
struct virtio_fs_vq *fsvq;
/* 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];
struct fuse_conn *fc = fm->fc;
struct virtio_fs *vfs = fc->iq.priv;
struct virtio_fs_vq *fsvq = &vfs->vqs[VQ_HIPRIO];
/* Stop dax worker. Soon evict_inodes() will be called which will
* free all memory ranges belonging to all inodes.
/* Stop dax worker. Soon evict_inodes() will be called which
* will free all memory ranges belonging to all inodes.
*/
if (IS_ENABLED(CONFIG_FUSE_DAX))
fuse_dax_cancel_work(fc);
......@@ -1351,9 +1345,9 @@ static void virtio_kill_sb(struct super_block *sb)
spin_unlock(&fsvq->lock);
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
* devices will drop their reference on fuse_conn and that in
* turn will drop its reference on virtio_fs object.
......@@ -1363,12 +1357,27 @@ static void virtio_kill_sb(struct super_block *sb)
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,
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,
......@@ -1378,7 +1387,7 @@ static int virtio_fs_set_super(struct super_block *sb,
err = get_anon_bdev(&sb->s_dev);
if (!err)
fuse_conn_get(fsc->s_fs_info);
fuse_mount_get(fsc->s_fs_info);
return err;
}
......@@ -1388,6 +1397,7 @@ static int virtio_fs_get_tree(struct fs_context *fsc)
struct virtio_fs *fs;
struct super_block *sb;
struct fuse_conn *fc;
struct fuse_mount *fm;
int err;
/* 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)
return -ENOMEM;
}
fuse_conn_init(fc, get_user_ns(current_user_ns()), &virtio_fs_fiq_ops,
fs);
fm = kzalloc(sizeof(struct fuse_mount), GFP_KERNEL);
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->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);
fuse_conn_put(fc);
fuse_mount_put(fm);
if (IS_ERR(sb))
return PTR_ERR(sb);
......
......@@ -14,12 +14,12 @@
int fuse_setxattr(struct inode *inode, const char *name, const void *value,
size_t size, int flags)
{
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_mount *fm = get_fuse_mount(inode);
FUSE_ARGS(args);
struct fuse_setxattr_in inarg;
int err;
if (fc->no_setxattr)
if (fm->fc->no_setxattr)
return -EOPNOTSUPP;
memset(&inarg, 0, sizeof(inarg));
......@@ -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[2].size = size;
args.in_args[2].value = value;
err = fuse_simple_request(fc, &args);
err = fuse_simple_request(fm, &args);
if (err == -ENOSYS) {
fc->no_setxattr = 1;
fm->fc->no_setxattr = 1;
err = -EOPNOTSUPP;
}
if (!err) {
......@@ -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,
size_t size)
{
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_mount *fm = get_fuse_mount(inode);
FUSE_ARGS(args);
struct fuse_getxattr_in inarg;
struct fuse_getxattr_out outarg;
ssize_t ret;
if (fc->no_getxattr)
if (fm->fc->no_getxattr)
return -EOPNOTSUPP;
memset(&inarg, 0, sizeof(inarg));
......@@ -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].value = &outarg;
}
ret = fuse_simple_request(fc, &args);
ret = fuse_simple_request(fm, &args);
if (!ret && !size)
ret = min_t(ssize_t, outarg.size, XATTR_SIZE_MAX);
if (ret == -ENOSYS) {
fc->no_getxattr = 1;
fm->fc->no_getxattr = 1;
ret = -EOPNOTSUPP;
}
return ret;
......@@ -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)
{
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);
struct fuse_getxattr_in inarg;
struct fuse_getxattr_out outarg;
ssize_t ret;
if (!fuse_allow_current_process(fc))
if (!fuse_allow_current_process(fm->fc))
return -EACCES;
if (fc->no_listxattr)
if (fm->fc->no_listxattr)
return -EOPNOTSUPP;
memset(&inarg, 0, sizeof(inarg));
......@@ -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].value = &outarg;
}
ret = fuse_simple_request(fc, &args);
ret = fuse_simple_request(fm, &args);
if (!ret && !size)
ret = min_t(ssize_t, outarg.size, XATTR_LIST_MAX);
if (ret > 0 && size)
ret = fuse_verify_xattr_list(list, ret);
if (ret == -ENOSYS) {
fc->no_listxattr = 1;
fm->fc->no_listxattr = 1;
ret = -EOPNOTSUPP;
}
return ret;
......@@ -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)
{
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_mount *fm = get_fuse_mount(inode);
FUSE_ARGS(args);
int err;
if (fc->no_removexattr)
if (fm->fc->no_removexattr)
return -EOPNOTSUPP;
args.opcode = FUSE_REMOVEXATTR;
......@@ -162,9 +162,9 @@ int fuse_removexattr(struct inode *inode, const char *name)
args.in_numargs = 1;
args.in_args[0].size = strlen(name) + 1;
args.in_args[0].value = name;
err = fuse_simple_request(fc, &args);
err = fuse_simple_request(fm, &args);
if (err == -ENOSYS) {
fc->no_removexattr = 1;
fm->fc->no_removexattr = 1;
err = -EOPNOTSUPP;
}
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