cgroup: avoid the unnecessary list_add(dying_tasks) in cgroup_exit()
cover cgroup: avoid the unnecessary list_add(dying_tasks) in cgroup_exit()
Hello,
Sorry for delay and for confusing you in our previous discussion here https://lore.kernel.org/all/[email protected]/
No, cgroup_exit() can't rely on group_dead, this is racy.
And no, we can't shift css_set_skip_task_iters/etc from cgroup_release() to cgroup_exit(), an execing sub-thread can change the group leader.
Let me at least send the simple patch which looks "obviously good" to me.
I would really like to remove the usage of signal->live in cgroup.c, but so far I do not see a simple solution.
With or without this change cgroup.procs can be empty but cgroup.threads is not. But at least the exiting sub-threads which have already passed atomic_dec_and_test() should call cgroup_exit() "soon".
Oleg.
PATCH 1/1 cgroup: avoid the unnecessary list_add(dying_tasks) in cgroup_exit()
cgroup_exit() needs to do this only if the exiting task is a leader and it is not the last live thread. The patch doesn't use delay_group_leader(), atomic_read(signal->live) matches the code css_task_iter_advance() more.
cgroup_release() can now check list_empty(task->cg_list) before it takes css_set_lock and calls ss_set_skip_task_iters().
--- kernel/cgroup/cgroup.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
kernel/cgroup/cgroup.c +9 -5
@@ -6686,8 +6686,10 @@ void cgroup_exit(struct task_struct *tsk)WARN_ON_ONCE (list_empty (&tsk->cg_list)); cset =task_css_set (tsk);css_set_move_task (tsk, cset,NULL , false); -list_add_tail (&tsk->cg_list, &cset->dying_tasks); cset->nr_tasks--; +/* matches the signal->live check in css_task_iter_advance() */ +if (thread_group_leader (tsk) &&atomic_read (&tsk->signal->live)) +list_add_tail (&tsk->cg_list, &cset->dying_tasks);if (dl_task (tsk))dec_dl_tasks_cs (tsk);
@@ -6714,10 +6716,12 @@ void cgroup_release(struct task_struct *task) ss->release (task); }while_each_subsys_mask (); -spin_lock_irq (&css_set_lock); -css_set_skip_task_iters (task_css_set (task), task); -list_del_init (&task->cg_list); -spin_unlock_irq (&css_set_lock); +if (!list_empty (&task->cg_list)) { +spin_lock_irq (&css_set_lock); +css_set_skip_task_iters (task_css_set (task), task); +list_del_init (&task->cg_list); +spin_unlock_irq (&css_set_lock); + } }void cgroup_free (struct task_struct *task)
Signature · 1 line
2.25.1.362.g51ebf55
Quoted 8 lines · Oleg Nesterov
cgroup_exit()needs to do this only if the exiting task is a leader and it is not the last live thread. The patch doesn't usedelay_group_leader(),atomic_read(signal->live)matches the codecss_task_iter_advance()more.
cgroup_release()can now checklist_empty(task->cg_list)before it takescss_set_lockand callsss_set_skip_task_iters().Signed-off-by Oleg Nesterov <[email protected]>
Applied to cgroup/for-6.11.
Thanks.
Signature · 1 line
tejun