All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ridong Chen <ridong.chen@linux.dev>
To: Waiman Long <longman@redhat.com>, Tejun Heo <tj@kernel.org>,
	Johannes Weiner <hannes@cmpxchg.org>,
	"Michal Koutn?" <mkoutny@suse.com>
Cc: Guopeng Zhang <guopeng.zhang@linux.dev>,
	Ridong Chen <ridong.chen@linux.dev>,
	cgroups@vger.kernel.org, linux-kernel@vger.kernel.org,
	Chen Ridong <chenridong@huawei.com>,
	Ridong Chen <chenridong@xiaomi.com>
Subject: [RFC PATCH -v4 20/22] cpuset: simplify the update_prstate() function
Date: Sun,  1 Nov 2026 19:42:04 +0800	[thread overview]
Message-ID: <20261101114206.2434398-21-ridong.chen@linux.dev> (raw)
In-Reply-To: <20261101114206.2434398-1-ridong.chen@linux.dev>

From: Chen Ridong <chenridong@huawei.com>

This patch introduces partition_switch() to handle both local partition
and remote partition root state switches between "root" and "isolated".
It first validates the partition, via validate_local_partition() for a
local partition or validate_partition() for a remote one. If validation
fails, it returns an error and the partition is disabled; if validation
passes, it enables the partition with the new root state.

update_prstate_disable() is added to disable a partition from
update_prstate(). A valid partition gives back its CPUs through
remote_partition_disable() or local_partition_disable(), while a member
or an invalid partition only has its state updated through
partition_disable().

To support this, remote_partition_disable() and local_partition_disable()
now take the new partition root state from the caller instead of
deriving it from the error code.

With these helpers, update_prstate() can be simplified. The
partition-related assignments and the partition change notification in
update_prstate() are redundant, as these operations are already handled
by partition_enable() and partition_disable(). They are therefore
removed.

Signed-off-by: Chen Ridong <chenridong@huawei.com>
Signed-off-by: Ridong Chen <chenridong@xiaomi.com>
---
 kernel/cgroup/cpuset.c | 141 ++++++++++++++++++++++-------------------
 1 file changed, 77 insertions(+), 64 deletions(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 1ff5f9e4c2fb..29bce718ef92 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1919,6 +1919,7 @@ static int remote_partition_enable(struct cpuset *cs, int new_prs,
 /*
  * remote_partition_disable - Remove current cpuset from remote partition list
  * @cs: the cpuset to update
+ * @new_prs: new partition root state, PRS_MEMBER or an invalid state
  * @prs_err: partition error, PERR_NONE when switching back to member
  * @tmp: temporary masks
  *
@@ -1926,11 +1927,9 @@ static int remote_partition_enable(struct cpuset *cs, int new_prs,
  *
  * cpuset_mutex must be held by the caller.
  */
-static void remote_partition_disable(struct cpuset *cs,
+static void remote_partition_disable(struct cpuset *cs, int new_prs,
 		enum prs_errcode prs_err, struct tmpmasks *tmp)
 {
-	int new_prs;
-
 	WARN_ON_ONCE(!is_remote_partition(cs));
 	/*
 	 * When a CPU is offlined, top_cpuset may end up with no available CPUs,
@@ -1941,7 +1940,6 @@ static void remote_partition_disable(struct cpuset *cs,
 	WARN_ON_ONCE(!cpumask_subset(cs->effective_xcpus, subpartitions_cpus) &&
 		     !cpumask_empty(subpartitions_cpus));
 
-	new_prs = prs_err ? -cs->partition_root_state : PRS_MEMBER;
 	partition_disable(cs, NULL, new_prs, prs_err);
 
 	/*
@@ -1977,7 +1975,7 @@ static void remote_cpus_update(struct cpuset *cs, struct cpumask *xcpus,
 	err = validate_remote_partition(cs, prs, excpus, tmp->addmask,
 					tmp->delmask);
 	if (err) {
-		remote_partition_disable(cs, err, tmp);
+		remote_partition_disable(cs, -prs, err, tmp);
 		return;
 	}
 
@@ -2090,14 +2088,15 @@ static int local_partition_enable(struct cpuset *cs,
 /**
  * local_partition_disable - Disable a local partition
  * @cs: Target cpuset (local partition root) to disable
+ * @new_prs: new partition root state, PRS_MEMBER or an invalid state
  * @part_error: partition error when @cs is disabled
  * @tmp: Temporary masks for CPU calculations
  */
-static void local_partition_disable(struct cpuset *cs, enum prs_errcode part_error,
+static void local_partition_disable(struct cpuset *cs, int new_prs,
+				    enum prs_errcode part_error,
 				    struct tmpmasks *tmp)
 {
 	struct cpuset *parent = parent_cs(cs);
-	int new_prs;
 
 	lockdep_assert_cpuset_lock_held();
 	WARN_ON_ONCE(is_remote_partition(cs));	/* For local partition only */
@@ -2105,7 +2104,6 @@ static void local_partition_disable(struct cpuset *cs, enum prs_errcode part_err
 	if (!is_partition_valid(cs))
 		return;
 
-	new_prs = part_error ? -cs->partition_root_state : PRS_MEMBER;
 	partition_disable(cs, parent, new_prs, part_error);
 
 	cpuset_update_tasks_cpumask(parent, tmp->addmask);
@@ -2163,7 +2161,7 @@ static int __local_partition_update(struct cpuset *cs, struct cpumask *xcpus,
 		 * cpuset can't become a valid local partition anyway.
 		 */
 		if (is_partition_valid(cs))
-			local_partition_disable(cs, part_error, tmp);
+			local_partition_disable(cs, -new_prs, part_error, tmp);
 		else if (is_partition_valid(parent))
 			WRITE_ONCE(cs->prs_err, part_error);
 		return part_error;
@@ -2489,13 +2487,15 @@ static void partition_cpus_change(struct cpuset *cs, struct cpuset *trialcs,
 
 	if (is_remote_partition(cs)) {
 		if (trialcs->prs_err)
-			remote_partition_disable(cs, trialcs->prs_err, tmp);
+			remote_partition_disable(cs, -cs->partition_root_state,
+						 trialcs->prs_err, tmp);
 		else
 			remote_cpus_update(cs, trialcs->exclusive_cpus,
 					   trialcs->effective_xcpus, tmp);
 	} else {
 		if (trialcs->prs_err)
-			local_partition_disable(cs, trialcs->prs_err, tmp);
+			local_partition_disable(cs, -cs->partition_root_state,
+						trialcs->prs_err, tmp);
 		else
 			__local_partition_update(cs, trialcs->exclusive_cpus,
 						 trialcs->effective_xcpus, tmp, false);
@@ -2906,6 +2906,56 @@ bool current_cpuset_is_being_rebound(void)
 	return ret;
 }
 
+/**
+ * partition_switch - Switch a valid partition between root and isolated
+ * @cs: The cpuset (local or remote partition root) to switch
+ * @new_prs: New partition root state, PRS_ROOT or PRS_ISOLATED
+ *
+ * Return: PERR_NONE if successful, error code otherwise
+ */
+static enum prs_errcode partition_switch(struct cpuset *cs, int new_prs)
+{
+	struct cpuset *parent = is_remote_partition(cs) ? NULL : parent_cs(cs);
+	enum prs_errcode err;
+
+	lockdep_assert_cpuset_lock_held();
+	WARN_ON_ONCE(new_prs <= 0 || !is_partition_valid(cs));
+	WARN_ON_ONCE(!cpuset_v2());
+
+	if (parent)
+		err = validate_local_partition(cs, new_prs, cs->effective_xcpus,
+					       false, NULL);
+	else
+		err = validate_partition(cs, NULL, new_prs, cs->effective_xcpus,
+					 NULL);
+	if (err)
+		return err;
+
+	partition_enable(cs, parent, new_prs, cs->effective_xcpus);
+	return PERR_NONE;
+}
+
+/*
+ * update_prstate_disable - Disable a partition from update_prstate()
+ * @cs: the cpuset to disable
+ * @new_prs: new partition root state, PRS_MEMBER or an invalid state
+ * @err: partition error
+ * @tmp: temporary masks
+ *
+ * A valid partition gives back its CPUs, a member or an invalid partition
+ * only has its state updated.
+ */
+static void update_prstate_disable(struct cpuset *cs, int new_prs,
+				   enum prs_errcode err, struct tmpmasks *tmp)
+{
+	if (is_remote_partition(cs))
+		remote_partition_disable(cs, new_prs, err, tmp);
+	else if (is_partition_valid(cs))
+		local_partition_disable(cs, new_prs, err, tmp);
+	else
+		partition_disable(cs, parent_cs(cs), new_prs, err);
+}
+
 /**
  * update_prstate - update partition_root_state
  * @cs: the cpuset to update
@@ -2919,8 +2969,6 @@ static int update_prstate(struct cpuset *cs, int new_prs)
 	int err = PERR_NONE, old_prs = cs->partition_root_state;
 	struct cpuset *parent = parent_cs(cs);
 	struct tmpmasks tmpmask;
-	bool isolcpus_updated = false;
-	bool disable_partition = false;
 
 	if (old_prs == new_prs)
 		return 0;
@@ -2966,68 +3014,31 @@ static int update_prstate(struct cpuset *cs, int new_prs)
 			err = remote_partition_enable(cs, new_prs, &tmpmask);
 		}
 	} else if (old_prs && new_prs) {
-		int parent_prs = is_remote_partition(cs)
-				 ? PRS_ROOT : parent->partition_root_state;
-
-		/*
-		 * A change in load balance state only, no change in cpumasks.
-		 * Need to update isolated_cpus.
-		 */
-		if (prstate_housekeeping_conflict(new_prs, parent_prs,
-						  cs->effective_xcpus, NULL))
-			err = PERR_HKEEPING;
-		else if (parent_prs == PRS_ISOLATED)
-			err = PERR_ISOPARENT;
-
-		if (!err)
-			isolcpus_updated = true;
-		else
-			disable_partition = true;
-	} else {
-		/*
-		 * Switching back to member is always allowed even if it
-		 * disables child partitions.
-		 */
-		disable_partition = true;
-	}
-
-	if (disable_partition) {
-		if (is_remote_partition(cs))
-			remote_partition_disable(cs, PERR_NONE, &tmpmask);
-		else
-			local_partition_disable(cs, PERR_NONE, &tmpmask);
-		/*
-		 * Invalidation of child partitions will be done in
-		 * update_cpumasks_hier() below.
-		 */
+		/* Root state switches, eg, root --> isolated */
+		err = partition_switch(cs, new_prs);
 	}
-out:
 	/*
-	 * Make partition invalid if an error happens.
+	 * Switching back to member is always allowed even if it disables
+	 * child partitions. Invalidation of child partitions will be done in
+	 * update_cpumasks_hier() below.
 	 */
+	if (!new_prs)
+		update_prstate_disable(cs, PRS_MEMBER, PERR_NONE, &tmpmask);
+out:
+	/* Make partition invalid if an error happens */
 	if (err)
-		new_prs = -new_prs;
-
-	spin_lock_irq(&callback_lock);
-	cs->partition_root_state = new_prs;
-	WRITE_ONCE(cs->prs_err, err);
-	if (!is_partition_valid(cs))
-		reset_partition_data(cs);
-	else if (isolcpus_updated)
-		isolated_cpus_update(old_prs, new_prs, cs->effective_xcpus);
-	spin_unlock_irq(&callback_lock);
+		update_prstate_disable(cs, -new_prs, err, &tmpmask);
 
 	/* Force update if partition is disabled & update effective_xcpus */
-	update_cpumasks_hier(cs, &tmpmask, disable_partition);
+	update_cpumasks_hier(cs, &tmpmask, !new_prs || err);
 
 	/* A newly created partition must have effective_xcpus set */
-	WARN_ON_ONCE(!old_prs && (new_prs > 0)
+	WARN_ON_ONCE(!old_prs && (new_prs > 0) && !err
 			      && cpumask_empty(cs->effective_xcpus));
 
 	/* Update sched domains and load balance flag */
 	update_partition_sd_lb(cs, old_prs);
 
-	notify_partition_change(cs, old_prs);
 	free_tmpmasks(&tmpmask);
 	return 0;
 }
@@ -3939,7 +3950,8 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
 		if (cpumask_empty(subpartitions_cpus) ||
 		    (cpumask_empty(&new_cpus) &&
 		     partition_is_populated(cs, NULL))) {
-			remote_partition_disable(cs, PERR_HOTPLUG, tmp);
+			remote_partition_disable(cs, -cs->partition_root_state,
+						 PERR_HOTPLUG, tmp);
 			compute_effective_cpumask(&new_cpus, cs, parent);
 		}
 		goto update_tasks;
@@ -3952,7 +3964,8 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
 	 * transition between valid and invalid partition states.
 	 */
 	if (is_local_partition(cs) && cpumask_empty(subpartitions_cpus))
-		local_partition_disable(cs, PERR_HOTPLUG, tmp);
+		local_partition_disable(cs, -cs->partition_root_state,
+					PERR_HOTPLUG, tmp);
 	else
 		local_partition_update(cs, tmp);
 
-- 
2.34.1


  parent reply	other threads:[~2026-11-01 11:44 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-01 11:41 [RFC PATCH -v4 00/22] cpuset: rework local partition logic Ridong Chen
2026-11-01 11:41 ` [RFC PATCH -v4 01/22] cpuset: add early empty cpumask check in partition_xcpus_add/del Ridong Chen
2026-11-01 11:41 ` [RFC PATCH -v4 02/22] cpuset: settle isolation state when CPUs are given back to parent Ridong Chen
2026-11-01 11:41 ` [RFC PATCH -v4 03/22] cpuset: generalize the validate_partition() interface Ridong Chen
2026-11-01 11:41 ` [RFC PATCH -v4 04/22] cpuset: introduce partition_enable() Ridong Chen
2026-11-01 11:41 ` [RFC PATCH -v4 05/22] cpuset: introduce partition_disable() Ridong Chen
2026-11-01 11:41 ` [RFC PATCH -v4 06/22] cpuset: introduce partition_update() Ridong Chen
2026-11-01 11:41 ` [RFC PATCH -v4 07/22] cpuset: use partition_enable() for remote partition enablement Ridong Chen
2026-11-01 11:41 ` [RFC PATCH -v4 08/22] cpuset: use partition_disable() for remote partition disablement Ridong Chen
2026-11-01 11:41 ` [RFC PATCH -v4 09/22] cpuset: use partition_update() for remote partition update Ridong Chen
2026-11-01 11:41 ` [RFC PATCH -v4 10/22] cpuset: introduce local_partition_enable() Ridong Chen
2026-11-01 11:41 ` [RFC PATCH -v4 11/22] cpuset: introduce local_partition_disable() Ridong Chen
2026-11-01 11:41 ` [RFC PATCH -v4 12/22] cpuset: use local_partition_disable() to invalidate local partition Ridong Chen
2026-11-01 11:41 ` [RFC PATCH -v4 13/22] cpuset: introduce local_partition_update() Ridong Chen
2026-11-01 11:41 ` [RFC PATCH -v4 14/22] cpuset: remove update_parent_effective_cpumask Ridong Chen
2026-11-01 11:41 ` [RFC PATCH -v4 15/22] cpuset: remove redundant partition field updates Ridong Chen
2026-11-01 11:42 ` [RFC PATCH -v4 16/22] cpuset: simplify partition update logic for hotplug tasks Ridong Chen
2026-11-01 11:42 ` [RFC PATCH -v4 17/22] cpuset: use partition_disable for compute_partition_effective_cpumask Ridong Chen
2026-11-01 11:42 ` [RFC PATCH -v4 18/22] cpuset: use validate_local_partition in local_partition_enable Ridong Chen
2026-11-01 11:42 ` [RFC PATCH -v4 19/22] cpuset: introduce validate_remote_partition Ridong Chen
2026-11-01 11:42 ` Ridong Chen [this message]
2026-11-01 11:42 ` [RFC PATCH -v4 21/22] cpuset: remove prs_err clear when notify_partition_change Ridong Chen
2026-11-01 11:42 ` [RFC PATCH -v4 22/22] cpuset: remove unnecessary validation in partition_cpus_change Ridong Chen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261101114206.2434398-21-ridong.chen@linux.dev \
    --to=ridong.chen@linux.dev \
    --cc=cgroups@vger.kernel.org \
    --cc=chenridong@huawei.com \
    --cc=chenridong@xiaomi.com \
    --cc=guopeng.zhang@linux.dev \
    --cc=hannes@cmpxchg.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=longman@redhat.com \
    --cc=mkoutny@suse.com \
    --cc=tj@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.