Skip to content

Commit 6b51c7e

Browse files
committed
cgroup/cpuset: Always use cpu_active_mask
JIRA: https://issues.redhat.com/browse/RHEL-107751 commit 7a0aabd Author: Waiman Long <longman@redhat.com> Date: Mon, 7 Apr 2025 17:21:03 -0400 cgroup/cpuset: Always use cpu_active_mask The current cpuset code uses both cpu_active_mask and cpu_online_mask and it can be confusing which one should be used if we need to update the code. The top_cpuset is always synchronized to cpu_active_mask and we should avoid using cpu_online_mask as much as possible. An active CPU is always an online CPU, but not vice versa. cpu_active_mask and cpu_online_mask can differ during hotplug operations. A CPU is marked active at the last stage of CPU bringup (CPUHP_AP_ACTIVE). It is also the stage where cpuset hotplug code will be called to update the sched domains so that the scheduler can move a normal task to a newly active CPU or remove tasks away from a newly inactivated CPU. The online bit is set much earlier in the CPU bringup process and cleared much later in CPU teardown. If cpu_online_mask is used while a hotunplug operation is happening in parallel, we may leave an offline CPU in cpu_allowed or have a higher chance of leaving an offline CPU in some other masks. Avoid this problem by always using cpu_active_mask in the cpuset code and leave a comment as to why the use of cpu_online_mask is discouraged. Signed-off-by: Waiman Long <longman@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Waiman Long <longman@redhat.com>
1 parent c9dadee commit 6b51c7e

File tree

1 file changed

+23
-9
lines changed

1 file changed

+23
-9
lines changed

kernel/cgroup/cpuset.c

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,20 @@ static inline void notify_partition_change(struct cpuset *cs, int old_prs)
192192
WRITE_ONCE(cs->prs_err, PERR_NONE);
193193
}
194194

195+
/*
196+
* The top_cpuset is always synchronized to cpu_active_mask and we should avoid
197+
* using cpu_online_mask as much as possible. An active CPU is always an online
198+
* CPU, but not vice versa. cpu_active_mask and cpu_online_mask can differ
199+
* during hotplug operations. A CPU is marked active at the last stage of CPU
200+
* bringup (CPUHP_AP_ACTIVE). It is also the stage where cpuset hotplug code
201+
* will be called to update the sched domains so that the scheduler can move
202+
* a normal task to a newly active CPU or remove tasks away from a newly
203+
* inactivated CPU. The online bit is set much earlier in the CPU bringup
204+
* process and cleared much later in CPU teardown.
205+
*
206+
* If cpu_online_mask is used while a hotunplug operation is happening in
207+
* parallel, we may leave an offline CPU in cpu_allowed or some other masks.
208+
*/
195209
static struct cpuset top_cpuset = {
196210
.flags = BIT(CS_ONLINE) | BIT(CS_CPU_EXCLUSIVE) |
197211
BIT(CS_MEM_EXCLUSIVE) | BIT(CS_SCHED_LOAD_BALANCE),
@@ -355,18 +369,18 @@ static inline bool partition_is_populated(struct cpuset *cs,
355369
* appropriate cpus.
356370
*
357371
* One way or another, we guarantee to return some non-empty subset
358-
* of cpu_online_mask.
372+
* of cpu_active_mask.
359373
*
360374
* Call with callback_lock or cpuset_mutex held.
361375
*/
362-
static void guarantee_online_cpus(struct task_struct *tsk,
376+
static void guarantee_active_cpus(struct task_struct *tsk,
363377
struct cpumask *pmask)
364378
{
365379
const struct cpumask *possible_mask = task_cpu_possible_mask(tsk);
366380
struct cpuset *cs;
367381

368-
if (WARN_ON(!cpumask_and(pmask, possible_mask, cpu_online_mask)))
369-
cpumask_copy(pmask, cpu_online_mask);
382+
if (WARN_ON(!cpumask_and(pmask, possible_mask, cpu_active_mask)))
383+
cpumask_copy(pmask, cpu_active_mask);
370384

371385
rcu_read_lock();
372386
cs = task_cs(tsk);
@@ -2286,7 +2300,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
22862300
bool force = false;
22872301
int old_prs = cs->partition_root_state;
22882302

2289-
/* top_cpuset.cpus_allowed tracks cpu_online_mask; it's read-only */
2303+
/* top_cpuset.cpus_allowed tracks cpu_active_mask; it's read-only */
22902304
if (cs == &top_cpuset)
22912305
return -EACCES;
22922306

@@ -3105,7 +3119,7 @@ static void cpuset_attach_task(struct cpuset *cs, struct task_struct *task)
31053119
lockdep_assert_held(&cpuset_mutex);
31063120

31073121
if (cs != &top_cpuset)
3108-
guarantee_online_cpus(task, cpus_attach);
3122+
guarantee_active_cpus(task, cpus_attach);
31093123
else
31103124
cpumask_andnot(cpus_attach, task_cpu_possible_mask(task),
31113125
subpartitions_cpus);
@@ -4049,7 +4063,7 @@ void __init cpuset_init_smp(void)
40494063
*
40504064
* Description: Returns the cpumask_var_t cpus_allowed of the cpuset
40514065
* attached to the specified @tsk. Guaranteed to return some non-empty
4052-
* subset of cpu_online_mask, even if this means going outside the
4066+
* subset of cpu_active_mask, even if this means going outside the
40534067
* tasks cpuset, except when the task is in the top cpuset.
40544068
**/
40554069

@@ -4063,7 +4077,7 @@ void cpuset_cpus_allowed(struct task_struct *tsk, struct cpumask *pmask)
40634077

40644078
cs = task_cs(tsk);
40654079
if (cs != &top_cpuset)
4066-
guarantee_online_cpus(tsk, pmask);
4080+
guarantee_active_cpus(tsk, pmask);
40674081
/*
40684082
* Tasks in the top cpuset won't get update to their cpumasks
40694083
* when a hotplug online/offline event happens. So we include all
@@ -4077,7 +4091,7 @@ void cpuset_cpus_allowed(struct task_struct *tsk, struct cpumask *pmask)
40774091
* allowable online cpu left, we fall back to all possible cpus.
40784092
*/
40794093
cpumask_andnot(pmask, possible_mask, subpartitions_cpus);
4080-
if (!cpumask_intersects(pmask, cpu_online_mask))
4094+
if (!cpumask_intersects(pmask, cpu_active_mask))
40814095
cpumask_copy(pmask, possible_mask);
40824096
}
40834097

0 commit comments

Comments
 (0)