diff options
author | Gleb Natapov <gleb@redhat.com> | 2012-01-08 10:07:28 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-13 23:39:44 -0500 |
commit | 69e4747ee9727d660b88d7e1efe0f4afcb35db1b (patch) | |
tree | 2dde4642ad0dba19688b664c4397c61cf9ebce25 /fs/aio.c | |
parent | a3301b751b19f0efbafddc4034f8e7ce6bf3007b (diff) |
Unused iocbs in a batch should not be accounted as active.
Since commit 080d676de095 ("aio: allocate kiocbs in batches") iocbs are
allocated in a batch during processing of first iocbs. All iocbs in a
batch are automatically added to ctx->active_reqs list and accounted in
ctx->reqs_active.
If one (not the last one) of iocbs submitted by an user fails, further
iocbs are not processed, but they are still present in ctx->active_reqs
and accounted in ctx->reqs_active. This causes process to stuck in a D
state in wait_for_all_aios() on exit since ctx->reqs_active will never
go down to zero. Furthermore since kiocb_batch_free() frees iocb
without removing it from active_reqs list the list become corrupted
which may cause oops.
Fix this by removing iocb from ctx->active_reqs and updating
ctx->reqs_active in kiocb_batch_free().
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Reviewed-by: Jeff Moyer <jmoyer@redhat.com>
Cc: stable@kernel.org # 3.2
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/aio.c')
-rw-r--r-- | fs/aio.c | 11 |
1 files changed, 9 insertions, 2 deletions
@@ -476,14 +476,21 @@ static void kiocb_batch_init(struct kiocb_batch *batch, long total) | |||
476 | batch->count = total; | 476 | batch->count = total; |
477 | } | 477 | } |
478 | 478 | ||
479 | static void kiocb_batch_free(struct kiocb_batch *batch) | 479 | static void kiocb_batch_free(struct kioctx *ctx, struct kiocb_batch *batch) |
480 | { | 480 | { |
481 | struct kiocb *req, *n; | 481 | struct kiocb *req, *n; |
482 | 482 | ||
483 | if (list_empty(&batch->head)) | ||
484 | return; | ||
485 | |||
486 | spin_lock_irq(&ctx->ctx_lock); | ||
483 | list_for_each_entry_safe(req, n, &batch->head, ki_batch) { | 487 | list_for_each_entry_safe(req, n, &batch->head, ki_batch) { |
484 | list_del(&req->ki_batch); | 488 | list_del(&req->ki_batch); |
489 | list_del(&req->ki_list); | ||
485 | kmem_cache_free(kiocb_cachep, req); | 490 | kmem_cache_free(kiocb_cachep, req); |
491 | ctx->reqs_active--; | ||
486 | } | 492 | } |
493 | spin_unlock_irq(&ctx->ctx_lock); | ||
487 | } | 494 | } |
488 | 495 | ||
489 | /* | 496 | /* |
@@ -1742,7 +1749,7 @@ long do_io_submit(aio_context_t ctx_id, long nr, | |||
1742 | } | 1749 | } |
1743 | blk_finish_plug(&plug); | 1750 | blk_finish_plug(&plug); |
1744 | 1751 | ||
1745 | kiocb_batch_free(&batch); | 1752 | kiocb_batch_free(ctx, &batch); |
1746 | put_ioctx(ctx); | 1753 | put_ioctx(ctx); |
1747 | return i ? i : ret; | 1754 | return i ? i : ret; |
1748 | } | 1755 | } |