]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
aio: change reqs_active to include unreaped completions
authorKent Overstreet <koverstreet@google.com>
Wed, 20 Mar 2013 04:08:57 +0000 (15:08 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Fri, 22 Mar 2013 04:34:10 +0000 (15:34 +1100)
The aio code tries really hard to avoid having to deal with the completion
ringbuffer overflowing.  To do that, it has to keep track of the number of
outstanding kiocbs, and the number of completions currently in the
ringbuffer - and it's got to check that every time we allocate a kiocb.
Ouch.

But - we can improve this quite a bit if we just change reqs_active to
mean "number of outstanding requests and unreaped completions" - that
means kiocb allocation doesn't have to look at the ringbuffer, which is a
fairly significant win.

Signed-off-by: Kent Overstreet <koverstreet@google.com>
Cc: Zach Brown <zab@redhat.com>
Cc: Felipe Balbi <balbi@ti.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Asai Thambi S P <asamymuthupa@micron.com>
Cc: Selvan Mani <smani@micron.com>
Cc: Sam Bradshaw <sbradshaw@micron.com>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Benjamin LaHaise <bcrl@kvack.org>
Cc: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
fs/aio.c

index 8c31d1e1fae1a3fcfe1062826593af2b3a706416..65d3d9222f3fb1e37b4b99d5aee26a1f5443a1c0 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -71,12 +71,6 @@ struct aio_ring_info {
        struct page             *internal_pages[AIO_RING_PAGES];
 };
 
-static inline unsigned aio_ring_avail(struct aio_ring_info *info,
-                                       struct aio_ring *ring)
-{
-       return (ring->head + info->nr - 1 - ring->tail) % info->nr;
-}
-
 struct kioctx {
        atomic_t                users;
        atomic_t                dead;
@@ -284,8 +278,11 @@ static void free_ioctx_rcu(struct rcu_head *head)
  */
 static void free_ioctx(struct kioctx *ctx)
 {
+       struct aio_ring_info *info = &ctx->ring_info;
+       struct aio_ring *ring;
        struct io_event res;
        struct kiocb *req;
+       unsigned head, avail;
 
        spin_lock_irq(&ctx->ctx_lock);
 
@@ -299,7 +296,21 @@ static void free_ioctx(struct kioctx *ctx)
 
        spin_unlock_irq(&ctx->ctx_lock);
 
-       wait_event(ctx->wait, !atomic_read(&ctx->reqs_active));
+       ring = kmap_atomic(info->ring_pages[0]);
+       head = ring->head;
+       kunmap_atomic(ring);
+
+       while (atomic_read(&ctx->reqs_active) > 0) {
+               wait_event(ctx->wait, head != info->tail);
+
+               avail = (head < info->tail ? info->tail : info->nr) - head;
+
+               atomic_sub(avail, &ctx->reqs_active);
+               head += avail;
+               head %= info->nr;
+       }
+
+       WARN_ON(atomic_read(&ctx->reqs_active) < 0);
 
        aio_free_ring(ctx);
 
@@ -548,7 +559,6 @@ static int kiocb_batch_refill(struct kioctx *ctx, struct kiocb_batch *batch)
        unsigned short allocated, to_alloc;
        long avail;
        struct kiocb *req, *n;
-       struct aio_ring *ring;
 
        to_alloc = min(batch->count, KIOCB_BATCH_SIZE);
        for (allocated = 0; allocated < to_alloc; allocated++) {
@@ -563,9 +573,8 @@ static int kiocb_batch_refill(struct kioctx *ctx, struct kiocb_batch *batch)
                goto out;
 
        spin_lock_irq(&ctx->ctx_lock);
-       ring = kmap_atomic(ctx->ring_info.ring_pages[0]);
 
-       avail = aio_ring_avail(&ctx->ring_info, ring) - atomic_read(&ctx->reqs_active);
+       avail = ctx->ring_info.nr - atomic_read(&ctx->reqs_active);
        BUG_ON(avail < 0);
        if (avail < allocated) {
                /* Trim back the number of requests. */
@@ -580,7 +589,6 @@ static int kiocb_batch_refill(struct kioctx *ctx, struct kiocb_batch *batch)
        batch->count -= allocated;
        atomic_add(allocated, &ctx->reqs_active);
 
-       kunmap_atomic(ring);
        spin_unlock_irq(&ctx->ctx_lock);
 
 out:
@@ -687,8 +695,11 @@ void aio_complete(struct kiocb *iocb, long res, long res2)
         * when the event got cancelled.
         */
        if (unlikely(xchg(&iocb->ki_cancel,
-                         KIOCB_CANCELLED) == KIOCB_CANCELLED))
+                         KIOCB_CANCELLED) == KIOCB_CANCELLED)) {
+               atomic_dec(&ctx->reqs_active);
+               /* Still need the wake_up in case free_ioctx is waiting */
                goto put_rq;
+       }
 
        /*
         * Add a completion event to the ring buffer. Must be done holding
@@ -745,7 +756,6 @@ void aio_complete(struct kiocb *iocb, long res, long res2)
 put_rq:
        /* everything turned out well, dispose of the aiocb. */
        aio_put_req(iocb);
-       atomic_dec(&ctx->reqs_active);
 
        /*
         * We have to order our ring_info tail store above and test
@@ -826,6 +836,8 @@ static int aio_read_events_ring(struct kioctx *ctx,
        flush_dcache_page(info->ring_pages[0]);
 
        pr_debug("%d  h%u t%u\n", ret, head, info->tail);
+
+       atomic_sub(ret, &ctx->reqs_active);
 out:
        mutex_unlock(&info->ring_lock);