From: Al Viro <viro@xxxxxxxxxxxxxxxxxx> We want iocb_put() happening on errors, to balance the extra reference we'd taken. As it is, we end up with a leak. The rules should be * error: iocb_put() to deal with the extra ref, return error, let the caller do another iocb_put(). * async: iocb_put() to deal with the extra ref, return 0. * no error, event present immediately: aio_poll_complete() to report it, iocb_put() to deal with the extra ref, return 0. Signed-off-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx> --- fs/aio.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/fs/aio.c b/fs/aio.c index 3a8b894378e0..22b288997441 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -1724,6 +1724,7 @@ static ssize_t aio_poll(struct aio_kiocb *aiocb, const struct iocb *iocb) struct kioctx *ctx = aiocb->ki_ctx; struct poll_iocb *req = &aiocb->poll; struct aio_poll_table apt; + bool async = false; __poll_t mask; /* reject any unknown events outside the normal event mask. */ @@ -1760,30 +1761,26 @@ static ssize_t aio_poll(struct aio_kiocb *aiocb, const struct iocb *iocb) spin_lock_irq(&ctx->ctx_lock); spin_lock(&req->head->lock); - if (req->woken) { - /* wake_up context handles the rest */ - mask = 0; + if (req->woken) { /* already taken up by aio_poll_wake() */ + async = true; apt.error = 0; - } else if (mask || apt.error) { - /* if we get an error or a mask we are done */ - WARN_ON_ONCE(list_empty(&req->wait.entry)); - list_del_init(&req->wait.entry); - } else { - /* actually waiting for an event */ + } else if (!mask && !apt.error) { /* actually waiting for an event */ list_add_tail(&aiocb->ki_list, &ctx->active_reqs); aiocb->ki_cancel = aio_poll_cancel; + async = true; + } else { /* if we get an error or a mask we are done */ + WARN_ON_ONCE(list_empty(&req->wait.entry)); + list_del_init(&req->wait.entry); + /* no wakeup in the future either; aiocb is ours to dispose of */ } spin_unlock(&req->head->lock); spin_unlock_irq(&ctx->ctx_lock); out: - if (unlikely(apt.error)) - return apt.error; - - if (mask) + if (async && !apt.error) aio_poll_complete(aiocb, mask); iocb_put(aiocb); - return 0; + return apt.error; } static int __io_submit_one(struct kioctx *ctx, const struct iocb *iocb, -- 2.11.0