* [PATCH v2 1/3] cgroup/cpuset: Simplify setsched decision check in task iteration loop of cpuset_can_attach()
2026-03-29 17:39 [PATCH v2 0/3] cgroup/cpuset: Fix v1 task migration failure from empty cpuset Waiman Long
@ 2026-03-29 17:39 ` Waiman Long
2026-03-29 17:39 ` [PATCH v2 2/3] cgroup/cpuset: Skip security check for hotplug induced v1 task migration Waiman Long
2026-03-29 17:39 ` [PATCH v2 3/3] cgroup/cpuset: Improve check for v1 task migration out of empty cpuset Waiman Long
2 siblings, 0 replies; 10+ messages in thread
From: Waiman Long @ 2026-03-29 17:39 UTC (permalink / raw)
To: Chen Ridong, Tejun Heo, Johannes Weiner, Michal Koutný
Cc: cgroups, linux-kernel, Waiman Long
Centralize the check required to run security_task_setscheduler() in
the task iteration loop of cpuset_can_attach() outside of the loop as
it has no dependency on the characteristics of the tasks themselves.
There is no functional change.
Signed-off-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index d21868455341..58c5b7b72cca 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2988,7 +2988,7 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
struct cgroup_subsys_state *css;
struct cpuset *cs, *oldcs;
struct task_struct *task;
- bool cpus_updated, mems_updated;
+ bool setsched_check;
int ret;
/* used later by cpuset_attach() */
@@ -3003,20 +3003,21 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
if (ret)
goto out_unlock;
- cpus_updated = !cpumask_equal(cs->effective_cpus, oldcs->effective_cpus);
- mems_updated = !nodes_equal(cs->effective_mems, oldcs->effective_mems);
+ /*
+ * Skip rights over task setsched check in v2 when nothing changes,
+ * migration permission derives from hierarchy ownership in
+ * cgroup_procs_write_permission()).
+ */
+ setsched_check = !cpuset_v2() ||
+ !cpumask_equal(cs->effective_cpus, oldcs->effective_cpus) ||
+ !nodes_equal(cs->effective_mems, oldcs->effective_mems);
cgroup_taskset_for_each(task, css, tset) {
ret = task_can_attach(task);
if (ret)
goto out_unlock;
- /*
- * Skip rights over task check in v2 when nothing changes,
- * migration permission derives from hierarchy ownership in
- * cgroup_procs_write_permission()).
- */
- if (!cpuset_v2() || (cpus_updated || mems_updated)) {
+ if (setsched_check) {
ret = security_task_setscheduler(task);
if (ret)
goto out_unlock;
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v2 2/3] cgroup/cpuset: Skip security check for hotplug induced v1 task migration
2026-03-29 17:39 [PATCH v2 0/3] cgroup/cpuset: Fix v1 task migration failure from empty cpuset Waiman Long
2026-03-29 17:39 ` [PATCH v2 1/3] cgroup/cpuset: Simplify setsched decision check in task iteration loop of cpuset_can_attach() Waiman Long
@ 2026-03-29 17:39 ` Waiman Long
2026-03-30 1:48 ` Chen Ridong
2026-03-29 17:39 ` [PATCH v2 3/3] cgroup/cpuset: Improve check for v1 task migration out of empty cpuset Waiman Long
2 siblings, 1 reply; 10+ messages in thread
From: Waiman Long @ 2026-03-29 17:39 UTC (permalink / raw)
To: Chen Ridong, Tejun Heo, Johannes Weiner, Michal Koutný
Cc: cgroups, linux-kernel, Waiman Long
When a CPU hot removal causes a v1 cpuset to lose all its CPUs, the
cpuset hotplug handler will schedule a work function to migrate tasks
in that cpuset with no CPU to its ancestor to enable those tasks to
continue running.
If a strict security policy is in place, however, the task migration
may fail when security_task_setscheduler() call in cpuset_can_attach()
returns a -EACCESS error. That will mean that those tasks will have
no CPU to run on. The system administrators will have to explicitly
intervene to either add CPUs to that cpuset or move the tasks elsewhere
if they are aware of it.
This problem was found by a reported test failure in the LTP's
cpuset_hotplug_test.sh. Fix this problem by treating this special case
as an exception to skip the setsched security check as it is initated
internally within the kernel itself instead of from user input. Do that
by setting a new one-off CS_TASKS_OUT flag in the affected cpuset by the
hotplug handler to allow cpuset_can_attach() to skip the security check.
With that patch applied, the cpuset_hotplug_test.sh test can be run
successfully without failure.
Signed-off-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset-internal.h | 1 +
kernel/cgroup/cpuset-v1.c | 3 +++
kernel/cgroup/cpuset.c | 14 ++++++++++++++
3 files changed, 18 insertions(+)
diff --git a/kernel/cgroup/cpuset-internal.h b/kernel/cgroup/cpuset-internal.h
index fd7d19842ded..75e2c20249ad 100644
--- a/kernel/cgroup/cpuset-internal.h
+++ b/kernel/cgroup/cpuset-internal.h
@@ -46,6 +46,7 @@ typedef enum {
CS_SCHED_LOAD_BALANCE,
CS_SPREAD_PAGE,
CS_SPREAD_SLAB,
+ CS_TASKS_OUT,
} cpuset_flagbits_t;
/* The various types of files and directories in a cpuset file system */
diff --git a/kernel/cgroup/cpuset-v1.c b/kernel/cgroup/cpuset-v1.c
index 7308e9b02495..0c818edd0a1d 100644
--- a/kernel/cgroup/cpuset-v1.c
+++ b/kernel/cgroup/cpuset-v1.c
@@ -322,6 +322,9 @@ void cpuset1_hotplug_update_tasks(struct cpuset *cs,
return;
}
+ /* Enable task removal without security check */
+ set_bit(CS_TASKS_OUT, &cs->flags);
+
s->cs = cs;
INIT_WORK(&s->work, cpuset_migrate_tasks_workfn);
schedule_work(&s->work);
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 58c5b7b72cca..24d3ceef7991 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -3011,6 +3011,20 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
setsched_check = !cpuset_v2() ||
!cpumask_equal(cs->effective_cpus, oldcs->effective_cpus) ||
!nodes_equal(cs->effective_mems, oldcs->effective_mems);
+ /*
+ * Also check if task migration away from the old cpuset is allowed
+ * without security check. This bit should only be set by the hotplug
+ * handler when task migration from a child v1 cpuset to its ancestor
+ * is needed because there is no CPU left for the tasks to run on after
+ * a hot CPU removal. Clear the bit if set as it is one-off. Also
+ * doube-check the CPU emptiness of oldcs to be sure before clearing
+ * setsched_check.
+ */
+ if (test_bit(CS_TASKS_OUT, &oldcs->flags)) {
+ if (cpumask_empty(oldcs->effective_cpus))
+ setsched_check = false;
+ clear_bit(CS_TASKS_OUT, &oldcs->flags);
+ }
cgroup_taskset_for_each(task, css, tset) {
ret = task_can_attach(task);
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v2 2/3] cgroup/cpuset: Skip security check for hotplug induced v1 task migration
2026-03-29 17:39 ` [PATCH v2 2/3] cgroup/cpuset: Skip security check for hotplug induced v1 task migration Waiman Long
@ 2026-03-30 1:48 ` Chen Ridong
2026-03-30 16:15 ` Waiman Long
0 siblings, 1 reply; 10+ messages in thread
From: Chen Ridong @ 2026-03-30 1:48 UTC (permalink / raw)
To: Waiman Long, Chen Ridong, Tejun Heo, Johannes Weiner,
Michal Koutný
Cc: cgroups, linux-kernel
On 2026/3/30 1:39, Waiman Long wrote:
> When a CPU hot removal causes a v1 cpuset to lose all its CPUs, the
> cpuset hotplug handler will schedule a work function to migrate tasks
> in that cpuset with no CPU to its ancestor to enable those tasks to
> continue running.
>
> If a strict security policy is in place, however, the task migration
> may fail when security_task_setscheduler() call in cpuset_can_attach()
> returns a -EACCESS error. That will mean that those tasks will have
> no CPU to run on. The system administrators will have to explicitly
> intervene to either add CPUs to that cpuset or move the tasks elsewhere
> if they are aware of it.
>
> This problem was found by a reported test failure in the LTP's
> cpuset_hotplug_test.sh. Fix this problem by treating this special case
> as an exception to skip the setsched security check as it is initated
> internally within the kernel itself instead of from user input. Do that
> by setting a new one-off CS_TASKS_OUT flag in the affected cpuset by the
> hotplug handler to allow cpuset_can_attach() to skip the security check.
>
> With that patch applied, the cpuset_hotplug_test.sh test can be run
> successfully without failure.
>
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
> kernel/cgroup/cpuset-internal.h | 1 +
> kernel/cgroup/cpuset-v1.c | 3 +++
> kernel/cgroup/cpuset.c | 14 ++++++++++++++
> 3 files changed, 18 insertions(+)
>
> diff --git a/kernel/cgroup/cpuset-internal.h b/kernel/cgroup/cpuset-internal.h
> index fd7d19842ded..75e2c20249ad 100644
> --- a/kernel/cgroup/cpuset-internal.h
> +++ b/kernel/cgroup/cpuset-internal.h
> @@ -46,6 +46,7 @@ typedef enum {
> CS_SCHED_LOAD_BALANCE,
> CS_SPREAD_PAGE,
> CS_SPREAD_SLAB,
> + CS_TASKS_OUT,
> } cpuset_flagbits_t;
>
> /* The various types of files and directories in a cpuset file system */
> diff --git a/kernel/cgroup/cpuset-v1.c b/kernel/cgroup/cpuset-v1.c
> index 7308e9b02495..0c818edd0a1d 100644
> --- a/kernel/cgroup/cpuset-v1.c
> +++ b/kernel/cgroup/cpuset-v1.c
> @@ -322,6 +322,9 @@ void cpuset1_hotplug_update_tasks(struct cpuset *cs,
> return;
> }
>
> + /* Enable task removal without security check */
> + set_bit(CS_TASKS_OUT, &cs->flags);
> +
> s->cs = cs;
> INIT_WORK(&s->work, cpuset_migrate_tasks_workfn);
> schedule_work(&s->work);
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 58c5b7b72cca..24d3ceef7991 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -3011,6 +3011,20 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
> setsched_check = !cpuset_v2() ||
> !cpumask_equal(cs->effective_cpus, oldcs->effective_cpus) ||
> !nodes_equal(cs->effective_mems, oldcs->effective_mems);
> + /*
> + * Also check if task migration away from the old cpuset is allowed
> + * without security check. This bit should only be set by the hotplug
> + * handler when task migration from a child v1 cpuset to its ancestor
> + * is needed because there is no CPU left for the tasks to run on after
> + * a hot CPU removal. Clear the bit if set as it is one-off. Also
> + * doube-check the CPU emptiness of oldcs to be sure before clearing
> + * setsched_check.
> + */
> + if (test_bit(CS_TASKS_OUT, &oldcs->flags)) {
> + if (cpumask_empty(oldcs->effective_cpus))
> + setsched_check = false;
> + clear_bit(CS_TASKS_OUT, &oldcs->flags);
> + }
>
If there are many tasks in the cpuset that has no CPUs, they will be migrated
one by one. I'm afraid that only the first task will succeed, and the rest will
fail because the flag is cleared after processing the first one.
--
Best regards,
Ridong
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v2 2/3] cgroup/cpuset: Skip security check for hotplug induced v1 task migration
2026-03-30 1:48 ` Chen Ridong
@ 2026-03-30 16:15 ` Waiman Long
2026-03-30 18:21 ` Tejun Heo
0 siblings, 1 reply; 10+ messages in thread
From: Waiman Long @ 2026-03-30 16:15 UTC (permalink / raw)
To: Chen Ridong, Chen Ridong, Tejun Heo, Johannes Weiner,
Michal Koutný
Cc: cgroups, linux-kernel
On 3/29/26 9:48 PM, Chen Ridong wrote:
>
> On 2026/3/30 1:39, Waiman Long wrote:
>> When a CPU hot removal causes a v1 cpuset to lose all its CPUs, the
>> cpuset hotplug handler will schedule a work function to migrate tasks
>> in that cpuset with no CPU to its ancestor to enable those tasks to
>> continue running.
>>
>> If a strict security policy is in place, however, the task migration
>> may fail when security_task_setscheduler() call in cpuset_can_attach()
>> returns a -EACCESS error. That will mean that those tasks will have
>> no CPU to run on. The system administrators will have to explicitly
>> intervene to either add CPUs to that cpuset or move the tasks elsewhere
>> if they are aware of it.
>>
>> This problem was found by a reported test failure in the LTP's
>> cpuset_hotplug_test.sh. Fix this problem by treating this special case
>> as an exception to skip the setsched security check as it is initated
>> internally within the kernel itself instead of from user input. Do that
>> by setting a new one-off CS_TASKS_OUT flag in the affected cpuset by the
>> hotplug handler to allow cpuset_can_attach() to skip the security check.
>>
>> With that patch applied, the cpuset_hotplug_test.sh test can be run
>> successfully without failure.
>>
>> Signed-off-by: Waiman Long <longman@redhat.com>
>> ---
>> kernel/cgroup/cpuset-internal.h | 1 +
>> kernel/cgroup/cpuset-v1.c | 3 +++
>> kernel/cgroup/cpuset.c | 14 ++++++++++++++
>> 3 files changed, 18 insertions(+)
>>
>> diff --git a/kernel/cgroup/cpuset-internal.h b/kernel/cgroup/cpuset-internal.h
>> index fd7d19842ded..75e2c20249ad 100644
>> --- a/kernel/cgroup/cpuset-internal.h
>> +++ b/kernel/cgroup/cpuset-internal.h
>> @@ -46,6 +46,7 @@ typedef enum {
>> CS_SCHED_LOAD_BALANCE,
>> CS_SPREAD_PAGE,
>> CS_SPREAD_SLAB,
>> + CS_TASKS_OUT,
>> } cpuset_flagbits_t;
>>
>> /* The various types of files and directories in a cpuset file system */
>> diff --git a/kernel/cgroup/cpuset-v1.c b/kernel/cgroup/cpuset-v1.c
>> index 7308e9b02495..0c818edd0a1d 100644
>> --- a/kernel/cgroup/cpuset-v1.c
>> +++ b/kernel/cgroup/cpuset-v1.c
>> @@ -322,6 +322,9 @@ void cpuset1_hotplug_update_tasks(struct cpuset *cs,
>> return;
>> }
>>
>> + /* Enable task removal without security check */
>> + set_bit(CS_TASKS_OUT, &cs->flags);
>> +
>> s->cs = cs;
>> INIT_WORK(&s->work, cpuset_migrate_tasks_workfn);
>> schedule_work(&s->work);
>> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
>> index 58c5b7b72cca..24d3ceef7991 100644
>> --- a/kernel/cgroup/cpuset.c
>> +++ b/kernel/cgroup/cpuset.c
>> @@ -3011,6 +3011,20 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
>> setsched_check = !cpuset_v2() ||
>> !cpumask_equal(cs->effective_cpus, oldcs->effective_cpus) ||
>> !nodes_equal(cs->effective_mems, oldcs->effective_mems);
>> + /*
>> + * Also check if task migration away from the old cpuset is allowed
>> + * without security check. This bit should only be set by the hotplug
>> + * handler when task migration from a child v1 cpuset to its ancestor
>> + * is needed because there is no CPU left for the tasks to run on after
>> + * a hot CPU removal. Clear the bit if set as it is one-off. Also
>> + * doube-check the CPU emptiness of oldcs to be sure before clearing
>> + * setsched_check.
>> + */
>> + if (test_bit(CS_TASKS_OUT, &oldcs->flags)) {
>> + if (cpumask_empty(oldcs->effective_cpus))
>> + setsched_check = false;
>> + clear_bit(CS_TASKS_OUT, &oldcs->flags);
>> + }
>>
> If there are many tasks in the cpuset that has no CPUs, they will be migrated
> one by one. I'm afraid that only the first task will succeed, and the rest will
> fail because the flag is cleared after processing the first one.
The setsched_check flag is used in the cgroup_taskset_for_each() loop
below. That loop is going to iterate all the tasks to be migrated and so
the flag will apply to all of them. So it is not just the first one.
Cheers,
Longman
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v2 2/3] cgroup/cpuset: Skip security check for hotplug induced v1 task migration
2026-03-30 16:15 ` Waiman Long
@ 2026-03-30 18:21 ` Tejun Heo
2026-03-31 3:15 ` Waiman Long
0 siblings, 1 reply; 10+ messages in thread
From: Tejun Heo @ 2026-03-30 18:21 UTC (permalink / raw)
To: Waiman Long
Cc: Chen Ridong, Chen Ridong, Johannes Weiner, Michal Koutný,
cgroups, linux-kernel
Hello,
On Mon, Mar 30, 2026 at 12:15:01PM -0400, Waiman Long wrote:
...
> > If there are many tasks in the cpuset that has no CPUs, they will be migrated
> > one by one. I'm afraid that only the first task will succeed, and the rest will
> > fail because the flag is cleared after processing the first one.
>
> The setsched_check flag is used in the cgroup_taskset_for_each() loop below.
> That loop is going to iterate all the tasks to be migrated and so the flag
> will apply to all of them. So it is not just the first one.
During migration, a taskset is used to group tasks in a thread group if
cgroup_migrate() called with %true @threadgroup. That doens't really apply
here. cgroup_transfer_tasks() doesn't set @threadgroup and even if it were
to set set, there can just be multiple procesess. Besides, it's rather odd
for it be a one-shot param that gets cleared deep in the stack. Wouldn't it
make more sense to make whoever sets it to be responsible for clearing it?
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/3] cgroup/cpuset: Skip security check for hotplug induced v1 task migration
2026-03-30 18:21 ` Tejun Heo
@ 2026-03-31 3:15 ` Waiman Long
0 siblings, 0 replies; 10+ messages in thread
From: Waiman Long @ 2026-03-31 3:15 UTC (permalink / raw)
To: Tejun Heo
Cc: Chen Ridong, Chen Ridong, Johannes Weiner, Michal Koutný,
cgroups, linux-kernel
On 3/30/26 2:21 PM, Tejun Heo wrote:
> Hello,
>
> On Mon, Mar 30, 2026 at 12:15:01PM -0400, Waiman Long wrote:
> ...
>>> If there are many tasks in the cpuset that has no CPUs, they will be migrated
>>> one by one. I'm afraid that only the first task will succeed, and the rest will
>>> fail because the flag is cleared after processing the first one.
>> The setsched_check flag is used in the cgroup_taskset_for_each() loop below.
>> That loop is going to iterate all the tasks to be migrated and so the flag
>> will apply to all of them. So it is not just the first one.
> During migration, a taskset is used to group tasks in a thread group if
> cgroup_migrate() called with %true @threadgroup. That doens't really apply
> here. cgroup_transfer_tasks() doesn't set @threadgroup and even if it were
> to set set, there can just be multiple procesess. Besides, it's rather odd
> for it be a one-shot param that gets cleared deep in the stack. Wouldn't it
> make more sense to make whoever sets it to be responsible for clearing it?
Apparently, I have misunderstood how cgroup_transfer_tasks() works.
Right, it calls cgroup_migrate_execute() on a process-by-process basis.
So I shouldn't clear the flag in the first call. As for clearing the
flag, I think we can do it in the CPU hot-add situation or when the
cpuset.cpus is modified.
Thanks,
Longman
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 3/3] cgroup/cpuset: Improve check for v1 task migration out of empty cpuset
2026-03-29 17:39 [PATCH v2 0/3] cgroup/cpuset: Fix v1 task migration failure from empty cpuset Waiman Long
2026-03-29 17:39 ` [PATCH v2 1/3] cgroup/cpuset: Simplify setsched decision check in task iteration loop of cpuset_can_attach() Waiman Long
2026-03-29 17:39 ` [PATCH v2 2/3] cgroup/cpuset: Skip security check for hotplug induced v1 task migration Waiman Long
@ 2026-03-29 17:39 ` Waiman Long
2026-03-30 18:25 ` Tejun Heo
2 siblings, 1 reply; 10+ messages in thread
From: Waiman Long @ 2026-03-29 17:39 UTC (permalink / raw)
To: Chen Ridong, Tejun Heo, Johannes Weiner, Michal Koutný
Cc: cgroups, linux-kernel, Waiman Long
With the "cpuset_v2_mode" mount option, cpuset v1 will emulate v2 in
how it handles the management of CPUs. As a result, the effective_cpus
can differ from cpus_allowed and an empty cpus_allowed will cause
effective_cpus to inherit the value from its parent. Therefore task
migration out of a cpuset with empty "cpuset.cpus" should no longer
be needed in this case.
The current code doesn't handle this particular case. Update the code to
correctly detect that the cpuset has really no CPUs left by checking
effective_cpus instead of cpus_allowed.
Signed-off-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset-v1.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/kernel/cgroup/cpuset-v1.c b/kernel/cgroup/cpuset-v1.c
index 0c818edd0a1d..9855de37d011 100644
--- a/kernel/cgroup/cpuset-v1.c
+++ b/kernel/cgroup/cpuset-v1.c
@@ -261,7 +261,7 @@ static void remove_tasks_in_empty_cpuset(struct cpuset *cs)
* has online cpus, so can't be empty).
*/
parent = parent_cs(cs);
- while (cpumask_empty(parent->cpus_allowed) ||
+ while (cpumask_empty(parent->effective_cpus) ||
nodes_empty(parent->mems_allowed))
parent = parent_cs(parent);
@@ -297,14 +297,16 @@ void cpuset1_hotplug_update_tasks(struct cpuset *cs,
/*
* Don't call cpuset_update_tasks_cpumask() if the cpuset becomes empty,
- * as the tasks will be migrated to an ancestor.
+ * as the tasks will be migrated to an ancestor. If cpuset_v2_mode mount
+ * option is used, effective_cpus can differ from cpus_allowed. So
+ * checking effective_cpus is more accurate for determining emptiness.
*/
- if (cpus_updated && !cpumask_empty(cs->cpus_allowed))
+ if (cpus_updated && !cpumask_empty(cs->effective_cpus))
cpuset_update_tasks_cpumask(cs, new_cpus);
if (mems_updated && !nodes_empty(cs->mems_allowed))
cpuset_update_tasks_nodemask(cs);
- is_empty = cpumask_empty(cs->cpus_allowed) ||
+ is_empty = cpumask_empty(cs->effective_cpus) ||
nodes_empty(cs->mems_allowed);
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2 3/3] cgroup/cpuset: Improve check for v1 task migration out of empty cpuset
2026-03-29 17:39 ` [PATCH v2 3/3] cgroup/cpuset: Improve check for v1 task migration out of empty cpuset Waiman Long
@ 2026-03-30 18:25 ` Tejun Heo
2026-03-31 1:05 ` Waiman Long
0 siblings, 1 reply; 10+ messages in thread
From: Tejun Heo @ 2026-03-30 18:25 UTC (permalink / raw)
To: Waiman Long
Cc: Chen Ridong, Johannes Weiner, Michal Koutný, cgroups,
linux-kernel
On Sun, Mar 29, 2026 at 01:39:58PM -0400, Waiman Long wrote:
> With the "cpuset_v2_mode" mount option, cpuset v1 will emulate v2 in
> how it handles the management of CPUs. As a result, the effective_cpus
> can differ from cpus_allowed and an empty cpus_allowed will cause
> effective_cpus to inherit the value from its parent. Therefore task
> migration out of a cpuset with empty "cpuset.cpus" should no longer
> be needed in this case.
>
> The current code doesn't handle this particular case. Update the code to
> correctly detect that the cpuset has really no CPUs left by checking
> effective_cpus instead of cpus_allowed.
>
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
> kernel/cgroup/cpuset-v1.c | 10 ++++++----
> 1 file changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/kernel/cgroup/cpuset-v1.c b/kernel/cgroup/cpuset-v1.c
> index 0c818edd0a1d..9855de37d011 100644
> --- a/kernel/cgroup/cpuset-v1.c
> +++ b/kernel/cgroup/cpuset-v1.c
> @@ -261,7 +261,7 @@ static void remove_tasks_in_empty_cpuset(struct cpuset *cs)
> * has online cpus, so can't be empty).
> */
> parent = parent_cs(cs);
> - while (cpumask_empty(parent->cpus_allowed) ||
> + while (cpumask_empty(parent->effective_cpus) ||
> nodes_empty(parent->mems_allowed))
> parent = parent_cs(parent);
>
> @@ -297,14 +297,16 @@ void cpuset1_hotplug_update_tasks(struct cpuset *cs,
>
> /*
> * Don't call cpuset_update_tasks_cpumask() if the cpuset becomes empty,
> - * as the tasks will be migrated to an ancestor.
> + * as the tasks will be migrated to an ancestor. If cpuset_v2_mode mount
> + * option is used, effective_cpus can differ from cpus_allowed. So
> + * checking effective_cpus is more accurate for determining emptiness.
> */
> - if (cpus_updated && !cpumask_empty(cs->cpus_allowed))
> + if (cpus_updated && !cpumask_empty(cs->effective_cpus))
> cpuset_update_tasks_cpumask(cs, new_cpus);
> if (mems_updated && !nodes_empty(cs->mems_allowed))
> cpuset_update_tasks_nodemask(cs);
>
> - is_empty = cpumask_empty(cs->cpus_allowed) ||
> + is_empty = cpumask_empty(cs->effective_cpus) ||
> nodes_empty(cs->mems_allowed);
Are these meaningful changes? cpuset1_hotplug_update_tasks() is called by
cpuset_hotplug_update_tasks() when !is_in_v2_mode(). As is_in_v2_mode() says
yes on cpuset_v2_mode, the above change doesn't really change anything, no?
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 3/3] cgroup/cpuset: Improve check for v1 task migration out of empty cpuset
2026-03-30 18:25 ` Tejun Heo
@ 2026-03-31 1:05 ` Waiman Long
0 siblings, 0 replies; 10+ messages in thread
From: Waiman Long @ 2026-03-31 1:05 UTC (permalink / raw)
To: Tejun Heo
Cc: Chen Ridong, Johannes Weiner, Michal Koutný, cgroups,
linux-kernel
On 3/30/26 2:25 PM, Tejun Heo wrote:
> On Sun, Mar 29, 2026 at 01:39:58PM -0400, Waiman Long wrote:
>> With the "cpuset_v2_mode" mount option, cpuset v1 will emulate v2 in
>> how it handles the management of CPUs. As a result, the effective_cpus
>> can differ from cpus_allowed and an empty cpus_allowed will cause
>> effective_cpus to inherit the value from its parent. Therefore task
>> migration out of a cpuset with empty "cpuset.cpus" should no longer
>> be needed in this case.
>>
>> The current code doesn't handle this particular case. Update the code to
>> correctly detect that the cpuset has really no CPUs left by checking
>> effective_cpus instead of cpus_allowed.
>>
>> Signed-off-by: Waiman Long <longman@redhat.com>
>> ---
>> kernel/cgroup/cpuset-v1.c | 10 ++++++----
>> 1 file changed, 6 insertions(+), 4 deletions(-)
>>
>> diff --git a/kernel/cgroup/cpuset-v1.c b/kernel/cgroup/cpuset-v1.c
>> index 0c818edd0a1d..9855de37d011 100644
>> --- a/kernel/cgroup/cpuset-v1.c
>> +++ b/kernel/cgroup/cpuset-v1.c
>> @@ -261,7 +261,7 @@ static void remove_tasks_in_empty_cpuset(struct cpuset *cs)
>> * has online cpus, so can't be empty).
>> */
>> parent = parent_cs(cs);
>> - while (cpumask_empty(parent->cpus_allowed) ||
>> + while (cpumask_empty(parent->effective_cpus) ||
>> nodes_empty(parent->mems_allowed))
>> parent = parent_cs(parent);
>>
>> @@ -297,14 +297,16 @@ void cpuset1_hotplug_update_tasks(struct cpuset *cs,
>>
>> /*
>> * Don't call cpuset_update_tasks_cpumask() if the cpuset becomes empty,
>> - * as the tasks will be migrated to an ancestor.
>> + * as the tasks will be migrated to an ancestor. If cpuset_v2_mode mount
>> + * option is used, effective_cpus can differ from cpus_allowed. So
>> + * checking effective_cpus is more accurate for determining emptiness.
>> */
>> - if (cpus_updated && !cpumask_empty(cs->cpus_allowed))
>> + if (cpus_updated && !cpumask_empty(cs->effective_cpus))
>> cpuset_update_tasks_cpumask(cs, new_cpus);
>> if (mems_updated && !nodes_empty(cs->mems_allowed))
>> cpuset_update_tasks_nodemask(cs);
>>
>> - is_empty = cpumask_empty(cs->cpus_allowed) ||
>> + is_empty = cpumask_empty(cs->effective_cpus) ||
>> nodes_empty(cs->mems_allowed);
> Are these meaningful changes? cpuset1_hotplug_update_tasks() is called by
> cpuset_hotplug_update_tasks() when !is_in_v2_mode(). As is_in_v2_mode() says
> yes on cpuset_v2_mode, the above change doesn't really change anything, no?
You are right. I missed that part. So it is really a no-op then. Will
drop this patch.
Thanks!
Longman
^ permalink raw reply [flat|nested] 10+ messages in thread