fuse: Optimize request_end() by not taking fiq->waitq.lock
authorKirill Tkhai <ktkhai@virtuozzo.com>
Thu, 8 Nov 2018 09:05:25 +0000 (12:05 +0300)
committerMiklos Szeredi <mszeredi@redhat.com>
Wed, 13 Feb 2019 12:15:13 +0000 (13:15 +0100)
We take global fiq->waitq.lock every time, when we are in this function,
but interrupted requests are just small subset of all requests. This patch
optimizes request_end() and makes it to take the lock when it's really
needed.

queue_interrupt() needs small change for that. After req is linked to
interrupt list, we do smp_mb() and check for FR_FINISHED again. In case of
FR_FINISHED bit has appeared, we remove req and leave the function:

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/fuse/dev.c

index 11246e7..74171d5 100644 (file)
@@ -431,10 +431,16 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
 
        if (test_and_set_bit(FR_FINISHED, &req->flags))
                goto put_request;
-
-       spin_lock(&fiq->waitq.lock);
-       list_del_init(&req->intr_entry);
-       spin_unlock(&fiq->waitq.lock);
+       /*
+        * test_and_set_bit() implies smp_mb() between bit
+        * changing and below intr_entry check. Pairs with
+        * smp_mb() from queue_interrupt().
+        */
+       if (!list_empty(&req->intr_entry)) {
+               spin_lock(&fiq->waitq.lock);
+               list_del_init(&req->intr_entry);
+               spin_unlock(&fiq->waitq.lock);
+       }
        WARN_ON(test_bit(FR_PENDING, &req->flags));
        WARN_ON(test_bit(FR_SENT, &req->flags));
        if (test_bit(FR_BACKGROUND, &req->flags)) {
@@ -473,12 +479,18 @@ put_request:
 static void queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req)
 {
        spin_lock(&fiq->waitq.lock);
-       if (test_bit(FR_FINISHED, &req->flags)) {
-               spin_unlock(&fiq->waitq.lock);
-               return;
-       }
        if (list_empty(&req->intr_entry)) {
                list_add_tail(&req->intr_entry, &fiq->interrupts);
+               /*
+                * Pairs with smp_mb() implied by test_and_set_bit()
+                * from request_end().
+                */
+               smp_mb();
+               if (test_bit(FR_FINISHED, &req->flags)) {
+                       list_del_init(&req->intr_entry);
+                       spin_unlock(&fiq->waitq.lock);
+                       return;
+               }
                wake_up_locked(&fiq->waitq);
                kill_fasync(&fiq->fasync, SIGIO, POLL_IN);
        }