aboutsummaryrefslogtreecommitdiffstats
path: root/fs/aio.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/aio.c')
-rw-r--r--fs/aio.c44
1 files changed, 30 insertions, 14 deletions
diff --git a/fs/aio.c b/fs/aio.c
index a062d75109cb..6bcd3fb5265a 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -68,9 +68,9 @@ struct aio_ring {
68#define AIO_RING_PAGES 8 68#define AIO_RING_PAGES 8
69 69
70struct kioctx_table { 70struct kioctx_table {
71 struct rcu_head rcu; 71 struct rcu_head rcu;
72 unsigned nr; 72 unsigned nr;
73 struct kioctx *table[]; 73 struct kioctx __rcu *table[];
74}; 74};
75 75
76struct kioctx_cpu { 76struct kioctx_cpu {
@@ -115,7 +115,8 @@ struct kioctx {
115 struct page **ring_pages; 115 struct page **ring_pages;
116 long nr_pages; 116 long nr_pages;
117 117
118 struct work_struct free_work; 118 struct rcu_head free_rcu;
119 struct work_struct free_work; /* see free_ioctx() */
119 120
120 /* 121 /*
121 * signals when all in-flight requests are done 122 * signals when all in-flight requests are done
@@ -329,7 +330,7 @@ static int aio_ring_mremap(struct vm_area_struct *vma)
329 for (i = 0; i < table->nr; i++) { 330 for (i = 0; i < table->nr; i++) {
330 struct kioctx *ctx; 331 struct kioctx *ctx;
331 332
332 ctx = table->table[i]; 333 ctx = rcu_dereference(table->table[i]);
333 if (ctx && ctx->aio_ring_file == file) { 334 if (ctx && ctx->aio_ring_file == file) {
334 if (!atomic_read(&ctx->dead)) { 335 if (!atomic_read(&ctx->dead)) {
335 ctx->user_id = ctx->mmap_base = vma->vm_start; 336 ctx->user_id = ctx->mmap_base = vma->vm_start;
@@ -588,6 +589,12 @@ static int kiocb_cancel(struct aio_kiocb *kiocb)
588 return cancel(&kiocb->common); 589 return cancel(&kiocb->common);
589} 590}
590 591
592/*
593 * free_ioctx() should be RCU delayed to synchronize against the RCU
594 * protected lookup_ioctx() and also needs process context to call
595 * aio_free_ring(), so the double bouncing through kioctx->free_rcu and
596 * ->free_work.
597 */
591static void free_ioctx(struct work_struct *work) 598static void free_ioctx(struct work_struct *work)
592{ 599{
593 struct kioctx *ctx = container_of(work, struct kioctx, free_work); 600 struct kioctx *ctx = container_of(work, struct kioctx, free_work);
@@ -601,6 +608,14 @@ static void free_ioctx(struct work_struct *work)
601 kmem_cache_free(kioctx_cachep, ctx); 608 kmem_cache_free(kioctx_cachep, ctx);
602} 609}
603 610
611static void free_ioctx_rcufn(struct rcu_head *head)
612{
613 struct kioctx *ctx = container_of(head, struct kioctx, free_rcu);
614
615 INIT_WORK(&ctx->free_work, free_ioctx);
616 schedule_work(&ctx->free_work);
617}
618
604static void free_ioctx_reqs(struct percpu_ref *ref) 619static void free_ioctx_reqs(struct percpu_ref *ref)
605{ 620{
606 struct kioctx *ctx = container_of(ref, struct kioctx, reqs); 621 struct kioctx *ctx = container_of(ref, struct kioctx, reqs);
@@ -609,8 +624,8 @@ static void free_ioctx_reqs(struct percpu_ref *ref)
609 if (ctx->rq_wait && atomic_dec_and_test(&ctx->rq_wait->count)) 624 if (ctx->rq_wait && atomic_dec_and_test(&ctx->rq_wait->count))
610 complete(&ctx->rq_wait->comp); 625 complete(&ctx->rq_wait->comp);
611 626
612 INIT_WORK(&ctx->free_work, free_ioctx); 627 /* Synchronize against RCU protected table->table[] dereferences */
613 schedule_work(&ctx->free_work); 628 call_rcu(&ctx->free_rcu, free_ioctx_rcufn);
614} 629}
615 630
616/* 631/*
@@ -651,9 +666,9 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
651 while (1) { 666 while (1) {
652 if (table) 667 if (table)
653 for (i = 0; i < table->nr; i++) 668 for (i = 0; i < table->nr; i++)
654 if (!table->table[i]) { 669 if (!rcu_access_pointer(table->table[i])) {
655 ctx->id = i; 670 ctx->id = i;
656 table->table[i] = ctx; 671 rcu_assign_pointer(table->table[i], ctx);
657 spin_unlock(&mm->ioctx_lock); 672 spin_unlock(&mm->ioctx_lock);
658 673
659 /* While kioctx setup is in progress, 674 /* While kioctx setup is in progress,
@@ -834,11 +849,11 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx,
834 } 849 }
835 850
836 table = rcu_dereference_raw(mm->ioctx_table); 851 table = rcu_dereference_raw(mm->ioctx_table);
837 WARN_ON(ctx != table->table[ctx->id]); 852 WARN_ON(ctx != rcu_access_pointer(table->table[ctx->id]));
838 table->table[ctx->id] = NULL; 853 RCU_INIT_POINTER(table->table[ctx->id], NULL);
839 spin_unlock(&mm->ioctx_lock); 854 spin_unlock(&mm->ioctx_lock);
840 855
841 /* percpu_ref_kill() will do the necessary call_rcu() */ 856 /* free_ioctx_reqs() will do the necessary RCU synchronization */
842 wake_up_all(&ctx->wait); 857 wake_up_all(&ctx->wait);
843 858
844 /* 859 /*
@@ -880,7 +895,8 @@ void exit_aio(struct mm_struct *mm)
880 895
881 skipped = 0; 896 skipped = 0;
882 for (i = 0; i < table->nr; ++i) { 897 for (i = 0; i < table->nr; ++i) {
883 struct kioctx *ctx = table->table[i]; 898 struct kioctx *ctx =
899 rcu_dereference_protected(table->table[i], true);
884 900
885 if (!ctx) { 901 if (!ctx) {
886 skipped++; 902 skipped++;
@@ -1069,7 +1085,7 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id)
1069 if (!table || id >= table->nr) 1085 if (!table || id >= table->nr)
1070 goto out; 1086 goto out;
1071 1087
1072 ctx = table->table[id]; 1088 ctx = rcu_dereference(table->table[id]);
1073 if (ctx && ctx->user_id == ctx_id) { 1089 if (ctx && ctx->user_id == ctx_id) {
1074 percpu_ref_get(&ctx->users); 1090 percpu_ref_get(&ctx->users);
1075 ret = ctx; 1091 ret = ctx;