fs/aio: Use RCU accessors for kioctx_table->table[]
While converting ioctx index from a list to a table,db446a08c2
("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:db446a08c2
("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+
This commit is contained in:
parent
a6d7cff472
commit
d0264c01e7
21
fs/aio.c
21
fs/aio.c
|
@ -68,9 +68,9 @@ struct aio_ring {
|
|||
#define AIO_RING_PAGES 8
|
||||
|
||||
struct kioctx_table {
|
||||
struct rcu_head rcu;
|
||||
unsigned nr;
|
||||
struct kioctx *table[];
|
||||
struct rcu_head rcu;
|
||||
unsigned nr;
|
||||
struct kioctx __rcu *table[];
|
||||
};
|
||||
|
||||
struct kioctx_cpu {
|
||||
|
@ -330,7 +330,7 @@ static int aio_ring_mremap(struct vm_area_struct *vma)
|
|||
for (i = 0; i < table->nr; i++) {
|
||||
struct kioctx *ctx;
|
||||
|
||||
ctx = table->table[i];
|
||||
ctx = rcu_dereference(table->table[i]);
|
||||
if (ctx && ctx->aio_ring_file == file) {
|
||||
if (!atomic_read(&ctx->dead)) {
|
||||
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)
|
|||
while (1) {
|
||||
if (table)
|
||||
for (i = 0; i < table->nr; i++)
|
||||
if (!table->table[i]) {
|
||||
if (!rcu_access_pointer(table->table[i])) {
|
||||
ctx->id = i;
|
||||
table->table[i] = ctx;
|
||||
rcu_assign_pointer(table->table[i], ctx);
|
||||
spin_unlock(&mm->ioctx_lock);
|
||||
|
||||
/* While kioctx setup is in progress,
|
||||
|
@ -849,8 +849,8 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx,
|
|||
}
|
||||
|
||||
table = rcu_dereference_raw(mm->ioctx_table);
|
||||
WARN_ON(ctx != table->table[ctx->id]);
|
||||
table->table[ctx->id] = NULL;
|
||||
WARN_ON(ctx != rcu_access_pointer(table->table[ctx->id]));
|
||||
RCU_INIT_POINTER(table->table[ctx->id], NULL);
|
||||
spin_unlock(&mm->ioctx_lock);
|
||||
|
||||
/* free_ioctx_reqs() will do the necessary RCU synchronization */
|
||||
|
@ -895,7 +895,8 @@ void exit_aio(struct mm_struct *mm)
|
|||
|
||||
skipped = 0;
|
||||
for (i = 0; i < table->nr; ++i) {
|
||||
struct kioctx *ctx = table->table[i];
|
||||
struct kioctx *ctx =
|
||||
rcu_dereference_protected(table->table[i], true);
|
||||
|
||||
if (!ctx) {
|
||||
skipped++;
|
||||
|
@ -1084,7 +1085,7 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id)
|
|||
if (!table || id >= table->nr)
|
||||
goto out;
|
||||
|
||||
ctx = table->table[id];
|
||||
ctx = rcu_dereference(table->table[id]);
|
||||
if (ctx && ctx->user_id == ctx_id) {
|
||||
percpu_ref_get(&ctx->users);
|
||||
ret = ctx;
|
||||
|
|
Loading…
Reference in New Issue