[PATCH] fuse: use a per-mount spinlock
Remove the global spinlock in favor of a per-mount one. This patch is basically find & replace. The difficult part has already been done by the previous patch. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
0720b31597
commit
d713311464
3 changed files with 74 additions and 84 deletions
122
fs/fuse/dev.c
122
fs/fuse/dev.c
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
FUSE: Filesystem in Userspace
|
FUSE: Filesystem in Userspace
|
||||||
Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
|
Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
|
||||||
|
|
||||||
This program can be distributed under the terms of the GNU GPL.
|
This program can be distributed under the terms of the GNU GPL.
|
||||||
See the file COPYING.
|
See the file COPYING.
|
||||||
|
@ -94,11 +94,11 @@ static struct fuse_req *do_get_request(struct fuse_conn *fc)
|
||||||
{
|
{
|
||||||
struct fuse_req *req;
|
struct fuse_req *req;
|
||||||
|
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
BUG_ON(list_empty(&fc->unused_list));
|
BUG_ON(list_empty(&fc->unused_list));
|
||||||
req = list_entry(fc->unused_list.next, struct fuse_req, list);
|
req = list_entry(fc->unused_list.next, struct fuse_req, list);
|
||||||
list_del_init(&req->list);
|
list_del_init(&req->list);
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
fuse_request_init(req);
|
fuse_request_init(req);
|
||||||
req->preallocated = 1;
|
req->preallocated = 1;
|
||||||
req->in.h.uid = current->fsuid;
|
req->in.h.uid = current->fsuid;
|
||||||
|
@ -124,7 +124,7 @@ struct fuse_req *fuse_get_request(struct fuse_conn *fc)
|
||||||
return do_get_request(fc);
|
return do_get_request(fc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Must be called with fuse_lock held */
|
/* Must be called with fc->lock held */
|
||||||
static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req)
|
static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
{
|
{
|
||||||
if (req->preallocated) {
|
if (req->preallocated) {
|
||||||
|
@ -143,9 +143,9 @@ static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
|
void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
{
|
{
|
||||||
if (atomic_dec_and_test(&req->count)) {
|
if (atomic_dec_and_test(&req->count)) {
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
fuse_putback_request(fc, req);
|
fuse_putback_request(fc, req);
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,15 +155,15 @@ static void fuse_put_request_locked(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
fuse_putback_request(fc, req);
|
fuse_putback_request(fc, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fuse_release_background(struct fuse_req *req)
|
void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
{
|
{
|
||||||
iput(req->inode);
|
iput(req->inode);
|
||||||
iput(req->inode2);
|
iput(req->inode2);
|
||||||
if (req->file)
|
if (req->file)
|
||||||
fput(req->file);
|
fput(req->file);
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
list_del(&req->bg_entry);
|
list_del(&req->bg_entry);
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -182,7 +182,7 @@ void fuse_release_background(struct fuse_req *req)
|
||||||
* interrupted and put in the background, it will return with an error
|
* interrupted and put in the background, it will return with an error
|
||||||
* and hence never be reset and reused.
|
* and hence never be reset and reused.
|
||||||
*
|
*
|
||||||
* Called with fuse_lock, unlocks it
|
* Called with fc->lock, unlocks it
|
||||||
*/
|
*/
|
||||||
static void request_end(struct fuse_conn *fc, struct fuse_req *req)
|
static void request_end(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
{
|
{
|
||||||
|
@ -191,14 +191,14 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
if (!req->background) {
|
if (!req->background) {
|
||||||
wake_up(&req->waitq);
|
wake_up(&req->waitq);
|
||||||
fuse_put_request_locked(fc, req);
|
fuse_put_request_locked(fc, req);
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
} else {
|
} else {
|
||||||
void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
|
void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
|
||||||
req->end = NULL;
|
req->end = NULL;
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
down_read(&fc->sbput_sem);
|
down_read(&fc->sbput_sem);
|
||||||
if (fc->mounted)
|
if (fc->mounted)
|
||||||
fuse_release_background(req);
|
fuse_release_background(fc, req);
|
||||||
up_read(&fc->sbput_sem);
|
up_read(&fc->sbput_sem);
|
||||||
if (end)
|
if (end)
|
||||||
end(fc, req);
|
end(fc, req);
|
||||||
|
@ -248,16 +248,16 @@ static void background_request(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
get_file(req->file);
|
get_file(req->file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called with fuse_lock held. Releases, and then reacquires it. */
|
/* Called with fc->lock held. Releases, and then reacquires it. */
|
||||||
static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
|
static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
{
|
{
|
||||||
sigset_t oldset;
|
sigset_t oldset;
|
||||||
|
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
block_sigs(&oldset);
|
block_sigs(&oldset);
|
||||||
wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED);
|
wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED);
|
||||||
restore_sigs(&oldset);
|
restore_sigs(&oldset);
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
if (req->state == FUSE_REQ_FINISHED && !req->interrupted)
|
if (req->state == FUSE_REQ_FINISHED && !req->interrupted)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -271,9 +271,9 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
locked state, there mustn't be any filesystem
|
locked state, there mustn't be any filesystem
|
||||||
operation (e.g. page fault), since that could lead
|
operation (e.g. page fault), since that could lead
|
||||||
to deadlock */
|
to deadlock */
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
wait_event(req->waitq, !req->locked);
|
wait_event(req->waitq, !req->locked);
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
}
|
}
|
||||||
if (req->state == FUSE_REQ_PENDING) {
|
if (req->state == FUSE_REQ_PENDING) {
|
||||||
list_del(&req->list);
|
list_del(&req->list);
|
||||||
|
@ -324,7 +324,7 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
void request_send(struct fuse_conn *fc, struct fuse_req *req)
|
void request_send(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
{
|
{
|
||||||
req->isreply = 1;
|
req->isreply = 1;
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
if (!fc->connected)
|
if (!fc->connected)
|
||||||
req->out.h.error = -ENOTCONN;
|
req->out.h.error = -ENOTCONN;
|
||||||
else if (fc->conn_error)
|
else if (fc->conn_error)
|
||||||
|
@ -337,15 +337,15 @@ void request_send(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
|
|
||||||
request_wait_answer(fc, req);
|
request_wait_answer(fc, req);
|
||||||
}
|
}
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
|
static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
{
|
{
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
if (fc->connected) {
|
if (fc->connected) {
|
||||||
queue_request(fc, req);
|
queue_request(fc, req);
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
} else {
|
} else {
|
||||||
req->out.h.error = -ENOTCONN;
|
req->out.h.error = -ENOTCONN;
|
||||||
request_end(fc, req);
|
request_end(fc, req);
|
||||||
|
@ -361,9 +361,9 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
void request_send_background(struct fuse_conn *fc, struct fuse_req *req)
|
void request_send_background(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
{
|
{
|
||||||
req->isreply = 1;
|
req->isreply = 1;
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
background_request(fc, req);
|
background_request(fc, req);
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
request_send_nowait(fc, req);
|
request_send_nowait(fc, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,16 +372,16 @@ void request_send_background(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
* anything that could cause a page-fault. If the request was already
|
* anything that could cause a page-fault. If the request was already
|
||||||
* interrupted bail out.
|
* interrupted bail out.
|
||||||
*/
|
*/
|
||||||
static int lock_request(struct fuse_req *req)
|
static int lock_request(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
if (req) {
|
if (req) {
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
if (req->interrupted)
|
if (req->interrupted)
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
else
|
else
|
||||||
req->locked = 1;
|
req->locked = 1;
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -391,18 +391,19 @@ static int lock_request(struct fuse_req *req)
|
||||||
* requester thread is currently waiting for it to be unlocked, so
|
* requester thread is currently waiting for it to be unlocked, so
|
||||||
* wake it up.
|
* wake it up.
|
||||||
*/
|
*/
|
||||||
static void unlock_request(struct fuse_req *req)
|
static void unlock_request(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
{
|
{
|
||||||
if (req) {
|
if (req) {
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
req->locked = 0;
|
req->locked = 0;
|
||||||
if (req->interrupted)
|
if (req->interrupted)
|
||||||
wake_up(&req->waitq);
|
wake_up(&req->waitq);
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fuse_copy_state {
|
struct fuse_copy_state {
|
||||||
|
struct fuse_conn *fc;
|
||||||
int write;
|
int write;
|
||||||
struct fuse_req *req;
|
struct fuse_req *req;
|
||||||
const struct iovec *iov;
|
const struct iovec *iov;
|
||||||
|
@ -415,11 +416,12 @@ struct fuse_copy_state {
|
||||||
unsigned len;
|
unsigned len;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void fuse_copy_init(struct fuse_copy_state *cs, int write,
|
static void fuse_copy_init(struct fuse_copy_state *cs, struct fuse_conn *fc,
|
||||||
struct fuse_req *req, const struct iovec *iov,
|
int write, struct fuse_req *req,
|
||||||
unsigned long nr_segs)
|
const struct iovec *iov, unsigned long nr_segs)
|
||||||
{
|
{
|
||||||
memset(cs, 0, sizeof(*cs));
|
memset(cs, 0, sizeof(*cs));
|
||||||
|
cs->fc = fc;
|
||||||
cs->write = write;
|
cs->write = write;
|
||||||
cs->req = req;
|
cs->req = req;
|
||||||
cs->iov = iov;
|
cs->iov = iov;
|
||||||
|
@ -449,7 +451,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
unlock_request(cs->req);
|
unlock_request(cs->fc, cs->req);
|
||||||
fuse_copy_finish(cs);
|
fuse_copy_finish(cs);
|
||||||
if (!cs->seglen) {
|
if (!cs->seglen) {
|
||||||
BUG_ON(!cs->nr_segs);
|
BUG_ON(!cs->nr_segs);
|
||||||
|
@ -472,7 +474,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
|
||||||
cs->seglen -= cs->len;
|
cs->seglen -= cs->len;
|
||||||
cs->addr += cs->len;
|
cs->addr += cs->len;
|
||||||
|
|
||||||
return lock_request(cs->req);
|
return lock_request(cs->fc, cs->req);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do as much copy to/from userspace buffer as we can */
|
/* Do as much copy to/from userspace buffer as we can */
|
||||||
|
@ -584,9 +586,9 @@ static void request_wait(struct fuse_conn *fc)
|
||||||
if (signal_pending(current))
|
if (signal_pending(current))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
schedule();
|
schedule();
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
}
|
}
|
||||||
set_current_state(TASK_RUNNING);
|
set_current_state(TASK_RUNNING);
|
||||||
remove_wait_queue(&fc->waitq, &wait);
|
remove_wait_queue(&fc->waitq, &wait);
|
||||||
|
@ -614,7 +616,7 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
restart:
|
restart:
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
err = -EAGAIN;
|
err = -EAGAIN;
|
||||||
if ((file->f_flags & O_NONBLOCK) && fc->connected &&
|
if ((file->f_flags & O_NONBLOCK) && fc->connected &&
|
||||||
list_empty(&fc->pending))
|
list_empty(&fc->pending))
|
||||||
|
@ -643,14 +645,14 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
|
||||||
request_end(fc, req);
|
request_end(fc, req);
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
fuse_copy_init(&cs, 1, req, iov, nr_segs);
|
fuse_copy_init(&cs, fc, 1, req, iov, nr_segs);
|
||||||
err = fuse_copy_one(&cs, &in->h, sizeof(in->h));
|
err = fuse_copy_one(&cs, &in->h, sizeof(in->h));
|
||||||
if (!err)
|
if (!err)
|
||||||
err = fuse_copy_args(&cs, in->numargs, in->argpages,
|
err = fuse_copy_args(&cs, in->numargs, in->argpages,
|
||||||
(struct fuse_arg *) in->args, 0);
|
(struct fuse_arg *) in->args, 0);
|
||||||
fuse_copy_finish(&cs);
|
fuse_copy_finish(&cs);
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
req->locked = 0;
|
req->locked = 0;
|
||||||
if (!err && req->interrupted)
|
if (!err && req->interrupted)
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
|
@ -665,12 +667,12 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
|
||||||
else {
|
else {
|
||||||
req->state = FUSE_REQ_SENT;
|
req->state = FUSE_REQ_SENT;
|
||||||
list_move_tail(&req->list, &fc->processing);
|
list_move_tail(&req->list, &fc->processing);
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
}
|
}
|
||||||
return reqsize;
|
return reqsize;
|
||||||
|
|
||||||
err_unlock:
|
err_unlock:
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,7 +741,7 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
|
||||||
if (!fc)
|
if (!fc)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
fuse_copy_init(&cs, 0, NULL, iov, nr_segs);
|
fuse_copy_init(&cs, fc, 0, NULL, iov, nr_segs);
|
||||||
if (nbytes < sizeof(struct fuse_out_header))
|
if (nbytes < sizeof(struct fuse_out_header))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -751,7 +753,7 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
|
||||||
oh.len != nbytes)
|
oh.len != nbytes)
|
||||||
goto err_finish;
|
goto err_finish;
|
||||||
|
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
if (!fc->connected)
|
if (!fc->connected)
|
||||||
goto err_unlock;
|
goto err_unlock;
|
||||||
|
@ -762,9 +764,9 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
|
||||||
goto err_unlock;
|
goto err_unlock;
|
||||||
|
|
||||||
if (req->interrupted) {
|
if (req->interrupted) {
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
fuse_copy_finish(&cs);
|
fuse_copy_finish(&cs);
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
request_end(fc, req);
|
request_end(fc, req);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
@ -772,12 +774,12 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
|
||||||
req->out.h = oh;
|
req->out.h = oh;
|
||||||
req->locked = 1;
|
req->locked = 1;
|
||||||
cs.req = req;
|
cs.req = req;
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
|
|
||||||
err = copy_out_args(&cs, &req->out, nbytes);
|
err = copy_out_args(&cs, &req->out, nbytes);
|
||||||
fuse_copy_finish(&cs);
|
fuse_copy_finish(&cs);
|
||||||
|
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
req->locked = 0;
|
req->locked = 0;
|
||||||
if (!err) {
|
if (!err) {
|
||||||
if (req->interrupted)
|
if (req->interrupted)
|
||||||
|
@ -789,7 +791,7 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
|
||||||
return err ? err : nbytes;
|
return err ? err : nbytes;
|
||||||
|
|
||||||
err_unlock:
|
err_unlock:
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
err_finish:
|
err_finish:
|
||||||
fuse_copy_finish(&cs);
|
fuse_copy_finish(&cs);
|
||||||
return err;
|
return err;
|
||||||
|
@ -813,12 +815,12 @@ static unsigned fuse_dev_poll(struct file *file, poll_table *wait)
|
||||||
|
|
||||||
poll_wait(file, &fc->waitq, wait);
|
poll_wait(file, &fc->waitq, wait);
|
||||||
|
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
if (!fc->connected)
|
if (!fc->connected)
|
||||||
mask = POLLERR;
|
mask = POLLERR;
|
||||||
else if (!list_empty(&fc->pending))
|
else if (!list_empty(&fc->pending))
|
||||||
mask |= POLLIN | POLLRDNORM;
|
mask |= POLLIN | POLLRDNORM;
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
|
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
@ -826,7 +828,7 @@ static unsigned fuse_dev_poll(struct file *file, poll_table *wait)
|
||||||
/*
|
/*
|
||||||
* Abort all requests on the given list (pending or processing)
|
* Abort all requests on the given list (pending or processing)
|
||||||
*
|
*
|
||||||
* This function releases and reacquires fuse_lock
|
* This function releases and reacquires fc->lock
|
||||||
*/
|
*/
|
||||||
static void end_requests(struct fuse_conn *fc, struct list_head *head)
|
static void end_requests(struct fuse_conn *fc, struct list_head *head)
|
||||||
{
|
{
|
||||||
|
@ -835,7 +837,7 @@ static void end_requests(struct fuse_conn *fc, struct list_head *head)
|
||||||
req = list_entry(head->next, struct fuse_req, list);
|
req = list_entry(head->next, struct fuse_req, list);
|
||||||
req->out.h.error = -ECONNABORTED;
|
req->out.h.error = -ECONNABORTED;
|
||||||
request_end(fc, req);
|
request_end(fc, req);
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -866,10 +868,10 @@ static void end_io_requests(struct fuse_conn *fc)
|
||||||
req->end = NULL;
|
req->end = NULL;
|
||||||
/* The end function will consume this reference */
|
/* The end function will consume this reference */
|
||||||
__fuse_get_request(req);
|
__fuse_get_request(req);
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
wait_event(req->waitq, !req->locked);
|
wait_event(req->waitq, !req->locked);
|
||||||
end(fc, req);
|
end(fc, req);
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -896,7 +898,7 @@ static void end_io_requests(struct fuse_conn *fc)
|
||||||
*/
|
*/
|
||||||
void fuse_abort_conn(struct fuse_conn *fc)
|
void fuse_abort_conn(struct fuse_conn *fc)
|
||||||
{
|
{
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
if (fc->connected) {
|
if (fc->connected) {
|
||||||
fc->connected = 0;
|
fc->connected = 0;
|
||||||
end_io_requests(fc);
|
end_io_requests(fc);
|
||||||
|
@ -905,18 +907,18 @@ void fuse_abort_conn(struct fuse_conn *fc)
|
||||||
wake_up_all(&fc->waitq);
|
wake_up_all(&fc->waitq);
|
||||||
kill_fasync(&fc->fasync, SIGIO, POLL_IN);
|
kill_fasync(&fc->fasync, SIGIO, POLL_IN);
|
||||||
}
|
}
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fuse_dev_release(struct inode *inode, struct file *file)
|
static int fuse_dev_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct fuse_conn *fc = fuse_get_conn(file);
|
struct fuse_conn *fc = fuse_get_conn(file);
|
||||||
if (fc) {
|
if (fc) {
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
fc->connected = 0;
|
fc->connected = 0;
|
||||||
end_requests(fc, &fc->pending);
|
end_requests(fc, &fc->pending);
|
||||||
end_requests(fc, &fc->processing);
|
end_requests(fc, &fc->processing);
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
fasync_helper(-1, file, 0, &fc->fasync);
|
fasync_helper(-1, file, 0, &fc->fasync);
|
||||||
kobject_put(&fc->kobj);
|
kobject_put(&fc->kobj);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
FUSE: Filesystem in Userspace
|
FUSE: Filesystem in Userspace
|
||||||
Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
|
Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
|
||||||
|
|
||||||
This program can be distributed under the terms of the GNU GPL.
|
This program can be distributed under the terms of the GNU GPL.
|
||||||
See the file COPYING.
|
See the file COPYING.
|
||||||
|
@ -144,7 +144,7 @@ struct fuse_req {
|
||||||
/*
|
/*
|
||||||
* The following bitfields are either set once before the
|
* The following bitfields are either set once before the
|
||||||
* request is queued or setting/clearing them is protected by
|
* request is queued or setting/clearing them is protected by
|
||||||
* fuse_lock
|
* fuse_conn->lock
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** True if the request has reply */
|
/** True if the request has reply */
|
||||||
|
@ -213,6 +213,9 @@ struct fuse_req {
|
||||||
* unmounted.
|
* unmounted.
|
||||||
*/
|
*/
|
||||||
struct fuse_conn {
|
struct fuse_conn {
|
||||||
|
/** Lock protecting accessess to members of this structure */
|
||||||
|
spinlock_t lock;
|
||||||
|
|
||||||
/** The user id for this mount */
|
/** The user id for this mount */
|
||||||
uid_t user_id;
|
uid_t user_id;
|
||||||
|
|
||||||
|
@ -351,21 +354,6 @@ static inline u64 get_node_id(struct inode *inode)
|
||||||
/** Device operations */
|
/** Device operations */
|
||||||
extern const struct file_operations fuse_dev_operations;
|
extern const struct file_operations fuse_dev_operations;
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the single global spinlock which protects FUSE's structures
|
|
||||||
*
|
|
||||||
* The following data is protected by this lock:
|
|
||||||
*
|
|
||||||
* - the private_data field of the device file
|
|
||||||
* - the s_fs_info field of the super block
|
|
||||||
* - unused_list, pending, processing lists in fuse_conn
|
|
||||||
* - background list in fuse_conn
|
|
||||||
* - the unique request ID counter reqctr in fuse_conn
|
|
||||||
* - the sb (super_block) field in fuse_conn
|
|
||||||
* - the file (device file) field in fuse_conn
|
|
||||||
*/
|
|
||||||
extern spinlock_t fuse_lock;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a filled in inode
|
* Get a filled in inode
|
||||||
*/
|
*/
|
||||||
|
@ -490,7 +478,7 @@ void request_send_background(struct fuse_conn *fc, struct fuse_req *req);
|
||||||
/**
|
/**
|
||||||
* Release inodes and file associated with background request
|
* Release inodes and file associated with background request
|
||||||
*/
|
*/
|
||||||
void fuse_release_background(struct fuse_req *req);
|
void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req);
|
||||||
|
|
||||||
/* Abort all requests */
|
/* Abort all requests */
|
||||||
void fuse_abort_conn(struct fuse_conn *fc);
|
void fuse_abort_conn(struct fuse_conn *fc);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
FUSE: Filesystem in Userspace
|
FUSE: Filesystem in Userspace
|
||||||
Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
|
Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
|
||||||
|
|
||||||
This program can be distributed under the terms of the GNU GPL.
|
This program can be distributed under the terms of the GNU GPL.
|
||||||
See the file COPYING.
|
See the file COPYING.
|
||||||
|
@ -22,7 +22,6 @@ MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
|
||||||
MODULE_DESCRIPTION("Filesystem in Userspace");
|
MODULE_DESCRIPTION("Filesystem in Userspace");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
spinlock_t fuse_lock;
|
|
||||||
static kmem_cache_t *fuse_inode_cachep;
|
static kmem_cache_t *fuse_inode_cachep;
|
||||||
static struct subsystem connections_subsys;
|
static struct subsystem connections_subsys;
|
||||||
|
|
||||||
|
@ -207,13 +206,14 @@ static void fuse_put_super(struct super_block *sb)
|
||||||
|
|
||||||
down_write(&fc->sbput_sem);
|
down_write(&fc->sbput_sem);
|
||||||
while (!list_empty(&fc->background))
|
while (!list_empty(&fc->background))
|
||||||
fuse_release_background(list_entry(fc->background.next,
|
fuse_release_background(fc,
|
||||||
|
list_entry(fc->background.next,
|
||||||
struct fuse_req, bg_entry));
|
struct fuse_req, bg_entry));
|
||||||
|
|
||||||
spin_lock(&fuse_lock);
|
spin_lock(&fc->lock);
|
||||||
fc->mounted = 0;
|
fc->mounted = 0;
|
||||||
fc->connected = 0;
|
fc->connected = 0;
|
||||||
spin_unlock(&fuse_lock);
|
spin_unlock(&fc->lock);
|
||||||
up_write(&fc->sbput_sem);
|
up_write(&fc->sbput_sem);
|
||||||
/* Flush all readers on this fs */
|
/* Flush all readers on this fs */
|
||||||
kill_fasync(&fc->fasync, SIGIO, POLL_IN);
|
kill_fasync(&fc->fasync, SIGIO, POLL_IN);
|
||||||
|
@ -388,6 +388,7 @@ static struct fuse_conn *new_conn(void)
|
||||||
fc = kzalloc(sizeof(*fc), GFP_KERNEL);
|
fc = kzalloc(sizeof(*fc), GFP_KERNEL);
|
||||||
if (fc) {
|
if (fc) {
|
||||||
int i;
|
int i;
|
||||||
|
spin_lock_init(&fc->lock);
|
||||||
init_waitqueue_head(&fc->waitq);
|
init_waitqueue_head(&fc->waitq);
|
||||||
INIT_LIST_HEAD(&fc->pending);
|
INIT_LIST_HEAD(&fc->pending);
|
||||||
INIT_LIST_HEAD(&fc->processing);
|
INIT_LIST_HEAD(&fc->processing);
|
||||||
|
@ -734,7 +735,6 @@ static int __init fuse_init(void)
|
||||||
printk("fuse init (API version %i.%i)\n",
|
printk("fuse init (API version %i.%i)\n",
|
||||||
FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
|
FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
|
||||||
|
|
||||||
spin_lock_init(&fuse_lock);
|
|
||||||
res = fuse_fs_init();
|
res = fuse_fs_init();
|
||||||
if (res)
|
if (res)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
Loading…
Reference in a new issue