fuse: introduce per-instance fuse_dev structure
Allow fuse device clones to refer to be distinguished. This patch just adds the infrastructure by associating a separate "struct fuse_dev" with each clone. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Reviewed-by: Ashish Samant <ashish.samant@oracle.com>
This commit is contained in:
parent
00c570f4ba
commit
cc080e9e9b
|
@ -489,6 +489,7 @@ static void cuse_fc_release(struct fuse_conn *fc)
|
||||||
*/
|
*/
|
||||||
static int cuse_channel_open(struct inode *inode, struct file *file)
|
static int cuse_channel_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
|
struct fuse_dev *fud;
|
||||||
struct cuse_conn *cc;
|
struct cuse_conn *cc;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -499,16 +500,22 @@ static int cuse_channel_open(struct inode *inode, struct file *file)
|
||||||
|
|
||||||
fuse_conn_init(&cc->fc);
|
fuse_conn_init(&cc->fc);
|
||||||
|
|
||||||
|
fud = fuse_dev_alloc(&cc->fc);
|
||||||
|
if (!fud) {
|
||||||
|
kfree(cc);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
INIT_LIST_HEAD(&cc->list);
|
INIT_LIST_HEAD(&cc->list);
|
||||||
cc->fc.release = cuse_fc_release;
|
cc->fc.release = cuse_fc_release;
|
||||||
|
|
||||||
cc->fc.initialized = 1;
|
cc->fc.initialized = 1;
|
||||||
rc = cuse_send_init(cc);
|
rc = cuse_send_init(cc);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
fuse_conn_put(&cc->fc);
|
fuse_dev_free(fud);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
file->private_data = &cc->fc; /* channel owns base reference to cc */
|
file->private_data = fud;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -526,7 +533,8 @@ static int cuse_channel_open(struct inode *inode, struct file *file)
|
||||||
*/
|
*/
|
||||||
static int cuse_channel_release(struct inode *inode, struct file *file)
|
static int cuse_channel_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct cuse_conn *cc = fc_to_cc(file->private_data);
|
struct fuse_dev *fud = file->private_data;
|
||||||
|
struct cuse_conn *cc = fc_to_cc(fud->fc);
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* remove from the conntbl, no more access from this point on */
|
/* remove from the conntbl, no more access from this point on */
|
||||||
|
|
|
@ -25,13 +25,13 @@ MODULE_ALIAS("devname:fuse");
|
||||||
|
|
||||||
static struct kmem_cache *fuse_req_cachep;
|
static struct kmem_cache *fuse_req_cachep;
|
||||||
|
|
||||||
static struct fuse_conn *fuse_get_conn(struct file *file)
|
static struct fuse_dev *fuse_get_dev(struct file *file)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Lockless access is OK, because file->private data is set
|
* Lockless access is OK, because file->private data is set
|
||||||
* once during mount and is valid until the file is released.
|
* once during mount and is valid until the file is released.
|
||||||
*/
|
*/
|
||||||
return file->private_data;
|
return ACCESS_ONCE(file->private_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fuse_request_init(struct fuse_req *req, struct page **pages,
|
static void fuse_request_init(struct fuse_req *req, struct page **pages,
|
||||||
|
@ -1348,8 +1348,9 @@ static ssize_t fuse_dev_read(struct kiocb *iocb, struct iov_iter *to)
|
||||||
{
|
{
|
||||||
struct fuse_copy_state cs;
|
struct fuse_copy_state cs;
|
||||||
struct file *file = iocb->ki_filp;
|
struct file *file = iocb->ki_filp;
|
||||||
struct fuse_conn *fc = fuse_get_conn(file);
|
struct fuse_dev *fud = fuse_get_dev(file);
|
||||||
if (!fc)
|
|
||||||
|
if (!fud)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
if (!iter_is_iovec(to))
|
if (!iter_is_iovec(to))
|
||||||
|
@ -1357,7 +1358,7 @@ static ssize_t fuse_dev_read(struct kiocb *iocb, struct iov_iter *to)
|
||||||
|
|
||||||
fuse_copy_init(&cs, 1, to);
|
fuse_copy_init(&cs, 1, to);
|
||||||
|
|
||||||
return fuse_dev_do_read(fc, file, &cs, iov_iter_count(to));
|
return fuse_dev_do_read(fud->fc, file, &cs, iov_iter_count(to));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
|
static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
|
||||||
|
@ -1369,8 +1370,9 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
|
||||||
int do_wakeup = 0;
|
int do_wakeup = 0;
|
||||||
struct pipe_buffer *bufs;
|
struct pipe_buffer *bufs;
|
||||||
struct fuse_copy_state cs;
|
struct fuse_copy_state cs;
|
||||||
struct fuse_conn *fc = fuse_get_conn(in);
|
struct fuse_dev *fud = fuse_get_dev(in);
|
||||||
if (!fc)
|
|
||||||
|
if (!fud)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL);
|
bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL);
|
||||||
|
@ -1380,7 +1382,7 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
|
||||||
fuse_copy_init(&cs, 1, NULL);
|
fuse_copy_init(&cs, 1, NULL);
|
||||||
cs.pipebufs = bufs;
|
cs.pipebufs = bufs;
|
||||||
cs.pipe = pipe;
|
cs.pipe = pipe;
|
||||||
ret = fuse_dev_do_read(fc, in, &cs, len);
|
ret = fuse_dev_do_read(fud->fc, in, &cs, len);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -1954,8 +1956,9 @@ static ssize_t fuse_dev_do_write(struct fuse_conn *fc,
|
||||||
static ssize_t fuse_dev_write(struct kiocb *iocb, struct iov_iter *from)
|
static ssize_t fuse_dev_write(struct kiocb *iocb, struct iov_iter *from)
|
||||||
{
|
{
|
||||||
struct fuse_copy_state cs;
|
struct fuse_copy_state cs;
|
||||||
struct fuse_conn *fc = fuse_get_conn(iocb->ki_filp);
|
struct fuse_dev *fud = fuse_get_dev(iocb->ki_filp);
|
||||||
if (!fc)
|
|
||||||
|
if (!fud)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
if (!iter_is_iovec(from))
|
if (!iter_is_iovec(from))
|
||||||
|
@ -1963,7 +1966,7 @@ static ssize_t fuse_dev_write(struct kiocb *iocb, struct iov_iter *from)
|
||||||
|
|
||||||
fuse_copy_init(&cs, 0, from);
|
fuse_copy_init(&cs, 0, from);
|
||||||
|
|
||||||
return fuse_dev_do_write(fc, &cs, iov_iter_count(from));
|
return fuse_dev_do_write(fud->fc, &cs, iov_iter_count(from));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
|
static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
|
||||||
|
@ -1974,12 +1977,12 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
|
||||||
unsigned idx;
|
unsigned idx;
|
||||||
struct pipe_buffer *bufs;
|
struct pipe_buffer *bufs;
|
||||||
struct fuse_copy_state cs;
|
struct fuse_copy_state cs;
|
||||||
struct fuse_conn *fc;
|
struct fuse_dev *fud;
|
||||||
size_t rem;
|
size_t rem;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
fc = fuse_get_conn(out);
|
fud = fuse_get_dev(out);
|
||||||
if (!fc)
|
if (!fud)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL);
|
bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL);
|
||||||
|
@ -2034,7 +2037,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
|
||||||
if (flags & SPLICE_F_MOVE)
|
if (flags & SPLICE_F_MOVE)
|
||||||
cs.move_pages = 1;
|
cs.move_pages = 1;
|
||||||
|
|
||||||
ret = fuse_dev_do_write(fc, &cs, len);
|
ret = fuse_dev_do_write(fud->fc, &cs, len);
|
||||||
|
|
||||||
for (idx = 0; idx < nbuf; idx++) {
|
for (idx = 0; idx < nbuf; idx++) {
|
||||||
struct pipe_buffer *buf = &bufs[idx];
|
struct pipe_buffer *buf = &bufs[idx];
|
||||||
|
@ -2049,11 +2052,12 @@ static unsigned fuse_dev_poll(struct file *file, poll_table *wait)
|
||||||
{
|
{
|
||||||
unsigned mask = POLLOUT | POLLWRNORM;
|
unsigned mask = POLLOUT | POLLWRNORM;
|
||||||
struct fuse_iqueue *fiq;
|
struct fuse_iqueue *fiq;
|
||||||
struct fuse_conn *fc = fuse_get_conn(file);
|
struct fuse_dev *fud = fuse_get_dev(file);
|
||||||
if (!fc)
|
|
||||||
|
if (!fud)
|
||||||
return POLLERR;
|
return POLLERR;
|
||||||
|
|
||||||
fiq = &fc->iq;
|
fiq = &fud->fc->iq;
|
||||||
poll_wait(file, &fiq->waitq, wait);
|
poll_wait(file, &fiq->waitq, wait);
|
||||||
|
|
||||||
spin_lock(&fiq->waitq.lock);
|
spin_lock(&fiq->waitq.lock);
|
||||||
|
@ -2175,12 +2179,15 @@ EXPORT_SYMBOL_GPL(fuse_abort_conn);
|
||||||
|
|
||||||
int fuse_dev_release(struct inode *inode, struct file *file)
|
int fuse_dev_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct fuse_conn *fc = fuse_get_conn(file);
|
struct fuse_dev *fud = fuse_get_dev(file);
|
||||||
if (fc) {
|
|
||||||
|
if (fud) {
|
||||||
|
struct fuse_conn *fc = fud->fc;
|
||||||
|
|
||||||
WARN_ON(!list_empty(&fc->pq.io));
|
WARN_ON(!list_empty(&fc->pq.io));
|
||||||
WARN_ON(fc->iq.fasync != NULL);
|
WARN_ON(fc->iq.fasync != NULL);
|
||||||
fuse_abort_conn(fc);
|
fuse_abort_conn(fc);
|
||||||
fuse_conn_put(fc);
|
fuse_dev_free(fud);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2189,20 +2196,27 @@ EXPORT_SYMBOL_GPL(fuse_dev_release);
|
||||||
|
|
||||||
static int fuse_dev_fasync(int fd, struct file *file, int on)
|
static int fuse_dev_fasync(int fd, struct file *file, int on)
|
||||||
{
|
{
|
||||||
struct fuse_conn *fc = fuse_get_conn(file);
|
struct fuse_dev *fud = fuse_get_dev(file);
|
||||||
if (!fc)
|
|
||||||
|
if (!fud)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
/* No locking - fasync_helper does its own locking */
|
/* No locking - fasync_helper does its own locking */
|
||||||
return fasync_helper(fd, file, on, &fc->iq.fasync);
|
return fasync_helper(fd, file, on, &fud->fc->iq.fasync);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fuse_device_clone(struct fuse_conn *fc, struct file *new)
|
static int fuse_device_clone(struct fuse_conn *fc, struct file *new)
|
||||||
{
|
{
|
||||||
|
struct fuse_dev *fud;
|
||||||
|
|
||||||
if (new->private_data)
|
if (new->private_data)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
new->private_data = fuse_conn_get(fc);
|
fud = fuse_dev_alloc(fc);
|
||||||
|
if (!fud)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
new->private_data = fud;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2221,11 +2235,11 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
if (old) {
|
if (old) {
|
||||||
struct fuse_conn *fc = fuse_get_conn(old);
|
struct fuse_dev *fud = fuse_get_dev(old);
|
||||||
|
|
||||||
if (fc) {
|
if (fud) {
|
||||||
mutex_lock(&fuse_mutex);
|
mutex_lock(&fuse_mutex);
|
||||||
err = fuse_device_clone(fc, file);
|
err = fuse_device_clone(fud->fc, file);
|
||||||
mutex_unlock(&fuse_mutex);
|
mutex_unlock(&fuse_mutex);
|
||||||
}
|
}
|
||||||
fput(old);
|
fput(old);
|
||||||
|
|
|
@ -417,6 +417,17 @@ struct fuse_pqueue {
|
||||||
struct list_head io;
|
struct list_head io;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fuse device instance
|
||||||
|
*/
|
||||||
|
struct fuse_dev {
|
||||||
|
/** Fuse connection for this device */
|
||||||
|
struct fuse_conn *fc;
|
||||||
|
|
||||||
|
/** list entry on fc->devices */
|
||||||
|
struct list_head entry;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Fuse connection.
|
* A Fuse connection.
|
||||||
*
|
*
|
||||||
|
@ -629,6 +640,9 @@ struct fuse_conn {
|
||||||
|
|
||||||
/** Read/write semaphore to hold when accessing sb. */
|
/** Read/write semaphore to hold when accessing sb. */
|
||||||
struct rw_semaphore killsb;
|
struct rw_semaphore killsb;
|
||||||
|
|
||||||
|
/** List of device instances belonging to this connection */
|
||||||
|
struct list_head devices;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
|
static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
|
||||||
|
@ -841,6 +855,9 @@ void fuse_conn_init(struct fuse_conn *fc);
|
||||||
*/
|
*/
|
||||||
void fuse_conn_put(struct fuse_conn *fc);
|
void fuse_conn_put(struct fuse_conn *fc);
|
||||||
|
|
||||||
|
struct fuse_dev *fuse_dev_alloc(struct fuse_conn *fc);
|
||||||
|
void fuse_dev_free(struct fuse_dev *fud);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add connection to control filesystem
|
* Add connection to control filesystem
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -598,6 +598,7 @@ void fuse_conn_init(struct fuse_conn *fc)
|
||||||
fuse_pqueue_init(&fc->pq);
|
fuse_pqueue_init(&fc->pq);
|
||||||
INIT_LIST_HEAD(&fc->bg_queue);
|
INIT_LIST_HEAD(&fc->bg_queue);
|
||||||
INIT_LIST_HEAD(&fc->entry);
|
INIT_LIST_HEAD(&fc->entry);
|
||||||
|
INIT_LIST_HEAD(&fc->devices);
|
||||||
atomic_set(&fc->num_waiting, 0);
|
atomic_set(&fc->num_waiting, 0);
|
||||||
fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND;
|
fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND;
|
||||||
fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD;
|
fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD;
|
||||||
|
@ -945,6 +946,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
|
|
||||||
static void fuse_free_conn(struct fuse_conn *fc)
|
static void fuse_free_conn(struct fuse_conn *fc)
|
||||||
{
|
{
|
||||||
|
WARN_ON(!list_empty(&fc->devices));
|
||||||
kfree_rcu(fc, rcu);
|
kfree_rcu(fc, rcu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -990,8 +992,41 @@ static int fuse_bdi_init(struct fuse_conn *fc, struct super_block *sb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct fuse_dev *fuse_dev_alloc(struct fuse_conn *fc)
|
||||||
|
{
|
||||||
|
struct fuse_dev *fud;
|
||||||
|
|
||||||
|
fud = kzalloc(sizeof(struct fuse_dev), GFP_KERNEL);
|
||||||
|
if (fud) {
|
||||||
|
fud->fc = fuse_conn_get(fc);
|
||||||
|
|
||||||
|
spin_lock(&fc->lock);
|
||||||
|
list_add_tail(&fud->entry, &fc->devices);
|
||||||
|
spin_unlock(&fc->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fud;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(fuse_dev_alloc);
|
||||||
|
|
||||||
|
void fuse_dev_free(struct fuse_dev *fud)
|
||||||
|
{
|
||||||
|
struct fuse_conn *fc = fud->fc;
|
||||||
|
|
||||||
|
if (fc) {
|
||||||
|
spin_lock(&fc->lock);
|
||||||
|
list_del(&fud->entry);
|
||||||
|
spin_unlock(&fc->lock);
|
||||||
|
|
||||||
|
fuse_conn_put(fc);
|
||||||
|
}
|
||||||
|
kfree(fud);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(fuse_dev_free);
|
||||||
|
|
||||||
static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
{
|
{
|
||||||
|
struct fuse_dev *fud;
|
||||||
struct fuse_conn *fc;
|
struct fuse_conn *fc;
|
||||||
struct inode *root;
|
struct inode *root;
|
||||||
struct fuse_mount_data d;
|
struct fuse_mount_data d;
|
||||||
|
@ -1043,11 +1078,15 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
fuse_conn_init(fc);
|
fuse_conn_init(fc);
|
||||||
fc->release = fuse_free_conn;
|
fc->release = fuse_free_conn;
|
||||||
|
|
||||||
|
fud = fuse_dev_alloc(fc);
|
||||||
|
if (!fud)
|
||||||
|
goto err_put_conn;
|
||||||
|
|
||||||
fc->dev = sb->s_dev;
|
fc->dev = sb->s_dev;
|
||||||
fc->sb = sb;
|
fc->sb = sb;
|
||||||
err = fuse_bdi_init(fc, sb);
|
err = fuse_bdi_init(fc, sb);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_put_conn;
|
goto err_dev_free;
|
||||||
|
|
||||||
sb->s_bdi = &fc->bdi;
|
sb->s_bdi = &fc->bdi;
|
||||||
|
|
||||||
|
@ -1068,7 +1107,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
root = fuse_get_root_inode(sb, d.rootmode);
|
root = fuse_get_root_inode(sb, d.rootmode);
|
||||||
root_dentry = d_make_root(root);
|
root_dentry = d_make_root(root);
|
||||||
if (!root_dentry)
|
if (!root_dentry)
|
||||||
goto err_put_conn;
|
goto err_dev_free;
|
||||||
/* only now - we want root dentry with NULL ->d_op */
|
/* only now - we want root dentry with NULL ->d_op */
|
||||||
sb->s_d_op = &fuse_dentry_operations;
|
sb->s_d_op = &fuse_dentry_operations;
|
||||||
|
|
||||||
|
@ -1094,7 +1133,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
|
|
||||||
list_add_tail(&fc->entry, &fuse_conn_list);
|
list_add_tail(&fc->entry, &fuse_conn_list);
|
||||||
sb->s_root = root_dentry;
|
sb->s_root = root_dentry;
|
||||||
file->private_data = fuse_conn_get(fc);
|
file->private_data = fud;
|
||||||
mutex_unlock(&fuse_mutex);
|
mutex_unlock(&fuse_mutex);
|
||||||
/*
|
/*
|
||||||
* atomic_dec_and_test() in fput() provides the necessary
|
* atomic_dec_and_test() in fput() provides the necessary
|
||||||
|
@ -1113,6 +1152,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
fuse_request_free(init_req);
|
fuse_request_free(init_req);
|
||||||
err_put_root:
|
err_put_root:
|
||||||
dput(root_dentry);
|
dput(root_dentry);
|
||||||
|
err_dev_free:
|
||||||
|
fuse_dev_free(fud);
|
||||||
err_put_conn:
|
err_put_conn:
|
||||||
fuse_bdi_destroy(fc);
|
fuse_bdi_destroy(fc);
|
||||||
fuse_conn_put(fc);
|
fuse_conn_put(fc);
|
||||||
|
|
Loading…
Reference in New Issue