Skip to content

Commit a6d7cff

Browse files
committed
fs/aio: Add explicit RCU grace period when freeing kioctx
While fixing refcounting, e34ecee ("aio: Fix a trinity splat") incorrectly removed explicit RCU grace period before freeing kioctx. The intention seems to be depending on the internal RCU grace periods of percpu_ref; however, percpu_ref uses a different flavor of RCU, sched-RCU. This can lead to kioctx being freed while RCU read protected dereferences are still in progress. Fix it by updating free_ioctx() to go through call_rcu() explicitly. v2: Comment added to explain double bouncing. Signed-off-by: Tejun Heo <[email protected]> Reported-by: Jann Horn <[email protected]> Fixes: e34ecee ("aio: Fix a trinity splat") Cc: Kent Overstreet <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: [email protected] # v3.13+
1 parent 3032f8c commit a6d7cff

File tree

1 file changed

+19
-4
lines changed

1 file changed

+19
-4
lines changed

fs/aio.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ struct kioctx {
115115
struct page **ring_pages;
116116
long nr_pages;
117117

118-
struct work_struct free_work;
118+
struct rcu_head free_rcu;
119+
struct work_struct free_work; /* see free_ioctx() */
119120

120121
/*
121122
* signals when all in-flight requests are done
@@ -588,6 +589,12 @@ static int kiocb_cancel(struct aio_kiocb *kiocb)
588589
return cancel(&kiocb->common);
589590
}
590591

592+
/*
593+
* free_ioctx() should be RCU delayed to synchronize against the RCU
594+
* protected lookup_ioctx() and also needs process context to call
595+
* aio_free_ring(), so the double bouncing through kioctx->free_rcu and
596+
* ->free_work.
597+
*/
591598
static void free_ioctx(struct work_struct *work)
592599
{
593600
struct kioctx *ctx = container_of(work, struct kioctx, free_work);
@@ -601,6 +608,14 @@ static void free_ioctx(struct work_struct *work)
601608
kmem_cache_free(kioctx_cachep, ctx);
602609
}
603610

611+
static void free_ioctx_rcufn(struct rcu_head *head)
612+
{
613+
struct kioctx *ctx = container_of(head, struct kioctx, free_rcu);
614+
615+
INIT_WORK(&ctx->free_work, free_ioctx);
616+
schedule_work(&ctx->free_work);
617+
}
618+
604619
static void free_ioctx_reqs(struct percpu_ref *ref)
605620
{
606621
struct kioctx *ctx = container_of(ref, struct kioctx, reqs);
@@ -609,8 +624,8 @@ static void free_ioctx_reqs(struct percpu_ref *ref)
609624
if (ctx->rq_wait && atomic_dec_and_test(&ctx->rq_wait->count))
610625
complete(&ctx->rq_wait->comp);
611626

612-
INIT_WORK(&ctx->free_work, free_ioctx);
613-
schedule_work(&ctx->free_work);
627+
/* Synchronize against RCU protected table->table[] dereferences */
628+
call_rcu(&ctx->free_rcu, free_ioctx_rcufn);
614629
}
615630

616631
/*
@@ -838,7 +853,7 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx,
838853
table->table[ctx->id] = NULL;
839854
spin_unlock(&mm->ioctx_lock);
840855

841-
/* percpu_ref_kill() will do the necessary call_rcu() */
856+
/* free_ioctx_reqs() will do the necessary RCU synchronization */
842857
wake_up_all(&ctx->wait);
843858

844859
/*

0 commit comments

Comments
 (0)