HK_TYPE_KERNEL_NOISE and HK_TYPE_DOMAIN are configured independently
when nohz_full=/isolcpus=nohz and isolcpus=domain are passed as
separate boot parameters, or when nohz_full=/isolcpus=nohz is passed
without isolcpus=domain at all.  Nothing stops a CPU from ending up
tick-suppressed (nohz_full) while still scheduled as part of the
normal, non-isolated sched domain, which defeats the point of
isolating it from kernel noise in the first place.

A CPU with the tick stopped must always be excluded from the normal
scheduler domain: HK_TYPE_KERNEL_NOISE's housekeeping set has to stay
a superset of HK_TYPE_DOMAIN's.  Checking this while __setup()
parameters are still being parsed is order-dependent: rejecting
nohz_full= the moment it is seen, before a later isolcpus=domain on
the same command line has been parsed yet, would discard a
perfectly valid combination just because of argument order.

Check the invariant once in housekeeping_init() instead, which runs
after every __setup() cmdline parameter has been parsed regardless of
order.  Disable HK_TYPE_KERNEL_NOISE rather than panicking or leaving
the inconsistency in place: this gives the same end state as not
having passed nohz_full=/isolcpus=nohz at all.

housekeeping_cpumask() only dereferences the real per-type masks once
housekeeping_overridden is enabled; before that every call returns
cpu_possible_mask regardless of housekeeping.flags.  Enable the static
key before the subset check runs, not after: checking first would
compare cpu_possible_mask against itself for both sides and never
reject anything.

Signed-off-by: Qiliang Yuan <[email protected]>
---
 Documentation/admin-guide/kernel-parameters.txt | 12 ++++++++++++
 kernel/sched/isolation.c                        | 24 ++++++++++++++++++++++++
 2 files changed, 36 insertions(+)

diff --git a/Documentation/admin-guide/kernel-parameters.txt 
b/Documentation/admin-guide/kernel-parameters.txt
index e75344f4e0cde..cd4fb6d752a6c 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2810,6 +2810,11 @@ Kernel parameters
                          so to protect individual CPUs the 'cpumask' file has 
to
                          be configured manually after bootup.
 
+                         When 'domain' is configured through a separate
+                         isolcpus= or nohz_full= invocation, every 'nohz'
+                         CPU must also be a 'domain' CPU; a combination that
+                         violates this is rejected at boot with a warning.
+
                        domain
                          Isolate from the general SMP balancing and scheduling
                          algorithms. Note that performing domain isolation 
this way
@@ -4564,6 +4569,13 @@ Kernel parameters
                        Note that this argument takes precedence over
                        the CONFIG_RCU_NOCB_CPU_DEFAULT_ALL option.
 
+                       When isolcpus=domain is also given, every CPU in
+                       this list (or in isolcpus=nohz) must also be in
+                       the isolcpus=domain list: a tick-suppressed CPU
+                       must always be excluded from the normal scheduler
+                       domain.  A combination that violates this is
+                       rejected at boot with a warning.
+
        noinitrd        [Deprecated,RAM] Tells the kernel not to load any 
configured
                        initial RAM disk. Currently this parameter applies to
                        initrd only, not to initramfs. But it applies to both
diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
index 156025ef81b75..c6a41095a9002 100644
--- a/kernel/sched/isolation.c
+++ b/kernel/sched/isolation.c
@@ -171,8 +171,32 @@ void __init housekeeping_init(void)
        if (!housekeeping.flags)
                return;
 
+       /*
+        * housekeeping_cpumask() only dereferences the real per-type masks
+        * once housekeeping_overridden is live; before that it always
+        * returns cpu_possible_mask regardless of housekeeping.flags, which
+        * would make the subset check below vacuously pass for every type.
+        * Enable it first so the check actually sees the parsed masks.
+        */
        static_branch_enable(&housekeeping_overridden);
 
+       /*
+        * A nohz_full CPU must always run on an isolated sched domain:
+        * reject nohz_full=/isolcpus=nohz unless isolcpus=domain covers
+        * at least the same CPUs.  Checked here, after all __setup()
+        * cmdline parsing has run, so the outcome does not depend on
+        * which of the two parameters came first on the command line.
+        */
+       if ((housekeeping.flags & HK_FLAG_KERNEL_NOISE) &&
+           !cpumask_subset(housekeeping_cpumask(HK_TYPE_DOMAIN),
+                           housekeeping_cpumask(HK_TYPE_KERNEL_NOISE))) {
+               pr_warn("Housekeeping: nohz_full=/isolcpus=nohz must be a 
subset "
+                       "of isolcpus=domain, disabling nohz_full\n");
+               housekeeping.flags &= ~HK_FLAG_KERNEL_NOISE;
+               if (!housekeeping.flags)
+                       return;
+       }
+
        if (housekeeping.flags & HK_FLAG_KERNEL_NOISE)
                sched_tick_offload_init();
        /*

-- 
2.43.0


Reply via email to