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:
Родитель
a6d7cff472
Коммит
d0264c01e7
21
fs/aio.c
21
fs/aio.c
|
@ -68,9 +68,9 @@ struct aio_ring {
|
||||||
#define AIO_RING_PAGES 8
|
#define AIO_RING_PAGES 8
|
||||||
|
|
||||||
struct kioctx_table {
|
struct kioctx_table {
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
unsigned nr;
|
unsigned nr;
|
||||||
struct kioctx *table[];
|
struct kioctx __rcu *table[];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct kioctx_cpu {
|
struct kioctx_cpu {
|
||||||
|
@ -330,7 +330,7 @@ static int aio_ring_mremap(struct vm_area_struct *vma)
|
||||||
for (i = 0; i < table->nr; i++) {
|
for (i = 0; i < table->nr; i++) {
|
||||||
struct kioctx *ctx;
|
struct kioctx *ctx;
|
||||||
|
|
||||||
ctx = table->table[i];
|
ctx = rcu_dereference(table->table[i]);
|
||||||
if (ctx && ctx->aio_ring_file == file) {
|
if (ctx && ctx->aio_ring_file == file) {
|
||||||
if (!atomic_read(&ctx->dead)) {
|
if (!atomic_read(&ctx->dead)) {
|
||||||
ctx->user_id = ctx->mmap_base = vma->vm_start;
|
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) {
|
while (1) {
|
||||||
if (table)
|
if (table)
|
||||||
for (i = 0; i < table->nr; i++)
|
for (i = 0; i < table->nr; i++)
|
||||||
if (!table->table[i]) {
|
if (!rcu_access_pointer(table->table[i])) {
|
||||||
ctx->id = i;
|
ctx->id = i;
|
||||||
table->table[i] = ctx;
|
rcu_assign_pointer(table->table[i], ctx);
|
||||||
spin_unlock(&mm->ioctx_lock);
|
spin_unlock(&mm->ioctx_lock);
|
||||||
|
|
||||||
/* While kioctx setup is in progress,
|
/* 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);
|
table = rcu_dereference_raw(mm->ioctx_table);
|
||||||
WARN_ON(ctx != table->table[ctx->id]);
|
WARN_ON(ctx != rcu_access_pointer(table->table[ctx->id]));
|
||||||
table->table[ctx->id] = NULL;
|
RCU_INIT_POINTER(table->table[ctx->id], NULL);
|
||||||
spin_unlock(&mm->ioctx_lock);
|
spin_unlock(&mm->ioctx_lock);
|
||||||
|
|
||||||
/* free_ioctx_reqs() will do the necessary RCU synchronization */
|
/* free_ioctx_reqs() will do the necessary RCU synchronization */
|
||||||
|
@ -895,7 +895,8 @@ void exit_aio(struct mm_struct *mm)
|
||||||
|
|
||||||
skipped = 0;
|
skipped = 0;
|
||||||
for (i = 0; i < table->nr; ++i) {
|
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) {
|
if (!ctx) {
|
||||||
skipped++;
|
skipped++;
|
||||||
|
@ -1084,7 +1085,7 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id)
|
||||||
if (!table || id >= table->nr)
|
if (!table || id >= table->nr)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ctx = table->table[id];
|
ctx = rcu_dereference(table->table[id]);
|
||||||
if (ctx && ctx->user_id == ctx_id) {
|
if (ctx && ctx->user_id == ctx_id) {
|
||||||
percpu_ref_get(&ctx->users);
|
percpu_ref_get(&ctx->users);
|
||||||
ret = ctx;
|
ret = ctx;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче