[PATCH] fuse: use a per-mount spinlock
authorMiklos Szeredi <miklos@szeredi.hu>
Tue, 11 Apr 2006 05:54:55 +0000 (22:54 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Tue, 11 Apr 2006 13:18:48 +0000 (06:18 -0700)
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>
fs/fuse/dev.c
fs/fuse/fuse_i.h
fs/fuse/inode.c

index c510533c684993863a799009f2b74e6d974f785d..63d2cf43b5e31c5df807523713a239f2527e9cf5 100644 (file)
@@ -1,6 +1,6 @@
 /*
   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.
   See the file COPYING.
@@ -94,11 +94,11 @@ static struct fuse_req *do_get_request(struct fuse_conn *fc)
 {
        struct fuse_req *req;
 
-       spin_lock(&fuse_lock);
+       spin_lock(&fc->lock);
        BUG_ON(list_empty(&fc->unused_list));
        req = list_entry(fc->unused_list.next, struct fuse_req, list);
        list_del_init(&req->list);
-       spin_unlock(&fuse_lock);
+       spin_unlock(&fc->lock);
        fuse_request_init(req);
        req->preallocated = 1;
        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);
 }
 
-/* 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)
 {
        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)
 {
        if (atomic_dec_and_test(&req->count)) {
-               spin_lock(&fuse_lock);
+               spin_lock(&fc->lock);
                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);
 }
 
-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->inode2);
        if (req->file)
                fput(req->file);
-       spin_lock(&fuse_lock);
+       spin_lock(&fc->lock);
        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
  * 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)
 {
@@ -191,14 +191,14 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
        if (!req->background) {
                wake_up(&req->waitq);
                fuse_put_request_locked(fc, req);
-               spin_unlock(&fuse_lock);
+               spin_unlock(&fc->lock);
        } else {
                void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
                req->end = NULL;
-               spin_unlock(&fuse_lock);
+               spin_unlock(&fc->lock);
                down_read(&fc->sbput_sem);
                if (fc->mounted)
-                       fuse_release_background(req);
+                       fuse_release_background(fc, req);
                up_read(&fc->sbput_sem);
                if (end)
                        end(fc, req);
@@ -248,16 +248,16 @@ static void background_request(struct fuse_conn *fc, struct fuse_req *req)
                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)
 {
        sigset_t oldset;
 
-       spin_unlock(&fuse_lock);
+       spin_unlock(&fc->lock);
        block_sigs(&oldset);
        wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED);
        restore_sigs(&oldset);
-       spin_lock(&fuse_lock);
+       spin_lock(&fc->lock);
        if (req->state == FUSE_REQ_FINISHED && !req->interrupted)
                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
                   operation (e.g. page fault), since that could lead
                   to deadlock */
-               spin_unlock(&fuse_lock);
+               spin_unlock(&fc->lock);
                wait_event(req->waitq, !req->locked);
-               spin_lock(&fuse_lock);
+               spin_lock(&fc->lock);
        }
        if (req->state == FUSE_REQ_PENDING) {
                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)
 {
        req->isreply = 1;
-       spin_lock(&fuse_lock);
+       spin_lock(&fc->lock);
        if (!fc->connected)
                req->out.h.error = -ENOTCONN;
        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);
        }
-       spin_unlock(&fuse_lock);
+       spin_unlock(&fc->lock);
 }
 
 static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
 {
-       spin_lock(&fuse_lock);
+       spin_lock(&fc->lock);
        if (fc->connected) {
                queue_request(fc, req);
-               spin_unlock(&fuse_lock);
+               spin_unlock(&fc->lock);
        } else {
                req->out.h.error = -ENOTCONN;
                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)
 {
        req->isreply = 1;
-       spin_lock(&fuse_lock);
+       spin_lock(&fc->lock);
        background_request(fc, req);
-       spin_unlock(&fuse_lock);
+       spin_unlock(&fc->lock);
        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
  * 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;
        if (req) {
-               spin_lock(&fuse_lock);
+               spin_lock(&fc->lock);
                if (req->interrupted)
                        err = -ENOENT;
                else
                        req->locked = 1;
-               spin_unlock(&fuse_lock);
+               spin_unlock(&fc->lock);
        }
        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
  * 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) {
-               spin_lock(&fuse_lock);
+               spin_lock(&fc->lock);
                req->locked = 0;
                if (req->interrupted)
                        wake_up(&req->waitq);
-               spin_unlock(&fuse_lock);
+               spin_unlock(&fc->lock);
        }
 }
 
 struct fuse_copy_state {
+       struct fuse_conn *fc;
        int write;
        struct fuse_req *req;
        const struct iovec *iov;
@@ -415,11 +416,12 @@ struct fuse_copy_state {
        unsigned len;
 };
 
-static void fuse_copy_init(struct fuse_copy_state *cs, int write,
-                          struct fuse_req *req, const struct iovec *iov,
-                          unsigned long nr_segs)
+static void fuse_copy_init(struct fuse_copy_state *cs, struct fuse_conn *fc,
+                          int write, struct fuse_req *req,
+                          const struct iovec *iov, unsigned long nr_segs)
 {
        memset(cs, 0, sizeof(*cs));
+       cs->fc = fc;
        cs->write = write;
        cs->req = req;
        cs->iov = iov;
@@ -449,7 +451,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
        unsigned long offset;
        int err;
 
-       unlock_request(cs->req);
+       unlock_request(cs->fc, cs->req);
        fuse_copy_finish(cs);
        if (!cs->seglen) {
                BUG_ON(!cs->nr_segs);
@@ -472,7 +474,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
        cs->seglen -= 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 */
@@ -584,9 +586,9 @@ static void request_wait(struct fuse_conn *fc)
                if (signal_pending(current))
                        break;
 
-               spin_unlock(&fuse_lock);
+               spin_unlock(&fc->lock);
                schedule();
-               spin_lock(&fuse_lock);
+               spin_lock(&fc->lock);
        }
        set_current_state(TASK_RUNNING);
        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;
 
  restart:
-       spin_lock(&fuse_lock);
+       spin_lock(&fc->lock);
        err = -EAGAIN;
        if ((file->f_flags & O_NONBLOCK) && fc->connected &&
            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);
                goto restart;
        }
-       spin_unlock(&fuse_lock);
-       fuse_copy_init(&cs, 1, req, iov, nr_segs);
+       spin_unlock(&fc->lock);
+       fuse_copy_init(&cs, fc, 1, req, iov, nr_segs);
        err = fuse_copy_one(&cs, &in->h, sizeof(in->h));
        if (!err)
                err = fuse_copy_args(&cs, in->numargs, in->argpages,
                                     (struct fuse_arg *) in->args, 0);
        fuse_copy_finish(&cs);
-       spin_lock(&fuse_lock);
+       spin_lock(&fc->lock);
        req->locked = 0;
        if (!err && req->interrupted)
                err = -ENOENT;
@@ -665,12 +667,12 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
        else {
                req->state = FUSE_REQ_SENT;
                list_move_tail(&req->list, &fc->processing);
-               spin_unlock(&fuse_lock);
+               spin_unlock(&fc->lock);
        }
        return reqsize;
 
  err_unlock:
-       spin_unlock(&fuse_lock);
+       spin_unlock(&fc->lock);
        return err;
 }
 
@@ -739,7 +741,7 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
        if (!fc)
                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))
                return -EINVAL;
 
@@ -751,7 +753,7 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
            oh.len != nbytes)
                goto err_finish;
 
-       spin_lock(&fuse_lock);
+       spin_lock(&fc->lock);
        err = -ENOENT;
        if (!fc->connected)
                goto err_unlock;
@@ -762,9 +764,9 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
                goto err_unlock;
 
        if (req->interrupted) {
-               spin_unlock(&fuse_lock);
+               spin_unlock(&fc->lock);
                fuse_copy_finish(&cs);
-               spin_lock(&fuse_lock);
+               spin_lock(&fc->lock);
                request_end(fc, req);
                return -ENOENT;
        }
@@ -772,12 +774,12 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
        req->out.h = oh;
        req->locked = 1;
        cs.req = req;
-       spin_unlock(&fuse_lock);
+       spin_unlock(&fc->lock);
 
        err = copy_out_args(&cs, &req->out, nbytes);
        fuse_copy_finish(&cs);
 
-       spin_lock(&fuse_lock);
+       spin_lock(&fc->lock);
        req->locked = 0;
        if (!err) {
                if (req->interrupted)
@@ -789,7 +791,7 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
        return err ? err : nbytes;
 
  err_unlock:
-       spin_unlock(&fuse_lock);
+       spin_unlock(&fc->lock);
  err_finish:
        fuse_copy_finish(&cs);
        return err;
@@ -813,12 +815,12 @@ static unsigned fuse_dev_poll(struct file *file, poll_table *wait)
 
        poll_wait(file, &fc->waitq, wait);
 
-       spin_lock(&fuse_lock);
+       spin_lock(&fc->lock);
        if (!fc->connected)
                mask = POLLERR;
        else if (!list_empty(&fc->pending))
                mask |= POLLIN | POLLRDNORM;
-       spin_unlock(&fuse_lock);
+       spin_unlock(&fc->lock);
 
        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)
  *
- * 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)
 {
@@ -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->out.h.error = -ECONNABORTED;
                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;
                        /* The end function will consume this reference */
                        __fuse_get_request(req);
-                       spin_unlock(&fuse_lock);
+                       spin_unlock(&fc->lock);
                        wait_event(req->waitq, !req->locked);
                        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)
 {
-       spin_lock(&fuse_lock);
+       spin_lock(&fc->lock);
        if (fc->connected) {
                fc->connected = 0;
                end_io_requests(fc);
@@ -905,18 +907,18 @@ void fuse_abort_conn(struct fuse_conn *fc)
                wake_up_all(&fc->waitq);
                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)
 {
        struct fuse_conn *fc = fuse_get_conn(file);
        if (fc) {
-               spin_lock(&fuse_lock);
+               spin_lock(&fc->lock);
                fc->connected = 0;
                end_requests(fc, &fc->pending);
                end_requests(fc, &fc->processing);
-               spin_unlock(&fuse_lock);
+               spin_unlock(&fc->lock);
                fasync_helper(-1, file, 0, &fc->fasync);
                kobject_put(&fc->kobj);
        }
index e5cb46b784376faa3fce884491c4a28400ec7c9f..6ed812fd62009e73a7a03ef2ce4884a3d7dc64bf 100644 (file)
@@ -1,6 +1,6 @@
 /*
   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.
   See the file COPYING.
@@ -144,7 +144,7 @@ struct fuse_req {
        /*
         * The following bitfields are either set once before the
         * request is queued or setting/clearing them is protected by
-        * fuse_lock
+        * fuse_conn->lock
         */
 
        /** True if the request has reply */
@@ -213,6 +213,9 @@ struct fuse_req {
  * unmounted.
  */
 struct fuse_conn {
+       /** Lock protecting accessess to  members of this structure */
+       spinlock_t lock;
+
        /** The user id for this mount */
        uid_t user_id;
 
@@ -351,21 +354,6 @@ static inline u64 get_node_id(struct inode *inode)
 /** Device 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
  */
@@ -490,7 +478,7 @@ void request_send_background(struct fuse_conn *fc, struct fuse_req *req);
 /**
  * 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 */
 void fuse_abort_conn(struct fuse_conn *fc);
index 620579a691073a3b0dee3ce18ac8ba6811528638..cc58debeabd40c68ac9ecac36d8b15ce2363f571 100644 (file)
@@ -1,6 +1,6 @@
 /*
   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.
   See the file COPYING.
@@ -22,7 +22,6 @@ MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
 MODULE_DESCRIPTION("Filesystem in Userspace");
 MODULE_LICENSE("GPL");
 
-spinlock_t fuse_lock;
 static kmem_cache_t *fuse_inode_cachep;
 static struct subsystem connections_subsys;
 
@@ -207,13 +206,14 @@ static void fuse_put_super(struct super_block *sb)
 
        down_write(&fc->sbput_sem);
        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));
 
-       spin_lock(&fuse_lock);
+       spin_lock(&fc->lock);
        fc->mounted = 0;
        fc->connected = 0;
-       spin_unlock(&fuse_lock);
+       spin_unlock(&fc->lock);
        up_write(&fc->sbput_sem);
        /* Flush all readers on this fs */
        kill_fasync(&fc->fasync, SIGIO, POLL_IN);
@@ -388,6 +388,7 @@ static struct fuse_conn *new_conn(void)
        fc = kzalloc(sizeof(*fc), GFP_KERNEL);
        if (fc) {
                int i;
+               spin_lock_init(&fc->lock);
                init_waitqueue_head(&fc->waitq);
                INIT_LIST_HEAD(&fc->pending);
                INIT_LIST_HEAD(&fc->processing);
@@ -734,7 +735,6 @@ static int __init fuse_init(void)
        printk("fuse init (API version %i.%i)\n",
               FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
 
-       spin_lock_init(&fuse_lock);
        res = fuse_fs_init();
        if (res)
                goto err;