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

