Commit c3696046 authored by Miklos Szeredi's avatar Miklos Szeredi

fuse: separate pqueue for clones

Make each fuse device clone refer to a separate processing queue.  The only
constraint on userspace code is that the request answer must be written to
the same device clone as it was read off.
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
parent cc080e9e
...@@ -1232,12 +1232,13 @@ __releases(fiq->waitq.lock) ...@@ -1232,12 +1232,13 @@ __releases(fiq->waitq.lock)
* request_end(). Otherwise add it to the processing list, and set * request_end(). Otherwise add it to the processing list, and set
* the 'sent' flag. * the 'sent' flag.
*/ */
static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file, static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
struct fuse_copy_state *cs, size_t nbytes) struct fuse_copy_state *cs, size_t nbytes)
{ {
ssize_t err; ssize_t err;
struct fuse_conn *fc = fud->fc;
struct fuse_iqueue *fiq = &fc->iq; struct fuse_iqueue *fiq = &fc->iq;
struct fuse_pqueue *fpq = &fc->pq; struct fuse_pqueue *fpq = &fud->pq;
struct fuse_req *req; struct fuse_req *req;
struct fuse_in *in; struct fuse_in *in;
unsigned reqsize; unsigned reqsize;
...@@ -1358,7 +1359,7 @@ static ssize_t fuse_dev_read(struct kiocb *iocb, struct iov_iter *to) ...@@ -1358,7 +1359,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(fud->fc, file, &cs, iov_iter_count(to)); return fuse_dev_do_read(fud, 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,
...@@ -1382,7 +1383,7 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos, ...@@ -1382,7 +1383,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(fud->fc, in, &cs, len); ret = fuse_dev_do_read(fud, in, &cs, len);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -1862,11 +1863,12 @@ static int copy_out_args(struct fuse_copy_state *cs, struct fuse_out *out, ...@@ -1862,11 +1863,12 @@ static int copy_out_args(struct fuse_copy_state *cs, struct fuse_out *out,
* it from the list and copy the rest of the buffer to the request. * it from the list and copy the rest of the buffer to the request.
* The request is finished by calling request_end() * The request is finished by calling request_end()
*/ */
static ssize_t fuse_dev_do_write(struct fuse_conn *fc, static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
struct fuse_copy_state *cs, size_t nbytes) struct fuse_copy_state *cs, size_t nbytes)
{ {
int err; int err;
struct fuse_pqueue *fpq = &fc->pq; struct fuse_conn *fc = fud->fc;
struct fuse_pqueue *fpq = &fud->pq;
struct fuse_req *req; struct fuse_req *req;
struct fuse_out_header oh; struct fuse_out_header oh;
...@@ -1966,7 +1968,7 @@ static ssize_t fuse_dev_write(struct kiocb *iocb, struct iov_iter *from) ...@@ -1966,7 +1968,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(fud->fc, &cs, iov_iter_count(from)); return fuse_dev_do_write(fud, &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,
...@@ -2037,7 +2039,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe, ...@@ -2037,7 +2039,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(fud->fc, &cs, len); ret = fuse_dev_do_write(fud, &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];
...@@ -2124,10 +2126,10 @@ static void end_polls(struct fuse_conn *fc) ...@@ -2124,10 +2126,10 @@ static void end_polls(struct fuse_conn *fc)
void fuse_abort_conn(struct fuse_conn *fc) void fuse_abort_conn(struct fuse_conn *fc)
{ {
struct fuse_iqueue *fiq = &fc->iq; struct fuse_iqueue *fiq = &fc->iq;
struct fuse_pqueue *fpq = &fc->pq;
spin_lock(&fc->lock); spin_lock(&fc->lock);
if (fc->connected) { if (fc->connected) {
struct fuse_dev *fud;
struct fuse_req *req, *next; struct fuse_req *req, *next;
LIST_HEAD(to_end1); LIST_HEAD(to_end1);
LIST_HEAD(to_end2); LIST_HEAD(to_end2);
...@@ -2135,6 +2137,9 @@ void fuse_abort_conn(struct fuse_conn *fc) ...@@ -2135,6 +2137,9 @@ void fuse_abort_conn(struct fuse_conn *fc)
fc->connected = 0; fc->connected = 0;
fc->blocked = 0; fc->blocked = 0;
fuse_set_initialized(fc); fuse_set_initialized(fc);
list_for_each_entry(fud, &fc->devices, entry) {
struct fuse_pqueue *fpq = &fud->pq;
spin_lock(&fpq->lock); spin_lock(&fpq->lock);
fpq->connected = 0; fpq->connected = 0;
list_for_each_entry_safe(req, next, &fpq->io, list) { list_for_each_entry_safe(req, next, &fpq->io, list) {
...@@ -2149,6 +2154,7 @@ void fuse_abort_conn(struct fuse_conn *fc) ...@@ -2149,6 +2154,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
} }
list_splice_init(&fpq->processing, &to_end2); list_splice_init(&fpq->processing, &to_end2);
spin_unlock(&fpq->lock); spin_unlock(&fpq->lock);
}
fc->max_background = UINT_MAX; fc->max_background = UINT_MAX;
flush_bg_queue(fc); flush_bg_queue(fc);
...@@ -2183,13 +2189,17 @@ int fuse_dev_release(struct inode *inode, struct file *file) ...@@ -2183,13 +2189,17 @@ int fuse_dev_release(struct inode *inode, struct file *file)
if (fud) { if (fud) {
struct fuse_conn *fc = fud->fc; struct fuse_conn *fc = fud->fc;
struct fuse_pqueue *fpq = &fud->pq;
WARN_ON(!list_empty(&fc->pq.io)); WARN_ON(!list_empty(&fpq->io));
end_requests(fc, &fpq->processing);
/* Are we the last open device? */
if (atomic_dec_and_test(&fc->dev_count)) {
WARN_ON(fc->iq.fasync != NULL); WARN_ON(fc->iq.fasync != NULL);
fuse_abort_conn(fc); fuse_abort_conn(fc);
}
fuse_dev_free(fud); fuse_dev_free(fud);
} }
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(fuse_dev_release); EXPORT_SYMBOL_GPL(fuse_dev_release);
...@@ -2217,6 +2227,7 @@ static int fuse_device_clone(struct fuse_conn *fc, struct file *new) ...@@ -2217,6 +2227,7 @@ static int fuse_device_clone(struct fuse_conn *fc, struct file *new)
return -ENOMEM; return -ENOMEM;
new->private_data = fud; new->private_data = fud;
atomic_inc(&fc->dev_count);
return 0; return 0;
} }
......
...@@ -424,6 +424,9 @@ struct fuse_dev { ...@@ -424,6 +424,9 @@ struct fuse_dev {
/** Fuse connection for this device */ /** Fuse connection for this device */
struct fuse_conn *fc; struct fuse_conn *fc;
/** Processing queue */
struct fuse_pqueue pq;
/** list entry on fc->devices */ /** list entry on fc->devices */
struct list_head entry; struct list_head entry;
}; };
...@@ -442,6 +445,9 @@ struct fuse_conn { ...@@ -442,6 +445,9 @@ struct fuse_conn {
/** Refcount */ /** Refcount */
atomic_t count; atomic_t count;
/** Number of fuse_dev's */
atomic_t dev_count;
struct rcu_head rcu; struct rcu_head rcu;
/** The user id for this mount */ /** The user id for this mount */
...@@ -462,9 +468,6 @@ struct fuse_conn { ...@@ -462,9 +468,6 @@ struct fuse_conn {
/** Input queue */ /** Input queue */
struct fuse_iqueue iq; struct fuse_iqueue iq;
/** Processing queue */
struct fuse_pqueue pq;
/** The next unique kernel file handle */ /** The next unique kernel file handle */
u64 khctr; u64 khctr;
......
...@@ -592,10 +592,10 @@ void fuse_conn_init(struct fuse_conn *fc) ...@@ -592,10 +592,10 @@ void fuse_conn_init(struct fuse_conn *fc)
spin_lock_init(&fc->lock); spin_lock_init(&fc->lock);
init_rwsem(&fc->killsb); init_rwsem(&fc->killsb);
atomic_set(&fc->count, 1); atomic_set(&fc->count, 1);
atomic_set(&fc->dev_count, 1);
init_waitqueue_head(&fc->blocked_waitq); init_waitqueue_head(&fc->blocked_waitq);
init_waitqueue_head(&fc->reserved_req_waitq); init_waitqueue_head(&fc->reserved_req_waitq);
fuse_iqueue_init(&fc->iq); fuse_iqueue_init(&fc->iq);
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); INIT_LIST_HEAD(&fc->devices);
...@@ -999,6 +999,7 @@ struct fuse_dev *fuse_dev_alloc(struct fuse_conn *fc) ...@@ -999,6 +999,7 @@ struct fuse_dev *fuse_dev_alloc(struct fuse_conn *fc)
fud = kzalloc(sizeof(struct fuse_dev), GFP_KERNEL); fud = kzalloc(sizeof(struct fuse_dev), GFP_KERNEL);
if (fud) { if (fud) {
fud->fc = fuse_conn_get(fc); fud->fc = fuse_conn_get(fc);
fuse_pqueue_init(&fud->pq);
spin_lock(&fc->lock); spin_lock(&fc->lock);
list_add_tail(&fud->entry, &fc->devices); list_add_tail(&fud->entry, &fc->devices);
......
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