cgroup/cpuset: Preserve boot-isolated CPUs on partition release

isolated_cpus tracks CPUs isolated with isolcpus= as well as CPUs in
isolated cpuset partitions. When an isolated partition is released,
isolated_cpus_update() removes its whole CPU mask. This also clears CPUs
which were already isolated at boot.

This can be reproduced on a cgroup v2 system booted with
isolcpus=domain,15:

    cd /sys/fs/cgroup
    echo +cpuset > cgroup.subtree_control
    mkdir cpuset-repro
    echo 15 > cpuset-repro/cpuset.cpus
    echo isolated > cpuset-repro/cpuset.cpus.partition
    echo member > cpuset-repro/cpuset.cpus.partition
    cat cpuset.cpus.isolated

CPU 15 is absent before the change. It must remain in
cpuset.cpus.isolated after the partition is released.

Update isolated_cpus one CPU at a time and keep CPUs outside the
boot-time domain housekeeping mask isolated.

Fixes: c188f33c86 ("cgroup/cpuset: Account for boot time isolated CPUs")
Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
Acked-by: Waiman Long <longman@redhat.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
Guopeng Zhang 2026-08-24 10:01:39 +08:00 committed by Tejun Heo
parent 2bf404b1bd
commit 6c37d7e074

View File

@ -1259,6 +1259,28 @@ static void reset_partition_data(struct cpuset *cs)
cpumask_copy(cs->effective_cpus, parent->effective_cpus);
}
/* Return true if isolated_cpus changes. */
static bool isolated_cpu_update(int new_prs, int cpu)
{
lockdep_assert_held(&callback_lock);
lockdep_assert_held(&cpuset_mutex);
if (new_prs == PRS_ISOLATED) {
if (cpumask_test_cpu(cpu, isolated_cpus))
return false;
cpumask_set_cpu(cpu, isolated_cpus);
return true;
}
/* CPUs isolated at boot must remain isolated. */
if (!cpumask_test_cpu(cpu,
housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT)) ||
!cpumask_test_cpu(cpu, isolated_cpus))
return false;
cpumask_clear_cpu(cpu, isolated_cpus);
return true;
}
/*
* isolated_cpus_update - Update the isolated_cpus mask
* @old_prs: old partition_root_state
@ -1267,19 +1289,16 @@ static void reset_partition_data(struct cpuset *cs)
*/
static void isolated_cpus_update(int old_prs, int new_prs, struct cpumask *xcpus)
{
bool updated = false;
int cpu;
WARN_ON_ONCE(old_prs == new_prs);
lockdep_assert_held(&callback_lock);
lockdep_assert_held(&cpuset_mutex);
if (new_prs == PRS_ISOLATED) {
if (cpumask_subset(xcpus, isolated_cpus))
return;
cpumask_or(isolated_cpus, isolated_cpus, xcpus);
} else {
if (!cpumask_intersects(xcpus, isolated_cpus))
return;
cpumask_andnot(isolated_cpus, isolated_cpus, xcpus);
}
update_housekeeping = true;
for_each_cpu(cpu, xcpus)
updated |= isolated_cpu_update(new_prs, cpu);
if (updated)
update_housekeeping = true;
}
/*