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: