An isolated cpuset partition already updates the HK_TYPE_DOMAIN
housekeeping mask.  Extend it to also update the kernel-noise masks
(HK_TYPE_KERNEL_NOISE and HK_TYPE_MANAGED_IRQ) so that creating or
destroying an isolated partition reconfigures the full set of
housekeeping cpumasks.

HK_TYPE_KERNEL_NOISE must stay a subset of HK_TYPE_DOMAIN: a CPU with
the tick suppressed still needs to be excluded from the normal sched
domain, or scheduler load balancing can keep nominating it as a
target.  Update the sched domain mask first and only touch the
kernel-noise types when that update succeeds, so the two masks can
never diverge for the same isolation request.

housekeeping_update() and housekeeping_update_types() are called after
dropping cpus_read_lock and cpuset_mutex, with only cpuset_top_mutex held
for mutual exclusion.

Signed-off-by: Qiliang Yuan <[email protected]>
---
 kernel/cgroup/cpuset.c | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 3f52717c19654..8b3bb034adf62 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1431,17 +1431,43 @@ static void cpuset_update_sd_hk_unlock(void)
                rebuild_sched_domains_locked();
 
        if (update_housekeeping) {
+               static const unsigned long noise_types =
+                       BIT(HK_TYPE_KERNEL_NOISE) | BIT(HK_TYPE_MANAGED_IRQ);
+               int ret;
+
                update_housekeeping = false;
                cpumask_copy(isolated_hk_cpus, isolated_cpus);
 
+               mutex_unlock(&cpuset_mutex);
+               cpus_read_unlock();
+
                /*
                 * housekeeping_update() is now called without holding
                 * cpus_read_lock and cpuset_mutex. Only cpuset_top_mutex
                 * is still being held for mutual exclusion.
                 */
-               mutex_unlock(&cpuset_mutex);
-               cpus_read_unlock();
-               WARN_ON_ONCE(housekeeping_update(isolated_hk_cpus));
+
+               /*
+                * Update the sched domain mask first; it must succeed
+                * before the kernel-noise types because workqueue flush
+                * and timer migration depend on the sched domain mask.
+                */
+               ret = housekeeping_update(isolated_hk_cpus);
+               WARN_ON_ONCE(ret);
+
+               /*
+                * Only touch the kernel-noise housekeeping masks
+                * (HK_TYPE_KERNEL_NOISE and HK_TYPE_MANAGED_IRQ) once the
+                * sched domain update above actually succeeded: HK_TYPE_
+                * KERNEL_NOISE must stay a subset of HK_TYPE_DOMAIN, so a CPU
+                * can never end up tick-suppressed while still scheduled as
+                * part of the normal (non-isolated) sched domain.  The tick,
+                * RCU and managed-interrupt state is reconfigured as the
+                * affected CPUs are cycled through the CPU hotplug machinery.
+                */
+               if (!ret)
+                       WARN_ON_ONCE(housekeeping_update_types(noise_types,
+                                                              
isolated_hk_cpus));
                mutex_unlock(&cpuset_top_mutex);
        } else {
                cpuset_full_unlock();

-- 
2.43.0


Reply via email to