aio: ctx->dead cleanups
v3 cover aio: ctx->dead cleanups
As Jeff suggested, 1/3 was changed to simply remove the ->dead check. I also updated the changelog.
Jeff, I preserved your acks in 2-3.
Oleg.
PATCH v3 1/3 aio_ring_remap: kill the bogus ctx->dead check
kill_ioctx() sets ctx->dead and removes ctx from ->ioctx_table "atomically" under mm->ioctx_lock, so aio_ring_remap() can never see a dead ctx.
And even -EINVAL doesn't look necessary. Yes, if mremap() races with kill_ioctx() vm_munmap(ctx->mmap_base, ctx->mmap_size) can unmap the wrong region. In this case the buggy application should blame itself. And there are other reasons why that vm_munmap() can be wrong. Say, an application can mremap() the part of aio region and then do io_destroy(). We could change aio_ring_remap() to verify vma->that vma_end - vma->vma_start == ctx->mmap_size but this won't help if the application does munmap() instead.
--- fs/aio.c | 9 +++------ 1 files changed, 3 insertions(+), 6 deletions(-)
fs/aio.c +3 -6
@@ -325,14 +325,11 @@ static int aio_ring_remap(struct file *file, struct vm_area_struct *vma)rcu_read_lock (); table =rcu_dereference (mm->ioctx_table);for (i =0 ; i < table->nr; i++) { -struct kioctx *ctx; +struct kioctx *ctx = table->table[i]; - ctx = table->table[i];if (ctx && ctx->aio_ring_file == file) { -if (!atomic_read (&ctx->dead)) { - ctx->user_id = ctx->mmap_base = vma->vm_start; - res =0 ; - } + ctx->user_id = ctx->mmap_base = vma->vm_start; + res =0 ;break ; } }
Signature · 1 line
1.5.5.1
PATCH v3 2/3 aio: make aio_ring->dead boolean
In reply to Oleg Nesterov"atomic_t dead" makes no sense. atomic_read() is the plain LOAD, it doesn't have some "additional" synchronization with xchg().
And now that kill_ioctx() sets "dead" under mm->ioctx_lock we do not even need xchg().
--- fs/aio.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)
fs/aio.c +5 -4
@@ -84,7 +84,7 @@ struct ctx_rq_wait {struct kioctx {struct percpu_ref users; -atomic_t dead; +bool dead;struct percpu_ref reqs;
@@ -765,7 +765,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) err_cleanup:aio_nr_sub (ctx->max_reqs); err_ctx: -atomic_set (&ctx->dead,1 ); + ctx->dead = true;/* unneeded */ if (ctx->mmap_size)vm_munmap (ctx->mmap_base, ctx->mmap_size);aio_free_ring (ctx);
@@ -790,11 +790,12 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx,struct kioctx_table *table;spin_lock (&mm->ioctx_lock); -if (atomic_xchg (&ctx->dead,1 )) { +if (unlikely (ctx->dead)) {spin_unlock (&mm->ioctx_lock);return -EINVAL ; } + ctx->dead = true; table =rcu_dereference_raw (mm->ioctx_table);WARN_ON (ctx != table->table[ctx->id]); table->table[ctx->id] =NULL ;
@@ -1236,7 +1237,7 @@ static bool aio_read_events(struct kioctx *ctx, long min_nr, long nr,if (ret >0 ) *i += ret; -if (unlikely (atomic_read (&ctx->dead))) +if (unlikely (ctx->dead)) ret = -EINVAL ;if (!*i)
Signature · 1 line
1.5.5.1
Re: [PATCH v3 2/3] aio: make aio_ring->dead boolean
Quoted 10 lines · Oleg Nesterov
"
atomic_tdead" makes no sense.atomic_read()is the plain LOAD, it doesn't have some "additional" synchronization withxchg().And now that
kill_ioctx()sets "dead" undermm->ioctx_lockwe do not even needxchg().Signed-off-by Oleg Nesterov <[email protected]>Reviewed-by Jeff Moyer <[email protected]>
fs/aio.c static struct kioctx *ioctx_alloc(unsigned nr_events) · line 768
Quoted 5 lines
fs/aio.c +1
-1@@ -765,7 +765,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) err_cleanup:aio_nr_sub (ctx->max_reqs); err_ctx: -atomic_set (&ctx->dead,1 ); + ctx->dead = true;/* unneeded */
I was hoping you'd remove this line entirely.
-Jeff
Re: [PATCH v3 2/3] aio: make aio_ring->dead boolean
Quoted 10 lines · Jeff Moyer
fs/aio.c static struct kioctx *ioctx_alloc(unsigned nr_events) · line 768
Quoted 6 lines · Oleg Nesterov
fs/aio.c +1
-1@@ -765,7 +765,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) err_cleanup:aio_nr_sub (ctx->max_reqs); err_ctx: -atomic_set (&ctx->dead,1 ); + ctx->dead = true;/* unneeded */ I was hoping you'd remove this line entirely.
Ah. I didn't understand you wamt me to do this... OK, please see v4.
Oleg.
PATCH v3 3/3 aio_free_ring: don't do page_count(NULL)
In reply to Oleg Nesterovaio_free_ring() can actually see the NULL page in ->ring_pages[], this can happen if aio_setup_ring() fails.
And in this case page_count(ctx->ring_pages[i]) can OOPS.
--- fs/aio.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)
fs/aio.c +4 -4
@@ -292,12 +292,12 @@ static void aio_free_ring(struct kioctx *ctx)put_aio_ring_file (ctx);for (i =0 ; i < ctx->nr_pages; i++) { -struct page *page; -pr_debug ("pid(%d) [%d] page->count=%d\n" , current->pid, i, -page_count (ctx->ring_pages[i])); - page = ctx->ring_pages[i]; +struct page *page = ctx->ring_pages[i];if (!page)continue ; + +pr_debug ("pid(%d) [%d] page->count=%d\n" , + current->pid, i,page_count (page)); ctx->ring_pages[i] =NULL ;put_page (page); }
Signature · 1 line
1.5.5.1