Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cc080e9e authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

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: default avatarMiklos Szeredi <mszeredi@suse.cz>
Reviewed-by: default avatarAshish Samant <ashish.samant@oracle.com>
parent 00c570f4
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -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 */
+42 −28
Original line number Diff line number Diff line
@@ -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);
+17 −0
Original line number Diff line number Diff line
@@ -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
 */
+44 −3
Original line number Diff line number Diff line
@@ -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);