aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2018-03-14 15:10:17 -0400
committerTejun Heo <tj@kernel.org>2018-03-14 15:10:17 -0400
commitd0264c01e7587001a8c4608a5d1818dba9a4c11a (patch)
treefe5161b426a3c3071a9b3b5ee590af2ddd03e0d1
parenta6d7cff472eea87d96899a20fa718d2bab7109f3 (diff)
fs/aio: Use RCU accessors for kioctx_table->table[]
While converting ioctx index from a list to a table, db446a08c23d ("aio: convert the ioctx list to table lookup v3") missed tagging kioctx_table->table[] as an array of RCU pointers and using the appropriate RCU accessors. This introduces a small window in the lookup path where init and access may race. Mark kioctx_table->table[] with __rcu and use the approriate RCU accessors when using the field. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: Jann Horn <jannh@google.com> Fixes: db446a08c23d ("aio: convert the ioctx list to table lookup v3") Cc: Benjamin LaHaise <bcrl@kvack.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: stable@vger.kernel.org # v3.12+
-rw-r--r--fs/aio.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/fs/aio.c b/fs/aio.c
index eb2e0cfbe2d2..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 {
@@ -330,7 +330,7 @@ static int aio_ring_mremap(struct vm_area_struct *vma)
330 for (i = 0; i < table->nr; i++) { 330 for (i = 0; i < table->nr; i++) {
331 struct kioctx *ctx; 331 struct kioctx *ctx;
332 332
333 ctx = table->table[i]; 333 ctx = rcu_dereference(table->table[i]);
334 if (ctx && ctx->aio_ring_file == file) { 334 if (ctx && ctx->aio_ring_file == file) {
335 if (!atomic_read(&ctx->dead)) { 335 if (!atomic_read(&ctx->dead)) {
336 ctx->user_id = ctx->mmap_base = vma->vm_start; 336 ctx->user_id = ctx->mmap_base = vma->vm_start;
@@ -666,9 +666,9 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
666 while (1) { 666 while (1) {
667 if (table) 667 if (table)
668 for (i = 0; i < table->nr; i++) 668 for (i = 0; i < table->nr; i++)
669 if (!table->table[i]) { 669 if (!rcu_access_pointer(table->table[i])) {
670 ctx->id = i; 670 ctx->id = i;
671 table->table[i] = ctx; 671 rcu_assign_pointer(table->table[i], ctx);
672 spin_unlock(&mm->ioctx_lock); 672 spin_unlock(&mm->ioctx_lock);
673 673
674 /* While kioctx setup is in progress, 674 /* While kioctx setup is in progress,
@@ -849,8 +849,8 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx,
849 } 849 }
850 850
851 table = rcu_dereference_raw(mm->ioctx_table); 851 table = rcu_dereference_raw(mm->ioctx_table);
852 WARN_ON(ctx != table->table[ctx->id]); 852 WARN_ON(ctx != rcu_access_pointer(table->table[ctx->id]));
853 table->table[ctx->id] = NULL; 853 RCU_INIT_POINTER(table->table[ctx->id], NULL);
854 spin_unlock(&mm->ioctx_lock); 854 spin_unlock(&mm->ioctx_lock);
855 855
856 /* free_ioctx_reqs() will do the necessary RCU synchronization */ 856 /* free_ioctx_reqs() will do the necessary RCU synchronization */
@@ -895,7 +895,8 @@ void exit_aio(struct mm_struct *mm)
895 895
896 skipped = 0; 896 skipped = 0;
897 for (i = 0; i < table->nr; ++i) { 897 for (i = 0; i < table->nr; ++i) {
898 struct kioctx *ctx = table->table[i]; 898 struct kioctx *ctx =
899 rcu_dereference_protected(table->table[i], true);
899 900
900 if (!ctx) { 901 if (!ctx) {
901 skipped++; 902 skipped++;
@@ -1084,7 +1085,7 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id)
1084 if (!table || id >= table->nr) 1085 if (!table || id >= table->nr)
1085 goto out; 1086 goto out;
1086 1087
1087 ctx = table->table[id]; 1088 ctx = rcu_dereference(table->table[id]);
1088 if (ctx && ctx->user_id == ctx_id) { 1089 if (ctx && ctx->user_id == ctx_id) {
1089 percpu_ref_get(&ctx->users); 1090 percpu_ref_get(&ctx->users);
1090 ret = ctx; 1091 ret = ctx;