cgroup/cpuset: Make cpuset_fork() handle CLONE_INTO_CGROUP properly
By default, the clone(2) syscall spawn a child process into the same cgroup as its parent. With the use of the CLONE_INTO_CGROUP flag introduced by commitef2c41cf38
("clone3: allow spawning processes into cgroups"), the child will be spawned into a different cgroup which is somewhat similar to writing the child's tid into "cgroup.threads". The current cpuset_fork() method does not properly handle the CLONE_INTO_CGROUP case where the cpuset of the child may be different from that of its parent. Update the cpuset_fork() method to treat the CLONE_INTO_CGROUP case similar to cpuset_attach(). Since the newly cloned task has not been running yet, its actual memory usage isn't known. So it is not necessary to make change to mm in cpuset_fork(). Fixes:ef2c41cf38
("clone3: allow spawning processes into cgroups") Reported-by: Giuseppe Scrivano <gscrivan@redhat.com> Signed-off-by: Waiman Long <longman@redhat.com> Cc: stable@vger.kernel.org # v5.7+ Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
parent
ba9182a896
commit
42a11bf5c5
1 changed files with 43 additions and 21 deletions
|
@ -2515,16 +2515,33 @@ static void cpuset_cancel_attach(struct cgroup_taskset *tset)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Protected by cpuset_rwsem. cpus_attach is used only by cpuset_attach()
|
* Protected by cpuset_rwsem. cpus_attach is used only by cpuset_attach_task()
|
||||||
* but we can't allocate it dynamically there. Define it global and
|
* but we can't allocate it dynamically there. Define it global and
|
||||||
* allocate from cpuset_init().
|
* allocate from cpuset_init().
|
||||||
*/
|
*/
|
||||||
static cpumask_var_t cpus_attach;
|
static cpumask_var_t cpus_attach;
|
||||||
|
static nodemask_t cpuset_attach_nodemask_to;
|
||||||
|
|
||||||
|
static void cpuset_attach_task(struct cpuset *cs, struct task_struct *task)
|
||||||
|
{
|
||||||
|
percpu_rwsem_assert_held(&cpuset_rwsem);
|
||||||
|
|
||||||
|
if (cs != &top_cpuset)
|
||||||
|
guarantee_online_cpus(task, cpus_attach);
|
||||||
|
else
|
||||||
|
cpumask_copy(cpus_attach, task_cpu_possible_mask(task));
|
||||||
|
/*
|
||||||
|
* can_attach beforehand should guarantee that this doesn't
|
||||||
|
* fail. TODO: have a better way to handle failure here
|
||||||
|
*/
|
||||||
|
WARN_ON_ONCE(set_cpus_allowed_ptr(task, cpus_attach));
|
||||||
|
|
||||||
|
cpuset_change_task_nodemask(task, &cpuset_attach_nodemask_to);
|
||||||
|
cpuset_update_task_spread_flags(cs, task);
|
||||||
|
}
|
||||||
|
|
||||||
static void cpuset_attach(struct cgroup_taskset *tset)
|
static void cpuset_attach(struct cgroup_taskset *tset)
|
||||||
{
|
{
|
||||||
/* static buf protected by cpuset_rwsem */
|
|
||||||
static nodemask_t cpuset_attach_nodemask_to;
|
|
||||||
struct task_struct *task;
|
struct task_struct *task;
|
||||||
struct task_struct *leader;
|
struct task_struct *leader;
|
||||||
struct cgroup_subsys_state *css;
|
struct cgroup_subsys_state *css;
|
||||||
|
@ -2555,20 +2572,8 @@ static void cpuset_attach(struct cgroup_taskset *tset)
|
||||||
|
|
||||||
guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
|
guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
|
||||||
|
|
||||||
cgroup_taskset_for_each(task, css, tset) {
|
cgroup_taskset_for_each(task, css, tset)
|
||||||
if (cs != &top_cpuset)
|
cpuset_attach_task(cs, task);
|
||||||
guarantee_online_cpus(task, cpus_attach);
|
|
||||||
else
|
|
||||||
cpumask_copy(cpus_attach, task_cpu_possible_mask(task));
|
|
||||||
/*
|
|
||||||
* can_attach beforehand should guarantee that this doesn't
|
|
||||||
* fail. TODO: have a better way to handle failure here
|
|
||||||
*/
|
|
||||||
WARN_ON_ONCE(set_cpus_allowed_ptr(task, cpus_attach));
|
|
||||||
|
|
||||||
cpuset_change_task_nodemask(task, &cpuset_attach_nodemask_to);
|
|
||||||
cpuset_update_task_spread_flags(cs, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Change mm for all threadgroup leaders. This is expensive and may
|
* Change mm for all threadgroup leaders. This is expensive and may
|
||||||
|
@ -3266,11 +3271,28 @@ static void cpuset_bind(struct cgroup_subsys_state *root_css)
|
||||||
*/
|
*/
|
||||||
static void cpuset_fork(struct task_struct *task)
|
static void cpuset_fork(struct task_struct *task)
|
||||||
{
|
{
|
||||||
if (task_css_is_root(task, cpuset_cgrp_id))
|
struct cpuset *cs;
|
||||||
return;
|
bool same_cs;
|
||||||
|
|
||||||
set_cpus_allowed_ptr(task, current->cpus_ptr);
|
rcu_read_lock();
|
||||||
task->mems_allowed = current->mems_allowed;
|
cs = task_cs(task);
|
||||||
|
same_cs = (cs == task_cs(current));
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
if (same_cs) {
|
||||||
|
if (cs == &top_cpuset)
|
||||||
|
return;
|
||||||
|
|
||||||
|
set_cpus_allowed_ptr(task, current->cpus_ptr);
|
||||||
|
task->mems_allowed = current->mems_allowed;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CLONE_INTO_CGROUP */
|
||||||
|
percpu_down_write(&cpuset_rwsem);
|
||||||
|
guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
|
||||||
|
cpuset_attach_task(cs, task);
|
||||||
|
percpu_up_write(&cpuset_rwsem);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cgroup_subsys cpuset_cgrp_subsys = {
|
struct cgroup_subsys cpuset_cgrp_subsys = {
|
||||||
|
|
Loading…
Add table
Reference in a new issue