From nobody Tue Feb 10 05:10:17 2026 Received: from dggsgout11.his.huawei.com (dggsgout11.his.huawei.com [45.249.212.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D7464323406; Thu, 25 Dec 2025 12:45:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766666761; cv=none; b=izMicOMiDs0KALvKsUQn8MSo7m5QdDLTRn3hOCJf372SNPQnzy6DLuT4lVN+e8bZUpEVg0q3wfqXOo7BisbTMJdCBjQwyfGODf0mL9Eh+mW2ZmwddoUQxOMcxo2XivN2wfG+3mKpaik5NBri+TfdIOxBM/s91ArHJrVUoTDAgvE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766666761; c=relaxed/simple; bh=lSjTHnOiErLSSSD/0QWpKmoJTr8DgaTsTRgROtfFXPY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=FM9H+PGX3POISh6qmLDz7sZy2KF9CxOnqg3r6xd8O3sJRAwhO2eh6vbEWLGPupnUCRLeB7GxbW8YGx+7P3Zg2JVKDVh0BrAJTGuWG6a/mIMJ7DnmEAImenRKs97cwcfZIYgvE3EsCLejNbSHNaCMnHulIR6KyPqpMWiDTkyWnQE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=none smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=45.249.212.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.19.163.177]) by dggsgout11.his.huawei.com (SkyGuard) with ESMTPS id 4dcT3q23QlzYQv5q; Thu, 25 Dec 2025 20:45:11 +0800 (CST) Received: from mail02.huawei.com (unknown [10.116.40.128]) by mail.maildlp.com (Postfix) with ESMTP id 9BAAA4058F; Thu, 25 Dec 2025 20:45:51 +0800 (CST) Received: from hulk-vt.huawei.com (unknown [10.67.174.121]) by APP4 (Coremail) with SMTP id gCh0CgDHdfb1MU1pT76_BQ--.27441S14; Thu, 25 Dec 2025 20:45:51 +0800 (CST) From: Chen Ridong To: longman@redhat.com, tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com Cc: cgroups@vger.kernel.org, linux-kernel@vger.kernel.org, lujialin4@huawei.com, chenridong@huaweicloud.com Subject: [PATCH RESEND -next 12/21] cpuset: introduce local_partition_update() Date: Thu, 25 Dec 2025 12:30:49 +0000 Message-Id: <20251225123058.231765-13-chenridong@huaweicloud.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20251225123058.231765-1-chenridong@huaweicloud.com> References: <20251225123058.231765-1-chenridong@huaweicloud.com> 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 X-CM-TRANSID: gCh0CgDHdfb1MU1pT76_BQ--.27441S14 X-Coremail-Antispam: 1UD129KBjvJXoW3WFWkXr4rWrWkurW8uw18Grg_yoW3CrW8pF yUCr42q3yUKry5u343tan7Cws5Kws2qF9Fy3ZxJ3WrJFy7t34vya4jya9Ivr45XFZrG345 Za90qF4xWFy7CwUanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPY14x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_JF0E3s1l82xGYI kIc2x26xkF7I0E14v26ryj6s0DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2 z4x0Y4vE2Ix0cI8IcVAFwI0_tr0E3s1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Gr1j6F 4UJwA2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwVC2z280aVCY1x0267AKxVW0oVCq 3wAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7 IYx2IY67AKxVWUJVWUGwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFVCjc4AY6r1j6r4U M4x0Y48IcxkI7VAKI48JM4x0x7Aq67IIx4CEVc8vx2IErcIFxwCY1x0262kKe7AKxVWUAV WUtwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v2 6r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jw0_GFylIxkGc2 Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVW8JVW5JwCI42IY6xIIjxv20xvEc7CjxVAFwI0_ Gr1j6F4UJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Gr0_Cr 1lIxAIcVC2z280aVCY1x0267AKxVW8Jr0_Cr1UYxBIdaVFxhVjvjDU0xZFpf9x0JUvYLPU UUUU= X-CM-SenderInfo: hfkh02xlgr0w46kxt4xhlfz01xgou0bp/ Content-Type: text/plain; charset="utf-8" From: Chen Ridong The local_partition_update() function replaces the command partcmd_update previously handled within update_parent_effective_cpumask(). The update logic follows a state-based approach: 1. Validation check: First verify if the local partition is currently valid 2. Invalidation handling: If the partition is invalid, trigger invalidation 3. State transition: If an invalid partition has no errors, transition to valid 4. cpumask updates: For local partition that only cpu maks changes, use partition_update() to handle partition change. Signed-off-by: Chen Ridong --- kernel/cgroup/cpuset.c | 151 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 146 insertions(+), 5 deletions(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 8f70867a9fe4..b16b15befca7 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -1743,6 +1743,62 @@ static void remote_cpus_update(struct cpuset *cs, st= ruct cpumask *xcpus, remote_partition_disable(cs, tmp); } =20 +static bool is_user_xcpus_exclusive(struct cpuset *cs) +{ + struct cpuset *parent =3D parent_cs(cs); + struct cgroup_subsys_state *css; + struct cpuset *child; + bool exclusive =3D true; + + rcu_read_lock(); + cpuset_for_each_child(child, css, parent) { + if (child =3D=3D cs) + continue; + if (!cpusets_are_exclusive(cs, child)) { + exclusive =3D false; + break; + } + } + rcu_read_unlock(); + return exclusive; +} + +/** + * validate_local_partition - Validate for local partition + * @cs: Target cpuset to validate + * @new_prs: New partition root state to validate + * @excpus: New exclusive effectuve CPUs mask to validate + * @excl_check: Flag to enable exclusive CPUs ownership validation + * @tmp: Temporary masks + * + * Return: PERR_NONE if validation passes, appropriate error code otherwise + * + * Important: The caller must ensure that @cs's cpu mask is updated before + * invoking this function when exclusive CPU validation is required. + */ +static enum prs_errcode validate_local_partition(struct cpuset *cs, int ne= w_prs, + struct cpumask *excpus, bool excl_check, struct tmpmasks *tmp) +{ + struct cpuset *parent =3D parent_cs(cs); + + /* + * The parent must be a partition root. + * The new cpumask, if present, or the current cpus_allowed must + * not be empty. + */ + if (!is_partition_valid(parent)) { + return is_partition_invalid(parent) + ? PERR_INVPARENT : PERR_NOTPART; + } + + if (excl_check && !is_user_xcpus_exclusive(cs)) + return PERR_NOTEXCL; + + if (!tmp) + return validate_partition(cs, new_prs, excpus, excpus, NULL); + return validate_partition(cs, new_prs, excpus, tmp->addmask, tmp->delmask= ); +} + /** * local_partition_enable - Enable local partition for a cpuset * @cs: Target cpuset to become a local partition root @@ -1814,6 +1870,85 @@ static void local_partition_disable(struct cpuset *c= s, enum prs_errcode part_err update_sibling_cpumasks(parent, cs, tmp); } =20 +/** + * __local_partition_update - Update local partition configuration + * @cs: Target cpuset to update + * @xcpus: New exclusive CPU mask + * @excpus: New effective exclusive CPU mask + * @tmp: Temporary mask storage for intermediate calculations + * @excl_check: Flag to enable exclusivity validation + * + * Handles updates to local CPU partition configurations by validating + * changes, managing state transitions, and propagating updates through + * the cpuset hierarchy. + * + * Note on exclusivity checking: Exclusivity validation is required when + * transitioning from an invalid to valid partition state. However, when + * updating cpus_allowed or exclusive_cpus, exclusivity should have already + * been verified by validate_change(). In such cases, excl_check must be + * false since the cs cpumasks are not yet updated. + * + * Return: Partition error code (PERR_NONE indicates success) + */ +static int __local_partition_update(struct cpuset *cs, struct cpumask *xcp= us, + struct cpumask *excpus, struct tmpmasks *tmp, + bool excl_check) +{ + struct cpuset *parent =3D parent_cs(cs); + int part_error =3D PERR_NONE; /* Partition error? */ + int old_prs, new_prs; + + lockdep_assert_held(&cpuset_mutex); + /* For local partition only */ + if (WARN_ON_ONCE(is_remote_partition(cs) || cs_is_member(cs))) + return PERR_NONE; + + old_prs =3D cs->partition_root_state; + /* + * If new_prs < 0, it might transition to valid partition state. + * Use absolute value for validation checks. + */ + new_prs =3D old_prs < 0 ? -old_prs : old_prs; + cpumask_andnot(tmp->addmask, excpus, cs->effective_xcpus); + cpumask_andnot(tmp->delmask, cs->effective_xcpus, excpus); + part_error =3D validate_local_partition(cs, new_prs, excpus, + excl_check, tmp); + if (part_error) { + local_partition_disable(cs, part_error, tmp); + return part_error; + } + + /* Nothing changes, return PERR_NONE */ + if (new_prs =3D=3D old_prs && + (cpumask_empty(tmp->addmask) && cpumask_empty(tmp->delmask))) + return PERR_NONE; + + /* + * If partition was previously invalid but now passes checks, + * re-enable it and update related flags. + * Otherwise, partition state doesn't change, only cpumasks change. + */ + if (is_partition_invalid(cs)) { + partition_enable(cs, parent, new_prs, excpus); + update_partition_exclusive_flag(cs, new_prs); + update_partition_sd_lb(cs, old_prs); + } else { + partition_update(cs, new_prs, xcpus, excpus, tmp); + } + + cpuset_update_tasks_cpumask(parent, tmp->addmask); + update_sibling_cpumasks(parent, cs, tmp); + return PERR_NONE; +} + +static int local_partition_update(struct cpuset *cs, struct tmpmasks *tmp) +{ + struct cpuset *parent =3D parent_cs(cs); + + cpumask_and(tmp->new_cpus, user_xcpus(cs), parent->effective_xcpus); + return __local_partition_update(cs, NULL, tmp->new_cpus, tmp, true); +} + /** * update_parent_effective_cpumask - update effective_cpus mask of parent = cpuset * @cs: The cpuset that requests change in partition root state @@ -2291,9 +2426,16 @@ static void update_cpumasks_hier(struct cpuset *cs, = struct tmpmasks *tmp, if (!css_tryget_online(&cp->css)) continue; rcu_read_unlock(); + /* + * The tmp->new_cpus may by modified. + * Update effective_cpus before passing tmp to other functions. + */ + spin_lock_irq(&callback_lock); + cpumask_copy(cp->effective_cpus, tmp->new_cpus); + spin_unlock_irq(&callback_lock); =20 if (update_parent) { - update_parent_effective_cpumask(cp, partcmd_update, NULL, tmp); + local_partition_update(cp, tmp); /* * The cpuset partition_root_state may become * invalid. Capture it. @@ -2302,7 +2444,6 @@ static void update_cpumasks_hier(struct cpuset *cs, s= truct tmpmasks *tmp, } =20 spin_lock_irq(&callback_lock); - cpumask_copy(cp->effective_cpus, tmp->new_cpus); cp->partition_root_state =3D new_prs; if (!cpumask_empty(cp->exclusive_cpus) && (cp !=3D cs)) compute_excpus(cp, cp->effective_xcpus); @@ -2491,8 +2632,8 @@ static void partition_cpus_change(struct cpuset *cs, = struct cpuset *trialcs, if (trialcs->prs_err) local_partition_disable(cs, trialcs->prs_err, tmp); else - update_parent_effective_cpumask(cs, partcmd_update, - trialcs->effective_xcpus, tmp); + __local_partition_update(cs, trialcs->exclusive_cpus, + trialcs->effective_xcpus, tmp, false); } } =20 @@ -3910,7 +4051,7 @@ static void cpuset_hotplug_update_tasks(struct cpuset= *cs, struct tmpmasks *tmp) else if (is_partition_valid(parent) && is_partition_invalid(cs) && !cpumask_empty(user_xcpus(cs))) { partcmd =3D partcmd_update; - update_parent_effective_cpumask(cs, partcmd, NULL, tmp); + local_partition_update(cs, tmp); } =20 if (partcmd >=3D 0) { --=20 2.34.1