diff options
-rw-r--r-- | fs/aio.c | 17 |
1 files changed, 17 insertions, 0 deletions
@@ -1642,6 +1642,23 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
1642 | goto out_put_req; | 1642 | goto out_put_req; |
1643 | 1643 | ||
1644 | spin_lock_irq(&ctx->ctx_lock); | 1644 | spin_lock_irq(&ctx->ctx_lock); |
1645 | /* | ||
1646 | * We could have raced with io_destroy() and are currently holding a | ||
1647 | * reference to ctx which should be destroyed. We cannot submit IO | ||
1648 | * since ctx gets freed as soon as io_submit() puts its reference. The | ||
1649 | * check here is reliable: io_destroy() sets ctx->dead before waiting | ||
1650 | * for outstanding IO and the barrier between these two is realized by | ||
1651 | * unlock of mm->ioctx_lock and lock of ctx->ctx_lock. Analogously we | ||
1652 | * increment ctx->reqs_active before checking for ctx->dead and the | ||
1653 | * barrier is realized by unlock and lock of ctx->ctx_lock. Thus if we | ||
1654 | * don't see ctx->dead set here, io_destroy() waits for our IO to | ||
1655 | * finish. | ||
1656 | */ | ||
1657 | if (ctx->dead) { | ||
1658 | spin_unlock_irq(&ctx->ctx_lock); | ||
1659 | ret = -EINVAL; | ||
1660 | goto out_put_req; | ||
1661 | } | ||
1645 | aio_run_iocb(req); | 1662 | aio_run_iocb(req); |
1646 | if (!list_empty(&ctx->run_list)) { | 1663 | if (!list_empty(&ctx->run_list)) { |
1647 | /* drain the run list */ | 1664 | /* drain the run list */ |