aio: fix io_setup/io_destroy race
[pandora-kernel.git] / fs / aio.c
index 78c514c..f6578cb 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -273,7 +273,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
        mm = ctx->mm = current->mm;
        atomic_inc(&mm->mm_count);
 
-       atomic_set(&ctx->users, 1);
+       atomic_set(&ctx->users, 2);
        spin_lock_init(&ctx->ctx_lock);
        spin_lock_init(&ctx->ring_info.ring_lock);
        init_waitqueue_head(&ctx->wait);
@@ -476,14 +476,23 @@ static void kiocb_batch_init(struct kiocb_batch *batch, long total)
        batch->count = total;
 }
 
-static void kiocb_batch_free(struct kiocb_batch *batch)
+static void kiocb_batch_free(struct kioctx *ctx, struct kiocb_batch *batch)
 {
        struct kiocb *req, *n;
 
+       if (list_empty(&batch->head))
+               return;
+
+       spin_lock_irq(&ctx->ctx_lock);
        list_for_each_entry_safe(req, n, &batch->head, ki_batch) {
                list_del(&req->ki_batch);
+               list_del(&req->ki_list);
                kmem_cache_free(kiocb_cachep, req);
+               ctx->reqs_active--;
        }
+       if (unlikely(!ctx->reqs_active && ctx->dead))
+               wake_up_all(&ctx->wait);
+       spin_unlock_irq(&ctx->ctx_lock);
 }
 
 /*
@@ -1329,10 +1338,10 @@ SYSCALL_DEFINE2(io_setup, unsigned, nr_events, aio_context_t __user *, ctxp)
        ret = PTR_ERR(ioctx);
        if (!IS_ERR(ioctx)) {
                ret = put_user(ioctx->user_id, ctxp);
-               if (!ret)
+               if (!ret) {
+                       put_ioctx(ioctx);
                        return 0;
-
-               get_ioctx(ioctx); /* io_destroy() expects us to hold a ref */
+               }
                io_destroy(ioctx);
        }
 
@@ -1742,7 +1751,7 @@ long do_io_submit(aio_context_t ctx_id, long nr,
        }
        blk_finish_plug(&plug);
 
-       kiocb_batch_free(&batch);
+       kiocb_batch_free(ctx, &batch);
        put_ioctx(ctx);
        return i ? i : ret;
 }