aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sched/auto_group.c')
-rw-r--r--kernel/sched/auto_group.c23
1 files changed, 12 insertions, 11 deletions
diff --git a/kernel/sched/auto_group.c b/kernel/sched/auto_group.c
index 750ed601ddf7..8620fd01b3d0 100644
--- a/kernel/sched/auto_group.c
+++ b/kernel/sched/auto_group.c
@@ -111,14 +111,11 @@ bool task_wants_autogroup(struct task_struct *p, struct task_group *tg)
111{ 111{
112 if (tg != &root_task_group) 112 if (tg != &root_task_group)
113 return false; 113 return false;
114
115 /* 114 /*
116 * We can only assume the task group can't go away on us if 115 * If we race with autogroup_move_group() the caller can use the old
117 * autogroup_move_group() can see us on ->thread_group list. 116 * value of signal->autogroup but in this case sched_move_task() will
117 * be called again before autogroup_kref_put().
118 */ 118 */
119 if (p->flags & PF_EXITING)
120 return false;
121
122 return true; 119 return true;
123} 120}
124 121
@@ -138,13 +135,17 @@ autogroup_move_group(struct task_struct *p, struct autogroup *ag)
138 } 135 }
139 136
140 p->signal->autogroup = autogroup_kref_get(ag); 137 p->signal->autogroup = autogroup_kref_get(ag);
141 138 /*
142 if (!READ_ONCE(sysctl_sched_autogroup_enabled)) 139 * We can't avoid sched_move_task() after we changed signal->autogroup,
143 goto out; 140 * this process can already run with task_group() == prev->tg or we can
144 141 * race with cgroup code which can read autogroup = prev under rq->lock.
142 * In the latter case for_each_thread() can not miss a migrating thread,
143 * cpu_cgroup_attach() must not be possible after cgroup_exit() and it
144 * can't be removed from thread list, we hold ->siglock.
145 */
145 for_each_thread(p, t) 146 for_each_thread(p, t)
146 sched_move_task(t); 147 sched_move_task(t);
147out: 148
148 unlock_task_sighand(p, &flags); 149 unlock_task_sighand(p, &flags);
149 autogroup_kref_put(prev); 150 autogroup_kref_put(prev);
150} 151}