aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorKent Overstreet <koverstreet@google.com>2013-06-12 17:04:59 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-06-12 19:29:46 -0400
commit4fcc712f5c48b1e32cdbf9b9cfba42a27b2e3160 (patch)
tree56ffa400b048d639e67b3c239a23d1e09a86ae76 /fs
parentbba00e59107275faa615573c44eb0a513a1220a6 (diff)
aio: fix io_destroy() regression by using call_rcu()
There was a regression introduced by 36f5588905c1 ("aio: refcounting cleanup"), reported by Jens Axboe - the refcounting cleanup switched to using RCU in the shutdown path, but the synchronize_rcu() was done in the context of the io_destroy() syscall greatly increasing the time it could block. This patch switches it to call_rcu() and makes shutdown asynchronous (more asynchronous than it was originally; before the refcount changes io_destroy() would still wait on pending kiocbs). Note that there's a global quota on the max outstanding kiocbs, and that quota must be manipulated synchronously; otherwise io_setup() could return -EAGAIN when there isn't quota available, and userspace won't have any way of waiting until shutdown of the old kioctxs has finished (besides busy looping). So we release our quota before kioctx shutdown has finished, which should be fine since the quota never corresponded to anything real anyways. Signed-off-by: Kent Overstreet <koverstreet@google.com> Cc: Zach Brown <zab@redhat.com> Cc: Felipe Balbi <balbi@ti.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Mark Fasheh <mfasheh@suse.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Rusty Russell <rusty@rustcorp.com.au> Reported-by: Jens Axboe <axboe@kernel.dk> Tested-by: Jens Axboe <axboe@kernel.dk> Cc: Asai Thambi S P <asamymuthupa@micron.com> Cc: Selvan Mani <smani@micron.com> Cc: Sam Bradshaw <sbradshaw@micron.com> Cc: Jeff Moyer <jmoyer@redhat.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Benjamin LaHaise <bcrl@kvack.org> Tested-by: Benjamin LaHaise <bcrl@kvack.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/aio.c36
1 files changed, 16 insertions, 20 deletions
diff --git a/fs/aio.c b/fs/aio.c
index 7fe5bdee1630..2bbcacf74d0c 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -141,9 +141,6 @@ static void aio_free_ring(struct kioctx *ctx)
141 for (i = 0; i < ctx->nr_pages; i++) 141 for (i = 0; i < ctx->nr_pages; i++)
142 put_page(ctx->ring_pages[i]); 142 put_page(ctx->ring_pages[i]);
143 143
144 if (ctx->mmap_size)
145 vm_munmap(ctx->mmap_base, ctx->mmap_size);
146
147 if (ctx->ring_pages && ctx->ring_pages != ctx->internal_pages) 144 if (ctx->ring_pages && ctx->ring_pages != ctx->internal_pages)
148 kfree(ctx->ring_pages); 145 kfree(ctx->ring_pages);
149} 146}
@@ -322,11 +319,6 @@ static void free_ioctx(struct kioctx *ctx)
322 319
323 aio_free_ring(ctx); 320 aio_free_ring(ctx);
324 321
325 spin_lock(&aio_nr_lock);
326 BUG_ON(aio_nr - ctx->max_reqs > aio_nr);
327 aio_nr -= ctx->max_reqs;
328 spin_unlock(&aio_nr_lock);
329
330 pr_debug("freeing %p\n", ctx); 322 pr_debug("freeing %p\n", ctx);
331 323
332 /* 324 /*
@@ -435,17 +427,24 @@ static void kill_ioctx(struct kioctx *ctx)
435{ 427{
436 if (!atomic_xchg(&ctx->dead, 1)) { 428 if (!atomic_xchg(&ctx->dead, 1)) {
437 hlist_del_rcu(&ctx->list); 429 hlist_del_rcu(&ctx->list);
438 /* Between hlist_del_rcu() and dropping the initial ref */
439 synchronize_rcu();
440 430
441 /* 431 /*
442 * We can't punt to workqueue here because put_ioctx() -> 432 * It'd be more correct to do this in free_ioctx(), after all
443 * free_ioctx() will unmap the ringbuffer, and that has to be 433 * the outstanding kiocbs have finished - but by then io_destroy
444 * done in the original process's context. kill_ioctx_rcu/work() 434 * has already returned, so io_setup() could potentially return
445 * exist for exit_aio(), as in that path free_ioctx() won't do 435 * -EAGAIN with no ioctxs actually in use (as far as userspace
446 * the unmap. 436 * could tell).
447 */ 437 */
448 kill_ioctx_work(&ctx->rcu_work); 438 spin_lock(&aio_nr_lock);
439 BUG_ON(aio_nr - ctx->max_reqs > aio_nr);
440 aio_nr -= ctx->max_reqs;
441 spin_unlock(&aio_nr_lock);
442
443 if (ctx->mmap_size)
444 vm_munmap(ctx->mmap_base, ctx->mmap_size);
445
446 /* Between hlist_del_rcu() and dropping the initial ref */
447 call_rcu(&ctx->rcu_head, kill_ioctx_rcu);
449 } 448 }
450} 449}
451 450
@@ -495,10 +494,7 @@ void exit_aio(struct mm_struct *mm)
495 */ 494 */
496 ctx->mmap_size = 0; 495 ctx->mmap_size = 0;
497 496
498 if (!atomic_xchg(&ctx->dead, 1)) { 497 kill_ioctx(ctx);
499 hlist_del_rcu(&ctx->list);
500 call_rcu(&ctx->rcu_head, kill_ioctx_rcu);
501 }
502 } 498 }
503} 499}
504 500