diff options
author | Mateusz Guzik <mguzik@redhat.com> | 2013-12-05 11:09:02 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-12-08 07:29:27 -0800 |
commit | f8715e7d2a096cedd1c5ef4768deae7126659dcf (patch) | |
tree | a013b91b5bd6f58d7adeea9b96bf4ce6b3ef7645 | |
parent | 604ae797e7cd1eca7897eac555961a5a25a9bde5 (diff) |
aio: restore locking of ioctx list on removal
Commit 36f5588905c10a8c4568a210d601fe8c3c27e0f0
"aio: refcounting cleanup" resulted in ioctx_lock not being held
during ctx removal, leaving the list susceptible to corruptions.
In mainline kernel the issue went away as a side effect of
db446a08c23d5475e6b08c87acca79ebb20f283c "aio: convert the ioctx list to
table lookup v3".
Fix the problem by restoring appropriate locking.
Signed-off-by: Mateusz Guzik <mguzik@redhat.com>
Reported-by: Eryu Guan <eguan@redhat.com>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Kent Overstreet <kmo@daterainc.com>
Acked-by: Benjamin LaHaise <bcrl@kvack.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | fs/aio.c | 10 |
1 files changed, 6 insertions, 4 deletions
@@ -423,10 +423,12 @@ static void kill_ioctx_rcu(struct rcu_head *head) * when the processes owning a context have all exited to encourage * the rapid destruction of the kioctx. */ -static void kill_ioctx(struct kioctx *ctx) +static void kill_ioctx(struct mm_struct *mm, struct kioctx *ctx) { if (!atomic_xchg(&ctx->dead, 1)) { + spin_lock(&mm->ioctx_lock); hlist_del_rcu(&ctx->list); + spin_unlock(&mm->ioctx_lock); /* * It'd be more correct to do this in free_ioctx(), after all @@ -494,7 +496,7 @@ void exit_aio(struct mm_struct *mm) */ ctx->mmap_size = 0; - kill_ioctx(ctx); + kill_ioctx(mm, ctx); } } @@ -852,7 +854,7 @@ SYSCALL_DEFINE2(io_setup, unsigned, nr_events, aio_context_t __user *, ctxp) if (!IS_ERR(ioctx)) { ret = put_user(ioctx->user_id, ctxp); if (ret) - kill_ioctx(ioctx); + kill_ioctx(current->mm, ioctx); put_ioctx(ioctx); } @@ -870,7 +872,7 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx) { struct kioctx *ioctx = lookup_ioctx(ctx); if (likely(NULL != ioctx)) { - kill_ioctx(ioctx); + kill_ioctx(current->mm, ioctx); put_ioctx(ioctx); return 0; } |