OSDN Git Service

aio: try to complete poll iocbs without context switch
authorChristoph Hellwig <hch@lst.de>
Sun, 20 May 2018 17:19:30 +0000 (19:19 +0200)
committerChristoph Hellwig <hch@lst.de>
Sat, 26 May 2018 07:16:44 +0000 (09:16 +0200)
If we can acquire ctx_lock without spinning we can just remove our
iocb from the active_reqs list, and thus complete the iocbs from the
wakeup context.

Signed-off-by: Christoph Hellwig <hch@lst.de>
fs/aio.c

index bd711cf..8274d09 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1633,6 +1633,7 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
                void *key)
 {
        struct poll_iocb *req = container_of(wait, struct poll_iocb, wait);
+       struct aio_kiocb *iocb = container_of(req, struct aio_kiocb, poll);
        struct file *file = req->file;
        __poll_t mask = key_to_poll(key);
 
@@ -1648,9 +1649,22 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
 
        __aio_poll_remove(req);
 
-       req->events = mask;
-       INIT_WORK(&req->work, aio_poll_work);
-       schedule_work(&req->work);
+       /*
+        * Try completing without a context switch if we can acquire ctx_lock
+        * without spinning.  Otherwise we need to defer to a workqueue to
+        * avoid a deadlock due to the lock order.
+        */
+       if (spin_trylock(&iocb->ki_ctx->ctx_lock)) {
+               list_del_init(&iocb->ki_list);
+               spin_unlock(&iocb->ki_ctx->ctx_lock);
+
+               __aio_poll_complete(req, mask);
+       } else {
+               req->events = mask;
+               INIT_WORK(&req->work, aio_poll_work);
+               schedule_work(&req->work);
+       }
+
        return 1;
 }