Re: [PATCH-next 2/6] cgroup/cpuset: Properly compute effective xcpus in update_parent_effective_cpumask()

From: Waiman Long

Date: Fri Oct 23 2026 - 16:49:23 EST


On 10/22/26 9:53 PM, Guopeng Zhang wrote:

在 2026/10/22 23:00, Waiman Long 写道:
On 10/22/26 9:45 AM, Guopeng Zhang wrote:
Hi Longman,

在 2026/10/22 11:16, Waiman Long 写道:
Since the introduction of cpuset.cpus.exclusive in commit
e2ffe502ba45 ("cgroup/cpuset: Add cpuset.cpus.exclusive for v2"), a
compute_effective_exclusive_cpumask() helper which is later renamed to
compute_excpus() is added to compute the effective xcpus of a partition
root. However update_parent_effective_cpumask() is not updated in all
proper places to use the new helper to check if a given cpuset should
remain a valid partition root. This can cause a cpuset to incorrectly
remain a valid partition root even if no effective xcpus is left.

Fix that problem by using compute_excpus() to compute the effective xcpus
into delmask in all cases except partcmd_disable and partcmd_invalidate
and use it for tasks_nocpu_error() check as well as checking its
emptiness. This enables us to catch invalid partition root more
accurately in update_parent_effective_cpumask().

I re-tested the repro from the link below on top of this series
(applied on cgroup/for-7.4-fixes), and it still fails:

   https://lore.kernel.org/all/20261010075947.333549-3-guopeng.zhang@xxxxxxxxx/

   cd /sys/fs/cgroup
   echo +cpuset > cgroup.subtree_control
   mkdir A
   echo 0-7 > A/cpuset.cpus
   echo 0-7 > A/cpuset.cpus.exclusive
   echo root > A/cpuset.cpus.partition
   cat A/cpuset.cpus.partition
   echo 1 > A/cpuset.cpus.exclusive
   cat A/cpuset.cpus.partition

The last command still shows "root invalid (Parent unable to distribute
cpu downstream)".

In this case compute_excpus() returns the stale user mask unchanged.
user_xcpus() is gone from update_parent_effective_cpumask(), but the
dependency just moved one level down: the new code calls
compute_excpus(cs, tmp->delmask), and its first line is

   cpumask_and(excpus, user_xcpus(cs), parent->effective_xcpus)

Here user_xcpus(cs) is cs->exclusive_cpus, which still holds the old
0-7 when compute_excpus() runs: update_exclusive_cpumask() publishes
cs->exclusive_cpus only after partition_cpus_change(). Nothing corrects
it either - the sibling trim is skipped as exclusive_cpus is non-empty,
and for a direct child of the root cpuset the intersection with
parent->effective_xcpus is a no-op. So the stale 0-7 mask still reaches
tasks_nocpu_error() and PERR_NOCPUS is set again. Please point it out
if I got the analysis wrong.

I have rebased my fix on top of this series and the partition recovers
correctly with it applied. Should the fix be folded into this patch,
or is there a better way to fix it? Happy to hear your thoughts.
You are right. My patch series won't fix this particular issue. However, converting an invalid partition back to a valid one is done on a best effort basis. There is no guarantee that it will always happen. Just echo "root" to "cpuset.cpus.partition" again will make it valid again. So it is not a real bug from my point of view. It is just a nice to have feature.

Thanks for the explanation. This helps me better understand the
intended behavior of partition recovery.

I did find the reason why your test case isn't working. I have made some adjustment in patch 2 which should make your test case work now with the v2 series.

Cheers,
Longman