path: root/kernel/exit.c
diff options
authorPaul E. McKenney <>2014-08-04 06:10:23 -0700
committerPaul E. McKenney <>2014-09-07 16:27:22 -0700
commit3f95aa81d265223fdb13ea2b59883766a05adbdf (patch)
tree5b6d2c42aaf8b20397bd09c0ac31738618f57046 /kernel/exit.c
parent53c6d4edf874d3cbc031a53738c6cba9277faea5 (diff)
rcu: Make TASKS_RCU handle tasks that are almost done exiting
Once a task has passed exit_notify() in the do_exit() code path, it is no longer on the task lists, and is therefore no longer visible to rcu_tasks_kthread(). This means that an almost-exited task might be preempted while within a trampoline, and this task won't be waited on by rcu_tasks_kthread(). This commit fixes this bug by adding an srcu_struct. An exiting task does srcu_read_lock() just before calling exit_notify(), and does the corresponding srcu_read_unlock() after doing the final preempt_disable(). This means that rcu_tasks_kthread() can do synchronize_srcu() to wait for all mostly-exited tasks to reach their final preempt_disable() region, and then use synchronize_sched() to wait for those tasks to finish exiting. Reported-by: Oleg Nesterov <> Suggested-by: Lai Jiangshan <> Signed-off-by: Paul E. McKenney <>
Diffstat (limited to 'kernel/exit.c')
1 files changed, 3 insertions, 0 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index 32c58f7433a3..d13f2eec4bb8 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -667,6 +667,7 @@ void do_exit(long code)
struct task_struct *tsk = current;
int group_dead;
+ TASKS_RCU(int tasks_rcu_i);
@@ -775,6 +776,7 @@ void do_exit(long code)
+ TASKS_RCU(tasks_rcu_i = __srcu_read_lock(&tasks_rcu_exit_srcu));
exit_notify(tsk, group_dead);
@@ -814,6 +816,7 @@ void do_exit(long code)
if (tsk->nr_dirtied)
__this_cpu_add(dirty_throttle_leaks, tsk->nr_dirtied);
+ TASKS_RCU(__srcu_read_unlock(&tasks_rcu_exit_srcu, tasks_rcu_i));
* The setting of TASK_RUNNING by try_to_wake_up() may be delayed