From nobody Sat Sep 26 10:01:23 2026 Received: from mta0.migadu.com (out-119.mta0.migadu.com [91.218.175.119]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6718144063B for ; Wed, 2 Sep 2026 10:26:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.119 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788344796; cv=none; b=DrQoJhUhY7BX2hGHRThZbcDVlI6x5e5OBIWH03ezpzrylckYIhCrKGBtrpM2qzicVfuv3cjGcVB/6EzZUvWB06JzuYN7kcUVai0jzhFrTH2LHe9uV6D7nSEB/F21ZojSyC8DTIIWsSVRpxERW6wsEXxeCQfSXA8Orlni9I5zJMI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788344796; c=relaxed/simple; bh=kQ4SUfFL7l6CK6D4M0vZTJ4yXI8I7EmpzCUw04y0Mtw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Nxc62zyxryZjF4RZTViXeKLHt9jna6brSBDhBDxwyNn5lBNywhG6nCL6ebkGB3CpdN70sNK/6d7Dt7xN7JJfvLkTeoa1Pr/X4hfxsFrT8RZnvYlLaAq6a9jq0OaQDzAc4G7RG6BAHdonUJqpMqjs6OpbMbTjx33KDRB568cb4Pk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=Z4jLufZg; arc=none smtp.client-ip=91.218.175.119 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="Z4jLufZg" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=kQ4SUfFL7l6CK6D4M0vZTJ4yXI8I7EmpzCUw04y0Mtw=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1788344791; v=1; x=1788949591; b=Z4jLufZgUef4DIgbPPU1Cyw4/bpI5GGQ4RxQup3T3iPBT/hODAZJ5bWcRfB9J8VMbz9XpKDh zIjuasbPK8qlbmx5JK5IS46/8qBK4/gz9+U55zlXGOSMJpfU93aENvSChlBu2KMEt0zjjLR9cIi 42LJzqKerGkBF9f9/rWnt11c= X-Envelope-To: linux-kernel@vger.kernel.org Received: by smtp.migadu.com with ESMTPS id b319449c4d0dc839; Wed, 02 Sep 2026 10:26:31 +0000 X-Mizu-Trace-ID: b319449c4d0dc839 X-Migadu-Flow: FLOW_OUT From: Guopeng Zhang To: cgroups@vger.kernel.org, longman@redhat.com, ridong.chen@linux.dev Cc: tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, shuah@kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Guopeng Zhang Subject: [PATCH v3 1/7] cgroup/cpuset: Factor out child partition validation Date: Wed, 2 Sep 2026 18:26:09 +0800 Message-ID: <20260902102615.79189-2-guopeng.zhang@linux.dev> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260902102615.79189-1-guopeng.zhang@linux.dev> References: <20260902102615.79189-1-guopeng.zhang@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Guopeng Zhang compute_partition_effective_cpumask() checks whether each valid child partition remains covered by the parent exclusive CPU mask and whether it would consume all remaining CPUs of a populated parent. Factor these two checks into child_partition_error() so the same rules can be reused when evaluating a proposed parent configuration. This is a preparatory refactoring with no intended functional change. Signed-off-by: Guopeng Zhang --- kernel/cgroup/cpuset.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 8f24171b6055..6994dc75d940 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -2085,6 +2085,26 @@ static int update_parent_effective_cpumask(struct cp= uset *cs, int cmd, return 0; } =20 +/* + * Return the error that will invalidate a child partition under a proposed + * parent partition configuration. + */ +static enum prs_errcode +child_partition_error(struct cpuset *child, + const struct cpumask *partition_cpus, + const struct cpumask *remaining_cpus, + bool parent_populated) +{ + if (!cpumask_subset(child->effective_xcpus, partition_cpus)) + return PERR_INVCPUS; + + if (parent_populated && + cpumask_subset(remaining_cpus, child->effective_xcpus)) + return PERR_NOCPUS; + + return PERR_NONE; +} + /** * compute_partition_effective_cpumask - compute effective_cpus for partit= ion * @cs: partition root cpuset @@ -2121,6 +2141,8 @@ static void compute_partition_effective_cpumask(struc= t cpuset *cs, =20 rcu_read_lock(); cpuset_for_each_child(child, css, cs) { + enum prs_errcode child_err; + if (!is_partition_valid(child)) continue; =20 @@ -2129,15 +2151,13 @@ static void compute_partition_effective_cpumask(str= uct cpuset *cs, * partition root. */ WARN_ON_ONCE(is_remote_partition(child)); - WRITE_ONCE(child->prs_err, 0); - if (!cpumask_subset(child->effective_xcpus, - cs->effective_xcpus)) - WRITE_ONCE(child->prs_err, PERR_INVCPUS); - else if (populated && - cpumask_subset(new_ecpus, child->effective_xcpus)) - WRITE_ONCE(child->prs_err, PERR_NOCPUS); - - if (child->prs_err) { + WRITE_ONCE(child->prs_err, PERR_NONE); + child_err =3D child_partition_error(child, cs->effective_xcpus, + new_ecpus, populated); + if (child_err) + WRITE_ONCE(child->prs_err, child_err); + + if (child_err) { int old_prs =3D child->partition_root_state; =20 /* --=20 2.43.0 From nobody Sat Sep 26 10:01:23 2026 Received: from mta1.migadu.com (out-154.mta1.migadu.com [95.215.58.154]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 565913A1E92 for ; Wed, 2 Sep 2026 10:26:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.154 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788344802; cv=none; b=BaZ586HReOtH9tGl4vs8jB+QNroGLT2P6u2l0cXttE6aEj/10kg1FNxNzGZCidipq7nkzlzUkf18STZu/Hc7dzGMMPE1Vy8FojKmHlOTNxlo4mNGKpBKNM7yV874irtio3xfEV7yOYMH3HApfdzJR5akSS5DfncEDe/VV9bQ2Nw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788344802; c=relaxed/simple; bh=76mSk235XDEvU0T6h3abZzmqTjj8sG7ZMLytmlitcUI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bbIzwjUfu8QaOsYhbkdJbOh7nmJW1xwtU9vL2gzX3aM4x0NZUj2ekD/sEcCj6b9RMRQynGfz15Yp9bXnJGN8gTjmidwjBv3MHhZOemLOD4mKRQ48gLmlwp8nQpwBXk85SIRWJDtP6TDdu6m9cFI4ETBD08HPYIUjpcXJWwEnTjY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=YeH/d3B2; arc=none smtp.client-ip=95.215.58.154 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="YeH/d3B2" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=76mSk235XDEvU0T6h3abZzmqTjj8sG7ZMLytmlitcUI=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1788344797; v=1; x=1788949597; b=YeH/d3B20hJisSy6M2VGJ7qbHx4icTKbj5Tdpu3CyC6o2Qb3ICz6d8BD0z54w1uFKvx2o0zT YKXhpztC4dtt5HNlN9gGTI0w7agdPQS3h4k2W3M5jvr7nL1tcwrm6LfNdH1ITca/RLQgV/7xSi4 8meyWIPGh5iw432ynSHR3ZV4= X-Envelope-To: linux-kernel@vger.kernel.org Received: by smtp.migadu.com with ESMTPS id 00d23fc2425b8e67; Wed, 02 Sep 2026 10:26:37 +0000 X-Mizu-Trace-ID: 00d23fc2425b8e67 X-Migadu-Flow: FLOW_OUT From: Guopeng Zhang To: cgroups@vger.kernel.org, longman@redhat.com, ridong.chen@linux.dev Cc: tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, shuah@kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Guopeng Zhang Subject: [PATCH v3 2/7] cgroup/cpuset: Account for child CPU ownership in partition changes Date: Wed, 2 Sep 2026 18:26:10 +0800 Message-ID: <20260902102615.79189-3-guopeng.zhang@linux.dev> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260902102615.79189-1-guopeng.zhang@linux.dev> References: <20260902102615.79189-1-guopeng.zhang@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Guopeng Zhang effective_xcpus includes CPUs granted to valid child partitions. A change to the parent must not apply its isolation state or housekeeping checks to CPUs which remain owned by those children. For example, on a cgroup v2 system with CPUs 0-3 online: cd /sys/fs/cgroup echo +cpuset > cgroup.subtree_control mkdir type-repro echo 1-3 > type-repro/cpuset.cpus echo isolated > type-repro/cpuset.cpus.partition echo +cpuset > type-repro/cgroup.subtree_control mkdir type-repro/child echo 2-3 > type-repro/child/cpuset.cpus echo isolated > type-repro/child/cpuset.cpus.partition echo root > type-repro/cpuset.cpus.partition cat cpuset.cpus.isolated The isolated mask should still contain CPUs 2-3 after the parent becomes a root partition. Without this change, those CPUs are removed even though the child remains isolated. Compute the CPUs owned directly by a partition by excluding CPUs granted to valid children. When validating a trial parent mask, exclude only CPUs granted to children that will remain valid under that mask. Reuse the child validation rules so PERR_INVCPUS and PERR_NOCPUS are handled consistently. Use the directly owned mask for root/isolated type changes and housekeeping validation. If a root child returns the last housekeeping CPU to an isolated parent, invalidate the outermost isolated ancestor so the child can still become a member without violating the housekeeping constraint. Link: https://sashiko.dev/#/patchset/20260820124202.517160-1-guopeng.zhang%= 40linux.dev?part=3D6 Link: https://sashiko.dev/#/patchset/20260828095643.13395-1-guopeng.zhang@l= inux.dev?part=3D1 Fixes: 4a74e418881f ("cgroup/cpuset: Check partition conflict with housekee= ping setup") Fixes: 11e5f407b64a ("cgroup/cpuset: Keep track of CPUs in isolated partiti= ons") Fixes: 103b08709e8a ("cgroup/cpuset: Fail if isolated and nohz_full don't l= eave any housekeeping") Fixes: b1034a690129 ("cgroup/cpuset: Ensure domain isolated CPUs stay in ro= ot or isolated partition") Signed-off-by: Guopeng Zhang --- kernel/cgroup/cpuset.c | 138 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 128 insertions(+), 10 deletions(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 6994dc75d940..19efa62bb694 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -2175,6 +2175,46 @@ static void compute_partition_effective_cpumask(stru= ct cpuset *cs, rcu_read_unlock(); } =20 +/* + * Compute CPUs owned directly by a partition. + * + * effective_xcpus includes CPUs granted to valid child partitions. Exclude + * those CPUs when checking or changing this partition's type. + */ +static void compute_partition_owned_cpumask(struct cpuset *cs, + const struct cpumask *partition_cpus, + struct cpumask *owned_cpus, + struct cpumask *remaining_cpus) +{ + struct cgroup_subsys_state *css; + struct cpuset *child; + bool populated =3D partition_is_populated(cs, NULL); + + lockdep_assert_held(&cpuset_mutex); + cpumask_copy(owned_cpus, partition_cpus); + cpumask_and(remaining_cpus, partition_cpus, cpu_active_mask); + + rcu_read_lock(); + cpuset_for_each_child(child, css, cs) { + if (!is_partition_valid(child)) + continue; + + /* + * A child that will become invalid under the proposed + * configuration cannot retain ownership of its CPUs. + */ + if (child_partition_error(child, partition_cpus, + remaining_cpus, populated)) + continue; + + cpumask_andnot(owned_cpus, owned_cpus, + child->effective_xcpus); + cpumask_andnot(remaining_cpus, remaining_cpus, + child->effective_xcpus); + } + rcu_read_unlock(); +} + /* * update_cpumasks_hier - Update effective cpumasks and tasks in the subtr= ee * @cs: the cpuset to consider @@ -2415,13 +2455,18 @@ static int parse_cpuset_cpulist(const char *buf, st= ruct cpumask *out_mask) * validate_partition - Validate a cpuset partition configuration * @cs: The cpuset to validate * @trialcs: The trial cpuset containing proposed configuration changes + * @owned_cpus: Scratch mask for CPUs owned directly by the trial partition + * @remaining_cpus: Scratch mask used to predict valid child partitions * * If any validation check fails, the appropriate error code is set in the * cpuset's prs_err field. * * Return: PRS error code (0 if valid, non-zero error code if invalid) */ -static enum prs_errcode validate_partition(struct cpuset *cs, struct cpuse= t *trialcs) +static enum prs_errcode validate_partition(struct cpuset *cs, + struct cpuset *trialcs, + struct cpumask *owned_cpus, + struct cpumask *remaining_cpus) { struct cpuset *parent =3D parent_cs(cs); =20 @@ -2431,8 +2476,10 @@ static enum prs_errcode validate_partition(struct cp= uset *cs, struct cpuset *tri if (cpumask_empty(trialcs->effective_xcpus)) return PERR_INVCPUS; =20 + compute_partition_owned_cpumask(cs, trialcs->effective_xcpus, + owned_cpus, remaining_cpus); if (prstate_housekeeping_conflict(trialcs->partition_root_state, - trialcs->effective_xcpus)) + owned_cpus)) return PERR_HKEEPING; =20 if (tasks_nocpu_error(parent, cs, trialcs->effective_xcpus)) @@ -2458,7 +2505,8 @@ static void partition_cpus_change(struct cpuset *cs, = struct cpuset *trialcs, if (cs_is_member(cs)) return; =20 - prs_err =3D validate_partition(cs, trialcs); + prs_err =3D validate_partition(cs, trialcs, tmp->new_cpus, + tmp->addmask); if (prs_err) { WRITE_ONCE(cs->prs_err, prs_err); trialcs->prs_err =3D prs_err; @@ -2937,6 +2985,48 @@ int cpuset_update_flag(cpuset_flagbits_t bit, struct= cpuset *cs, return err; } =20 +/* + * Invalidate the highest isolated partition that contains @cs. + * + * A root partition returning CPUs to an isolated parent can consume the l= ast + * housekeeping CPU. Invalidating the whole chain returns the CPUs to a ro= ot + * partition instead. + */ +static struct cpuset *invalidate_isolated_ancestor(struct cpuset *cs, + struct tmpmasks *tmp) +{ + struct cpuset *ancestor =3D parent_cs(cs); + struct cpuset *parent; + int err; + + lockdep_assert_held(&cpuset_mutex); + if (WARN_ON_ONCE(!ancestor)) + return NULL; + + while ((ancestor !=3D &top_cpuset) && + !is_remote_partition(ancestor)) { + parent =3D parent_cs(ancestor); + if (!parent || + parent->partition_root_state !=3D PRS_ISOLATED) + break; + ancestor =3D parent; + } + + if (WARN_ON_ONCE(ancestor =3D=3D &top_cpuset)) + return NULL; + + WRITE_ONCE(ancestor->prs_err, PERR_HKEEPING); + if (is_remote_partition(ancestor)) { + remote_partition_disable(ancestor, tmp); + } else { + err =3D update_parent_effective_cpumask(ancestor, + partcmd_invalidate, NULL, tmp); + WARN_ON_ONCE(err); + } + + return ancestor; +} + /** * update_prstate - update partition_root_state * @cs: the cpuset to update @@ -2949,6 +3039,8 @@ static int update_prstate(struct cpuset *cs, int new_= prs) { int err =3D PERR_NONE, old_prs =3D cs->partition_root_state; struct cpuset *parent =3D parent_cs(cs); + struct cpuset *invalidated =3D NULL; + struct cpumask *isolcpus_update_cpus =3D cs->effective_xcpus; struct tmpmasks tmpmask; bool isolcpus_updated =3D false; =20 @@ -3005,19 +3097,38 @@ static int update_prstate(struct cpuset *cs, int ne= w_prs) } else if (old_prs && new_prs) { /* * A change in load balance state only, no change in cpumasks. - * Need to update isolated_cpus. + * Need to update isolated_cpus for CPUs owned by this partition, + * excluding CPUs distributed to valid child partitions. */ + compute_partition_owned_cpumask(cs, cs->effective_xcpus, + tmpmask.new_cpus, + tmpmask.addmask); if (((new_prs =3D=3D PRS_ISOLATED) && - !isolated_cpus_can_update(cs->effective_xcpus, NULL)) || - prstate_housekeeping_conflict(new_prs, cs->effective_xcpus)) + !isolated_cpus_can_update(tmpmask.new_cpus, NULL)) || + prstate_housekeeping_conflict(new_prs, tmpmask.new_cpus)) { err =3D PERR_HKEEPING; - else + } else { + /* + * Only directly owned CPUs change isolation state for a + * successful root <-> isolated type change. + */ + isolcpus_update_cpus =3D tmpmask.new_cpus; isolcpus_updated =3D true; + } } else { /* * Switching back to member is always allowed even if it - * disables child partitions. + * disables child partitions. If returning CPUs to an isolated + * parent would consume the last housekeeping CPU, invalidate + * the outermost isolated ancestor and return its CPUs instead. */ + if (old_prs =3D=3D PRS_ROOT && + parent->partition_root_state =3D=3D PRS_ISOLATED && + !isolated_cpus_can_update(cs->effective_xcpus, NULL)) + invalidated =3D invalidate_isolated_ancestor(cs, &tmpmask); + if (invalidated) + goto out; + if (is_remote_partition(cs)) remote_partition_disable(cs, &tmpmask); else @@ -3045,11 +3156,18 @@ static int update_prstate(struct cpuset *cs, int ne= w_prs) if (!is_partition_valid(cs)) reset_partition_data(cs); else if (isolcpus_updated) - isolated_cpus_update(old_prs, new_prs, cs->effective_xcpus); + isolated_cpus_update(old_prs, new_prs, + isolcpus_update_cpus); spin_unlock_irq(&callback_lock); =20 /* Force update if switching back to member & update effective_xcpus */ - update_cpumasks_hier(cs, &tmpmask, !new_prs); + if (invalidated) { + update_cpumasks_hier(invalidated, &tmpmask, false); + update_partition_sd_lb(invalidated, PRS_ISOLATED); + notify_partition_change(invalidated, PRS_ISOLATED); + } else { + update_cpumasks_hier(cs, &tmpmask, !new_prs); + } =20 /* A newly created partition must have effective_xcpus set */ WARN_ON_ONCE(!old_prs && (new_prs > 0) --=20 2.43.0 From nobody Sat Sep 26 10:01:23 2026 Received: from mta1.migadu.com (out-161.mta1.migadu.com [95.215.58.161]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 81BC6446040 for ; Wed, 2 Sep 2026 10:26:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.161 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788344809; cv=none; b=oCNeaquXd0cgaJXhFow0Q8JdDrqTdVzxpN5EhDW8vJXGi+7KOLscBQ5PoynKHg0AIGZm2X3TT/asjEwHE6fbWuyeQugJib4F/NJYkLt0lAe1TGYzfQ36N0DnK74Fkv7puLBrjX/GF1epHg/OaloSFUqa2BgdSAHtRJQ5bedrIOU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788344809; c=relaxed/simple; bh=ni9ymu1bo/+HVfz4tuMZ5Mef8jLcWqHZ49PPQPF2/B4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZTkNcpTwilAGoUpvEex1N8KaiBuRHde6fuFItwSiBEdaEXMq1y0IiWACMNJ+ETd4kO+a+hHV5fFTqVR2jP1TeMT1k6aDNBifAPci6i9vjrWmYDo9Qvn8tKeqLlhcHk8fuuSOVevBbljK1aL7sPuS7aI7QvsQuuyOGVBS/OrolaI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=xvmKZEj2; arc=none smtp.client-ip=95.215.58.161 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="xvmKZEj2" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=ni9ymu1bo/+HVfz4tuMZ5Mef8jLcWqHZ49PPQPF2/B4=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1788344805; v=1; x=1788949605; b=xvmKZEj2IbgdY8wIzGU2pmVFftv4rYLtP+PYQWFZ4D2LS7Vg26fmHXGSBTNyPQF+XFwoLNX4 E0DCeyqCU4V+3p3DI4k1Syhwub5EHW7RprU7YslqJ76WeY5fOEP/dTIQDF5ZOogcqaSS+5ay115 I3fw271G+czuBlP6WAetjl3M= X-Envelope-To: linux-kernel@vger.kernel.org Received: by smtp.migadu.com with ESMTPS id fb81639c0672beb6; Wed, 02 Sep 2026 10:26:45 +0000 X-Mizu-Trace-ID: fb81639c0672beb6 X-Migadu-Flow: FLOW_OUT From: Guopeng Zhang To: cgroups@vger.kernel.org, longman@redhat.com, ridong.chen@linux.dev Cc: tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, shuah@kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Guopeng Zhang Subject: [PATCH v3 3/7] selftests/cgroup: Add tests for type-change isolation accounting Date: Wed, 2 Sep 2026 18:26:11 +0800 Message-ID: <20260902102615.79189-4-guopeng.zhang@linux.dev> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260902102615.79189-1-guopeng.zhang@linux.dev> References: <20260902102615.79189-1-guopeng.zhang@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Guopeng Zhang Add two matrix cases for parent type changes with valid child partitions. Cover root-to-isolated while the child remains root, and isolated-to-root while the child remains isolated. Check that only CPUs owned directly by the parent change isolation state. Signed-off-by: Guopeng Zhang --- tools/testing/selftests/cgroup/test_cpuset_prs.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/test= ing/selftests/cgroup/test_cpuset_prs.sh index 131d8b4551ef..9a1cce4807b4 100755 --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh @@ -224,6 +224,8 @@ TEST_MATRIX=3D( " C0-1 . . C2-3:P1 . . . C2 0 " " C0-1 . . C2-3:P1 . . . C4-5 0 B1:4-5" " C0-3:P1 C2-3:P1 . . . . . . 0 A1:0-1|A2:= 2-3|XA2:2-3" + " C0-3:P1 C2-3:P1 . . P2 . . . 0 A1:0-1|A2:= 2-3 A1:P2|A2:P1 0-1" + " C0-3:P2 C2-3:P2 . . P1 . . . 0 A1:0-1|A2:= 2-3 A1:P1|A2:P2 2-3" " C0-3:P1 C2-3:P1 . . C1-3 . . . 0 A1:1|A2:2-= 3|XA2:2-3" " C2-3:P1 C3:P1 . . C3 . . . 0 A1:|A2:3|X= A2:3 A1:P1|A2:P1" " C2-3:P1 C3:P1 . . C3 P0 . . 0 A1:3|A2:3 = A1:P1|A2:P0" --=20 2.43.0 From nobody Sat Sep 26 10:01:23 2026 Received: from mta0.migadu.com (out-133.mta0.migadu.com [91.218.175.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 67AFD442FD1 for ; Wed, 2 Sep 2026 10:26:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.133 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788344818; cv=none; b=rjkQ44beub344WxdqGlX/ZFcBH2ZKE/AtAZVGkXrOdeT6VZ+0nw42nsUA91Mi5uJF6zDIdHcP2frcaaddMb3KYj8/WDe1LUir35N91ITGUgwrwZr2kxDomIuwsh+Mx0MIFJOS5Vg+kVv40cziTSK5g0ikd7saCLI5x6Nw6n7aHE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788344818; c=relaxed/simple; bh=/ikd6VTrvjXZj78tpx3i6udPWaTYHhZauv7sMPOjvO8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ASFrU/mjtdtz6mdW6Ogb7nuJJJHmAZm3jgdYrQYwZuErvb2gwdRXl2ewm76yH7sUKU3JdwWhx6XrID9MkfJpOoboE9Y+lzabJHehkFus3uB8RltVP+D32bsD916n65TMkQiqZeOMSKxRXvTUrbLza/75jvahXhbPmec2k+LEXSM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=o5o828pN; arc=none smtp.client-ip=91.218.175.133 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="o5o828pN" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=/ikd6VTrvjXZj78tpx3i6udPWaTYHhZauv7sMPOjvO8=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1788344814; v=1; x=1788949614; b=o5o828pNx8hX9eiYWQ/Q3YmA0iuFmlmbjpUfuJC28Vd1MhKt/42v5L/0m92Pzvi1EVYfHAm+ Z20jBA5edgBlKMKc4i84Zws2m6eXh6A9PoaJdgeBGTnsOuVqPO7/g5hbike+g+KDw8Wui7RePBX oYQc5/2vHs+v68yV6uwyVzF8= X-Envelope-To: linux-kernel@vger.kernel.org Received: by smtp.migadu.com with ESMTPS id 9d0f1adc879670a0; Wed, 02 Sep 2026 10:26:54 +0000 X-Mizu-Trace-ID: 9d0f1adc879670a0 X-Migadu-Flow: FLOW_OUT From: Guopeng Zhang To: cgroups@vger.kernel.org, longman@redhat.com, ridong.chen@linux.dev Cc: tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, shuah@kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Guopeng Zhang Subject: [PATCH v3 4/7] selftests/cgroup: Test child CPU ownership in partition changes Date: Wed, 2 Sep 2026 18:26:12 +0800 Message-ID: <20260902102615.79189-5-guopeng.zhang@linux.dev> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260902102615.79189-1-guopeng.zhang@linux.dev> References: <20260902102615.79189-1-guopeng.zhang@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Guopeng Zhang Create an isolated child which owns a boot-isolated CPU, then change its parent's partition type and CPU mask. Verify that a valid child keeps its CPUs and isolation state. Also test trial parent masks which would invalidate the child because its CPU mask is no longer covered or because it would consume every remaining CPU of a populated parent. Verify that the returning boot-isolated CPU is included in the parent's housekeeping check. Cache the boot-isolated CPU during setup so the tests do not depend on the order in which earlier test cases run. Signed-off-by: Guopeng Zhang --- .../selftests/cgroup/test_cpuset_prs.sh | 186 +++++++++++++++++- 1 file changed, 182 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/test= ing/selftests/cgroup/test_cpuset_prs.sh index 9a1cce4807b4..a3df6b094e0f 100755 --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh @@ -107,6 +107,17 @@ then echo "Pre-isolated CPUs: $BOOT_ISOLCPUS" fi =20 +# Cache the CPUs isolated from scheduler domains at boot. +BOOT_ISOLATED_FILE=3D/sys/devices/system/cpu/isolated +BOOT_CPUS=3D +BOOT_CPU=3D +if [[ -r $BOOT_ISOLATED_FILE ]] +then + BOOT_CPUS=3D$(cat $BOOT_ISOLATED_FILE) + [[ -n "$BOOT_CPUS" ]] && + BOOT_CPU=3D$(echo "$BOOT_CPUS" | sed -e 's/[,-].*//') +fi + cleanup() { online_cpus @@ -1158,25 +1169,22 @@ test_isolated() } =20 # -# Select an online CPU isolated from scheduler domains at boot. +# Check that a boot-isolated CPU selected during initialization is online. # $1: test name used in the skip message # get_boot_isolated_cpu() { TEST_NAME=3D$1 - BOOT_ISOLATED_FILE=3D/sys/devices/system/cpu/isolated =20 [[ -r $BOOT_ISOLATED_FILE ]] || { echo "$TEST_NAME test SKIPPED: boot isolation state unavailable" return 1 } - BOOT_CPUS=3D$(cat $BOOT_ISOLATED_FILE) [[ -n "$BOOT_CPUS" ]] || { echo "$TEST_NAME test SKIPPED: no boot-isolated CPU" return 1 } =20 - BOOT_CPU=3D$(echo "$BOOT_CPUS" | sed -e 's/[,-].*//') CPU_ONLINE=3D/sys/devices/system/cpu/cpu${BOOT_CPU}/online [[ ! -e $CPU_ONLINE || $(cat $CPU_ONLINE) -eq 1 ]] || { echo "$TEST_NAME test SKIPPED: CPU $BOOT_CPU is offline" @@ -1214,6 +1222,174 @@ test_boot_isolated() echo "$TEST_NAME test PASSED." } =20 +# +# A parent's type and CPU-mask changes must check only CPUs owned directly= by +# the parent, not a boot-isolated CPU owned by a valid child partition. +# +test_child_owned_cpus() +{ + TEST_NAME=3D"Child-owned CPU type change" + get_boot_isolated_cpu "$TEST_NAME" || return 0 + echo "Running $TEST_NAME test ..." + + cd $CGROUP2/test + echo member > cpuset.cpus.partition + echo +cpuset > cgroup.subtree_control + echo 2,$BOOT_CPU > cpuset.cpus + [[ $(cat cpuset.cpus.effective) =3D "2,$BOOT_CPU" ]] || { + echo "$TEST_NAME test SKIPPED: CPUs 2,$BOOT_CPU are unavailable" + echo "" > cpuset.cpus + cd $CGROUP2 + return 0 + } + test_partition isolated + mkdir A1 + cd A1 + echo $BOOT_CPU > cpuset.cpus + test_partition isolated + cd .. + test_effective_cpus 2 + test_partition root + echo 2-3,$BOOT_CPU > cpuset.cpus + test_effective_cpus 2-3 + [[ $(cat cpuset.cpus.partition) =3D root ]] || { + echo "Parent partition became invalid during CPU update" + exit 1 + } + [[ $(cat A1/cpuset.cpus.partition) =3D isolated ]] || { + echo "Child partition changed during parent update" + exit 1 + } + check_isolcpus "." || { + echo "Parent update corrupted child isolation" + exit 1 + } + cd A1 + test_partition member + cd .. + rmdir A1 + test_partition member + echo "" > cpuset.cpus + cd $CGROUP2 + echo "$TEST_NAME test PASSED." +} + +# +# A child that will become invalid under a trial parent CPU mask no longer +# owns its CPUs for the purpose of the parent's housekeeping validation. +# +test_trial_child_invalidation() +{ + TEST_NAME=3D"Trial child partition invalidation" + get_boot_isolated_cpu "$TEST_NAME" || return 0 + echo "Running $TEST_NAME test ..." + + cd $CGROUP2/test + echo member > cpuset.cpus.partition + echo +cpuset > cgroup.subtree_control + echo 2-3,$BOOT_CPU > cpuset.cpus + [[ $(cat cpuset.cpus.effective) =3D "2-3,$BOOT_CPU" ]] || { + echo "$TEST_NAME test SKIPPED: CPUs 2-3,$BOOT_CPU are unavailable" + echo "" > cpuset.cpus + cd $CGROUP2 + return 0 + } + + # + # The child would fail validation with PERR_INVCPUS because CPU 2 is + # absent from the trial parent mask. CPU $BOOT_CPU must therefore be + # checked as a CPU that will return to the parent, not subtracted as + # child-owned. + # + test_partition isolated + mkdir A1 + cd A1 + echo 2,$BOOT_CPU > cpuset.cpus + test_partition isolated + cd .. + test_partition root + test_effective_cpus 3 + echo 3,$BOOT_CPU > cpuset.cpus + grep -q '^root invalid (partition config conflicts with housekeeping setu= p)$' \ + cpuset.cpus.partition || { + echo "PERR_INVCPUS trial allowed the parent to bypass housekeeping valid= ation" + exit 1 + } + [[ $(cat A1/cpuset.cpus.partition) =3D "isolated invalid"* ]] || { + echo "Child did not become invalid after the parent CPU update" + exit 1 + } + [[ $(cat $CGROUP2/cpuset.cpus.effective) =3D "$CPULIST" ]] || { + echo "PERR_INVCPUS trial did not release the parent partition CPUs" + exit 1 + } + # + # An invalid isolated child retains its isolation state after its + # effective_xcpus is cleared. Explicitly transition CPU 2 through an + # isolated partition before starting the next case. + # + echo member > A1/cpuset.cpus.partition + rmdir A1 + echo member > cpuset.cpus.partition + echo "" > cpuset.cpus + echo 2 > cpuset.cpus + test_partition isolated + test_partition member + echo "" > cpuset.cpus + check_isolcpus "." || { + echo "PERR_INVCPUS trial cleanup left CPU 2 isolated" + exit 1 + } + + # + # With a task in the parent, the child would fail validation with + # PERR_NOCPUS because it consumes all CPUs in the trial mask. Its + # boot-isolated CPU must therefore participate in the parent's + # housekeeping validation. + # + echo 2-3,$BOOT_CPU > cpuset.cpus + test_partition isolated + mkdir A1 + cd A1 + echo 2,$BOOT_CPU > cpuset.cpus + test_partition isolated + cd .. + test_partition root + test_effective_cpus 3 + echo 0 > cgroup.procs + echo 2,$BOOT_CPU > cpuset.cpus + echo 0 > $CGROUP2/cgroup.procs + grep -q '^root invalid (partition config conflicts with housekeeping setu= p)$' \ + cpuset.cpus.partition || { + echo "PERR_NOCPUS trial allowed the parent to bypass housekeeping valida= tion" + exit 1 + } + [[ $(cat A1/cpuset.cpus.partition) =3D "isolated invalid"* ]] || { + echo "Child did not become invalid after exhausting the parent CPUs" + exit 1 + } + [[ $(cat $CGROUP2/cpuset.cpus.effective) =3D "$CPULIST" ]] || { + echo "PERR_NOCPUS trial did not release the parent partition CPUs" + exit 1 + } + # Clean up the retained isolation state as in the PERR_INVCPUS case. + echo member > A1/cpuset.cpus.partition + rmdir A1 + echo member > cpuset.cpus.partition + echo "" > cpuset.cpus + echo 2 > cpuset.cpus + test_partition isolated + test_partition member + echo "" > cpuset.cpus + check_isolcpus "." || { + echo "PERR_NOCPUS trial cleanup left CPU 2 isolated" + exit 1 + } + + cd $CGROUP2 + echo "$TEST_NAME test PASSED." +} + # # Wait for inotify event for the given file and read it # $1: cgroup file to wait for @@ -1286,5 +1462,7 @@ run_state_test TEST_MATRIX run_remote_state_test REMOTE_TEST_MATRIX test_isolated test_boot_isolated +test_child_owned_cpus +test_trial_child_invalidation test_inotify echo "All tests PASSED." --=20 2.43.0 From nobody Sat Sep 26 10:01:23 2026 Received: from mta0.migadu.com (out-139.mta0.migadu.com [91.218.175.139]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E36EA444705 for ; Wed, 2 Sep 2026 10:27:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.139 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788344826; cv=none; b=i0OiXOEh72L/7zSCy5ZGWvkGxRsPBk8wY2FQBW39fEtlJcQCnNzplwwxLJQAYGkfpN6D2DxfCDdWP/xE3j6jlysYBDX9bLa+a9Cn3RCIjZVJ18Nf/LeHMh0e96d2XszvzfhrxMhWQHYetZwNxIeFbKPHcA8a/yvpqGZBDy8vaUU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788344826; c=relaxed/simple; bh=zGfpNOf8GXS1tMO1sxnV8iyUOnNhZeoiOgLvLa85HC0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PGpMbP4NhxLcII0QIjX+08NLt/9zcFyhmNT20CIRq3/vFC+HT2w9eAqnNPfWI5VqVE0D2rXIEw9eujtLZD7wJKuPJfy/8RhFbOuGjchCiPr8ob4fJRnhCOCT979HDGlKq5IsrAsdR6ut9340bzD07p4gZ5I0hqzUGeGNfyl56cU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=RSbAmmlB; arc=none smtp.client-ip=91.218.175.139 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="RSbAmmlB" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=zGfpNOf8GXS1tMO1sxnV8iyUOnNhZeoiOgLvLa85HC0=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1788344818; v=1; x=1788949618; b=RSbAmmlBJqheij3VFWqKKkoU/X0hiJYl9BX9D1/hCaNSl59Z8Re1/swq/aERbOcT9zozqMvP 9JwEklbdmr3L12IqrWXz38dh0DTzEvs7xya7dvqETvTvRbT7zty/2pejzsupWVVFZ2bYfh1ECoR O9/u+I9nzjvccM2IoQMCuASA= X-Envelope-To: linux-kernel@vger.kernel.org Received: by smtp.migadu.com with ESMTPS id d11d726b60207fc6; Wed, 02 Sep 2026 10:26:58 +0000 X-Mizu-Trace-ID: d11d726b60207fc6 X-Migadu-Flow: FLOW_OUT From: Guopeng Zhang To: cgroups@vger.kernel.org, longman@redhat.com, ridong.chen@linux.dev Cc: tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, shuah@kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Guopeng Zhang Subject: [PATCH v3 5/7] selftests/cgroup: Add tests for housekeeping CPU return to isolated parents Date: Wed, 2 Sep 2026 18:26:13 +0800 Message-ID: <20260902102615.79189-6-guopeng.zhang@linux.dev> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260902102615.79189-1-guopeng.zhang@linux.dev> References: <20260902102615.79189-1-guopeng.zhang@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Guopeng Zhang Return the last housekeeping CPU from a root child to an isolated parent. Check that the parent becomes invalid and releases its CPUs instead of adding the returned CPU to the isolated mask. Repeat the test with two isolated ancestors and check that the outermost isolated partition is invalidated. Add the nested test cgroup to the global cleanup list so a failed assertion does not leave the test hierarchy behind. Signed-off-by: Guopeng Zhang --- .../selftests/cgroup/test_cpuset_prs.sh | 149 +++++++++++++++++- 1 file changed, 148 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/test= ing/selftests/cgroup/test_cpuset_prs.sh index a3df6b094e0f..99cba4e5277d 100755 --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh @@ -122,7 +122,8 @@ cleanup() { online_cpus cd $CGROUP2 - rmdir A1/A2/A3 A1/A2 A1 B1 test/A1 test/B1 test > /dev/null 2>&1 + rmdir A1/A2/A3 A1/A2 A1 B1 \ + test/A1/A2 test/A1 test/B1 test > /dev/null 2>&1 rmdir rtest/p1/c11 rtest/p1/c12 rtest/p2/c21 \ rtest/p2/c22 rtest/p1 rtest/p2 rtest > /dev/null 2>&1 [[ -n "$SCHED_DEBUG" ]] && @@ -1222,6 +1223,30 @@ test_boot_isolated() echo "$TEST_NAME test PASSED." } =20 +# Return success if CPU $2 is present in cpulist $1. +cpulist_contains() +{ + local CPULIST_ARG=3D$1 + local CPU_ARG=3D$2 + local ITEM FIRST LAST + local OLD_IFS=3D$IFS + + IFS=3D, + for ITEM in $CPULIST_ARG + do + FIRST=3D${ITEM%-*} + LAST=3D${ITEM#*-} + [[ $ITEM !=3D *-* ]] && LAST=3D$FIRST + if [[ $CPU_ARG -ge $FIRST && $CPU_ARG -le $LAST ]] + then + IFS=3D$OLD_IFS + return 0 + fi + done + IFS=3D$OLD_IFS + return 1 +} + # # A parent's type and CPU-mask changes must check only CPUs owned directly= by # the parent, not a boot-isolated CPU owned by a valid child partition. @@ -1390,6 +1415,127 @@ test_trial_child_invalidation() echo "$TEST_NAME test PASSED." } =20 +# +# Returning the last housekeeping CPU to an isolated parent must invalidate +# the isolated partition instead of adding that CPU to the isolated mask. +# +test_housekeeping_cpu_return() +{ + TEST_NAME=3D"Housekeeping CPU return" + NOHZ_FILE=3D/sys/devices/system/cpu/nohz_full + [[ -r $NOHZ_FILE ]] || { + echo "$TEST_NAME test SKIPPED: no nohz_full state" + return 0 + } + NOHZ_CPUS=3D$(cat $NOHZ_FILE) + [[ -n "$NOHZ_CPUS" && "$NOHZ_CPUS" !=3D "(null)" ]] || { + echo "$TEST_NAME test SKIPPED: no nohz_full CPUs" + return 0 + } + + HK_CPU=3D + HK_COUNT=3D0 + TYPE_CPUS=3D() + for ((CPU=3D0; CPU < NR_CPUS; CPU++)) + do + CPU_ONLINE=3D/sys/devices/system/cpu/cpu${CPU}/online + [[ ! -e $CPU_ONLINE || $(cat $CPU_ONLINE) -eq 1 ]] || continue + cpulist_contains "$BOOT_CPUS" $CPU && continue + if cpulist_contains "$NOHZ_CPUS" $CPU + then + [[ ${#TYPE_CPUS[@]} -lt 3 ]] && TYPE_CPUS+=3D("$CPU") + else + HK_CPU=3D$CPU + ((HK_COUNT++)) + fi + done + + [[ $HK_COUNT -eq 1 && ${#TYPE_CPUS[@]} -ge 2 ]] || { + echo "$TEST_NAME test SKIPPED: requires one full housekeeping CPU" + return 0 + } + echo "Running $TEST_NAME test ..." + + cd $CGROUP2/test + echo member > cpuset.cpus.partition + echo +cpuset > cgroup.subtree_control + echo $HK_CPU,${TYPE_CPUS[0]},${TYPE_CPUS[1]} > cpuset.cpus + test_partition root + mkdir A1 + cd A1 + echo $HK_CPU > cpuset.cpus + test_partition root + cd .. + test_partition isolated + cd A1 + test_partition member + cd .. + grep -q '^isolated invalid (partition config conflicts with housekeeping = setup)$' \ + cpuset.cpus.partition || { + echo "Isolated parent remained valid after housekeeping CPU return" + exit 1 + } + [[ $(cat $CGROUP2/cpuset.cpus.effective) =3D "$CPULIST" ]] || { + echo "Housekeeping CPU return did not release the partition CPUs" + exit 1 + } + check_isolcpus "." || { + echo "Housekeeping CPU was added to the isolated mask" + exit 1 + } + rmdir A1 + echo member > cpuset.cpus.partition + echo "" > cpuset.cpus + + if [[ ${#TYPE_CPUS[@]} -lt 3 ]] + then + echo "Nested $TEST_NAME test SKIPPED: requires three nohz_full CPUs" + cd $CGROUP2 + echo "$TEST_NAME test PASSED." + return 0 + fi + + # Repeat the check with two isolated ancestors. + echo $HK_CPU,${TYPE_CPUS[0]},${TYPE_CPUS[1]},${TYPE_CPUS[2]} > cpuset.cpus + test_partition root + mkdir A1 + cd A1 + echo $HK_CPU,${TYPE_CPUS[1]},${TYPE_CPUS[2]} > cpuset.cpus + test_partition root + echo +cpuset > cgroup.subtree_control + mkdir A2 + cd A2 + echo $HK_CPU > cpuset.cpus + test_partition root + cd .. + test_partition isolated + cd .. + test_partition isolated + cd A1/A2 + test_partition member + cd ../.. + grep -q '^isolated invalid (partition config conflicts with housekeeping = setup)$' \ + cpuset.cpus.partition || { + echo "Outermost isolated partition remained valid after housekeeping CPU= return" + exit 1 + } + [[ $(cat $CGROUP2/cpuset.cpus.effective) =3D "$CPULIST" ]] || { + echo "Nested housekeeping CPU return did not release the partition CPUs" + exit 1 + } + check_isolcpus "." || { + echo "Nested housekeeping CPU return added the CPU to the isolated mask" + exit 1 + } + rmdir A1/A2 + echo member > A1/cpuset.cpus.partition + rmdir A1 + echo member > cpuset.cpus.partition + echo "" > cpuset.cpus + cd $CGROUP2 + echo "$TEST_NAME test PASSED." +} + # # Wait for inotify event for the given file and read it # $1: cgroup file to wait for @@ -1464,5 +1610,6 @@ test_isolated test_boot_isolated test_child_owned_cpus test_trial_child_invalidation +test_housekeeping_cpu_return test_inotify echo "All tests PASSED." --=20 2.43.0 From nobody Sat Sep 26 10:01:23 2026 Received: from mta1.migadu.com (out-175.mta1.migadu.com [95.215.58.175]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F410A44062E for ; Wed, 2 Sep 2026 10:27:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788344833; cv=none; b=efSUxZNe8OPd5qL3uqIFFZjj5hL8nJ/P7xcHOwBIVNCJMZSBdrRJUI9fHwwFS/5w/D+3yGKkfkcC3kZKqCugX6oBct8+E3+tOnEpE1LtC8s+WW4DiFdi4UUqToZKA5aVsR2CA1WBsZu7JoENwZ0KyEzWQgEwxNBeela1obb8aZg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788344833; c=relaxed/simple; bh=+0zvnt4F50BkbJRzuovmFvfMHcY1XlEE3MUtbFEME9I=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UagtdOpVLiIA0aPBVanvuenNdqTMwQQiC1M6ee9AJTUGohZj5YXp1qXhdRz4FXFrDadc7rokbQ5AzjT9KYQSn4lPT1FHKqiLVlavdlB89mdNFJweYKr5nQb6XV5+mP8pMZp7kENfDIcjhKWJql6g6MwuGNA+DkNbXC+xvdmqGoI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=Ecb8Gaws; arc=none smtp.client-ip=95.215.58.175 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="Ecb8Gaws" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=+0zvnt4F50BkbJRzuovmFvfMHcY1XlEE3MUtbFEME9I=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1788344827; v=1; x=1788949627; b=Ecb8GawsHAdDxiR2kluHMiWRyiOq9wGoMQ1E/BPPZFa3OMXOltgN+t1dIF/RVfuq0OrYFzS4 YKoIaqoXc4ctRojGLvt5fgaZbSbbm1PaxjUnBLPgKsX+gc9SRzrwvOXSg+x1BwQZQs9WtePabl9 xQQh0P/kOUNe1daOAGzCc0Gc= X-Envelope-To: linux-kernel@vger.kernel.org Received: by smtp.migadu.com with ESMTPS id 8e989ec727cfae15; Wed, 02 Sep 2026 10:27:07 +0000 X-Mizu-Trace-ID: 8e989ec727cfae15 X-Migadu-Flow: FLOW_OUT From: Guopeng Zhang To: cgroups@vger.kernel.org, longman@redhat.com, ridong.chen@linux.dev Cc: tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, shuah@kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Guopeng Zhang Subject: [PATCH v3 6/7] cgroup/cpuset: Release CPUs when type-change validation fails Date: Wed, 2 Sep 2026 18:26:14 +0800 Message-ID: <20260902102615.79189-7-guopeng.zhang@linux.dev> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260902102615.79189-1-guopeng.zhang@linux.dev> References: <20260902102615.79189-1-guopeng.zhang@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Guopeng Zhang When housekeeping validation fails during a root/isolated type change, update_prstate() marks the requested state invalid without running the partition-disable path. The failed partition's effective_xcpus may be cleared, but its CPUs remain unavailable to the partition which owns the invalidated subtree. This can be reproduced on a cgroup v2 system booted with isolcpus=3Ddomain,15: cd /sys/fs/cgroup echo +cpuset > cgroup.subtree_control mkdir type-fail-repro echo 15 > type-fail-repro/cpuset.cpus echo isolated > type-fail-repro/cpuset.cpus.partition echo root > type-fail-repro/cpuset.cpus.partition cat type-fail-repro/cpuset.cpus.partition cat cpuset.cpus.effective The requested root state is recorded as invalid, but CPU 15 remains unavailable to the top cpuset. Run the common partition-disable path when housekeeping validation fails. Disable remote partitions with remote_partition_disable() and return local partition CPUs to their parent. If that would consume the last housekeeping CPU, invalidate the outermost isolated ancestor instead. Fixes: 103b08709e8a ("cgroup/cpuset: Fail if isolated and nohz_full don't l= eave any housekeeping") Fixes: b1034a690129 ("cgroup/cpuset: Ensure domain isolated CPUs stay in ro= ot or isolated partition") Signed-off-by: Guopeng Zhang --- kernel/cgroup/cpuset.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 19efa62bb694..30d9ea5f3859 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -3042,6 +3042,7 @@ static int update_prstate(struct cpuset *cs, int new_= prs) struct cpuset *invalidated =3D NULL; struct cpumask *isolcpus_update_cpus =3D cs->effective_xcpus; struct tmpmasks tmpmask; + bool disable_partition =3D false; bool isolcpus_updated =3D false; =20 if (old_prs =3D=3D new_prs) @@ -3107,6 +3108,7 @@ static int update_prstate(struct cpuset *cs, int new_= prs) !isolated_cpus_can_update(tmpmask.new_cpus, NULL)) || prstate_housekeeping_conflict(new_prs, tmpmask.new_cpus)) { err =3D PERR_HKEEPING; + disable_partition =3D true; } else { /* * Only directly owned CPUs change isolation state for a @@ -3122,6 +3124,10 @@ static int update_prstate(struct cpuset *cs, int new= _prs) * parent would consume the last housekeeping CPU, invalidate * the outermost isolated ancestor and return its CPUs instead. */ + disable_partition =3D true; + } + + if (disable_partition) { if (old_prs =3D=3D PRS_ROOT && parent->partition_root_state =3D=3D PRS_ISOLATED && !isolated_cpus_can_update(cs->effective_xcpus, NULL)) --=20 2.43.0 From nobody Sat Sep 26 10:01:23 2026 Received: from mta0.migadu.com (out-151.mta0.migadu.com [91.218.175.151]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E9BF14483A5 for ; Wed, 2 Sep 2026 10:27:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.151 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788344837; cv=none; b=MckhKFT3uN9ANyGoowze4kaRAmMYeqZ7vM4GZ02ddgppUhJNg1pLWOMajOyDdmiQjrllwDwESZBFghbZbbnPA+kOz43qvnQbsGWiw+7UzuNu0ooqSkaTBmHfrio4OTvtO+VwiaIWoFDgFwbz6DRYpTpjeBK6lcuuhoxG8PsHnUM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788344837; c=relaxed/simple; bh=ULUIui1KfyIMde5PCChpeFIcnSVcCftAFOx2xLDTPzg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iYpnAvRwEdGu71JiQiOI6enZ2bYFi17O+jUl2dAYnTMHkfMz+TUl50cjyN79hLQhhb0z9s/4xK55W2UmEjADNsX/3+53SYlCpd20iMzKXIHXE5NuilIzOd76Jacrtnm4VoNzZYUICOmag2P/GQPkM/ZLRSD69qaurCGDhP3DbM8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=CP7UHxXM; arc=none smtp.client-ip=91.218.175.151 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="CP7UHxXM" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=ULUIui1KfyIMde5PCChpeFIcnSVcCftAFOx2xLDTPzg=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1788344831; v=1; x=1788949631; b=CP7UHxXMPu70HYKxgHFNajpEJKwR5dR+DkJsNAHuUT+oE/IzntpmLNXPE0uI+La3dgscJtHk 9jmYs+sCRJvC2h4FPbTJgrsOB1NU74Ln6FlzuW+Kfyn6YdbtRIyiToIrHNFeXypSPrjvZfwr/0B oI+t5DvyQgR+bueWISVn4G5k= X-Envelope-To: linux-kernel@vger.kernel.org Received: by smtp.migadu.com with ESMTPS id 9dfd94571ddcc271; Wed, 02 Sep 2026 10:27:11 +0000 X-Mizu-Trace-ID: 9dfd94571ddcc271 X-Migadu-Flow: FLOW_OUT From: Guopeng Zhang To: cgroups@vger.kernel.org, longman@redhat.com, ridong.chen@linux.dev Cc: tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, shuah@kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Guopeng Zhang Subject: [PATCH v3 7/7] selftests/cgroup: Add CPU release tests for type-change validation failures Date: Wed, 2 Sep 2026 18:26:15 +0800 Message-ID: <20260902102615.79189-8-guopeng.zhang@linux.dev> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260902102615.79189-1-guopeng.zhang@linux.dev> References: <20260902102615.79189-1-guopeng.zhang@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Guopeng Zhang Exercise housekeeping validation failures for local and remote partition type changes. Check that the requested partition type becomes invalid, its CPUs are returned to the top cpuset and their boot-time isolation state is preserved. Signed-off-by: Guopeng Zhang --- .../selftests/cgroup/test_cpuset_prs.sh | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/test= ing/selftests/cgroup/test_cpuset_prs.sh index 99cba4e5277d..a31dc69c6c2f 100755 --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh @@ -1536,6 +1536,97 @@ test_housekeeping_cpu_return() echo "$TEST_NAME test PASSED." } =20 +# +# A local type change that fails the boot housekeeping constraint must rel= ease +# the partition CPUs and preserve their boot-isolated state. +# +test_partition_type_failure() +{ + TEST_NAME=3D"Local partition type-change validation failure" + get_boot_isolated_cpu "$TEST_NAME" || return 0 + echo "Running $TEST_NAME test ..." + + cd $CGROUP2/test + echo member > cpuset.cpus.partition + echo $BOOT_CPU > cpuset.cpus + [[ $(cat cpuset.cpus.effective) =3D "$BOOT_CPU" ]] || { + echo "$TEST_NAME test SKIPPED: CPU $BOOT_CPU is unavailable" + echo "" > cpuset.cpus + cd $CGROUP2 + return 0 + } + test_partition isolated + echo root > cpuset.cpus.partition + grep -q '^root invalid (partition config conflicts with housekeeping setu= p)$' \ + cpuset.cpus.partition || { + echo "Partition type failure did not produce the expected state" + exit 1 + } + [[ $(cat $CGROUP2/cpuset.cpus.effective) =3D "$CPULIST" ]] || { + echo "Partition type failure did not release CPU $BOOT_CPU" + exit 1 + } + check_isolcpus "." || { + echo "Partition type failure lost boot-isolated CPU $BOOT_CPU" + exit 1 + } + echo member > cpuset.cpus.partition + echo "" > cpuset.cpus + cd $CGROUP2 + echo "$TEST_NAME test PASSED." +} + +# +# Exercise the same type-change validation failure for a remote partition. +# +test_remote_partition_type_failure() +{ + TEST_NAME=3D"Remote partition type-change validation failure" + get_boot_isolated_cpu "$TEST_NAME" || return 0 + echo "Running $TEST_NAME test ..." + + cd $CGROUP2/test + echo member > cpuset.cpus.partition + echo +cpuset > cgroup.subtree_control + echo $BOOT_CPU > cpuset.cpus + echo $BOOT_CPU > cpuset.cpus.exclusive + [[ $(cat cpuset.cpus.effective) =3D "$BOOT_CPU" ]] || { + echo "$TEST_NAME test SKIPPED: CPU $BOOT_CPU is unavailable" + echo "" > cpuset.cpus.exclusive + echo "" > cpuset.cpus + cd $CGROUP2 + return 0 + } + mkdir A1 + cd A1 + echo $BOOT_CPU > cpuset.cpus + echo $BOOT_CPU > cpuset.cpus.exclusive + test_partition isolated + echo root > cpuset.cpus.partition + grep -q '^root invalid (partition config conflicts with housekeeping setu= p)$' \ + cpuset.cpus.partition || { + echo "Remote type failure did not produce the expected state" + exit 1 + } + [[ $(cat $CGROUP2/cpuset.cpus.effective) =3D "$CPULIST" ]] || { + echo "Remote type failure did not release CPU $BOOT_CPU" + exit 1 + } + check_isolcpus "." || { + echo "Remote type failure lost boot-isolated CPU $BOOT_CPU" + exit 1 + } + echo member > cpuset.cpus.partition + echo "" > cpuset.cpus.exclusive + echo "" > cpuset.cpus + cd .. + rmdir A1 + echo "" > cpuset.cpus.exclusive + echo "" > cpuset.cpus + cd $CGROUP2 + echo "$TEST_NAME test PASSED." +} + # # Wait for inotify event for the given file and read it # $1: cgroup file to wait for @@ -1611,5 +1702,7 @@ test_boot_isolated test_child_owned_cpus test_trial_child_invalidation test_housekeeping_cpu_return +test_partition_type_failure +test_remote_partition_type_failure test_inotify echo "All tests PASSED." --=20 2.43.0