Skip to content

Commit eee8785

Browse files
Waiman-Longhtejun
authored andcommitted
cgroup/cpuset: Add cpuset_can_fork() and cpuset_cancel_fork() methods
In the case of CLONE_INTO_CGROUP, not all cpusets are ready to accept new tasks. It is too late to check that in cpuset_fork(). So we need to add the cpuset_can_fork() and cpuset_cancel_fork() methods to pre-check it before we can allow attachment to a different cpuset. We also need to set the attach_in_progress flag to alert other code that a new task is going to be added to the cpuset. Fixes: ef2c41c ("clone3: allow spawning processes into cgroups") Suggested-by: Michal Koutný <mkoutny@suse.com> Signed-off-by: Waiman Long <longman@redhat.com> Cc: stable@vger.kernel.org # v5.7+ Signed-off-by: Tejun Heo <tj@kernel.org>
1 parent 42a11bf commit eee8785

1 file changed

Lines changed: 86 additions & 11 deletions

File tree

kernel/cgroup/cpuset.c

Lines changed: 86 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2453,6 +2453,20 @@ static int fmeter_getrate(struct fmeter *fmp)
24532453

24542454
static struct cpuset *cpuset_attach_old_cs;
24552455

2456+
/*
2457+
* Check to see if a cpuset can accept a new task
2458+
* For v1, cpus_allowed and mems_allowed can't be empty.
2459+
* For v2, effective_cpus can't be empty.
2460+
* Note that in v1, effective_cpus = cpus_allowed.
2461+
*/
2462+
static int cpuset_can_attach_check(struct cpuset *cs)
2463+
{
2464+
if (cpumask_empty(cs->effective_cpus) ||
2465+
(!is_in_v2_mode() && nodes_empty(cs->mems_allowed)))
2466+
return -ENOSPC;
2467+
return 0;
2468+
}
2469+
24562470
/* Called by cgroups to determine if a cpuset is usable; cpuset_rwsem held */
24572471
static int cpuset_can_attach(struct cgroup_taskset *tset)
24582472
{
@@ -2467,16 +2481,9 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
24672481

24682482
percpu_down_write(&cpuset_rwsem);
24692483

2470-
/* allow moving tasks into an empty cpuset if on default hierarchy */
2471-
ret = -ENOSPC;
2472-
if (!is_in_v2_mode() &&
2473-
(cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed)))
2474-
goto out_unlock;
2475-
2476-
/*
2477-
* Task cannot be moved to a cpuset with empty effective cpus.
2478-
*/
2479-
if (cpumask_empty(cs->effective_cpus))
2484+
/* Check to see if task is allowed in the cpuset */
2485+
ret = cpuset_can_attach_check(cs);
2486+
if (ret)
24802487
goto out_unlock;
24812488

24822489
cgroup_taskset_for_each(task, css, tset) {
@@ -2493,7 +2500,6 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
24932500
* changes which zero cpus/mems_allowed.
24942501
*/
24952502
cs->attach_in_progress++;
2496-
ret = 0;
24972503
out_unlock:
24982504
percpu_up_write(&cpuset_rwsem);
24992505
return ret;
@@ -3264,6 +3270,68 @@ static void cpuset_bind(struct cgroup_subsys_state *root_css)
32643270
percpu_up_write(&cpuset_rwsem);
32653271
}
32663272

3273+
/*
3274+
* In case the child is cloned into a cpuset different from its parent,
3275+
* additional checks are done to see if the move is allowed.
3276+
*/
3277+
static int cpuset_can_fork(struct task_struct *task, struct css_set *cset)
3278+
{
3279+
struct cpuset *cs = css_cs(cset->subsys[cpuset_cgrp_id]);
3280+
bool same_cs;
3281+
int ret;
3282+
3283+
rcu_read_lock();
3284+
same_cs = (cs == task_cs(current));
3285+
rcu_read_unlock();
3286+
3287+
if (same_cs)
3288+
return 0;
3289+
3290+
lockdep_assert_held(&cgroup_mutex);
3291+
percpu_down_write(&cpuset_rwsem);
3292+
3293+
/* Check to see if task is allowed in the cpuset */
3294+
ret = cpuset_can_attach_check(cs);
3295+
if (ret)
3296+
goto out_unlock;
3297+
3298+
ret = task_can_attach(task, cs->effective_cpus);
3299+
if (ret)
3300+
goto out_unlock;
3301+
3302+
ret = security_task_setscheduler(task);
3303+
if (ret)
3304+
goto out_unlock;
3305+
3306+
/*
3307+
* Mark attach is in progress. This makes validate_change() fail
3308+
* changes which zero cpus/mems_allowed.
3309+
*/
3310+
cs->attach_in_progress++;
3311+
out_unlock:
3312+
percpu_up_write(&cpuset_rwsem);
3313+
return ret;
3314+
}
3315+
3316+
static void cpuset_cancel_fork(struct task_struct *task, struct css_set *cset)
3317+
{
3318+
struct cpuset *cs = css_cs(cset->subsys[cpuset_cgrp_id]);
3319+
bool same_cs;
3320+
3321+
rcu_read_lock();
3322+
same_cs = (cs == task_cs(current));
3323+
rcu_read_unlock();
3324+
3325+
if (same_cs)
3326+
return;
3327+
3328+
percpu_down_write(&cpuset_rwsem);
3329+
cs->attach_in_progress--;
3330+
if (!cs->attach_in_progress)
3331+
wake_up(&cpuset_attach_wq);
3332+
percpu_up_write(&cpuset_rwsem);
3333+
}
3334+
32673335
/*
32683336
* Make sure the new task conform to the current state of its parent,
32693337
* which could have been changed by cpuset just after it inherits the
@@ -3292,6 +3360,11 @@ static void cpuset_fork(struct task_struct *task)
32923360
percpu_down_write(&cpuset_rwsem);
32933361
guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
32943362
cpuset_attach_task(cs, task);
3363+
3364+
cs->attach_in_progress--;
3365+
if (!cs->attach_in_progress)
3366+
wake_up(&cpuset_attach_wq);
3367+
32953368
percpu_up_write(&cpuset_rwsem);
32963369
}
32973370

@@ -3305,6 +3378,8 @@ struct cgroup_subsys cpuset_cgrp_subsys = {
33053378
.attach = cpuset_attach,
33063379
.post_attach = cpuset_post_attach,
33073380
.bind = cpuset_bind,
3381+
.can_fork = cpuset_can_fork,
3382+
.cancel_fork = cpuset_cancel_fork,
33083383
.fork = cpuset_fork,
33093384
.legacy_cftypes = legacy_files,
33103385
.dfl_cftypes = dfl_files,

0 commit comments

Comments
 (0)