diff options
author | Benjamin LaHaise <bcrl@kvack.org> | 2013-08-05 13:21:43 -0400 |
---|---|---|
committer | Benjamin LaHaise <bcrl@kvack.org> | 2013-08-05 13:21:43 -0400 |
commit | da90382c2ec367aac88ff6aa76afb659ee0e4235 (patch) | |
tree | b0fd73537a51048b61a23732559100371d777b07 /fs | |
parent | 6878ea72a5d1aa6caae86449975a50b7fe9abed5 (diff) |
aio: fix error handling and rcu usage in "convert the ioctx list to table lookup v3"
In the patch "aio: convert the ioctx list to table lookup v3", incorrect
handling in the ioctx_alloc() error path was introduced that lead to an
ioctx being added via ioctx_add_table() while freed when the ioctx_alloc()
call returned -EAGAIN due to hitting the aio_max_nr limit. Fix this by
only calling ioctx_add_table() as the last step in ioctx_alloc().
Also, several unnecessary rcu_dereference() calls were added that lead to
RCU warnings where the system was already protected by a spin lock for
accessing mm->ioctx_table.
Signed-off-by: Benjamin LaHaise <bcrl@kvack.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/aio.c | 17 |
1 files changed, 9 insertions, 8 deletions
@@ -475,7 +475,7 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm) | |||
475 | struct aio_ring *ring; | 475 | struct aio_ring *ring; |
476 | 476 | ||
477 | spin_lock(&mm->ioctx_lock); | 477 | spin_lock(&mm->ioctx_lock); |
478 | table = rcu_dereference(mm->ioctx_table); | 478 | table = mm->ioctx_table; |
479 | 479 | ||
480 | while (1) { | 480 | while (1) { |
481 | if (table) | 481 | if (table) |
@@ -503,7 +503,7 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm) | |||
503 | table->nr = new_nr; | 503 | table->nr = new_nr; |
504 | 504 | ||
505 | spin_lock(&mm->ioctx_lock); | 505 | spin_lock(&mm->ioctx_lock); |
506 | old = rcu_dereference(mm->ioctx_table); | 506 | old = mm->ioctx_table; |
507 | 507 | ||
508 | if (!old) { | 508 | if (!old) { |
509 | rcu_assign_pointer(mm->ioctx_table, table); | 509 | rcu_assign_pointer(mm->ioctx_table, table); |
@@ -579,10 +579,6 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) | |||
579 | if (ctx->req_batch < 1) | 579 | if (ctx->req_batch < 1) |
580 | ctx->req_batch = 1; | 580 | ctx->req_batch = 1; |
581 | 581 | ||
582 | err = ioctx_add_table(ctx, mm); | ||
583 | if (err) | ||
584 | goto out_cleanup_noerr; | ||
585 | |||
586 | /* limit the number of system wide aios */ | 582 | /* limit the number of system wide aios */ |
587 | spin_lock(&aio_nr_lock); | 583 | spin_lock(&aio_nr_lock); |
588 | if (aio_nr + nr_events > (aio_max_nr * 2UL) || | 584 | if (aio_nr + nr_events > (aio_max_nr * 2UL) || |
@@ -595,13 +591,18 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) | |||
595 | 591 | ||
596 | percpu_ref_get(&ctx->users); /* io_setup() will drop this ref */ | 592 | percpu_ref_get(&ctx->users); /* io_setup() will drop this ref */ |
597 | 593 | ||
594 | err = ioctx_add_table(ctx, mm); | ||
595 | if (err) | ||
596 | goto out_cleanup_put; | ||
597 | |||
598 | pr_debug("allocated ioctx %p[%ld]: mm=%p mask=0x%x\n", | 598 | pr_debug("allocated ioctx %p[%ld]: mm=%p mask=0x%x\n", |
599 | ctx, ctx->user_id, mm, ctx->nr_events); | 599 | ctx, ctx->user_id, mm, ctx->nr_events); |
600 | return ctx; | 600 | return ctx; |
601 | 601 | ||
602 | out_cleanup_put: | ||
603 | percpu_ref_put(&ctx->users); | ||
602 | out_cleanup: | 604 | out_cleanup: |
603 | err = -EAGAIN; | 605 | err = -EAGAIN; |
604 | out_cleanup_noerr: | ||
605 | aio_free_ring(ctx); | 606 | aio_free_ring(ctx); |
606 | out_freepcpu: | 607 | out_freepcpu: |
607 | free_percpu(ctx->cpu); | 608 | free_percpu(ctx->cpu); |
@@ -626,7 +627,7 @@ static void kill_ioctx(struct mm_struct *mm, struct kioctx *ctx) | |||
626 | struct kioctx_table *table; | 627 | struct kioctx_table *table; |
627 | 628 | ||
628 | spin_lock(&mm->ioctx_lock); | 629 | spin_lock(&mm->ioctx_lock); |
629 | table = rcu_dereference(mm->ioctx_table); | 630 | table = mm->ioctx_table; |
630 | 631 | ||
631 | WARN_ON(ctx != table->table[ctx->id]); | 632 | WARN_ON(ctx != table->table[ctx->id]); |
632 | table->table[ctx->id] = NULL; | 633 | table->table[ctx->id] = NULL; |