cgroup/cpuset: Rebind/migrate mm only for threadgroup leader in cpuset_update_tasks_nodemask()

As reported by sashiko [1], cpuset_update_tasks_nodemask() will do
mpol_rebind_mm() and possibly cpuset_migrate_mm() for all threads of
a multithreaded process. Since commit 3df9ca0a2b ("cpuset: migrate
memory only for threadgroup leaders"), cpuset_attach() had been updated
to rebind and migrate memory only for threadgroup leaders to mark the
group leader as the owner of the mm_struct.

To be consistent and avoid unnecessary performance overhead for heavily
multithreaded processes, follow the cpuset_attach() example and perform
memory rebind and migration only for threadgroup leaders.

Also add a paragraph in cgroup-v2.rst under cpuset.mems that the
threadgroup leader is the memory owner of that threadgroup. Therefore
the non-leading threads shouldn't be in other cgroups whose "cpuset.mems"
doesn't fully overlap that of the group leader.

[1] https://sashiko.dev/#/patchset/20260621032816.1806773-1-longman%40redhat.com

Signed-off-by: Waiman Long <longman@redhat.com>
Reviewed-by: Ridong Chen <ridong.chen@linux.dev>
Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
Waiman Long 2026-06-23 19:04:13 -04:00 committed by Tejun Heo
parent 866f587e9c
commit eda17a3a70
2 changed files with 11 additions and 0 deletions

View File

@ -2527,6 +2527,13 @@ Cpuset Interface Files
a need to change "cpuset.mems" with active tasks, it shouldn't
be done frequently.
For a multithreaded process, the threadgroup leader is
considered the owner of the group's memory. Memory policy
rebinding and migration will only happen with respect to the
threadgroup leader. To avoid unexpected results, non-leading
threads shouldn't be put into another cgroup whose "cpuset.mems"
doesn't fully overlap that of the threadgroup leader.
cpuset.mems.effective
A read-only multiple values file which exists on all
cpuset-enabled cgroups.

View File

@ -2661,6 +2661,10 @@ void cpuset_update_tasks_nodemask(struct cpuset *cs)
cpuset_change_task_nodemask(task, &newmems);
/* Rebind and migrate mm only for thread group leader */
if (!thread_group_leader(task))
continue;
mm = get_task_mm(task);
if (!mm)
continue;