summaryrefslogtreecommitdiff
path: root/kernel/cgroup
diff options
context:
space:
mode:
authorWaiman Long <longman@redhat.com>2026-06-23 19:04:12 -0400
committerTejun Heo <tj@kernel.org>2026-06-24 09:41:37 -1000
commit866f587e9c70566a0391bf402123555605a82f81 (patch)
tree56aad6b888f3541090acd8dd70b29a739ed3d0ca /kernel/cgroup
parenta2ba161d17836d6c81aca32a35e75c913207142b (diff)
cgroup/cpuset: Avoid unnecessary cpus & mems update in cpuset_hotplug_update_tasks()
As reported by sashiko [1], cpuset_hotplug_update_tasks() may perform unnecessary task iteration and updating of tasks' CPU and node masks when mems_allowed and/or cpus_allowed are not set in cpuset v2. It is due to the fact that the temporary new_cpus and new_mems masks do not inherit parent's effective_cpus/mems when they are empty which is the expected behavior for cpuset v2 since commit 4ec22e9c5a90 ("cpuset: Enable cpuset controller in default hierarchy"). Fix that and avoid unnecessary work by enhancing compute_effective_cpumask() to add the empty cpumask check and inheriting the parent's versions if empty when in v2. A new compute_effective_nodemask() helper is also added to perform a similar function for new effective_mems. Add new test_cpuset_prs.sh test cases to confirm that effective_cpus will inherit the parent's version if cpuset.cpus is empty. [1] https://sashiko.dev/#/patchset/20260621032816.1806773-1-longman%40redhat.com Suggested-by: Ridong Chen <ridong.chen@linux.dev> Fixes: 4ec22e9c5a90 ("cpuset: Enable cpuset controller in default hierarchy") Signed-off-by: Waiman Long <longman@redhat.com> Reviewed-by: Ridong Chen <ridong.chen@linux.dev> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel/cgroup')
-rw-r--r--kernel/cgroup/cpuset.c45
1 files changed, 26 insertions, 19 deletions
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 591e3aa487fc..a404894411dc 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1089,12 +1089,35 @@ void cpuset_update_tasks_cpumask(struct cpuset *cs, struct cpumask *new_cpus)
* @cs: the cpuset the need to recompute the new effective_cpus mask
* @parent: the parent cpuset
*
+ * For v2, the parent's effective_cpus is inherited if cpumask is empty.
* The result is valid only if the given cpuset isn't a partition root.
*/
static void compute_effective_cpumask(struct cpumask *new_cpus,
struct cpuset *cs, struct cpuset *parent)
{
- cpumask_and(new_cpus, cs->cpus_allowed, parent->effective_cpus);
+ bool has_cpus;
+
+ has_cpus = cpumask_and(new_cpus, cs->cpus_allowed, parent->effective_cpus);
+ if (!has_cpus && is_in_v2_mode())
+ cpumask_copy(new_cpus, parent->effective_cpus);
+}
+
+/**
+ * compute_effective_nodemask - Compute the effective nodemask of the cpuset
+ * @new_mems: the temp variable for the new effective_mems mask
+ * @cs: the cpuset the need to recompute the new effective_mems mask
+ * @parent: the parent cpuset
+ *
+ * For v2, the parent's effective_mems is inherited if nodemask is empty.
+ */
+static void compute_effective_nodemask(nodemask_t *new_mems,
+ struct cpuset *cs, struct cpuset *parent)
+{
+ bool has_mems;
+
+ has_mems = nodes_and(*new_mems, cs->mems_allowed, parent->effective_mems);
+ if (!has_mems && is_in_v2_mode())
+ nodes_copy(*new_mems, parent->effective_mems);
}
/*
@@ -2144,15 +2167,6 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
}
/*
- * If it becomes empty, inherit the effective mask of the
- * parent, which is guaranteed to have some CPUs unless
- * it is a partition root that has explicitly distributed
- * out all its CPUs.
- */
- if (is_in_v2_mode() && !remote && cpumask_empty(tmp->new_cpus))
- cpumask_copy(tmp->new_cpus, parent->effective_cpus);
-
- /*
* Skip the whole subtree if
* 1) the cpumask remains the same,
* 2) has no partition root state,
@@ -2692,14 +2706,7 @@ static void update_nodemasks_hier(struct cpuset *cs, nodemask_t *new_mems)
cpuset_for_each_descendant_pre(cp, pos_css, cs) {
struct cpuset *parent = parent_cs(cp);
- bool has_mems = nodes_and(*new_mems, cp->mems_allowed, parent->effective_mems);
-
- /*
- * If it becomes empty, inherit the effective mask of the
- * parent, which is guaranteed to have some MEMs.
- */
- if (is_in_v2_mode() && !has_mems)
- *new_mems = parent->effective_mems;
+ compute_effective_nodemask(new_mems, cp, parent);
/* Skip the whole subtree if the nodemask remains the same. */
if (nodes_equal(*new_mems, cp->effective_mems)) {
@@ -3773,7 +3780,7 @@ retry:
parent = parent_cs(cs);
compute_effective_cpumask(&new_cpus, cs, parent);
- nodes_and(new_mems, cs->mems_allowed, parent->effective_mems);
+ compute_effective_nodemask(&new_mems, cs, parent);
if (!tmp || !cs->partition_root_state)
goto update_tasks;