Skip to content

Commit e4e1e80

Browse files
Frederic Weisbeckerpaulmckrcu
authored andcommitted
rcu-tasks: Improve comments explaining tasks_rcu_exit_srcu purpose
Make sure we don't need to look again into the depths of git blame in order not to miss a subtle part about how rcu-tasks is dealing with exiting tasks. Suggested-by: Boqun Feng <[email protected]> Suggested-by: Neeraj Upadhyay <[email protected]> Suggested-by: Paul E. McKenney <[email protected]> Cc: Oleg Nesterov <[email protected]> Cc: Lai Jiangshan <[email protected]> Cc: Eric W. Biederman <[email protected]> Signed-off-by: Frederic Weisbecker <[email protected]> Signed-off-by: Paul E. McKenney <[email protected]>
1 parent 9420fb9 commit e4e1e80

File tree

1 file changed

+29
-8
lines changed

1 file changed

+29
-8
lines changed

kernel/rcu/tasks.h

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -827,11 +827,21 @@ static void rcu_tasks_pertask(struct task_struct *t, struct list_head *hop)
827827
static void rcu_tasks_postscan(struct list_head *hop)
828828
{
829829
/*
830-
* Wait for tasks that are in the process of exiting. This
831-
* does only part of the job, ensuring that all tasks that were
832-
* previously exiting reach the point where they have disabled
833-
* preemption, allowing the later synchronize_rcu() to finish
834-
* the job.
830+
* Exiting tasks may escape the tasklist scan. Those are vulnerable
831+
* until their final schedule() with TASK_DEAD state. To cope with
832+
* this, divide the fragile exit path part in two intersecting
833+
* read side critical sections:
834+
*
835+
* 1) An _SRCU_ read side starting before calling exit_notify(),
836+
* which may remove the task from the tasklist, and ending after
837+
* the final preempt_disable() call in do_exit().
838+
*
839+
* 2) An _RCU_ read side starting with the final preempt_disable()
840+
* call in do_exit() and ending with the final call to schedule()
841+
* with TASK_DEAD state.
842+
*
843+
* This handles the part 1). And postgp will handle part 2) with a
844+
* call to synchronize_rcu().
835845
*/
836846
synchronize_srcu(&tasks_rcu_exit_srcu);
837847
}
@@ -898,7 +908,10 @@ static void rcu_tasks_postgp(struct rcu_tasks *rtp)
898908
*
899909
* In addition, this synchronize_rcu() waits for exiting tasks
900910
* to complete their final preempt_disable() region of execution,
901-
* cleaning up after the synchronize_srcu() above.
911+
* cleaning up after synchronize_srcu(&tasks_rcu_exit_srcu),
912+
* enforcing the whole region before tasklist removal until
913+
* the final schedule() with TASK_DEAD state to be an RCU TASKS
914+
* read side critical section.
902915
*/
903916
synchronize_rcu();
904917
}
@@ -988,15 +1001,23 @@ void show_rcu_tasks_classic_gp_kthread(void)
9881001
EXPORT_SYMBOL_GPL(show_rcu_tasks_classic_gp_kthread);
9891002
#endif // !defined(CONFIG_TINY_RCU)
9901003

991-
/* Do the srcu_read_lock() for the above synchronize_srcu(). */
1004+
/*
1005+
* Contribute to protect against tasklist scan blind spot while the
1006+
* task is exiting and may be removed from the tasklist. See
1007+
* corresponding synchronize_srcu() for further details.
1008+
*/
9921009
void exit_tasks_rcu_start(void) __acquires(&tasks_rcu_exit_srcu)
9931010
{
9941011
preempt_disable();
9951012
current->rcu_tasks_idx = __srcu_read_lock(&tasks_rcu_exit_srcu);
9961013
preempt_enable();
9971014
}
9981015

999-
/* Do the srcu_read_unlock() for the above synchronize_srcu(). */
1016+
/*
1017+
* Contribute to protect against tasklist scan blind spot while the
1018+
* task is exiting and may be removed from the tasklist. See
1019+
* corresponding synchronize_srcu() for further details.
1020+
*/
10001021
void exit_tasks_rcu_finish(void) __releases(&tasks_rcu_exit_srcu)
10011022
{
10021023
struct task_struct *t = current;

0 commit comments

Comments
 (0)