* [PATCH -next 01/11] cpuset: move the root cpuset write check earlier
2025-09-17 6:04 [PATCH -next 00/11] Refactor cpus mask setting Chen Ridong
@ 2025-09-17 6:04 ` Chen Ridong
2025-09-17 6:04 ` [PATCH -next 02/11] cpuset: remove unused assignment to trialcs->partition_root_state Chen Ridong
` (10 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Chen Ridong @ 2025-09-17 6:04 UTC (permalink / raw)
To: longman, tj, hannes, mkoutny; +Cc: cgroups, linux-kernel, lujialin4, chenridong
From: Chen Ridong <chenridong@huawei.com>
The 'cpus' or 'mems' lists of the top_cpuset cannot be modified.
This check can be moved before acquiring any locks as a common code
block to improve efficiency and maintainability.
Signed-off-by: Chen Ridong <chenridong@huawei.com>
Reviewed-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 17 ++++-------------
1 file changed, 4 insertions(+), 13 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 0d41b4993f8c..819adf4fd591 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2338,10 +2338,6 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
bool force = false;
int old_prs = cs->partition_root_state;
- /* top_cpuset.cpus_allowed tracks cpu_active_mask; it's read-only */
- if (cs == &top_cpuset)
- return -EACCES;
-
/*
* An empty cpus_allowed is ok only if the cpuset has no tasks.
* Since cpulist_parse() fails on an empty mask, we special case
@@ -2802,15 +2798,6 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs,
{
int retval;
- /*
- * top_cpuset.mems_allowed tracks node_stats[N_MEMORY];
- * it's read-only
- */
- if (cs == &top_cpuset) {
- retval = -EACCES;
- goto done;
- }
-
/*
* An empty mems_allowed is ok iff there are no tasks in the cpuset.
* Since nodelist_parse() fails on an empty mask, we special case
@@ -3280,6 +3267,10 @@ ssize_t cpuset_write_resmask(struct kernfs_open_file *of,
struct cpuset *trialcs;
int retval = -ENODEV;
+ /* root is read-only */
+ if (cs == &top_cpuset)
+ return -EACCES;
+
buf = strstrip(buf);
cpuset_full_lock();
if (!is_cpuset_online(cs))
--
2.34.1
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH -next 02/11] cpuset: remove unused assignment to trialcs->partition_root_state
2025-09-17 6:04 [PATCH -next 00/11] Refactor cpus mask setting Chen Ridong
2025-09-17 6:04 ` [PATCH -next 01/11] cpuset: move the root cpuset write check earlier Chen Ridong
@ 2025-09-17 6:04 ` Chen Ridong
2025-09-17 6:04 ` [PATCH -next 03/11] cpuset: change return type of is_partition_[in]valid to bool Chen Ridong
` (9 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Chen Ridong @ 2025-09-17 6:04 UTC (permalink / raw)
To: longman, tj, hannes, mkoutny; +Cc: cgroups, linux-kernel, lujialin4, chenridong
From: Chen Ridong <chenridong@huawei.com>
The trialcs->partition_root_state field is not used during the
configuration of 'cpuset.cpus' or 'cpuset.cpus.exclusive'. Therefore,
the assignment of values to this field can be safely removed.
Signed-off-by: Chen Ridong <chenridong@huawei.com>
Reviewed-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 819adf4fd591..5452c3702b80 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2363,7 +2363,6 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
* trialcs->effective_xcpus is used as a temporary cpumask
* for checking validity of the partition root.
*/
- trialcs->partition_root_state = PRS_MEMBER;
if (!cpumask_empty(trialcs->exclusive_cpus) || is_partition_valid(cs))
compute_effective_exclusive_cpumask(trialcs, NULL, cs);
}
@@ -2497,7 +2496,6 @@ static int update_exclusive_cpumask(struct cpuset *cs, struct cpuset *trialcs,
return 0;
if (*buf) {
- trialcs->partition_root_state = PRS_MEMBER;
/*
* Reject the change if there is exclusive CPUs conflict with
* the siblings.
--
2.34.1
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH -next 03/11] cpuset: change return type of is_partition_[in]valid to bool
2025-09-17 6:04 [PATCH -next 00/11] Refactor cpus mask setting Chen Ridong
2025-09-17 6:04 ` [PATCH -next 01/11] cpuset: move the root cpuset write check earlier Chen Ridong
2025-09-17 6:04 ` [PATCH -next 02/11] cpuset: remove unused assignment to trialcs->partition_root_state Chen Ridong
@ 2025-09-17 6:04 ` Chen Ridong
2025-09-17 6:04 ` [PATCH -next 04/11] cpuset: Refactor exclusive CPU mask computation logic Chen Ridong
` (8 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Chen Ridong @ 2025-09-17 6:04 UTC (permalink / raw)
To: longman, tj, hannes, mkoutny; +Cc: cgroups, linux-kernel, lujialin4, chenridong
From: Chen Ridong <chenridong@huawei.com>
The functions is_partition_valid() and is_partition_invalid() logically
return boolean values, but were previously declared with return type
'int'. This patch changes their return type to 'bool' to better reflect
their semantic meaning and improve type safety.
Signed-off-by: Chen Ridong <chenridong@huawei.com>
Reviewed-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 5452c3702b80..24ef975a4878 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -160,12 +160,12 @@ void dec_dl_tasks_cs(struct task_struct *p)
cs->nr_deadline_tasks--;
}
-static inline int is_partition_valid(const struct cpuset *cs)
+static inline bool is_partition_valid(const struct cpuset *cs)
{
return cs->partition_root_state > 0;
}
-static inline int is_partition_invalid(const struct cpuset *cs)
+static inline bool is_partition_invalid(const struct cpuset *cs)
{
return cs->partition_root_state < 0;
}
--
2.34.1
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH -next 04/11] cpuset: Refactor exclusive CPU mask computation logic
2025-09-17 6:04 [PATCH -next 00/11] Refactor cpus mask setting Chen Ridong
` (2 preceding siblings ...)
2025-09-17 6:04 ` [PATCH -next 03/11] cpuset: change return type of is_partition_[in]valid to bool Chen Ridong
@ 2025-09-17 6:04 ` Chen Ridong
2025-09-17 6:04 ` [PATCH -next 05/11] cpuset: refactor CPU mask buffer parsing logic Chen Ridong
` (7 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Chen Ridong @ 2025-09-17 6:04 UTC (permalink / raw)
To: longman, tj, hannes, mkoutny; +Cc: cgroups, linux-kernel, lujialin4, chenridong
From: Chen Ridong <chenridong@huawei.com>
The current compute_effective_exclusive_cpumask function handles multiple
scenarios with different input parameters, making the code difficult to
follow. This patch refactors it into two separate functions:
compute_excpus and compute_trialcs_excpus.
The compute_excpus function calculates the exclusive CPU mask for a given
input and excludes exclusive CPUs from sibling cpusets when cs's
exclusive_cpus is not explicitly set.
The compute_trialcs_excpus function specifically handles exclusive CPU
computation for trial cpusets used during CPU mask configuration updates,
and always excludes exclusive CPUs from sibling cpusets.
This refactoring significantly improves code readability and clarity,
making it explicit which function to call for each use case and what
parameters should be provided.
Signed-off-by: Chen Ridong <chenridong@huawei.com>
Reviewed-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 103 ++++++++++++++++++++++++++---------------
1 file changed, 65 insertions(+), 38 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 24ef975a4878..ddf69ac29e3f 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1401,38 +1401,25 @@ bool cpuset_cpu_is_isolated(int cpu)
}
EXPORT_SYMBOL_GPL(cpuset_cpu_is_isolated);
-/*
- * compute_effective_exclusive_cpumask - compute effective exclusive CPUs
- * @cs: cpuset
- * @xcpus: effective exclusive CPUs value to be set
- * @real_cs: the real cpuset (can be NULL)
- * Return: 0 if there is no sibling conflict, > 0 otherwise
+/**
+ * rm_siblings_excl_cpus - Remove exclusive CPUs that are used by sibling cpusets
+ * @parent: Parent cpuset containing all siblings
+ * @cs: Current cpuset (will be skipped)
+ * @excpus: exclusive effective CPU mask to modify
*
- * If exclusive_cpus isn't explicitly set or a real_cs is provided, we have to
- * scan the sibling cpusets and exclude their exclusive_cpus or effective_xcpus
- * as well. The provision of real_cs means that a cpumask is being changed and
- * the given cs is a trial one.
+ * This function ensures the given @excpus mask doesn't include any CPUs that
+ * are exclusively allocated to sibling cpusets. It walks through all siblings
+ * of @cs under @parent and removes their exclusive CPUs from @excpus.
*/
-static int compute_effective_exclusive_cpumask(struct cpuset *cs,
- struct cpumask *xcpus,
- struct cpuset *real_cs)
+static int rm_siblings_excl_cpus(struct cpuset *parent, struct cpuset *cs,
+ struct cpumask *excpus)
{
struct cgroup_subsys_state *css;
- struct cpuset *parent = parent_cs(cs);
struct cpuset *sibling;
int retval = 0;
- if (!xcpus)
- xcpus = cs->effective_xcpus;
-
- cpumask_and(xcpus, user_xcpus(cs), parent->effective_xcpus);
-
- if (!real_cs) {
- if (!cpumask_empty(cs->exclusive_cpus))
- return 0;
- } else {
- cs = real_cs;
- }
+ if (cpumask_empty(excpus))
+ return retval;
/*
* Exclude exclusive CPUs from siblings
@@ -1442,20 +1429,60 @@ static int compute_effective_exclusive_cpumask(struct cpuset *cs,
if (sibling == cs)
continue;
- if (cpumask_intersects(xcpus, sibling->exclusive_cpus)) {
- cpumask_andnot(xcpus, xcpus, sibling->exclusive_cpus);
+ if (cpumask_intersects(excpus, sibling->exclusive_cpus)) {
+ cpumask_andnot(excpus, excpus, sibling->exclusive_cpus);
retval++;
continue;
}
- if (cpumask_intersects(xcpus, sibling->effective_xcpus)) {
- cpumask_andnot(xcpus, xcpus, sibling->effective_xcpus);
+ if (cpumask_intersects(excpus, sibling->effective_xcpus)) {
+ cpumask_andnot(excpus, excpus, sibling->effective_xcpus);
retval++;
}
}
rcu_read_unlock();
+
return retval;
}
+/*
+ * compute_excpus - compute effective exclusive CPUs
+ * @cs: cpuset
+ * @xcpus: effective exclusive CPUs value to be set
+ * Return: 0 if there is no sibling conflict, > 0 otherwise
+ *
+ * If exclusive_cpus isn't explicitly set , we have to scan the sibling cpusets
+ * and exclude their exclusive_cpus or effective_xcpus as well.
+ */
+static int compute_excpus(struct cpuset *cs, struct cpumask *excpus)
+{
+ struct cpuset *parent = parent_cs(cs);
+
+ cpumask_and(excpus, user_xcpus(cs), parent->effective_xcpus);
+
+ if (!cpumask_empty(cs->exclusive_cpus))
+ return 0;
+
+ return rm_siblings_excl_cpus(parent, cs, excpus);
+}
+
+/*
+ * compute_trialcs_excpus - Compute effective exclusive CPUs for a trial cpuset
+ * @trialcs: The trial cpuset containing the proposed new configuration
+ * @cs: The original cpuset that the trial configuration is based on
+ * Return: 0 if successful with no sibling conflict, >0 if a conflict is found
+ *
+ * Computes the effective_xcpus for a trial configuration. @cs is provided to represent
+ * the real cs.
+ */
+static int compute_trialcs_excpus(struct cpuset *trialcs, struct cpuset *cs)
+{
+ struct cpuset *parent = parent_cs(trialcs);
+ struct cpumask *excpus = trialcs->effective_xcpus;
+
+ cpumask_and(excpus, user_xcpus(trialcs), parent->effective_xcpus);
+ return rm_siblings_excl_cpus(parent, cs, excpus);
+}
+
static inline bool is_remote_partition(struct cpuset *cs)
{
return !list_empty(&cs->remote_sibling);
@@ -1497,7 +1524,7 @@ static int remote_partition_enable(struct cpuset *cs, int new_prs,
* Note that creating a remote partition with any local partition root
* above it or remote partition root underneath it is not allowed.
*/
- compute_effective_exclusive_cpumask(cs, tmp->new_cpus, NULL);
+ compute_excpus(cs, tmp->new_cpus);
WARN_ON_ONCE(cpumask_intersects(tmp->new_cpus, subpartitions_cpus));
if (!cpumask_intersects(tmp->new_cpus, cpu_active_mask) ||
cpumask_subset(top_cpuset.effective_cpus, tmp->new_cpus))
@@ -1546,7 +1573,7 @@ static void remote_partition_disable(struct cpuset *cs, struct tmpmasks *tmp)
cs->partition_root_state = PRS_MEMBER;
/* effective_xcpus may need to be changed */
- compute_effective_exclusive_cpumask(cs, NULL, NULL);
+ compute_excpus(cs, cs->effective_xcpus);
reset_partition_data(cs);
spin_unlock_irq(&callback_lock);
update_unbound_workqueue_cpumask(isolcpus_updated);
@@ -1747,12 +1774,12 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
if ((cmd == partcmd_enable) || (cmd == partcmd_enablei)) {
/*
- * Need to call compute_effective_exclusive_cpumask() in case
+ * Need to call compute_excpus() in case
* exclusive_cpus not set. Sibling conflict should only happen
* if exclusive_cpus isn't set.
*/
xcpus = tmp->delmask;
- if (compute_effective_exclusive_cpumask(cs, xcpus, NULL))
+ if (compute_excpus(cs, xcpus))
WARN_ON_ONCE(!cpumask_empty(cs->exclusive_cpus));
/*
@@ -2034,7 +2061,7 @@ static void compute_partition_effective_cpumask(struct cpuset *cs,
* 2) All the effective_cpus will be used up and cp
* has tasks
*/
- compute_effective_exclusive_cpumask(cs, new_ecpus, NULL);
+ compute_excpus(cs, new_ecpus);
cpumask_and(new_ecpus, new_ecpus, cpu_active_mask);
rcu_read_lock();
@@ -2113,7 +2140,7 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
* its value is being processed.
*/
if (remote && (cp != cs)) {
- compute_effective_exclusive_cpumask(cp, tmp->new_cpus, NULL);
+ compute_excpus(cp, tmp->new_cpus);
if (cpumask_equal(cp->effective_xcpus, tmp->new_cpus)) {
pos_css = css_rightmost_descendant(pos_css);
continue;
@@ -2215,7 +2242,7 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
cpumask_copy(cp->effective_cpus, tmp->new_cpus);
cp->partition_root_state = new_prs;
if (!cpumask_empty(cp->exclusive_cpus) && (cp != cs))
- compute_effective_exclusive_cpumask(cp, NULL, NULL);
+ compute_excpus(cp, cp->effective_xcpus);
/*
* Make sure effective_xcpus is properly set for a valid
@@ -2364,7 +2391,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
* for checking validity of the partition root.
*/
if (!cpumask_empty(trialcs->exclusive_cpus) || is_partition_valid(cs))
- compute_effective_exclusive_cpumask(trialcs, NULL, cs);
+ compute_trialcs_excpus(trialcs, cs);
}
/* Nothing to do if the cpus didn't change */
@@ -2500,7 +2527,7 @@ static int update_exclusive_cpumask(struct cpuset *cs, struct cpuset *trialcs,
* Reject the change if there is exclusive CPUs conflict with
* the siblings.
*/
- if (compute_effective_exclusive_cpumask(trialcs, NULL, cs))
+ if (compute_trialcs_excpus(trialcs, cs))
return -EINVAL;
}
--
2.34.1
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH -next 05/11] cpuset: refactor CPU mask buffer parsing logic
2025-09-17 6:04 [PATCH -next 00/11] Refactor cpus mask setting Chen Ridong
` (3 preceding siblings ...)
2025-09-17 6:04 ` [PATCH -next 04/11] cpuset: Refactor exclusive CPU mask computation logic Chen Ridong
@ 2025-09-17 6:04 ` Chen Ridong
2025-09-17 6:04 ` [PATCH -next 06/11] cpuset: introduce cpus_excl_conflict and mems_excl_conflict helpers Chen Ridong
` (6 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Chen Ridong @ 2025-09-17 6:04 UTC (permalink / raw)
To: longman, tj, hannes, mkoutny; +Cc: cgroups, linux-kernel, lujialin4, chenridong
From: Chen Ridong <chenridong@huawei.com>
The current implementation contains redundant handling for empty mask
inputs, as cpulist_parse() already properly handles these cases. This
refactoring introduces a new helper function parse_cpuset_cpulist() to
consolidate CPU list parsing logic and eliminate special-case checks for
empty inputs.
Additionally, the effective_xcpus computation for trial cpusets has been
simplified. Rather than computing effective_xcpus only when exclusive_cpus
is set or when the cpuset forms a valid partition, we now recalculate it
on every cpuset.cpus update. This approach ensures consistency and allows
removal of redundant effective_xcpus logic in subsequent patches.
The trial cpuset's effective_xcpus calculation follows two distinct cases:
1. For member cpusets: effective_xcpus is determined by the intersection
of cpuset->exclusive_cpus and the parent's effective_xcpus.
2. For non-member cpusets: effective_xcpus is derived from the intersection
of user_xcpus and the parent's effective_xcpus.
Signed-off-by: Chen Ridong <chenridong@huawei.com>
Reviewed-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 59 +++++++++++++++++++++---------------------
1 file changed, 30 insertions(+), 29 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index ddf69ac29e3f..a72b5eed4865 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -170,6 +170,11 @@ static inline bool is_partition_invalid(const struct cpuset *cs)
return cs->partition_root_state < 0;
}
+static inline bool cs_is_member(const struct cpuset *cs)
+{
+ return cs->partition_root_state == PRS_MEMBER;
+}
+
/*
* Callers should hold callback_lock to modify partition_root_state.
*/
@@ -1479,7 +1484,13 @@ static int compute_trialcs_excpus(struct cpuset *trialcs, struct cpuset *cs)
struct cpuset *parent = parent_cs(trialcs);
struct cpumask *excpus = trialcs->effective_xcpus;
- cpumask_and(excpus, user_xcpus(trialcs), parent->effective_xcpus);
+ /* trialcs is member, cpuset.cpus has no impact to excpus */
+ if (cs_is_member(cs))
+ cpumask_and(excpus, trialcs->exclusive_cpus,
+ parent->effective_xcpus);
+ else
+ cpumask_and(excpus, user_xcpus(trialcs), parent->effective_xcpus);
+
return rm_siblings_excl_cpus(parent, cs, excpus);
}
@@ -2349,6 +2360,19 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs,
rcu_read_unlock();
}
+static int parse_cpuset_cpulist(const char *buf, struct cpumask *out_mask)
+{
+ int retval;
+
+ retval = cpulist_parse(buf, out_mask);
+ if (retval < 0)
+ return retval;
+ if (!cpumask_subset(out_mask, top_cpuset.cpus_allowed))
+ return -EINVAL;
+
+ return 0;
+}
+
/**
* update_cpumask - update the cpus_allowed mask of a cpuset and all tasks in it
* @cs: the cpuset to consider
@@ -2365,34 +2389,9 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
bool force = false;
int old_prs = cs->partition_root_state;
- /*
- * An empty cpus_allowed is ok only if the cpuset has no tasks.
- * Since cpulist_parse() fails on an empty mask, we special case
- * that parsing. The validate_change() call ensures that cpusets
- * with tasks have cpus.
- */
- if (!*buf) {
- cpumask_clear(trialcs->cpus_allowed);
- if (cpumask_empty(trialcs->exclusive_cpus))
- cpumask_clear(trialcs->effective_xcpus);
- } else {
- retval = cpulist_parse(buf, trialcs->cpus_allowed);
- if (retval < 0)
- return retval;
-
- if (!cpumask_subset(trialcs->cpus_allowed,
- top_cpuset.cpus_allowed))
- return -EINVAL;
-
- /*
- * When exclusive_cpus isn't explicitly set, it is constrained
- * by cpus_allowed and parent's effective_xcpus. Otherwise,
- * trialcs->effective_xcpus is used as a temporary cpumask
- * for checking validity of the partition root.
- */
- if (!cpumask_empty(trialcs->exclusive_cpus) || is_partition_valid(cs))
- compute_trialcs_excpus(trialcs, cs);
- }
+ retval = parse_cpuset_cpulist(buf, trialcs->cpus_allowed);
+ if (retval < 0)
+ return retval;
/* Nothing to do if the cpus didn't change */
if (cpumask_equal(cs->cpus_allowed, trialcs->cpus_allowed))
@@ -2401,6 +2400,8 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
if (alloc_tmpmasks(&tmp))
return -ENOMEM;
+ compute_trialcs_excpus(trialcs, cs);
+
if (old_prs) {
if (is_partition_valid(cs) &&
cpumask_empty(trialcs->effective_xcpus)) {
--
2.34.1
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH -next 06/11] cpuset: introduce cpus_excl_conflict and mems_excl_conflict helpers
2025-09-17 6:04 [PATCH -next 00/11] Refactor cpus mask setting Chen Ridong
` (4 preceding siblings ...)
2025-09-17 6:04 ` [PATCH -next 05/11] cpuset: refactor CPU mask buffer parsing logic Chen Ridong
@ 2025-09-17 6:04 ` Chen Ridong
2025-09-17 6:04 ` [PATCH -next 07/11] cpuset: refactor out validate_partition Chen Ridong
` (5 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Chen Ridong @ 2025-09-17 6:04 UTC (permalink / raw)
To: longman, tj, hannes, mkoutny; +Cc: cgroups, linux-kernel, lujialin4, chenridong
From: Chen Ridong <chenridong@huawei.com>
This patch adds cpus_excl_conflict() and mems_excl_conflict() helper
functions to improve code readability and maintainability. The exclusive
conflict checking follows these rules:
1. If either cpuset has the 'exclusive' flag set, their user_xcpus must
not have any overlap.
2. If neither cpuset has the 'exclusive' flag set, their
'cpuset.cpus.exclusive' (only for v2) values must not intersect.
3. The 'cpuset.cpus' of one cpuset must not form a subset of another
cpuset's 'cpuset.cpus.exclusive'.
Signed-off-by: Chen Ridong <chenridong@huawei.com>
Reviewed-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 74 +++++++++++++++++++++++++-----------------
1 file changed, 44 insertions(+), 30 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index a72b5eed4865..8e9727352a5d 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -583,6 +583,47 @@ static inline bool cpusets_are_exclusive(struct cpuset *cs1, struct cpuset *cs2)
return true;
}
+/**
+ * cpus_excl_conflict - Check if two cpusets have exclusive CPU conflicts
+ * @cs1: first cpuset to check
+ * @cs2: second cpuset to check
+ *
+ * Returns: true if CPU exclusivity conflict exists, false otherwise
+ *
+ * Conflict detection rules:
+ * 1. If either cpuset is CPU exclusive, they must be mutually exclusive
+ * 2. exclusive_cpus masks cannot intersect between cpusets
+ * 3. The allowed CPUs of one cpuset cannot be a subset of another's exclusive CPUs
+ */
+static inline bool cpus_excl_conflict(struct cpuset *cs1, struct cpuset *cs2)
+{
+ /* If either cpuset is exclusive, check if they are mutually exclusive */
+ if (is_cpu_exclusive(cs1) || is_cpu_exclusive(cs2))
+ return !cpusets_are_exclusive(cs1, cs2);
+
+ /* Exclusive_cpus cannot intersect */
+ if (cpumask_intersects(cs1->exclusive_cpus, cs2->exclusive_cpus))
+ return true;
+
+ /* The cpus_allowed of one cpuset cannot be a subset of another cpuset's exclusive_cpus */
+ if (!cpumask_empty(cs1->cpus_allowed) &&
+ cpumask_subset(cs1->cpus_allowed, cs2->exclusive_cpus))
+ return true;
+
+ if (!cpumask_empty(cs2->cpus_allowed) &&
+ cpumask_subset(cs2->cpus_allowed, cs1->exclusive_cpus))
+ return true;
+
+ return false;
+}
+
+static inline bool mems_excl_conflict(struct cpuset *cs1, struct cpuset *cs2)
+{
+ if ((is_mem_exclusive(cs1) || is_mem_exclusive(cs2)))
+ return nodes_intersects(cs1->mems_allowed, cs2->mems_allowed);
+ return false;
+}
+
/*
* validate_change() - Used to validate that any proposed cpuset change
* follows the structural rules for cpusets.
@@ -664,38 +705,11 @@ static int validate_change(struct cpuset *cur, struct cpuset *trial)
*/
ret = -EINVAL;
cpuset_for_each_child(c, css, par) {
- bool txset, cxset; /* Are exclusive_cpus set? */
-
if (c == cur)
continue;
-
- txset = !cpumask_empty(trial->exclusive_cpus);
- cxset = !cpumask_empty(c->exclusive_cpus);
- if (is_cpu_exclusive(trial) || is_cpu_exclusive(c) ||
- (txset && cxset)) {
- if (!cpusets_are_exclusive(trial, c))
- goto out;
- } else if (txset || cxset) {
- struct cpumask *xcpus, *acpus;
-
- /*
- * When just one of the exclusive_cpus's is set,
- * cpus_allowed of the other cpuset, if set, cannot be
- * a subset of it or none of those CPUs will be
- * available if these exclusive CPUs are activated.
- */
- if (txset) {
- xcpus = trial->exclusive_cpus;
- acpus = c->cpus_allowed;
- } else {
- xcpus = c->exclusive_cpus;
- acpus = trial->cpus_allowed;
- }
- if (!cpumask_empty(acpus) && cpumask_subset(acpus, xcpus))
- goto out;
- }
- if ((is_mem_exclusive(trial) || is_mem_exclusive(c)) &&
- nodes_intersects(trial->mems_allowed, c->mems_allowed))
+ if (cpus_excl_conflict(trial, c))
+ goto out;
+ if (mems_excl_conflict(trial, c))
goto out;
}
--
2.34.1
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH -next 07/11] cpuset: refactor out validate_partition
2025-09-17 6:04 [PATCH -next 00/11] Refactor cpus mask setting Chen Ridong
` (5 preceding siblings ...)
2025-09-17 6:04 ` [PATCH -next 06/11] cpuset: introduce cpus_excl_conflict and mems_excl_conflict helpers Chen Ridong
@ 2025-09-17 6:04 ` Chen Ridong
2025-09-17 6:04 ` [PATCH -next 08/11] cpuset: refactor cpus_allowed_validate_change Chen Ridong
` (4 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Chen Ridong @ 2025-09-17 6:04 UTC (permalink / raw)
To: longman, tj, hannes, mkoutny; +Cc: cgroups, linux-kernel, lujialin4, chenridong
From: Chen Ridong <chenridong@huawei.com>
Refactor the validate_partition function to handle cpuset partition
validation when modifying cpuset.cpus. This refactoring also makes the
function reusable for handling cpuset.cpus.exclusive updates in subsequent
patches.
Signed-off-by: Chen Ridong <chenridong@huawei.com>
Reviewed-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 48 +++++++++++++++++++++++++++++++-----------
1 file changed, 36 insertions(+), 12 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 8e9727352a5d..aaf8244b3cea 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2387,6 +2387,37 @@ static int parse_cpuset_cpulist(const char *buf, struct cpumask *out_mask)
return 0;
}
+/**
+ * validate_partition - Validate a cpuset partition configuration
+ * @cs: The cpuset to validate
+ * @trialcs: The trial cpuset containing proposed configuration changes
+ *
+ * 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 cpuset *trialcs)
+{
+ struct cpuset *parent = parent_cs(cs);
+
+ if (cs_is_member(trialcs))
+ return PERR_NONE;
+
+ if (cpumask_empty(trialcs->effective_xcpus))
+ return PERR_INVCPUS;
+
+ if (prstate_housekeeping_conflict(trialcs->partition_root_state,
+ trialcs->effective_xcpus))
+ return PERR_HKEEPING;
+
+ if (tasks_nocpu_error(parent, cs, trialcs->effective_xcpus))
+ return PERR_NOCPUS;
+
+ return PERR_NONE;
+}
+
+
/**
* update_cpumask - update the cpus_allowed mask of a cpuset and all tasks in it
* @cs: the cpuset to consider
@@ -2402,6 +2433,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
bool invalidate = false;
bool force = false;
int old_prs = cs->partition_root_state;
+ enum prs_errcode prs_err;
retval = parse_cpuset_cpulist(buf, trialcs->cpus_allowed);
if (retval < 0)
@@ -2416,18 +2448,10 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
compute_trialcs_excpus(trialcs, cs);
- if (old_prs) {
- if (is_partition_valid(cs) &&
- cpumask_empty(trialcs->effective_xcpus)) {
- invalidate = true;
- cs->prs_err = PERR_INVCPUS;
- } else if (prstate_housekeeping_conflict(old_prs, trialcs->effective_xcpus)) {
- invalidate = true;
- cs->prs_err = PERR_HKEEPING;
- } else if (tasks_nocpu_error(parent, cs, trialcs->effective_xcpus)) {
- invalidate = true;
- cs->prs_err = PERR_NOCPUS;
- }
+ prs_err = validate_partition(cs, trialcs);
+ if (prs_err) {
+ invalidate = true;
+ cs->prs_err = prs_err;
}
/*
--
2.34.1
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH -next 08/11] cpuset: refactor cpus_allowed_validate_change
2025-09-17 6:04 [PATCH -next 00/11] Refactor cpus mask setting Chen Ridong
` (6 preceding siblings ...)
2025-09-17 6:04 ` [PATCH -next 07/11] cpuset: refactor out validate_partition Chen Ridong
@ 2025-09-17 6:04 ` Chen Ridong
2025-09-19 9:49 ` [PATCH cgroup/for-next] cpuset: fix missing error return in update_cpumask Chen Ridong
2025-09-17 6:04 ` [PATCH -next 09/11] cpuset: introduce partition_cpus_change Chen Ridong
` (3 subsequent siblings)
11 siblings, 1 reply; 17+ messages in thread
From: Chen Ridong @ 2025-09-17 6:04 UTC (permalink / raw)
To: longman, tj, hannes, mkoutny; +Cc: cgroups, linux-kernel, lujialin4, chenridong
From: Chen Ridong <chenridong@huawei.com>
Refactor cpus_allowed_validate_change to handle the special case where
cpuset.cpus can be set even when violating partition sibling CPU
exclusivity rules. This differs from the general validation logic in
validate_change. Add a wrapper function to properly handle this
exceptional case.
The trialcs->prs_err field is cleared before performing validation checks
for both CPU changes and partition errors. If cpus_allowed_validate_change
fails its validation, trialcs->prs_err is set to PERR_NOTEXCL. If partition
validation fails, the specific error code returned by validate_partition
is assigned to trialcs->prs_err.
With the partition validation status now directly available through
trialcs->prs_err, the local boolean variable 'invalidate' becomes
redundant and can be safely removed.
Signed-off-by: Chen Ridong <chenridong@huawei.com>
Reviewed-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 84 ++++++++++++++++++++++--------------------
1 file changed, 45 insertions(+), 39 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index aaf8244b3cea..ab8572038fce 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2417,6 +2417,42 @@ static enum prs_errcode validate_partition(struct cpuset *cs, struct cpuset *tri
return PERR_NONE;
}
+static int cpus_allowed_validate_change(struct cpuset *cs, struct cpuset *trialcs,
+ struct tmpmasks *tmp)
+{
+ int retval;
+ struct cpuset *parent = parent_cs(cs);
+
+ retval = validate_change(cs, trialcs);
+
+ if ((retval == -EINVAL) && cpuset_v2()) {
+ struct cgroup_subsys_state *css;
+ struct cpuset *cp;
+
+ /*
+ * The -EINVAL error code indicates that partition sibling
+ * CPU exclusivity rule has been violated. We still allow
+ * the cpumask change to proceed while invalidating the
+ * partition. However, any conflicting sibling partitions
+ * have to be marked as invalid too.
+ */
+ trialcs->prs_err = PERR_NOTEXCL;
+ rcu_read_lock();
+ cpuset_for_each_child(cp, css, parent) {
+ struct cpumask *xcpus = user_xcpus(trialcs);
+
+ if (is_partition_valid(cp) &&
+ cpumask_intersects(xcpus, cp->effective_xcpus)) {
+ rcu_read_unlock();
+ update_parent_effective_cpumask(cp, partcmd_invalidate, NULL, tmp);
+ rcu_read_lock();
+ }
+ }
+ rcu_read_unlock();
+ retval = 0;
+ }
+ return retval;
+}
/**
* update_cpumask - update the cpus_allowed mask of a cpuset and all tasks in it
@@ -2429,8 +2465,6 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
{
int retval;
struct tmpmasks tmp;
- struct cpuset *parent = parent_cs(cs);
- bool invalidate = false;
bool force = false;
int old_prs = cs->partition_root_state;
enum prs_errcode prs_err;
@@ -2447,12 +2481,10 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
return -ENOMEM;
compute_trialcs_excpus(trialcs, cs);
+ trialcs->prs_err = PERR_NONE;
- prs_err = validate_partition(cs, trialcs);
- if (prs_err) {
- invalidate = true;
- cs->prs_err = prs_err;
- }
+ if (cpus_allowed_validate_change(cs, trialcs, &tmp) < 0)
+ goto out_free;
/*
* Check all the descendants in update_cpumasks_hier() if
@@ -2460,40 +2492,14 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
*/
force = !cpumask_equal(cs->effective_xcpus, trialcs->effective_xcpus);
- retval = validate_change(cs, trialcs);
-
- if ((retval == -EINVAL) && cpuset_v2()) {
- struct cgroup_subsys_state *css;
- struct cpuset *cp;
-
- /*
- * The -EINVAL error code indicates that partition sibling
- * CPU exclusivity rule has been violated. We still allow
- * the cpumask change to proceed while invalidating the
- * partition. However, any conflicting sibling partitions
- * have to be marked as invalid too.
- */
- invalidate = true;
- rcu_read_lock();
- cpuset_for_each_child(cp, css, parent) {
- struct cpumask *xcpus = user_xcpus(trialcs);
-
- if (is_partition_valid(cp) &&
- cpumask_intersects(xcpus, cp->effective_xcpus)) {
- rcu_read_unlock();
- update_parent_effective_cpumask(cp, partcmd_invalidate, NULL, &tmp);
- rcu_read_lock();
- }
- }
- rcu_read_unlock();
- retval = 0;
+ prs_err = validate_partition(cs, trialcs);
+ if (prs_err) {
+ trialcs->prs_err = prs_err;
+ cs->prs_err = prs_err;
}
- if (retval < 0)
- goto out_free;
-
if (is_partition_valid(cs) ||
- (is_partition_invalid(cs) && !invalidate)) {
+ (is_partition_invalid(cs) && !trialcs->prs_err)) {
struct cpumask *xcpus = trialcs->effective_xcpus;
if (cpumask_empty(xcpus) && is_partition_invalid(cs))
@@ -2504,7 +2510,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
*/
if (is_remote_partition(cs))
remote_cpus_update(cs, NULL, xcpus, &tmp);
- else if (invalidate)
+ else if (trialcs->prs_err)
update_parent_effective_cpumask(cs, partcmd_invalidate,
NULL, &tmp);
else
--
2.34.1
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH cgroup/for-next] cpuset: fix missing error return in update_cpumask
2025-09-17 6:04 ` [PATCH -next 08/11] cpuset: refactor cpus_allowed_validate_change Chen Ridong
@ 2025-09-19 9:49 ` Chen Ridong
2025-09-19 10:12 ` Chen Ridong
2025-09-19 16:43 ` Tejun Heo
0 siblings, 2 replies; 17+ messages in thread
From: Chen Ridong @ 2025-09-19 9:49 UTC (permalink / raw)
To: longman, tj, hannes, mkoutny; +Cc: cgroups, linux-kernel, lujialin4, chenridong
From: Chen Ridong <chenridong@huawei.com>
The commit c6366739804f ("cpuset: refactor cpus_allowed_validate_change")
inadvertently removed the error return when cpus_allowed_validate_change()
fails. This patch restores the proper error handling by returning retval
when the validation check fails.
Fixes: c6366739804f ("cpuset: refactor cpus_allowed_validate_change")
Signed-off-by: Chen Ridong <chenridong@huawei.com>
---
kernel/cgroup/cpuset.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 506a7178f0b3..20dface3c3e0 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2515,7 +2515,8 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
compute_trialcs_excpus(trialcs, cs);
trialcs->prs_err = PERR_NONE;
- if (cpus_allowed_validate_change(cs, trialcs, &tmp) < 0)
+ retval = cpus_allowed_validate_change(cs, trialcs, &tmp);
+ if (retval < 0)
goto out_free;
/*
--
2.34.1
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH cgroup/for-next] cpuset: fix missing error return in update_cpumask
2025-09-19 9:49 ` [PATCH cgroup/for-next] cpuset: fix missing error return in update_cpumask Chen Ridong
@ 2025-09-19 10:12 ` Chen Ridong
2025-09-19 16:43 ` Tejun Heo
1 sibling, 0 replies; 17+ messages in thread
From: Chen Ridong @ 2025-09-19 10:12 UTC (permalink / raw)
To: longman, tj, hannes, mkoutny; +Cc: cgroups, linux-kernel, lujialin4, chenridong
On 2025/9/19 17:49, Chen Ridong wrote:
> From: Chen Ridong <chenridong@huawei.com>
>
> The commit c6366739804f ("cpuset: refactor cpus_allowed_validate_change")
> inadvertently removed the error return when cpus_allowed_validate_change()
> fails. This patch restores the proper error handling by returning retval
> when the validation check fails.
>
> Fixes: c6366739804f ("cpuset: refactor cpus_allowed_validate_change")
> Signed-off-by: Chen Ridong <chenridong@huawei.com>
> ---
> kernel/cgroup/cpuset.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 506a7178f0b3..20dface3c3e0 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -2515,7 +2515,8 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
> compute_trialcs_excpus(trialcs, cs);
> trialcs->prs_err = PERR_NONE;
>
> - if (cpus_allowed_validate_change(cs, trialcs, &tmp) < 0)
> + retval = cpus_allowed_validate_change(cs, trialcs, &tmp);
> + if (retval < 0)
> goto out_free;
>
> /*
Hi Longman, TJ,
Sorry about the bug introduced in patch 8. Could you please apply this patch to fix the issue?
--
Best regards,
Ridong
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH cgroup/for-next] cpuset: fix missing error return in update_cpumask
2025-09-19 9:49 ` [PATCH cgroup/for-next] cpuset: fix missing error return in update_cpumask Chen Ridong
2025-09-19 10:12 ` Chen Ridong
@ 2025-09-19 16:43 ` Tejun Heo
2025-09-20 0:54 ` Chen Ridong
1 sibling, 1 reply; 17+ messages in thread
From: Tejun Heo @ 2025-09-19 16:43 UTC (permalink / raw)
To: Chen Ridong
Cc: longman, hannes, mkoutny, cgroups, linux-kernel, lujialin4, chenridong
On Fri, Sep 19, 2025 at 09:49:03AM +0000, Chen Ridong wrote:
> From: Chen Ridong <chenridong@huawei.com>
>
> The commit c6366739804f ("cpuset: refactor cpus_allowed_validate_change")
> inadvertently removed the error return when cpus_allowed_validate_change()
> fails. This patch restores the proper error handling by returning retval
> when the validation check fails.
>
> Fixes: c6366739804f ("cpuset: refactor cpus_allowed_validate_change")
> Signed-off-by: Chen Ridong <chenridong@huawei.com>
Applied to cgroup/for-6.18.
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH cgroup/for-next] cpuset: fix missing error return in update_cpumask
2025-09-19 16:43 ` Tejun Heo
@ 2025-09-20 0:54 ` Chen Ridong
0 siblings, 0 replies; 17+ messages in thread
From: Chen Ridong @ 2025-09-20 0:54 UTC (permalink / raw)
To: Tejun Heo
Cc: longman, hannes, mkoutny, cgroups, linux-kernel, lujialin4, chenridong
On 2025/9/20 0:43, Tejun Heo wrote:
> On Fri, Sep 19, 2025 at 09:49:03AM +0000, Chen Ridong wrote:
>> From: Chen Ridong <chenridong@huawei.com>
>>
>> The commit c6366739804f ("cpuset: refactor cpus_allowed_validate_change")
>> inadvertently removed the error return when cpus_allowed_validate_change()
>> fails. This patch restores the proper error handling by returning retval
>> when the validation check fails.
>>
>> Fixes: c6366739804f ("cpuset: refactor cpus_allowed_validate_change")
>> Signed-off-by: Chen Ridong <chenridong@huawei.com>
>
> Applied to cgroup/for-6.18.
>
> Thanks.
>
Thank you very much.
--
Best regards,
Ridong
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH -next 09/11] cpuset: introduce partition_cpus_change
2025-09-17 6:04 [PATCH -next 00/11] Refactor cpus mask setting Chen Ridong
` (7 preceding siblings ...)
2025-09-17 6:04 ` [PATCH -next 08/11] cpuset: refactor cpus_allowed_validate_change Chen Ridong
@ 2025-09-17 6:04 ` Chen Ridong
2025-09-17 6:04 ` [PATCH -next 10/11] cpuset: use parse_cpulist for setting cpus.exclusive Chen Ridong
` (2 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Chen Ridong @ 2025-09-17 6:04 UTC (permalink / raw)
To: longman, tj, hannes, mkoutny; +Cc: cgroups, linux-kernel, lujialin4, chenridong
From: Chen Ridong <chenridong@huawei.com>
Introduce the partition_cpus_change function to handle both regular CPU
set updates and exclusive CPU modifications, either of which may trigger
partition state changes. This generalized function will also be utilized
for exclusive CPU updates in subsequent patches.
With the introduction of compute_trialcs_excpus in a previous patch,
the trialcs->effective_xcpus field is now consistently computed and
maintained. Consequently, the legacy logic which assigned
**trialcs->allowed_cpus to a local 'xcpus' variable** when
trialcs->effective_xcpus was empty has been removed.
This removal is safe because when trialcs is not a partition member,
trialcs->effective_xcpus is now correctly populated with the intersection
of user_xcpus and the parent's effective_xcpus. This calculation inherently
covers the scenario previously handled by the removed code.
Signed-off-by: Chen Ridong <chenridong@huawei.com>
Reviewed-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 64 +++++++++++++++++++++++++-----------------
1 file changed, 38 insertions(+), 26 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index ab8572038fce..6107f657bf35 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2454,6 +2454,43 @@ static int cpus_allowed_validate_change(struct cpuset *cs, struct cpuset *trialc
return retval;
}
+/**
+ * partition_cpus_change - Handle partition state changes due to CPU mask updates
+ * @cs: The target cpuset being modified
+ * @trialcs: The trial cpuset containing proposed configuration changes
+ * @tmp: Temporary masks for intermediate calculations
+ *
+ * This function handles partition state transitions triggered by CPU mask changes.
+ * CPU modifications may cause a partition to be disabled or require state updates.
+ */
+static void partition_cpus_change(struct cpuset *cs, struct cpuset *trialcs,
+ struct tmpmasks *tmp)
+{
+ enum prs_errcode prs_err;
+
+ if (cs_is_member(cs))
+ return;
+
+ prs_err = validate_partition(cs, trialcs);
+ if (prs_err)
+ trialcs->prs_err = cs->prs_err = prs_err;
+
+ if (is_remote_partition(cs)) {
+ if (trialcs->prs_err)
+ remote_partition_disable(cs, tmp);
+ else
+ remote_cpus_update(cs, trialcs->exclusive_cpus,
+ trialcs->effective_xcpus, tmp);
+ } else {
+ if (trialcs->prs_err)
+ update_parent_effective_cpumask(cs, partcmd_invalidate,
+ NULL, tmp);
+ else
+ update_parent_effective_cpumask(cs, partcmd_update,
+ trialcs->effective_xcpus, tmp);
+ }
+}
+
/**
* update_cpumask - update the cpus_allowed mask of a cpuset and all tasks in it
* @cs: the cpuset to consider
@@ -2467,7 +2504,6 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
struct tmpmasks tmp;
bool force = false;
int old_prs = cs->partition_root_state;
- enum prs_errcode prs_err;
retval = parse_cpuset_cpulist(buf, trialcs->cpus_allowed);
if (retval < 0)
@@ -2492,31 +2528,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
*/
force = !cpumask_equal(cs->effective_xcpus, trialcs->effective_xcpus);
- prs_err = validate_partition(cs, trialcs);
- if (prs_err) {
- trialcs->prs_err = prs_err;
- cs->prs_err = prs_err;
- }
-
- if (is_partition_valid(cs) ||
- (is_partition_invalid(cs) && !trialcs->prs_err)) {
- struct cpumask *xcpus = trialcs->effective_xcpus;
-
- if (cpumask_empty(xcpus) && is_partition_invalid(cs))
- xcpus = trialcs->cpus_allowed;
-
- /*
- * Call remote_cpus_update() to handle valid remote partition
- */
- if (is_remote_partition(cs))
- remote_cpus_update(cs, NULL, xcpus, &tmp);
- else if (trialcs->prs_err)
- update_parent_effective_cpumask(cs, partcmd_invalidate,
- NULL, &tmp);
- else
- update_parent_effective_cpumask(cs, partcmd_update,
- xcpus, &tmp);
- }
+ partition_cpus_change(cs, trialcs, &tmp);
spin_lock_irq(&callback_lock);
cpumask_copy(cs->cpus_allowed, trialcs->cpus_allowed);
--
2.34.1
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH -next 10/11] cpuset: use parse_cpulist for setting cpus.exclusive
2025-09-17 6:04 [PATCH -next 00/11] Refactor cpus mask setting Chen Ridong
` (8 preceding siblings ...)
2025-09-17 6:04 ` [PATCH -next 09/11] cpuset: introduce partition_cpus_change Chen Ridong
@ 2025-09-17 6:04 ` Chen Ridong
2025-09-17 6:04 ` [PATCH -next 11/11] cpuset: use partition_cpus_change for setting exclusive cpus Chen Ridong
2025-09-17 20:15 ` [PATCH -next 00/11] Refactor cpus mask setting Tejun Heo
11 siblings, 0 replies; 17+ messages in thread
From: Chen Ridong @ 2025-09-17 6:04 UTC (permalink / raw)
To: longman, tj, hannes, mkoutny; +Cc: cgroups, linux-kernel, lujialin4, chenridong
From: Chen Ridong <chenridong@huawei.com>
Previous patches made parse_cpulist handle empty cpu mask input.
Now use this helper for exclusive cpus setting. Also, compute_trialcs_xcpus
can be called with empty cpus and handles it correctly.
Signed-off-by: Chen Ridong <chenridong@huawei.com>
Reviewed-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 25 +++++++++----------------
1 file changed, 9 insertions(+), 16 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 6107f657bf35..c1eefbb7d941 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2566,27 +2566,20 @@ static int update_exclusive_cpumask(struct cpuset *cs, struct cpuset *trialcs,
bool force = false;
int old_prs = cs->partition_root_state;
- if (!*buf) {
- cpumask_clear(trialcs->exclusive_cpus);
- cpumask_clear(trialcs->effective_xcpus);
- } else {
- retval = cpulist_parse(buf, trialcs->exclusive_cpus);
- if (retval < 0)
- return retval;
- }
+ retval = parse_cpuset_cpulist(buf, trialcs->exclusive_cpus);
+ if (retval < 0)
+ return retval;
/* Nothing to do if the CPUs didn't change */
if (cpumask_equal(cs->exclusive_cpus, trialcs->exclusive_cpus))
return 0;
- if (*buf) {
- /*
- * Reject the change if there is exclusive CPUs conflict with
- * the siblings.
- */
- if (compute_trialcs_excpus(trialcs, cs))
- return -EINVAL;
- }
+ /*
+ * Reject the change if there is exclusive CPUs conflict with
+ * the siblings.
+ */
+ if (compute_trialcs_excpus(trialcs, cs))
+ return -EINVAL;
/*
* Check all the descendants in update_cpumasks_hier() if
--
2.34.1
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH -next 11/11] cpuset: use partition_cpus_change for setting exclusive cpus
2025-09-17 6:04 [PATCH -next 00/11] Refactor cpus mask setting Chen Ridong
` (9 preceding siblings ...)
2025-09-17 6:04 ` [PATCH -next 10/11] cpuset: use parse_cpulist for setting cpus.exclusive Chen Ridong
@ 2025-09-17 6:04 ` Chen Ridong
2025-09-17 20:15 ` [PATCH -next 00/11] Refactor cpus mask setting Tejun Heo
11 siblings, 0 replies; 17+ messages in thread
From: Chen Ridong @ 2025-09-17 6:04 UTC (permalink / raw)
To: longman, tj, hannes, mkoutny; +Cc: cgroups, linux-kernel, lujialin4, chenridong
From: Chen Ridong <chenridong@huawei.com>
A previous patch has introduced a new helper function
partition_cpus_change(). Now replace the exclusive cpus setting logic
with this helper function.
Signed-off-by: Chen Ridong <chenridong@huawei.com>
Reviewed-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 29 ++---------------------------
1 file changed, 2 insertions(+), 27 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index c1eefbb7d941..5cfc960f7b15 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2561,8 +2561,6 @@ static int update_exclusive_cpumask(struct cpuset *cs, struct cpuset *trialcs,
{
int retval;
struct tmpmasks tmp;
- struct cpuset *parent = parent_cs(cs);
- bool invalidate = false;
bool force = false;
int old_prs = cs->partition_root_state;
@@ -2594,32 +2592,9 @@ static int update_exclusive_cpumask(struct cpuset *cs, struct cpuset *trialcs,
if (alloc_tmpmasks(&tmp))
return -ENOMEM;
- if (old_prs) {
- if (cpumask_empty(trialcs->effective_xcpus)) {
- invalidate = true;
- cs->prs_err = PERR_INVCPUS;
- } else if (prstate_housekeeping_conflict(old_prs, trialcs->effective_xcpus)) {
- invalidate = true;
- cs->prs_err = PERR_HKEEPING;
- } else if (tasks_nocpu_error(parent, cs, trialcs->effective_xcpus)) {
- invalidate = true;
- cs->prs_err = PERR_NOCPUS;
- }
+ trialcs->prs_err = PERR_NONE;
+ partition_cpus_change(cs, trialcs, &tmp);
- if (is_remote_partition(cs)) {
- if (invalidate)
- remote_partition_disable(cs, &tmp);
- else
- remote_cpus_update(cs, trialcs->exclusive_cpus,
- trialcs->effective_xcpus, &tmp);
- } else if (invalidate) {
- update_parent_effective_cpumask(cs, partcmd_invalidate,
- NULL, &tmp);
- } else {
- update_parent_effective_cpumask(cs, partcmd_update,
- trialcs->effective_xcpus, &tmp);
- }
- }
spin_lock_irq(&callback_lock);
cpumask_copy(cs->exclusive_cpus, trialcs->exclusive_cpus);
cpumask_copy(cs->effective_xcpus, trialcs->effective_xcpus);
--
2.34.1
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH -next 00/11] Refactor cpus mask setting
2025-09-17 6:04 [PATCH -next 00/11] Refactor cpus mask setting Chen Ridong
` (10 preceding siblings ...)
2025-09-17 6:04 ` [PATCH -next 11/11] cpuset: use partition_cpus_change for setting exclusive cpus Chen Ridong
@ 2025-09-17 20:15 ` Tejun Heo
11 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2025-09-17 20:15 UTC (permalink / raw)
To: Chen Ridong
Cc: longman, hannes, mkoutny, cgroups, linux-kernel, lujialin4, chenridong
On Wed, Sep 17, 2025 at 06:04:43AM +0000, Chen Ridong wrote:
> From: Chen Ridong <chenridong@huawei.com>
>
> This patch series refactors the CPU mask configuration logic for both
> cpuset.cpus and cpuset.cpus.exclusive settings. The primary goal is to
> improve code readability through comprehensive function restructuring.
>
> The CPU mask update process follows these steps:
> 1. Parse user input
> 2. Skip processing if no actual change to CPU mask
> 3. Compute trial cpuset's effective exclusive CPUs
> 4. Validate changes and return error if invalid
> 5. Handle partition state changes resulting from CPU mask modifications
> 6. Apply new CPU mask to the cpuset
> 7. Propagate changes through the hierarchy
>
> The series is organized as follows:
> patches 1-3: Code cleanup and preparation for refactoring
> patches 4-9: Refactoring of cpuset.cpus configuration logic
> patches 10-11: Refactoring of cpuset.cpus.exclusive configuration logic
Applied to cgroup/for-6.18.
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 17+ messages in thread