|
Michal Kubecek |
f6f6da |
From 8ca09d5fa3549d142c2080a72a4c70ce389163cd Mon Sep 17 00:00:00 2001
|
|
Michal Kubecek |
f6f6da |
From: Linus Torvalds <torvalds@linux-foundation.org>
|
|
Michal Kubecek |
f6f6da |
Date: Mon, 6 Mar 2023 12:15:13 -0800
|
|
Michal Kubecek |
f6f6da |
Subject: cpumask: fix incorrect cpumask scanning result checks
|
|
Michal Kubecek |
f6f6da |
Patch-mainline: v6.3-rc2
|
|
Michal Kubecek |
f6f6da |
Git-commit: 8ca09d5fa3549d142c2080a72a4c70ce389163cd
|
|
Michal Kubecek |
f6f6da |
References: https://lkml.iu.edu/hypermail/linux/kernel/2303.0/05801.html
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
It turns out that commit 596ff4a09b89 ("cpumask: re-introduce
|
|
Michal Kubecek |
f6f6da |
constant-sized cpumask optimizations") exposed a number of cases of
|
|
Michal Kubecek |
f6f6da |
drivers not checking the result of "cpumask_next()" and friends
|
|
Michal Kubecek |
f6f6da |
correctly.
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
The documented correct check for "no more cpus in the cpumask" is to
|
|
Michal Kubecek |
f6f6da |
check for the result being equal or larger than the number of possible
|
|
Michal Kubecek |
f6f6da |
CPU ids, exactly _because_ we've always done those constant-sized
|
|
Michal Kubecek |
f6f6da |
cpumask scans using a widened type before. So the return value of a
|
|
Michal Kubecek |
f6f6da |
cpumask scan should be checked with
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
if (cpu >= nr_cpu_ids)
|
|
Michal Kubecek |
f6f6da |
...
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
because the cpumask scan did not necessarily stop exactly *at* that
|
|
Michal Kubecek |
f6f6da |
maximum CPU id.
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
But a few cases ended up instead using checks like
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
if (cpu == nr_cpumask_bits)
|
|
Michal Kubecek |
f6f6da |
...
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
which used that internal "widened" number of bits. And that used to
|
|
Michal Kubecek |
f6f6da |
work pretty much by accident (ok, in this case "by accident" is simply
|
|
Michal Kubecek |
f6f6da |
because it matched the historical internal implementation of the cpumask
|
|
Michal Kubecek |
f6f6da |
scanning, so it was more of a "intentionally using implementation
|
|
Michal Kubecek |
f6f6da |
details rather than an accident").
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
But the extended constant-sized optimizations then did that internal
|
|
Michal Kubecek |
f6f6da |
implementation differently, and now that code that did things wrong but
|
|
Michal Kubecek |
f6f6da |
matched the old implementation no longer worked at all.
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
Which then causes subsequent odd problems due to using what ends up
|
|
Michal Kubecek |
f6f6da |
being an invalid CPU ID.
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
Most of these cases require either unusual hardware or special uses to
|
|
Michal Kubecek |
f6f6da |
hit, but the random.c one triggers quite easily.
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
All you really need is to have a sufficiently small CONFIG_NR_CPUS value
|
|
Michal Kubecek |
f6f6da |
for the bit scanning optimization to be triggered, but not enough CPUs
|
|
Michal Kubecek |
f6f6da |
to then actually fill that widened cpumask. At that point, the cpumask
|
|
Michal Kubecek |
f6f6da |
scanning will return the NR_CPUS constant, which is _not_ the same as
|
|
Michal Kubecek |
f6f6da |
nr_cpumask_bits.
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
This just does the mindless fix with
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
sed -i 's/== nr_cpumask_bits/>= nr_cpu_ids/'
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
to fix the incorrect uses.
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
The ones in the SCSI lpfc driver in particular could probably be fixed
|
|
Michal Kubecek |
f6f6da |
more cleanly by just removing that repeated pattern entirely, but I am
|
|
Michal Kubecek |
f6f6da |
not emptionally invested enough in that driver to care.
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
Reported-and-tested-by: Guenter Roeck <linux@roeck-us.net>
|
|
Michal Kubecek |
f6f6da |
Link: https://lore.kernel.org/lkml/481b19b5-83a0-4793-b4fd-194ad7b978c3@roeck-us.net/
|
|
Michal Kubecek |
f6f6da |
Reported-and-tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
|
|
Michal Kubecek |
f6f6da |
Link: https://lore.kernel.org/lkml/CAMuHMdUKo_Sf7TjKzcNDa8Ve+6QrK+P8nSQrSQ=6LTRmcBKNww@mail.gmail.com/
|
|
Michal Kubecek |
f6f6da |
Reported-by: Vernon Yang <vernon2gm@gmail.com>
|
|
Michal Kubecek |
f6f6da |
Link: https://lore.kernel.org/lkml/20230306160651.2016767-1-vernon2gm@gmail.com/
|
|
Michal Kubecek |
f6f6da |
Cc: Yury Norov <yury.norov@gmail.com>
|
|
Michal Kubecek |
f6f6da |
Cc: Jason A. Donenfeld <Jason@zx2c4.com>
|
|
Michal Kubecek |
f6f6da |
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
|
Michal Kubecek |
f6f6da |
Acked-by: Michal Kubecek <mkubecek@suse.cz>
|
|
Michal Kubecek |
f6f6da |
---
|
|
Michal Kubecek |
f6f6da |
arch/powerpc/xmon/xmon.c | 2 +-
|
|
Michal Kubecek |
f6f6da |
drivers/char/random.c | 2 +-
|
|
Michal Kubecek |
f6f6da |
drivers/net/wireguard/queueing.h | 2 +-
|
|
Michal Kubecek |
f6f6da |
drivers/scsi/lpfc/lpfc_init.c | 14 +++++++-------
|
|
Michal Kubecek |
f6f6da |
4 files changed, 10 insertions(+), 10 deletions(-)
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
--- a/arch/powerpc/xmon/xmon.c
|
|
Michal Kubecek |
f6f6da |
+++ b/arch/powerpc/xmon/xmon.c
|
|
Michal Kubecek |
f6f6da |
@@ -1275,7 +1275,7 @@ static int xmon_batch_next_cpu(void)
|
|
Michal Kubecek |
f6f6da |
while (!cpumask_empty(&xmon_batch_cpus)) {
|
|
Michal Kubecek |
f6f6da |
cpu = cpumask_next_wrap(smp_processor_id(), &xmon_batch_cpus,
|
|
Michal Kubecek |
f6f6da |
xmon_batch_start_cpu, true);
|
|
Michal Kubecek |
f6f6da |
- if (cpu == nr_cpumask_bits)
|
|
Michal Kubecek |
f6f6da |
+ if (cpu >= nr_cpu_ids)
|
|
Michal Kubecek |
f6f6da |
break;
|
|
Michal Kubecek |
f6f6da |
if (xmon_batch_start_cpu == -1)
|
|
Michal Kubecek |
f6f6da |
xmon_batch_start_cpu = cpu;
|
|
Michal Kubecek |
f6f6da |
--- a/drivers/char/random.c
|
|
Michal Kubecek |
f6f6da |
+++ b/drivers/char/random.c
|
|
Michal Kubecek |
f6f6da |
@@ -1311,7 +1311,7 @@ static void __cold try_to_generate_entropy(void)
|
|
Michal Kubecek |
f6f6da |
/* Basic CPU round-robin, which avoids the current CPU. */
|
|
Michal Kubecek |
f6f6da |
do {
|
|
Michal Kubecek |
f6f6da |
cpu = cpumask_next(cpu, &timer_cpus);
|
|
Michal Kubecek |
f6f6da |
- if (cpu == nr_cpumask_bits)
|
|
Michal Kubecek |
f6f6da |
+ if (cpu >= nr_cpu_ids)
|
|
Michal Kubecek |
f6f6da |
cpu = cpumask_first(&timer_cpus);
|
|
Michal Kubecek |
f6f6da |
} while (cpu == smp_processor_id() && num_cpus > 1);
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
--- a/drivers/net/wireguard/queueing.h
|
|
Michal Kubecek |
f6f6da |
+++ b/drivers/net/wireguard/queueing.h
|
|
Michal Kubecek |
f6f6da |
@@ -106,7 +106,7 @@ static inline int wg_cpumask_choose_online(int *stored_cpu, unsigned int id)
|
|
Michal Kubecek |
f6f6da |
{
|
|
Michal Kubecek |
f6f6da |
unsigned int cpu = *stored_cpu, cpu_index, i;
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
- if (unlikely(cpu == nr_cpumask_bits ||
|
|
Michal Kubecek |
f6f6da |
+ if (unlikely(cpu >= nr_cpu_ids ||
|
|
Michal Kubecek |
f6f6da |
!cpumask_test_cpu(cpu, cpu_online_mask))) {
|
|
Michal Kubecek |
f6f6da |
cpu_index = id % cpumask_weight(cpu_online_mask);
|
|
Michal Kubecek |
f6f6da |
cpu = cpumask_first(cpu_online_mask);
|
|
Michal Kubecek |
f6f6da |
--- a/drivers/scsi/lpfc/lpfc_init.c
|
|
Michal Kubecek |
f6f6da |
+++ b/drivers/scsi/lpfc/lpfc_init.c
|
|
Michal Kubecek |
f6f6da |
@@ -12563,7 +12563,7 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
|
|
Michal Kubecek |
f6f6da |
goto found_same;
|
|
Michal Kubecek |
f6f6da |
new_cpu = cpumask_next(
|
|
Michal Kubecek |
f6f6da |
new_cpu, cpu_present_mask);
|
|
Michal Kubecek |
f6f6da |
- if (new_cpu == nr_cpumask_bits)
|
|
Michal Kubecek |
f6f6da |
+ if (new_cpu >= nr_cpu_ids)
|
|
Michal Kubecek |
f6f6da |
new_cpu = first_cpu;
|
|
Michal Kubecek |
f6f6da |
}
|
|
Michal Kubecek |
f6f6da |
/* At this point, we leave the CPU as unassigned */
|
|
Michal Kubecek |
f6f6da |
@@ -12577,7 +12577,7 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
|
|
Michal Kubecek |
f6f6da |
* selecting the same IRQ.
|
|
Michal Kubecek |
f6f6da |
*/
|
|
Michal Kubecek |
f6f6da |
start_cpu = cpumask_next(new_cpu, cpu_present_mask);
|
|
Michal Kubecek |
f6f6da |
- if (start_cpu == nr_cpumask_bits)
|
|
Michal Kubecek |
f6f6da |
+ if (start_cpu >= nr_cpu_ids)
|
|
Michal Kubecek |
f6f6da |
start_cpu = first_cpu;
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
Michal Kubecek |
f6f6da |
@@ -12613,7 +12613,7 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
|
|
Michal Kubecek |
f6f6da |
goto found_any;
|
|
Michal Kubecek |
f6f6da |
new_cpu = cpumask_next(
|
|
Michal Kubecek |
f6f6da |
new_cpu, cpu_present_mask);
|
|
Michal Kubecek |
f6f6da |
- if (new_cpu == nr_cpumask_bits)
|
|
Michal Kubecek |
f6f6da |
+ if (new_cpu >= nr_cpu_ids)
|
|
Michal Kubecek |
f6f6da |
new_cpu = first_cpu;
|
|
Michal Kubecek |
f6f6da |
}
|
|
Michal Kubecek |
f6f6da |
/* We should never leave an entry unassigned */
|
|
Michal Kubecek |
f6f6da |
@@ -12631,7 +12631,7 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
|
|
Michal Kubecek |
f6f6da |
* selecting the same IRQ.
|
|
Michal Kubecek |
f6f6da |
*/
|
|
Michal Kubecek |
f6f6da |
start_cpu = cpumask_next(new_cpu, cpu_present_mask);
|
|
Michal Kubecek |
f6f6da |
- if (start_cpu == nr_cpumask_bits)
|
|
Michal Kubecek |
f6f6da |
+ if (start_cpu >= nr_cpu_ids)
|
|
Michal Kubecek |
f6f6da |
start_cpu = first_cpu;
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
Michal Kubecek |
f6f6da |
@@ -12704,7 +12704,7 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
|
|
Michal Kubecek |
f6f6da |
goto found_hdwq;
|
|
Michal Kubecek |
f6f6da |
}
|
|
Michal Kubecek |
f6f6da |
new_cpu = cpumask_next(new_cpu, cpu_present_mask);
|
|
Michal Kubecek |
f6f6da |
- if (new_cpu == nr_cpumask_bits)
|
|
Michal Kubecek |
f6f6da |
+ if (new_cpu >= nr_cpu_ids)
|
|
Michal Kubecek |
f6f6da |
new_cpu = first_cpu;
|
|
Michal Kubecek |
f6f6da |
}
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
@@ -12719,7 +12719,7 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
|
|
Michal Kubecek |
f6f6da |
goto found_hdwq;
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
new_cpu = cpumask_next(new_cpu, cpu_present_mask);
|
|
Michal Kubecek |
f6f6da |
- if (new_cpu == nr_cpumask_bits)
|
|
Michal Kubecek |
f6f6da |
+ if (new_cpu >= nr_cpu_ids)
|
|
Michal Kubecek |
f6f6da |
new_cpu = first_cpu;
|
|
Michal Kubecek |
f6f6da |
}
|
|
Michal Kubecek |
f6f6da |
|
|
Michal Kubecek |
f6f6da |
@@ -12730,7 +12730,7 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
|
|
Michal Kubecek |
f6f6da |
found_hdwq:
|
|
Michal Kubecek |
f6f6da |
/* We found an available entry, copy the IRQ info */
|
|
Michal Kubecek |
f6f6da |
start_cpu = cpumask_next(new_cpu, cpu_present_mask);
|
|
Michal Kubecek |
f6f6da |
- if (start_cpu == nr_cpumask_bits)
|
|
Michal Kubecek |
f6f6da |
+ if (start_cpu >= nr_cpu_ids)
|
|
Michal Kubecek |
f6f6da |
start_cpu = first_cpu;
|
|
Michal Kubecek |
f6f6da |
cpup->hdwq = new_cpup->hdwq;
|
|
Michal Kubecek |
f6f6da |
logit:
|