1
0
Fork 0

[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>
hifive-unleashed-5.1
Miklos Szeredi 2006-04-10 22:54:55 -07:00 committed by Linus Torvalds
parent 0720b31597
commit d713311464
3 changed files with 74 additions and 84 deletions

View File

@ -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);
} }

View File

@ -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);

View File

@ -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;