fuse: introduce per-instance fuse_dev structure
authorMiklos Szeredi <mszeredi@suse.cz>
Wed, 1 Jul 2015 14:26:08 +0000 (16:26 +0200)
committerMiklos Szeredi <mszeredi@suse.cz>
Wed, 1 Jul 2015 14:26:08 +0000 (16:26 +0200)
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>
fs/fuse/cuse.c
fs/fuse/dev.c
fs/fuse/fuse_i.h
fs/fuse/inode.c

index 0993d9a266d3f83711d6f89db1514a70ddc89425..eae2c11268bcb484075cfd08482beeb172dd66bc 100644 (file)
@@ -489,6 +489,7 @@ static void cuse_fc_release(struct fuse_conn *fc)
  */
 static int cuse_channel_open(struct inode *inode, struct file *file)
 {
+       struct fuse_dev *fud;
        struct cuse_conn *cc;
        int rc;
 
@@ -499,16 +500,22 @@ static int cuse_channel_open(struct inode *inode, struct file *file)
 
        fuse_conn_init(&cc->fc);
 
+       fud = fuse_dev_alloc(&cc->fc);
+       if (!fud) {
+               kfree(cc);
+               return -ENOMEM;
+       }
+
        INIT_LIST_HEAD(&cc->list);
        cc->fc.release = cuse_fc_release;
 
        cc->fc.initialized = 1;
        rc = cuse_send_init(cc);
        if (rc) {
-               fuse_conn_put(&cc->fc);
+               fuse_dev_free(fud);
                return rc;
        }
-       file->private_data = &cc->fc;   /* channel owns base reference to cc */
+       file->private_data = fud;
 
        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)
 {
-       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;
 
        /* remove from the conntbl, no more access from this point on */
index d405c1fa4618f7ef5cf0f4de43f07177593624b3..99e94584f17fd7bd65493d8f6cb2cf296588ea81 100644 (file)
@@ -25,13 +25,13 @@ MODULE_ALIAS("devname:fuse");
 
 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
         * 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,
@@ -1348,8 +1348,9 @@ static ssize_t fuse_dev_read(struct kiocb *iocb, struct iov_iter *to)
 {
        struct fuse_copy_state cs;
        struct file *file = iocb->ki_filp;
-       struct fuse_conn *fc = fuse_get_conn(file);
-       if (!fc)
+       struct fuse_dev *fud = fuse_get_dev(file);
+
+       if (!fud)
                return -EPERM;
 
        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);
 
-       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,
@@ -1369,8 +1370,9 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
        int do_wakeup = 0;
        struct pipe_buffer *bufs;
        struct fuse_copy_state cs;
-       struct fuse_conn *fc = fuse_get_conn(in);
-       if (!fc)
+       struct fuse_dev *fud = fuse_get_dev(in);
+
+       if (!fud)
                return -EPERM;
 
        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);
        cs.pipebufs = bufs;
        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)
                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)
 {
        struct fuse_copy_state cs;
-       struct fuse_conn *fc = fuse_get_conn(iocb->ki_filp);
-       if (!fc)
+       struct fuse_dev *fud = fuse_get_dev(iocb->ki_filp);
+
+       if (!fud)
                return -EPERM;
 
        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);
 
-       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,
@@ -1974,12 +1977,12 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
        unsigned idx;
        struct pipe_buffer *bufs;
        struct fuse_copy_state cs;
-       struct fuse_conn *fc;
+       struct fuse_dev *fud;
        size_t rem;
        ssize_t ret;
 
-       fc = fuse_get_conn(out);
-       if (!fc)
+       fud = fuse_get_dev(out);
+       if (!fud)
                return -EPERM;
 
        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)
                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++) {
                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;
        struct fuse_iqueue *fiq;
-       struct fuse_conn *fc = fuse_get_conn(file);
-       if (!fc)
+       struct fuse_dev *fud = fuse_get_dev(file);
+
+       if (!fud)
                return POLLERR;
 
-       fiq = &fc->iq;
+       fiq = &fud->fc->iq;
        poll_wait(file, &fiq->waitq, wait);
 
        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)
 {
-       struct fuse_conn *fc = fuse_get_conn(file);
-       if (fc) {
+       struct fuse_dev *fud = fuse_get_dev(file);
+
+       if (fud) {
+               struct fuse_conn *fc = fud->fc;
+
                WARN_ON(!list_empty(&fc->pq.io));
                WARN_ON(fc->iq.fasync != NULL);
                fuse_abort_conn(fc);
-               fuse_conn_put(fc);
+               fuse_dev_free(fud);
        }
 
        return 0;
@@ -2189,20 +2196,27 @@ EXPORT_SYMBOL_GPL(fuse_dev_release);
 
 static int fuse_dev_fasync(int fd, struct file *file, int on)
 {
-       struct fuse_conn *fc = fuse_get_conn(file);
-       if (!fc)
+       struct fuse_dev *fud = fuse_get_dev(file);
+
+       if (!fud)
                return -EPERM;
 
        /* 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)
 {
+       struct fuse_dev *fud;
+
        if (new->private_data)
                return -EINVAL;
 
-       new->private_data = fuse_conn_get(fc);
+       fud = fuse_dev_alloc(fc);
+       if (!fud)
+               return -ENOMEM;
+
+       new->private_data = fud;
 
        return 0;
 }
@@ -2221,11 +2235,11 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
 
                        err = -EINVAL;
                        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);
-                                       err = fuse_device_clone(fc, file);
+                                       err = fuse_device_clone(fud->fc, file);
                                        mutex_unlock(&fuse_mutex);
                                }
                                fput(old);
index a9507fd97d5e118ea227d1e0eff4e4bec77cbfac..42d59cbd47e70de05565a6e5ffeaa7e664ba72d2 100644 (file)
@@ -417,6 +417,17 @@ struct fuse_pqueue {
        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.
  *
@@ -629,6 +640,9 @@ struct fuse_conn {
 
        /** Read/write semaphore to hold when accessing sb. */
        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)
@@ -841,6 +855,9 @@ void fuse_conn_init(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
  */
index 8373f59dc2a88947e9e3c603018454002d16c4f1..e399383d87c85e1e27d93262e0d8a214b9e2284b 100644 (file)
@@ -598,6 +598,7 @@ void fuse_conn_init(struct fuse_conn *fc)
        fuse_pqueue_init(&fc->pq);
        INIT_LIST_HEAD(&fc->bg_queue);
        INIT_LIST_HEAD(&fc->entry);
+       INIT_LIST_HEAD(&fc->devices);
        atomic_set(&fc->num_waiting, 0);
        fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND;
        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)
 {
+       WARN_ON(!list_empty(&fc->devices));
        kfree_rcu(fc, rcu);
 }
 
@@ -990,8 +992,41 @@ static int fuse_bdi_init(struct fuse_conn *fc, struct super_block *sb)
        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)
 {
+       struct fuse_dev *fud;
        struct fuse_conn *fc;
        struct inode *root;
        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);
        fc->release = fuse_free_conn;
 
+       fud = fuse_dev_alloc(fc);
+       if (!fud)
+               goto err_put_conn;
+
        fc->dev = sb->s_dev;
        fc->sb = sb;
        err = fuse_bdi_init(fc, sb);
        if (err)
-               goto err_put_conn;
+               goto err_dev_free;
 
        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_dentry = d_make_root(root);
        if (!root_dentry)
-               goto err_put_conn;
+               goto err_dev_free;
        /* only now - we want root dentry with NULL ->d_op */
        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);
        sb->s_root = root_dentry;
-       file->private_data = fuse_conn_get(fc);
+       file->private_data = fud;
        mutex_unlock(&fuse_mutex);
        /*
         * 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);
  err_put_root:
        dput(root_dentry);
+ err_dev_free:
+       fuse_dev_free(fud);
  err_put_conn:
        fuse_bdi_destroy(fc);
        fuse_conn_put(fc);