diff options
Diffstat (limited to 'fs/aio.c')
-rw-r--r-- | fs/aio.c | 13 |
1 files changed, 12 insertions, 1 deletions
@@ -793,6 +793,8 @@ void exit_aio(struct mm_struct *mm) | |||
793 | 793 | ||
794 | for (i = 0; i < table->nr; ++i) { | 794 | for (i = 0; i < table->nr; ++i) { |
795 | struct kioctx *ctx = table->table[i]; | 795 | struct kioctx *ctx = table->table[i]; |
796 | struct completion requests_done = | ||
797 | COMPLETION_INITIALIZER_ONSTACK(requests_done); | ||
796 | 798 | ||
797 | if (!ctx) | 799 | if (!ctx) |
798 | continue; | 800 | continue; |
@@ -804,7 +806,10 @@ void exit_aio(struct mm_struct *mm) | |||
804 | * that it needs to unmap the area, just set it to 0. | 806 | * that it needs to unmap the area, just set it to 0. |
805 | */ | 807 | */ |
806 | ctx->mmap_size = 0; | 808 | ctx->mmap_size = 0; |
807 | kill_ioctx(mm, ctx, NULL); | 809 | kill_ioctx(mm, ctx, &requests_done); |
810 | |||
811 | /* Wait until all IO for the context are done. */ | ||
812 | wait_for_completion(&requests_done); | ||
808 | } | 813 | } |
809 | 814 | ||
810 | RCU_INIT_POINTER(mm->ioctx_table, NULL); | 815 | RCU_INIT_POINTER(mm->ioctx_table, NULL); |
@@ -1111,6 +1116,12 @@ static long aio_read_events_ring(struct kioctx *ctx, | |||
1111 | tail = ring->tail; | 1116 | tail = ring->tail; |
1112 | kunmap_atomic(ring); | 1117 | kunmap_atomic(ring); |
1113 | 1118 | ||
1119 | /* | ||
1120 | * Ensure that once we've read the current tail pointer, that | ||
1121 | * we also see the events that were stored up to the tail. | ||
1122 | */ | ||
1123 | smp_rmb(); | ||
1124 | |||
1114 | pr_debug("h%u t%u m%u\n", head, tail, ctx->nr_events); | 1125 | pr_debug("h%u t%u m%u\n", head, tail, ctx->nr_events); |
1115 | 1126 | ||
1116 | if (head == tail) | 1127 | if (head == tail) |