From: u=Sébastien Dugué Clean up the notification path and fixes a possible release on a task ref that was not taken in aio_setup_sigevent(). Signed-off-by: Sébastien Dugué Cc: Laurent Vivier Cc: Bharata B Rao Cc: Christoph Hellwig Cc: Suparna Bhattacharya Cc: Zach Brown Cc: Oleg Nesterov Cc: Badari Pulavarty Cc: Benjamin LaHaise Cc: Jean Pierre Dion Signed-off-by: Andrew Morton --- fs/aio.c | 15 ++++++++++----- 1 files changed, 10 insertions(+), 5 deletions(-) diff -puN fs/aio.c~aio-completion-signal-notification-fixes-and-cleanups fs/aio.c --- a/fs/aio.c~aio-completion-signal-notification-fixes-and-cleanups +++ a/fs/aio.c @@ -468,8 +468,7 @@ static inline void really_put_req(struct kfree(req->ki_iovec); /* Release task ref */ - if (req->ki_notify.notify == SIGEV_THREAD_ID || - req->ki_notify.notify == SIGEV_SIGNAL) + if (req->ki_notify.notify != SIGEV_NONE) put_task_struct(req->ki_notify.target); kmem_cache_free(kiocb_cachep, req); @@ -969,8 +968,14 @@ static long aio_setup_sigevent(struct ai rcu_read_lock(); target = sigevent_find_task(&event); - if (unlikely(!target)) + if (unlikely(!target)) { + /* + * Revert notify to SIGEV_NONE so that really_put_req() + * knows that no ref has been taken on a task. + */ + notify->notify = SIGEV_NONE; goto out_unlock; + } /* * At this point, we know that notify is either SIGEV_SIGNAL or @@ -995,7 +1000,7 @@ static long aio_setup_sigevent(struct ai return 0; out_unlock: - read_unlock(&tasklist_lock); + rcu_read_unlock(); return -EINVAL; } @@ -1691,7 +1696,7 @@ int fastcall io_submit_one(struct kioctx (struct sigevent __user *)(unsigned long) iocb->aio_sigeventp); if (ret) - goto out_put_req; + goto out_sigqfree; } ret = aio_setup_iocb(req); _