* [PATCH v2 1/2] powerpc/rtasd: Use struct_size() to simplify log_rtas_len()
From: Thorsten Blum @ 2026-06-27 10:47 UTC (permalink / raw)
To: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP), Haren Myneni, Mahesh Salgaonkar,
Tyrel Datwyler
Cc: Thorsten Blum, linuxppc-dev, linux-kernel
Now that struct rtas_error_log uses a flexible array member for the
extended log buffer, use struct_size() to calculate the total RTAS error
log size and avoid using the hard-coded header size of 8 bytes.
Use min() to replace the open-coded implementation while at it.
Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
---
No changes in patch 1/2.
---
arch/powerpc/kernel/rtasd.c | 19 ++++++-------------
1 file changed, 6 insertions(+), 13 deletions(-)
diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c
index 6336ec9aedd0..fd40864bdb70 100644
--- a/arch/powerpc/kernel/rtasd.c
+++ b/arch/powerpc/kernel/rtasd.c
@@ -10,6 +10,7 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/of.h>
+#include <linux/overflow.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
@@ -160,25 +161,17 @@ static void printk_log_rtas(char *buf, int len)
static int log_rtas_len(char * buf)
{
- int len;
+ size_t len;
struct rtas_error_log *err;
- uint32_t extended_log_length;
+ u32 extended_log_length;
- /* rtas fixed header */
- len = 8;
err = (struct rtas_error_log *)buf;
- extended_log_length = rtas_error_extended_log_length(err);
- if (rtas_error_extended(err) && extended_log_length) {
-
- /* extended header */
- len += extended_log_length;
- }
+ extended_log_length = rtas_error_extended(err) ? rtas_error_extended_log_length(err) : 0;
+ len = struct_size(err, buffer, extended_log_length);
if (rtas_error_log_max == 0)
rtas_error_log_max = rtas_get_error_log_max();
-
- if (len > rtas_error_log_max)
- len = rtas_error_log_max;
+ len = min(len, rtas_error_log_max);
return len;
}
base-commit: ab8bbf8024b7434e2b630965fd373fba5b89f29f
^ permalink raw reply related
* [PATCH v2 2/2] powerpc/pseries/ras: Use struct_size() to simplify fwnmi_get_errinfo()
From: Thorsten Blum @ 2026-06-27 10:47 UTC (permalink / raw)
To: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP)
Cc: Thorsten Blum, linuxppc-dev, linux-kernel
In-Reply-To: <20260627104730.276858-3-thorsten.blum@linux.dev>
Now that struct rtas_error_log uses a flexible array member for the
extended log buffer, use struct_size() to calculate the total RTAS error
log size and avoid using the hard-coded header size of 8 bytes.
Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
---
Changes in v2:
- memcpy_and_pad() cannot be used in real mode; use memset() + memcpy()
- v1: https://lore.kernel.org/r/20260626184750.166642-4-thorsten.blum@linux.dev/
---
arch/powerpc/platforms/pseries/ras.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index adafd593d9d3..7b8713bdd978 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -7,6 +7,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of.h>
+#include <linux/overflow.h>
#include <linux/fs.h>
#include <linux/reboot.h>
#include <linux/irq_work.h>
@@ -440,6 +441,8 @@ static __be64 *fwnmi_get_savep(struct pt_regs *regs)
static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
{
struct rtas_error_log *h;
+ u32 extended_log_length;
+ size_t len;
__be64 *savep;
savep = fwnmi_get_savep(regs);
@@ -449,17 +452,12 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */
h = (struct rtas_error_log *)&savep[1];
+ extended_log_length = rtas_error_extended(h) ? rtas_error_extended_log_length(h) : 0;
+ len = struct_size(h, buffer, extended_log_length);
+ len = min(len, RTAS_ERROR_LOG_MAX);
/* Use the per cpu buffer from paca to store rtas error log */
memset(local_paca->mce_data_buf, 0, RTAS_ERROR_LOG_MAX);
- if (!rtas_error_extended(h)) {
- memcpy(local_paca->mce_data_buf, h, sizeof(__u64));
- } else {
- int len, error_log_length;
-
- error_log_length = 8 + rtas_error_extended_log_length(h);
- len = min_t(int, error_log_length, RTAS_ERROR_LOG_MAX);
- memcpy(local_paca->mce_data_buf, h, len);
- }
+ memcpy(local_paca->mce_data_buf, h, len);
return (struct rtas_error_log *)local_paca->mce_data_buf;
}
^ permalink raw reply related
* [PATCH v3] perf scripts: Add configurable sorting option to powerpc-hcalls
From: Shivani Nittor @ 2026-06-27 9:03 UTC (permalink / raw)
To: acme, jolsa, adrian.hunter, mpetlan, tmricht, maddy, irogers,
namhyung, ravi.bangoria
Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, Tejas.Manhas1,
Tanushree.Shah, shivani
The powerpc-hcalls.py script currently prints hypercall
statistics in a fixed sort order based on the number of
hcall occurrences, making it difficult to analyze hcalls
from different execution characteristics.
Add support for runtime-configurable sorting so users
can order hypercall statistics by count, minimum
latency, maximum latency, or average latency using
a --sort option.
Parse arguments through sys.argv to support perf script
argument passing semantics.
Example:
perf record -a -e powerpc* sleep 10
perf script -s ./powerpc-hcalls.py -i ./perf.data -- --sort=max
SORT KEY = max
hcall count min(ns) max(ns) avg(ns)
H_SEND_LOGICAL_LAN 47 7380 40148 8739
H_VIO_SIGNAL 706 880 17454 1911
H_RANDOM 1 15176 15176 15176
H_PUT_TCE_INDIRECT 4 3032 10444 4956
H_ADD_LOGICAL_LAN_BUFFER 363 1250 8716 1534
H_SEND_CRQ 8 2086 6846 3044
H_PUT_TCE 9 1284 4932 2646
H_STUFF_TCE 13 1620 3962 2358
This makes it easier to identify frequently occurring
or high-latency hypercalls depending on the analysis
being performed.
Signed-off-by: Shivani Nittor <shivani@linux.ibm.com>
---
Changelog:
v2 -> v3
- Add validation for supported sort keys
- Print valid sort options for invalid input
v1 -> v2
- Add bounds check for --sort argument handling
- Prevent IndexError when sort key is omitted
tools/perf/scripts/python/powerpc-hcalls.py | 46 ++++++++++++++++++++-
1 file changed, 45 insertions(+), 1 deletion(-)
diff --git a/tools/perf/scripts/python/powerpc-hcalls.py b/tools/perf/scripts/python/powerpc-hcalls.py
index 8b78dc790adb..bfa628d8c952 100644
--- a/tools/perf/scripts/python/powerpc-hcalls.py
+++ b/tools/perf/scripts/python/powerpc-hcalls.py
@@ -25,6 +25,7 @@ from Util import *
# } ...
# }
output = {}
+sort_key = 'count'
# d_enter: {
# cpu: {
@@ -158,10 +159,53 @@ def hcall_table_lookup(opcode):
print_ptrn = '%-28s%10s%10s%10s%10s'
+def sort_output(opcode):
+ stats = output[opcode]
+
+ if sort_key == 'min':
+ return stats['min']
+ if sort_key == 'max':
+ return stats['max']
+ if sort_key == 'avg':
+ return stats['time'] // stats['cnt']
+
+ return stats['cnt']
+
+def trace_begin():
+ global sort_key
+
+ valid_sort_keys = ['count', 'min', 'max', 'avg']
+
+ i = 1
+ while i < len(sys.argv):
+ arg = sys.argv[i]
+
+ if arg == '-s' or arg == '--sort':
+ if i + 1 >= len(sys.argv):
+ print("Error: -s/--sort requires a sort key argument")
+ sys.exit(1)
+ sort_key = sys.argv[i + 1]
+ i += 2
+ continue
+
+ if arg.startswith('--sort='):
+ sort_key = arg.split('=', 1)[1]
+ i += 1
+ continue
+
+ i += 1
+
+ if sort_key not in valid_sort_keys:
+ print(f"Error: Invalid sort key '{sort_key}'. Valid options are: {', '.join(valid_sort_keys)}")
+ sys.exit(1)
+
+ print("SORT KEY =", sort_key)
+
def trace_end():
print(print_ptrn % ('hcall', 'count', 'min(ns)', 'max(ns)', 'avg(ns)'))
print('-' * 68)
- for opcode in output:
+ for opcode in sorted(output, key = sort_output,
+ reverse=True):
h_name = hcall_table_lookup(opcode)
time = output[opcode]['time']
cnt = output[opcode]['cnt']
--
2.54.0
^ permalink raw reply related
* Re: cleanup the RAID6 P/Q library v3
From: H. Peter Anvin @ 2026-06-27 0:52 UTC (permalink / raw)
To: Christoph Hellwig, Andrew Morton
Cc: Catalin Marinas, Will Deacon, Ard Biesheuvel, Huacai Chen,
WANG Xuerui, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, Herbert Xu, Dan Williams, Chris Mason,
David Sterba, Arnd Bergmann, Song Liu, Yu Kuai, Li Nan,
linux-kernel, linux-arm-kernel, loongarch, linuxppc-dev,
linux-riscv, linux-s390, linux-crypto, linux-btrfs, linux-arch,
linux-raid
In-Reply-To: <20260519082432.GA14956@lst.de>
On 2026-05-19 01:24, Christoph Hellwig wrote:
>
> raid6: rework registration of optimized algorithms
>
> - avx2 instead of avx512 is probably the right thing for no
> benchmarking, but if it was intentional (it wasn't), that should
> be document. So I'll just switch back to the previous version to
> keep the state of the art
It is unlikely to be the right thing *going forward*, though.
The very unfortunate performance inversion is likely model-specific. It is one
of those things where you largely would have to have a list of quirks :(
-hpa
^ permalink raw reply
* Re: [PATCH 08/18] raid6: warn when using less than four devices
From: H. Peter Anvin @ 2026-06-27 1:14 UTC (permalink / raw)
To: Christoph Hellwig, Andrew Morton
Cc: Catalin Marinas, Will Deacon, Ard Biesheuvel, Huacai Chen,
WANG Xuerui, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, Herbert Xu, Dan Williams, Chris Mason,
David Sterba, Arnd Bergmann, Song Liu, Yu Kuai, Li Nan,
linux-kernel, linux-arm-kernel, loongarch, linuxppc-dev,
linux-riscv, linux-s390, linux-crypto, linux-btrfs, linux-arch,
linux-raid
In-Reply-To: <20260518051804.462141-9-hch@lst.de>
On 2026-05-17 22:17, Christoph Hellwig wrote:
> Quoting H. Peter Anvin who came up with the RAID6 P/Q algorithm, and
> who wrote the initial implementation, then still part of the md driver:
>
> The RAID-6 code has *never* supported only 3 units, and if it ever
> worked for *any* of the implementations it was purely by accident.
> Speaking as the original author I should know; this was deliberate as
> in some cases the degenerate case (3) would have required extra trays
Stupid autocorrect. That was of course supposed to be "tests" (as in extra
code paths) not "trays" :)
> in the code to no user benefit.
>
> While md never allowed less than 4 devices, btrfs does. This new
> warning will trigger for such file systems, but given how it already
> causes havoc that is a good thing. If btrfs wants to fix third, it
> should switch to transparently use three-way mirroring underneath,
> which will work as P and Q are copies of the single data device by
> the definition of the Linux RAID 6 P/Q algorithm.
For what it's worth, this is also true in the degenerate two-drive RAID-4|5
case (D = P).
-hpa
^ permalink raw reply
* Re: [PATCH 2/2] powerpc/pseries/ras: Use struct_size() to simplify fwnmi_get_errinfo()
From: Thorsten Blum @ 2026-06-26 19:25 UTC (permalink / raw)
To: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP)
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20260626184750.166642-4-thorsten.blum@linux.dev>
On Fri, Jun 26, 2026 at 08:47:50PM +0200, Thorsten Blum wrote:
> Now that struct rtas_error_log uses a flexible array member for the
> extended log buffer, use struct_size() to calculate the total RTAS error
> log size and avoid using the hard-coded header size of 8 bytes.
>
> Use memcpy_and_pad() instead of memset() and memcpy() while at it.
>
> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
> ---
> arch/powerpc/platforms/pseries/ras.c | 17 +++++++----------
> 1 file changed, 7 insertions(+), 10 deletions(-)
>
> diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
> index adafd593d9d3..d54030fd2324 100644
> --- a/arch/powerpc/platforms/pseries/ras.c
> +++ b/arch/powerpc/platforms/pseries/ras.c
> @@ -7,6 +7,7 @@
> #include <linux/interrupt.h>
> #include <linux/irq.h>
> #include <linux/of.h>
> +#include <linux/overflow.h>
> #include <linux/fs.h>
> #include <linux/reboot.h>
> #include <linux/irq_work.h>
> @@ -440,6 +441,8 @@ static __be64 *fwnmi_get_savep(struct pt_regs *regs)
> static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
> {
> struct rtas_error_log *h;
> + u32 extended_log_length;
> + size_t len;
> __be64 *savep;
>
> savep = fwnmi_get_savep(regs);
> @@ -449,17 +452,11 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
> regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */
>
> h = (struct rtas_error_log *)&savep[1];
> + extended_log_length = rtas_error_extended(h) ? rtas_error_extended_log_length(h) : 0;
> + len = struct_size(h, buffer, extended_log_length);
> + len = min(len, RTAS_ERROR_LOG_MAX);
> /* Use the per cpu buffer from paca to store rtas error log */
> - memset(local_paca->mce_data_buf, 0, RTAS_ERROR_LOG_MAX);
> - if (!rtas_error_extended(h)) {
> - memcpy(local_paca->mce_data_buf, h, sizeof(__u64));
> - } else {
> - int len, error_log_length;
> -
> - error_log_length = 8 + rtas_error_extended_log_length(h);
> - len = min_t(int, error_log_length, RTAS_ERROR_LOG_MAX);
> - memcpy(local_paca->mce_data_buf, h, len);
> - }
> + memcpy_and_pad(local_paca->mce_data_buf, RTAS_ERROR_LOG_MAX, h, len, 0);
Sashiko found that memcpy_and_pad() isn't safe here because
fwnmi_get_errinfo() is part of a real-mode path:
https://sashiko.dev/#/patchset/20260626184750.166642-3-thorsten.blum%40linux.dev
I'll send a v2 and keep memset() and memcpy() separate.
^ permalink raw reply
* Re: [PATCH v4 2/2] tracing: Remove trace_printk.h from kernel.h
From: Nathan Chancellor @ 2026-06-26 19:03 UTC (permalink / raw)
To: Steven Rostedt
Cc: linux-kernel, linux-trace-kernel, Masami Hiramatsu, Mark Rutland,
Mathieu Desnoyers, Andrew Morton, Linus Torvalds,
Sebastian Andrzej Siewior, John Ogness, Thomas Gleixner,
Peter Zijlstra, Julia Lawall, Yury Norov, linux-doc, linux-kbuild,
linuxppc-dev, dri-devel, linux-stm32, linux-arm-kernel,
linux-rdma, linux-usb, linux-ext4, linux-nfs, kvm, intel-gfx
In-Reply-To: <20260626045119.659d1e6b@fedora>
On Fri, Jun 26, 2026 at 04:51:19AM -0400, Steven Rostedt wrote:
> On Thu, 25 Jun 2026 16:41:58 -0700
> Nathan Chancellor <nathan@kernel.org> wrote:
>
>
> > The following diff resolves it for me, should I send it as a separate
> > patch or do you want to just fold it in with a note?
> >
> > diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
> > index 621566345406..2301a701ffbb 100644
> > --- a/include/linux/lockdep.h
> > +++ b/include/linux/lockdep.h
> > @@ -10,6 +10,7 @@
> > #ifndef __LINUX_LOCKDEP_H
> > #define __LINUX_LOCKDEP_H
> >
> > +#include <linux/instruction_pointer.h>
>
> Ah, so the reason for this breakage is because lockdep was relying on
> instruction_pointer.h, that just happened to be included in kernel.h
> via trace_printk.h.
Correct.
> This is a separate issue, so it should be a separate patch. I'll add it
> as patch 1 of this series.
Sounds good, thanks!
> Can you send me the config you used. This didn't trigger in my tests.
It is a plain allmodconfig, for example on arm:
$ make -skj"$(nproc)" ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- allmodconfig lib/test_context-analysis.o
In file included from include/linux/local_lock_internal.h:8,
from include/linux/local_lock.h:5,
from lib/test_context-analysis.c:9:
include/linux/local_lock_internal.h: In function 'local_lock_acquire':
include/linux/lockdep.h:541:87: error: '_THIS_IP_' undeclared (first use in this function)
541 | #define lock_map_acquire(l) lock_acquire_exclusive(l, 0, 0, NULL, _THIS_IP_)
| ^~~~~~~~~
include/linux/lockdep.h:509:88: note: in definition of macro 'lock_acquire_exclusive'
509 | #define lock_acquire_exclusive(l, s, t, n, i) lock_acquire(l, s, t, 0, 1, n, i)
| ^
include/linux/local_lock_internal.h:46:9: note: in expansion of macro 'lock_map_acquire'
46 | lock_map_acquire(&l->dep_map);
| ^~~~~~~~~~~~~~~~
include/linux/lockdep.h:541:87: note: each undeclared identifier is reported only once for each function it appears in
...
I also reproduced it on top of allnoconfig:
$ cat allno.config
CONFIG_CONTEXT_ANALYSIS_TEST=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_EXPERT=y
CONFIG_MMU=y
CONFIG_RUNTIME_TESTING_MENU=y
$ make -skj"$(nproc)" ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- KCONFIG_ALLCONFIG=1 clean allnoconfig lib/test_context-analysis.o
<same error as above>
--
Cheers,
Nathan
^ permalink raw reply
* [PATCH 2/2] powerpc/pseries/ras: Use struct_size() to simplify fwnmi_get_errinfo()
From: Thorsten Blum @ 2026-06-26 18:47 UTC (permalink / raw)
To: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP)
Cc: Thorsten Blum, linuxppc-dev, linux-kernel
In-Reply-To: <20260626184750.166642-3-thorsten.blum@linux.dev>
Now that struct rtas_error_log uses a flexible array member for the
extended log buffer, use struct_size() to calculate the total RTAS error
log size and avoid using the hard-coded header size of 8 bytes.
Use memcpy_and_pad() instead of memset() and memcpy() while at it.
Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
---
arch/powerpc/platforms/pseries/ras.c | 17 +++++++----------
1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index adafd593d9d3..d54030fd2324 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -7,6 +7,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of.h>
+#include <linux/overflow.h>
#include <linux/fs.h>
#include <linux/reboot.h>
#include <linux/irq_work.h>
@@ -440,6 +441,8 @@ static __be64 *fwnmi_get_savep(struct pt_regs *regs)
static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
{
struct rtas_error_log *h;
+ u32 extended_log_length;
+ size_t len;
__be64 *savep;
savep = fwnmi_get_savep(regs);
@@ -449,17 +452,11 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */
h = (struct rtas_error_log *)&savep[1];
+ extended_log_length = rtas_error_extended(h) ? rtas_error_extended_log_length(h) : 0;
+ len = struct_size(h, buffer, extended_log_length);
+ len = min(len, RTAS_ERROR_LOG_MAX);
/* Use the per cpu buffer from paca to store rtas error log */
- memset(local_paca->mce_data_buf, 0, RTAS_ERROR_LOG_MAX);
- if (!rtas_error_extended(h)) {
- memcpy(local_paca->mce_data_buf, h, sizeof(__u64));
- } else {
- int len, error_log_length;
-
- error_log_length = 8 + rtas_error_extended_log_length(h);
- len = min_t(int, error_log_length, RTAS_ERROR_LOG_MAX);
- memcpy(local_paca->mce_data_buf, h, len);
- }
+ memcpy_and_pad(local_paca->mce_data_buf, RTAS_ERROR_LOG_MAX, h, len, 0);
return (struct rtas_error_log *)local_paca->mce_data_buf;
}
^ permalink raw reply related
* [PATCH 1/2] powerpc/rtasd: Use struct_size() to simplify log_rtas_len()
From: Thorsten Blum @ 2026-06-26 18:47 UTC (permalink / raw)
To: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP), Tyrel Datwyler, Mahesh Salgaonkar,
Haren Myneni
Cc: Thorsten Blum, linuxppc-dev, linux-kernel
Now that struct rtas_error_log uses a flexible array member for the
extended log buffer, use struct_size() to calculate the total RTAS error
log size and avoid using the hard-coded header size of 8 bytes.
Use min() to replace the open-coded implementation while at it.
Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
---
arch/powerpc/kernel/rtasd.c | 19 ++++++-------------
1 file changed, 6 insertions(+), 13 deletions(-)
diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c
index 6336ec9aedd0..fd40864bdb70 100644
--- a/arch/powerpc/kernel/rtasd.c
+++ b/arch/powerpc/kernel/rtasd.c
@@ -10,6 +10,7 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/of.h>
+#include <linux/overflow.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
@@ -160,25 +161,17 @@ static void printk_log_rtas(char *buf, int len)
static int log_rtas_len(char * buf)
{
- int len;
+ size_t len;
struct rtas_error_log *err;
- uint32_t extended_log_length;
+ u32 extended_log_length;
- /* rtas fixed header */
- len = 8;
err = (struct rtas_error_log *)buf;
- extended_log_length = rtas_error_extended_log_length(err);
- if (rtas_error_extended(err) && extended_log_length) {
-
- /* extended header */
- len += extended_log_length;
- }
+ extended_log_length = rtas_error_extended(err) ? rtas_error_extended_log_length(err) : 0;
+ len = struct_size(err, buffer, extended_log_length);
if (rtas_error_log_max == 0)
rtas_error_log_max = rtas_get_error_log_max();
-
- if (len > rtas_error_log_max)
- len = rtas_error_log_max;
+ len = min(len, rtas_error_log_max);
return len;
}
^ permalink raw reply related
* [PATCH v3] perf dso: Fix kallsyms DSO detection with fallback logic
From: Tanushree Shah @ 2026-06-26 16:10 UTC (permalink / raw)
To: acme, jolsa, adrian.hunter, vmolnaro, mpetlan, tmricht, maddy,
irogers, namhyung
Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, Tejas.Manhas1,
Tanushree.Shah, Shivani.Nittor, Tanushree Shah
The current kallsyms detection in dso__is_kallsyms() uses the
dso_binary_type enum which fixes the issue of kallsyms being cached in
the build-id cache for out-of-tree modules.
However, during build-id injection in perf record/inject, dso_binary_type
has not been explicitly set yet,so dso__binary_type() returns
DSO_BINARY_TYPE__NOT_FOUND instead of DSO_BINARY_TYPE__KALLSYMS for the
kernel DSO. The current check then fails to identify it as kallsyms,
causing build-id symlinks to not be created in ~/.debug/.build-id/ and
perf archive to fail with "Cannot stat" errors.
Steps to reproduce the issue:
1. rm -rf ~/.debug/.build-id
2. perf record sleep 1
3. perf archive
Fix by falling back to matching long_name against the known kallsyms
strings explicitly when binary_type is not yet set
(== DSO_BINARY_TYPE__NOT_FOUND). Use strcmp() for exact matching of
fixed names and strict validation for guest kallsyms with embedded PID
to prevent path traversal attacks.
Fixes: ebf0b332732d ("perf dso: fix dso__is_kallsyms() check")
Signed-off-by: Tanushree Shah <tshah@linux.ibm.com>
---
v2 -> v3: Replace strncmp() prefix matching with strcmp() for fixed
kallsyms names and add is_guest_kallsyms_pid_name() to
strictly validate guest kallsyms with PID format, preventing
path traversal attacks.
v1 -> v2: Rename DSO__NAME_GUEST_KALLSYMS to DSO__PREFIX_GUEST_KALLSYMS
to reflect that it is a prefix, not a full name.
v1: https://lore.kernel.org/all/20260410071225.708005-2-tshah@linux.ibm.com/
tools/perf/util/dso.h | 57 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index ede691e9a249..8763e6f65316 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -9,6 +9,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <linux/bitops.h>
+#include <string.h>
#include "build-id.h"
#include "debuginfo.h"
#include "mutex.h"
@@ -20,6 +21,40 @@ struct perf_env;
#define DSO__NAME_KALLSYMS "[kernel.kallsyms]"
#define DSO__NAME_KCORE "[kernel.kcore]"
+#define DSO__NAME_GUEST_KALLSYMS "[guest.kernel.kallsyms]"
+#define DSO__NAME_GUEST_KALLSYMS_PID_PREFIX "[guest.kernel.kallsyms."
+
+/*
+ * Validate names of the form "[guest.kernel.kallsyms.<pid>]", where
+ * <pid> is the PID of the guest VM and varies per guest, so it
+ * cannot be matched with strcmp() against a fixed string.
+ *
+ * Every character after the fixed prefix must be a decimal digit,
+ * with ']' immediately terminating the digit run and nothing
+ * following it. This rules out '/', "..", or any other character
+ * being smuggled into the name.
+ */
+static inline bool is_guest_kallsyms_pid_name(const char *name)
+{
+ const size_t prefix_len = sizeof(DSO__NAME_GUEST_KALLSYMS_PID_PREFIX) - 1;
+ size_t digits;
+
+ if (strncmp(name, DSO__NAME_GUEST_KALLSYMS_PID_PREFIX, prefix_len) != 0)
+ return false;
+
+ digits = strspn(name + prefix_len, "0123456789");
+ if (digits == 0)
+ return false;
+
+ /* ']' must terminate the digit run, with nothing trailing it */
+ if (name[prefix_len + digits] != ']')
+ return false;
+
+ if (name[prefix_len + digits + 1] != '\0')
+ return false;
+
+ return true;
+}
/**
* enum dso_binary_type - The kind of DSO generally associated with a memory
@@ -914,8 +949,28 @@ static inline bool dso__is_kcore(const struct dso *dso)
static inline bool dso__is_kallsyms(const struct dso *dso)
{
enum dso_binary_type bt = dso__binary_type(dso);
+ const char *name;
+
+ if (bt == DSO_BINARY_TYPE__KALLSYMS || bt == DSO_BINARY_TYPE__GUEST_KALLSYMS)
+ return true;
+
+ if (bt != DSO_BINARY_TYPE__NOT_FOUND)
+ return false;
+
+ if (!RC_CHK_ACCESS(dso)->kernel)
+ return false;
+
+ name = RC_CHK_ACCESS(dso)->long_name;
+ if (!name)
+ return false;
+
+ if (!strcmp(name, DSO__NAME_KALLSYMS))
+ return true;
+
+ if (!strcmp(name, DSO__NAME_GUEST_KALLSYMS))
+ return true;
- return bt == DSO_BINARY_TYPE__KALLSYMS || bt == DSO_BINARY_TYPE__GUEST_KALLSYMS;
+ return is_guest_kallsyms_pid_name(name);
}
bool dso__is_object_file(const struct dso *dso);
--
2.47.3
^ permalink raw reply related
* Re: [PATCH 2/2] selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes
From: David Hildenbrand (Arm) @ 2026-06-26 15:55 UTC (permalink / raw)
To: Sayali Patil, Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: Zi Yan, Michal Hocko, Oscar Salvador, Lorenzo Stoakes, Dev Jain,
Liam.Howlett, linuxppc-dev, Miaohe Lin, Venkat Rao Bagalkote
In-Reply-To: <8540b58ef1fdbc2e5cb2f9fe28a2d2a54a5bc6a8.1782365671.git.sayalip@linux.ibm.com>
>
> +static int count_mem_nodes(void)
> +{
> + int node, count = 0;
> +
> + for (node = 0; node <= numa_max_node(); node++) {
> + if (numa_node_size(node, NULL) > 0)
> + count++;
> + }
> +
> + return count;
> +}
> +
Can we instead build upon our existing helpers get_first_mem_node() +
get_next_mem_node() ?
From 432774fb50237519c1c041e402fddfdf4b35aa2c Mon Sep 17 00:00:00 2001
From: "David Hildenbrand (Arm)" <david@kernel.org>
Date: Fri, 26 Jun 2026 17:52:21 +0200
Subject: [PATCH] tmp
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
tools/testing/selftests/mm/ksm_tests.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/tools/testing/selftests/mm/ksm_tests.c b/tools/testing/selftests/mm/ksm_tests.c
index a050f4840cfa3..2ebbb544c6711 100644
--- a/tools/testing/selftests/mm/ksm_tests.c
+++ b/tools/testing/selftests/mm/ksm_tests.c
@@ -440,9 +440,9 @@ static int get_next_mem_node(int node)
mem_node = i % (max_node + 1);
node_size = numa_node_size(mem_node, NULL);
if (node_size > 0)
- break;
+ return mem_node;
}
- return mem_node;
+ return -ENODEV;
}
static int get_first_mem_node(void)
@@ -455,8 +455,8 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeo
{
void *numa1_map_ptr, *numa2_map_ptr;
struct timespec start_time;
+ int first_node, second_node;
int page_count = 2;
- int first_node;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time)) {
ksft_perror("clock_gettime");
@@ -467,17 +467,19 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeo
ksft_print_msg("NUMA support not enabled\n");
return KSFT_SKIP;
}
- if (numa_num_configured_nodes() <= 1) {
- ksft_print_msg("At least 2 NUMA nodes must be available\n");
+ first_node = get_first_mem_node();
+ second_node = get_next_mem_node(first_node);
+
+ if (second_node < 0) {
+ ksft_print_msg("At least 2 NUMA nodes with memory must be available\n");
return KSFT_SKIP;
}
if (ksm_write_sysfs(KSM_FP("merge_across_nodes"), merge_across_nodes))
return KSFT_FAIL;
/* allocate 2 pages in 2 different NUMA nodes and fill them with the same data */
- first_node = get_first_mem_node();
numa1_map_ptr = numa_alloc_onnode(page_size, first_node);
- numa2_map_ptr = numa_alloc_onnode(page_size, get_next_mem_node(first_node));
+ numa2_map_ptr = numa_alloc_onnode(page_size, second_node);
if (!numa1_map_ptr || !numa2_map_ptr) {
ksft_perror("numa_alloc_onnode");
return KSFT_FAIL;
--
2.43.0
--
Cheers,
David
^ permalink raw reply related
* Re: [PATCH v3 4/4] panic: use sys_info_with_filter() to avoid duplicate backtraces
From: Bradley Morgan @ 2026-06-26 14:58 UTC (permalink / raw)
To: Petr Mladek
Cc: Andrew Morton, Feng Tang, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Madhavan Srinivasan, Douglas Anderson,
linux-kernel, linuxppc-dev, stable
In-Reply-To: <aj6Q8JcogaIaQit4@pathway.suse.cz>
On June 26, 2026 3:47:12 PM GMT+01:00, Petr Mladek <pmladek@suse.com>
wrote:
>On Fri 2026-06-26 15:35:19, Bradley Morgan wrote:
>> On June 26, 2026 3:26:11 PM GMT+01:00, Petr Mladek <pmladek@suse.com>
>> wrote:
>> >On Fri 2026-06-26 13:32:38, Bradley Morgan wrote:
>> >> On June 26, 2026 1:17:13 PM GMT+01:00, Bradley Morgan
>> ><include@grrlz.net>
>> >> wrote:
>> >> >On June 26, 2026 1:14:14 PM GMT+01:00, Petr Mladek
><pmladek@suse.com>
>> >> >wrote:
>> >> >>On Fri 2026-06-26 12:23:50, Petr Mladek wrote:
>> >> >>> On Thu 2026-06-25 15:25:58, Bradley Morgan wrote:
>> >> >>> But it all becomes very hairy. We have several levels:
>> >> >>>
>> >> >>> + watchdog-all_bt-specific option, e.g.
>> >> >>sysctl_hardlockup_all_cpu_backtrace
>> >> >>>
>> >> >>> + watchdog-specific si_info preferences, e.g.
>hardlockup_si_mask
>> >> >>>
>> >> >>> + panic-specific si_info: panic_print
>> >> >>>
>> >> >>> + universal fallback for any layer: kernel_si_info
>> >> >>>
>> >> >>> Now, we try to check all these variables back and forth to
>> >> >>> trigger all backtraces or to avoid triggering them.
>> >> >>> And it clearly does not work well and the code is more and more
>> >> >>> hairy.
>> >> >>>
>> >> >>> I think about another approach. The word "waterfall" comes to my
>> >mind.
>> >> >>> Instead of checking all the settings back and forth, let's
>process
>> >> >>> each setting one by one and just remember what has been done and
>> >> >>> skip this in the next level.
>> >> >>>
>> >> >>> All the si_info actions seems to dump a global system state.
>> >> >>> So, it would make sense to remember the state in a global
>variable
>> >> >>> even when it might be modified by more CPUs in parallel.
>> >> >>>
>> >> Hmm.. new idea
>> >>
>> >> kernel/dump_filter.c ?
>> >>
>> >> What this file could do is to handle a generic lockup state machine
>> >> so any subsystem can log what it already dumped?
>> >>
>> >> I know it may bloat, but it's better then cramming fixes in.
>> >
>> >I am not sure what exactly you would like to achieve but it sounds
>> >a bit scary ;-)
>> >
>> >Anyway, we should not synchronize the watchdog reports against
>> >each other, definitely. They are running in non-compatible contexts
>> >(task vs interrupt vs NMI). Also we should not add any locking
>> >because they usually print something when the system has enough
>> >troubles.
>> >
>> >Also I think that it is not worth preventing duplicated backtraces
>> >or reports from a single CPU. IMHO, it is not a big problem
>> >in practice.
>> >
>> >So, we are down to large reports, like backtraces from all CPUs,
>> >timers, locks, ... which are handled by sys_info(). So, I think
>> >that it should be enough to handle this inside the sys_info() API.
>> >
>> >I do not want to say that my proposal was the best solution.
>> >I am sure that there are better ones. But we need to consider
>> >the gain vs. complexity.
>> >
>> >Honestly, I am already a bit scared by the complexity which
>> >we the sys_info() API added. And it is hard to imagine that
>> >adding another API would make it easier. But I might be wrong.
>> >
>> >Instead, it might make sense to integrate the conflicting
>> >subsystem-specific calls under the sys_info() API.
>> >I mean that, for example watchdog_hardlockup_check() won't
>> >call trigger_allbutcpu_cpu_backtrace() directly but
>> >it would call it via sys_info() API so that sys_info()
>> >could keep track of it. Something like:
>> >
>> >void sys_info_allbutcpu_bt(int cpu)
>> >{
>> > trigger_allbutcpu_cpu_backtrace(cpu);
>> > /*
>> > * The caller likely printed backtrace of the given @cpu
>> > * on its own. Prevent duplicate backtraces from all
>> > * CPUs with potential next sys_info() call.
>> > */
>> > sys_info_done(SYS_INFO_ALL_BT);
>> >}
>> >
>> >But I am not sure if it is really easier to follow
>> >than calling sys_info_done() from the watchdog code.
>> >
>> >Some watchdogs try to optimize the output and print backtraces
>> >only from CPUs which are relevant for the given lockup.
>> >We should keep the logic for selecting the set of CPUs
>> >in the watchdog code. We just need to solve how to elegantly
>> >make sys_info() aware of it or at least about the more massive
>> >reports.
>> >
>> >Anyway, I would prefer to keep it simple until we see some problems
>> >in practice.
>> >
>> >Best Regards,
>> >Petr
>> >
>>
>>
>> I understand it's scary. To make a new file in the first place.
>>
>> But I was a bit vague of what I wanted, and I'm sorry.
>>
>> So, the reason why I'd suggest a new file, is because if any subsystem
>> Theoretically bypasses sys_info to log a lockup, this completely misses
>> the filter and duplicates the dump
>>
>> My file would act as a generic lockless state machine that any
>> subsystem can update regardless of how they dump logs.
>>
>> If you have any questions, feel absolutely free to ask! :)
>>
>> Discussion is a way to make everyone happy!
>
>Honestly, I am more and more wondering whether your are a real person
>or AI bot.
Sigh..
I can verify myself through video call if you don't believe I am human :)
why I suggested a new file is because AI said it would be a good idea.
I told it what I should do, and it told me to do a new file.
I knew it was over engineering slightly, but I was a bit stressed,
and I wanted some sort of just new API which is less buggy imho
I should've told you that I used AI to figure the whole new file idea,
Really sorry petr..
>Best Regards,
>Petr
>
Thanks!
^ permalink raw reply
* Re: [PATCH 1/2] selftests/mm: handle EINVAL when configuring gigantic hugepages
From: Usama Arif @ 2026-06-26 14:48 UTC (permalink / raw)
To: Sayali Patil
Cc: Usama Arif, Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani, David Hildenbrand, Zi Yan,
Michal Hocko, Oscar Salvador, Lorenzo Stoakes, Dev Jain,
Liam.Howlett, linuxppc-dev, Miaohe Lin, Venkat Rao Bagalkote
In-Reply-To: <8bfa921e30eb94072685103f6496784aa23bb166.1782365671.git.sayalip@linux.ibm.com>
On Thu, 25 Jun 2026 18:10:16 +0530 Sayali Patil <sayalip@linux.ibm.com> wrote:
> Some MM selftests attempt to configure the amount of
> HugeTLB pages of different sizes by writing to nr_hugepages.
>
> PowerPC hash MMU pSeries systems advertise gigantic hugepage sizes
> but do not support runtime allocation of such pages, writes
> to the corresponding nr_hugepages file fail with -EINVAL.
> This causes the test to bail out even though the failure is due
> to a platform limitation rather than the
> functionality being tested.
>
> Treat -EINVAL from the sysfs write as a skipped configuration request
> and continue running the test instead of failing.
>
> Before patch:
> -------------------------
> running ./hugetlb-madvise
> -------------------------
> TAP version 13
> 1..1
> [INFO] detected hugetlb page size: 16777216 KiB
> [INFO] detected hugetlb page size: 16384 KiB
> ok 1 MADV_DONTNEED and MADV_REMOVE on hugetlb
> Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
> Bail out! /sys/kernel/mm/hugepages/hugepages-16777216kB/nr_hugepages
> write(0) failed: Invalid argument
> Totals: pass:0 fail:0 xfail:0 xpass:0 skip:0 error:0
> [FAIL]
>
> After patch:
> -------------------------
> running ./hugetlb-madvise
> -------------------------
> TAP version 13
> 1..1
> [INFO] detected hugetlb page size: 16777216 KiB
> [INFO] detected hugetlb page size: 16384 KiB
> ok 1 MADV_DONTNEED and MADV_REMOVE on hugetlb
> Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
> /sys/kernel/mm/hugepages/hugepages-16777216kB/nr_hugepages
> write(0) failed: Invalid argument
> [PASS]
>
> Fixes: 9d07250ea1eb ("selftests/mm: hugepage_settings: add APIs to get and set nr_hugepages")
> Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
> ---
> tools/testing/selftests/mm/vm_util.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
> index 311fc5b4513e..a8f16eef5c7c 100644
> --- a/tools/testing/selftests/mm/vm_util.c
> +++ b/tools/testing/selftests/mm/vm_util.c
> @@ -735,6 +735,13 @@ void write_file(const char *path, const char *buf, size_t buflen)
> saved_errno = errno;
> close(fd);
> errno = saved_errno;
> +
> + if (numwritten < 0 && errno == EINVAL) {
> + ksft_print_msg("%s write(%.*s) failed: %s\n", path,
> + (int)(buflen - 1), buf, strerror(errno));
> + return;
> + }
> +
This makes write_file() silently succeed for every EINVAL, not just the
gigantic-hugetlb setup case. Several callers use this helper for writes where
EINVAL is a real test failure, for example drop_caches or split huge page
setup. Those tests can now continue after a failed setup and report misleading
results.
Please keep the common helper strict and ignore EINVAL only in the hugetlb
path that is probing unsupported gigantic page runtime allocation.
> if (numwritten < 0)
> ksft_exit_fail_msg("%s write(%.*s) failed: %s\n", path, (int)(buflen - 1),
> buf, strerror(errno));
> --
> 2.52.0
>
>
^ permalink raw reply
* Re: [PATCH v3 4/4] panic: use sys_info_with_filter() to avoid duplicate backtraces
From: Petr Mladek @ 2026-06-26 14:47 UTC (permalink / raw)
To: Bradley Morgan
Cc: Andrew Morton, Feng Tang, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Madhavan Srinivasan, Douglas Anderson,
linux-kernel, linuxppc-dev, stable
In-Reply-To: <688433ED-A478-43F7-9103-995398A6BF63@grrlz.net>
On Fri 2026-06-26 15:35:19, Bradley Morgan wrote:
> On June 26, 2026 3:26:11 PM GMT+01:00, Petr Mladek <pmladek@suse.com>
> wrote:
> >On Fri 2026-06-26 13:32:38, Bradley Morgan wrote:
> >> On June 26, 2026 1:17:13 PM GMT+01:00, Bradley Morgan
> ><include@grrlz.net>
> >> wrote:
> >> >On June 26, 2026 1:14:14 PM GMT+01:00, Petr Mladek <pmladek@suse.com>
> >> >wrote:
> >> >>On Fri 2026-06-26 12:23:50, Petr Mladek wrote:
> >> >>> On Thu 2026-06-25 15:25:58, Bradley Morgan wrote:
> >> >>> But it all becomes very hairy. We have several levels:
> >> >>>
> >> >>> + watchdog-all_bt-specific option, e.g.
> >> >>sysctl_hardlockup_all_cpu_backtrace
> >> >>>
> >> >>> + watchdog-specific si_info preferences, e.g. hardlockup_si_mask
> >> >>>
> >> >>> + panic-specific si_info: panic_print
> >> >>>
> >> >>> + universal fallback for any layer: kernel_si_info
> >> >>>
> >> >>> Now, we try to check all these variables back and forth to
> >> >>> trigger all backtraces or to avoid triggering them.
> >> >>> And it clearly does not work well and the code is more and more
> >> >>> hairy.
> >> >>>
> >> >>> I think about another approach. The word "waterfall" comes to my
> >mind.
> >> >>> Instead of checking all the settings back and forth, let's process
> >> >>> each setting one by one and just remember what has been done and
> >> >>> skip this in the next level.
> >> >>>
> >> >>> All the si_info actions seems to dump a global system state.
> >> >>> So, it would make sense to remember the state in a global variable
> >> >>> even when it might be modified by more CPUs in parallel.
> >> >>>
> >> Hmm.. new idea
> >>
> >> kernel/dump_filter.c ?
> >>
> >> What this file could do is to handle a generic lockup state machine
> >> so any subsystem can log what it already dumped?
> >>
> >> I know it may bloat, but it's better then cramming fixes in.
> >
> >I am not sure what exactly you would like to achieve but it sounds
> >a bit scary ;-)
> >
> >Anyway, we should not synchronize the watchdog reports against
> >each other, definitely. They are running in non-compatible contexts
> >(task vs interrupt vs NMI). Also we should not add any locking
> >because they usually print something when the system has enough
> >troubles.
> >
> >Also I think that it is not worth preventing duplicated backtraces
> >or reports from a single CPU. IMHO, it is not a big problem
> >in practice.
> >
> >So, we are down to large reports, like backtraces from all CPUs,
> >timers, locks, ... which are handled by sys_info(). So, I think
> >that it should be enough to handle this inside the sys_info() API.
> >
> >I do not want to say that my proposal was the best solution.
> >I am sure that there are better ones. But we need to consider
> >the gain vs. complexity.
> >
> >Honestly, I am already a bit scared by the complexity which
> >we the sys_info() API added. And it is hard to imagine that
> >adding another API would make it easier. But I might be wrong.
> >
> >Instead, it might make sense to integrate the conflicting
> >subsystem-specific calls under the sys_info() API.
> >I mean that, for example watchdog_hardlockup_check() won't
> >call trigger_allbutcpu_cpu_backtrace() directly but
> >it would call it via sys_info() API so that sys_info()
> >could keep track of it. Something like:
> >
> >void sys_info_allbutcpu_bt(int cpu)
> >{
> > trigger_allbutcpu_cpu_backtrace(cpu);
> > /*
> > * The caller likely printed backtrace of the given @cpu
> > * on its own. Prevent duplicate backtraces from all
> > * CPUs with potential next sys_info() call.
> > */
> > sys_info_done(SYS_INFO_ALL_BT);
> >}
> >
> >But I am not sure if it is really easier to follow
> >than calling sys_info_done() from the watchdog code.
> >
> >Some watchdogs try to optimize the output and print backtraces
> >only from CPUs which are relevant for the given lockup.
> >We should keep the logic for selecting the set of CPUs
> >in the watchdog code. We just need to solve how to elegantly
> >make sys_info() aware of it or at least about the more massive
> >reports.
> >
> >Anyway, I would prefer to keep it simple until we see some problems
> >in practice.
> >
> >Best Regards,
> >Petr
> >
>
>
> I understand it's scary. To make a new file in the first place.
>
> But I was a bit vague of what I wanted, and I'm sorry.
>
> So, the reason why I'd suggest a new file, is because if any subsystem
> Theoretically bypasses sys_info to log a lockup, this completely misses
> the filter and duplicates the dump
>
> My file would act as a generic lockless state machine that any
> subsystem can update regardless of how they dump logs.
>
> If you have any questions, feel absolutely free to ask! :)
>
> Discussion is a way to make everyone happy!
Honestly, I am more and more wondering whether your are a real person
or AI bot.
Best Regards,
Petr
^ permalink raw reply
* Re: [PATCH v3 4/4] panic: use sys_info_with_filter() to avoid duplicate backtraces
From: Bradley Morgan @ 2026-06-26 14:35 UTC (permalink / raw)
To: Petr Mladek
Cc: Andrew Morton, Feng Tang, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Madhavan Srinivasan, Douglas Anderson,
linux-kernel, linuxppc-dev, stable
In-Reply-To: <aj6MAxQKpLeK1Mp6@pathway.suse.cz>
On June 26, 2026 3:26:11 PM GMT+01:00, Petr Mladek <pmladek@suse.com>
wrote:
>On Fri 2026-06-26 13:32:38, Bradley Morgan wrote:
>> On June 26, 2026 1:17:13 PM GMT+01:00, Bradley Morgan
><include@grrlz.net>
>> wrote:
>> >On June 26, 2026 1:14:14 PM GMT+01:00, Petr Mladek <pmladek@suse.com>
>> >wrote:
>> >>On Fri 2026-06-26 12:23:50, Petr Mladek wrote:
>> >>> On Thu 2026-06-25 15:25:58, Bradley Morgan wrote:
>> >>> But it all becomes very hairy. We have several levels:
>> >>>
>> >>> + watchdog-all_bt-specific option, e.g.
>> >>sysctl_hardlockup_all_cpu_backtrace
>> >>>
>> >>> + watchdog-specific si_info preferences, e.g. hardlockup_si_mask
>> >>>
>> >>> + panic-specific si_info: panic_print
>> >>>
>> >>> + universal fallback for any layer: kernel_si_info
>> >>>
>> >>> Now, we try to check all these variables back and forth to
>> >>> trigger all backtraces or to avoid triggering them.
>> >>> And it clearly does not work well and the code is more and more
>> >>> hairy.
>> >>>
>> >>> I think about another approach. The word "waterfall" comes to my
>mind.
>> >>> Instead of checking all the settings back and forth, let's process
>> >>> each setting one by one and just remember what has been done and
>> >>> skip this in the next level.
>> >>>
>> >>> All the si_info actions seems to dump a global system state.
>> >>> So, it would make sense to remember the state in a global variable
>> >>> even when it might be modified by more CPUs in parallel.
>> >>>
>> Hmm.. new idea
>>
>> kernel/dump_filter.c ?
>>
>> What this file could do is to handle a generic lockup state machine
>> so any subsystem can log what it already dumped?
>>
>> I know it may bloat, but it's better then cramming fixes in.
>
>I am not sure what exactly you would like to achieve but it sounds
>a bit scary ;-)
>
>Anyway, we should not synchronize the watchdog reports against
>each other, definitely. They are running in non-compatible contexts
>(task vs interrupt vs NMI). Also we should not add any locking
>because they usually print something when the system has enough
>troubles.
>
>Also I think that it is not worth preventing duplicated backtraces
>or reports from a single CPU. IMHO, it is not a big problem
>in practice.
>
>So, we are down to large reports, like backtraces from all CPUs,
>timers, locks, ... which are handled by sys_info(). So, I think
>that it should be enough to handle this inside the sys_info() API.
>
>I do not want to say that my proposal was the best solution.
>I am sure that there are better ones. But we need to consider
>the gain vs. complexity.
>
>Honestly, I am already a bit scared by the complexity which
>we the sys_info() API added. And it is hard to imagine that
>adding another API would make it easier. But I might be wrong.
>
>Instead, it might make sense to integrate the conflicting
>subsystem-specific calls under the sys_info() API.
>I mean that, for example watchdog_hardlockup_check() won't
>call trigger_allbutcpu_cpu_backtrace() directly but
>it would call it via sys_info() API so that sys_info()
>could keep track of it. Something like:
>
>void sys_info_allbutcpu_bt(int cpu)
>{
> trigger_allbutcpu_cpu_backtrace(cpu);
> /*
> * The caller likely printed backtrace of the given @cpu
> * on its own. Prevent duplicate backtraces from all
> * CPUs with potential next sys_info() call.
> */
> sys_info_done(SYS_INFO_ALL_BT);
>}
>
>But I am not sure if it is really easier to follow
>than calling sys_info_done() from the watchdog code.
>
>Some watchdogs try to optimize the output and print backtraces
>only from CPUs which are relevant for the given lockup.
>We should keep the logic for selecting the set of CPUs
>in the watchdog code. We just need to solve how to elegantly
>make sys_info() aware of it or at least about the more massive
>reports.
>
>Anyway, I would prefer to keep it simple until we see some problems
>in practice.
>
>Best Regards,
>Petr
>
I understand it's scary. To make a new file in the first place.
But I was a bit vague of what I wanted, and I'm sorry.
So, the reason why I'd suggest a new file, is because if any subsystem
Theoretically bypasses sys_info to log a lockup, this completely misses
the filter and duplicates the dump
My file would act as a generic lockless state machine that any
subsystem can update regardless of how they dump logs.
If you have any questions, feel absolutely free to ask! :)
Discussion is a way to make everyone happy!
Thanks!
^ permalink raw reply
* Re: [PATCH] powerpc/syscall: Fix seccomp errno handling with GENERIC_ENTRY
From: Christophe Leroy (CS GROUP) @ 2026-06-26 14:31 UTC (permalink / raw)
To: Mukesh Kumar Chaurasiya (IBM), maddy, mpe, npiggin, sshegde,
mkchauras, kees, mark.rutland, ryan.roberts, linuxppc-dev,
linux-kernel
Cc: Michal Suchánek
In-Reply-To: <20260624171520.772408-1-mkchauras@gmail.com>
Le 24/06/2026 à 19:15, Mukesh Kumar Chaurasiya (IBM) a écrit :
> After enabling GENERIC_ENTRY on PowerPC, seccomp filters using
> SCMP_ACT_ERRNO without an explicit errnoRet value return ENOSYS
> (Function not implemented) instead of the expected EPERM (Operation
> not permitted).
>
> The issue occurs in system_call_exception() when syscall_enter_from_user_mode()
> returns -1 to indicate the syscall should be skipped (e.g., blocked by seccomp).
> The current code treats this -1 as a syscall number and compares it against
> NR_syscalls. Since -1 (when cast to unsigned long) is greater than NR_syscalls,
> the code incorrectly returns -ENOSYS, overwriting the errno that seccomp
> already set via syscall_set_return_value().
>
> The generic entry code in syscall_trace_enter() calls __secure_computing(),
> which sets the appropriate errno in regs->gpr[3] and returns -1 to signal
> that the syscall should be skipped. However, the PowerPC syscall handler
> was not checking for this -1 return value before validating the syscall
> number.
>
> Fix this by explicitly checking if syscall_enter_from_user_mode() returns
> -1 and returning the value already set in regs->gpr[3] (the errno from
> seccomp) before performing the syscall number validation.
>
> This aligns PowerPC's behavior with other architectures using GENERIC_ENTRY
> and restores correct seccomp errno handling.
>
> Fixes: bee25f97ad24 ("powerpc: Enable GENERIC_ENTRY feature")
> Reported-by: Michal Suchánek <msuchanek@suse.de>
Closes: https://lore.kernel.org/all/ajpp-_XnbF3UTM_E@kunlun.suse.cz/
> Signed-off-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com>
> ---
> arch/powerpc/kernel/syscall.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/arch/powerpc/kernel/syscall.c b/arch/powerpc/kernel/syscall.c
> index a9da2af6efa8..5b58c8d396c8 100644
> --- a/arch/powerpc/kernel/syscall.c
> +++ b/arch/powerpc/kernel/syscall.c
> @@ -22,6 +22,10 @@ notrace long system_call_exception(struct pt_regs *regs, unsigned long r0)
> add_random_kstack_offset();
> r0 = syscall_enter_from_user_mode(regs, r0);
>
> + /* Seccomp or ptrace may have set return value, skip syscall */
> + if (unlikely(r0 == -1L))
Is it really needed to add the L after 1 ?
> + return regs->gpr[3];
> +
> if (unlikely(r0 >= NR_syscalls)) {
> if (unlikely(trap_is_unsupported_scv(regs))) {
> /* Unsupported scv vector */
^ permalink raw reply
* Re: [PATCH] powerpc/syscall: Fix seccomp errno handling with GENERIC_ENTRY
From: Christophe Leroy (CS GROUP) @ 2026-06-26 14:30 UTC (permalink / raw)
To: Kees Cook, Mukesh Kumar Chaurasiya (IBM)
Cc: maddy, mpe, npiggin, sshegde, mkchauras, mark.rutland,
ryan.roberts, linuxppc-dev, linux-kernel, Michal Suchánek
In-Reply-To: <202606260050.681FAA94E@keescook>
Le 26/06/2026 à 09:50, Kees Cook a écrit :
> On Wed, Jun 24, 2026 at 10:45:20PM +0530, Mukesh Kumar Chaurasiya (IBM) wrote:
>> After enabling GENERIC_ENTRY on PowerPC, seccomp filters using
>> SCMP_ACT_ERRNO without an explicit errnoRet value return ENOSYS
>> (Function not implemented) instead of the expected EPERM (Operation
>> not permitted).
>
> Was this noticed by the seccomp_bpf kselftest? (If not, I'd love a
> regression test added for this case...)
>
Was reported here:
https://lore.kernel.org/all/ajpp-_XnbF3UTM_E@kunlun.suse.cz/
^ permalink raw reply
* Re: [PATCH v3 4/4] panic: use sys_info_with_filter() to avoid duplicate backtraces
From: Petr Mladek @ 2026-06-26 14:26 UTC (permalink / raw)
To: Bradley Morgan
Cc: Andrew Morton, Feng Tang, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Madhavan Srinivasan, Douglas Anderson,
linux-kernel, linuxppc-dev, stable
In-Reply-To: <4CF5AE3F-D7ED-47F8-A920-61D0AA078CF9@grrlz.net>
On Fri 2026-06-26 13:32:38, Bradley Morgan wrote:
> On June 26, 2026 1:17:13 PM GMT+01:00, Bradley Morgan <include@grrlz.net>
> wrote:
> >On June 26, 2026 1:14:14 PM GMT+01:00, Petr Mladek <pmladek@suse.com>
> >wrote:
> >>On Fri 2026-06-26 12:23:50, Petr Mladek wrote:
> >>> On Thu 2026-06-25 15:25:58, Bradley Morgan wrote:
> >>> But it all becomes very hairy. We have several levels:
> >>>
> >>> + watchdog-all_bt-specific option, e.g.
> >>sysctl_hardlockup_all_cpu_backtrace
> >>>
> >>> + watchdog-specific si_info preferences, e.g. hardlockup_si_mask
> >>>
> >>> + panic-specific si_info: panic_print
> >>>
> >>> + universal fallback for any layer: kernel_si_info
> >>>
> >>> Now, we try to check all these variables back and forth to
> >>> trigger all backtraces or to avoid triggering them.
> >>> And it clearly does not work well and the code is more and more
> >>> hairy.
> >>>
> >>> I think about another approach. The word "waterfall" comes to my mind.
> >>> Instead of checking all the settings back and forth, let's process
> >>> each setting one by one and just remember what has been done and
> >>> skip this in the next level.
> >>>
> >>> All the si_info actions seems to dump a global system state.
> >>> So, it would make sense to remember the state in a global variable
> >>> even when it might be modified by more CPUs in parallel.
> >>>
> Hmm.. new idea
>
> kernel/dump_filter.c ?
>
> What this file could do is to handle a generic lockup state machine
> so any subsystem can log what it already dumped?
>
> I know it may bloat, but it's better then cramming fixes in.
I am not sure what exactly you would like to achieve but it sounds
a bit scary ;-)
Anyway, we should not synchronize the watchdog reports against
each other, definitely. They are running in non-compatible contexts
(task vs interrupt vs NMI). Also we should not add any locking
because they usually print something when the system has enough
troubles.
Also I think that it is not worth preventing duplicated backtraces
or reports from a single CPU. IMHO, it is not a big problem
in practice.
So, we are down to large reports, like backtraces from all CPUs,
timers, locks, ... which are handled by sys_info(). So, I think
that it should be enough to handle this inside the sys_info() API.
I do not want to say that my proposal was the best solution.
I am sure that there are better ones. But we need to consider
the gain vs. complexity.
Honestly, I am already a bit scared by the complexity which
we the sys_info() API added. And it is hard to imagine that
adding another API would make it easier. But I might be wrong.
Instead, it might make sense to integrate the conflicting
subsystem-specific calls under the sys_info() API.
I mean that, for example watchdog_hardlockup_check() won't
call trigger_allbutcpu_cpu_backtrace() directly but
it would call it via sys_info() API so that sys_info()
could keep track of it. Something like:
void sys_info_allbutcpu_bt(int cpu)
{
trigger_allbutcpu_cpu_backtrace(cpu);
/*
* The caller likely printed backtrace of the given @cpu
* on its own. Prevent duplicate backtraces from all
* CPUs with potential next sys_info() call.
*/
sys_info_done(SYS_INFO_ALL_BT);
}
But I am not sure if it is really easier to follow
than calling sys_info_done() from the watchdog code.
Some watchdogs try to optimize the output and print backtraces
only from CPUs which are relevant for the given lockup.
We should keep the logic for selecting the set of CPUs
in the watchdog code. We just need to solve how to elegantly
make sys_info() aware of it or at least about the more massive
reports.
Anyway, I would prefer to keep it simple until we see some problems
in practice.
Best Regards,
Petr
^ permalink raw reply
* [PATCH v2] powerpc/powernv: Cache OPAL check_token() results
From: Shivang Upadhyay @ 2026-06-26 12:35 UTC (permalink / raw)
To: shivangu
Cc: adityag, chleroy, linux-kernel, linuxppc-dev, maddy, mahesh, mpe,
npiggin, sourabhjain, thuth
`opal_check_token()` function is used to determine if a specific
OPAL firmware call is supported on the current platform. This check
is performed frequently during boot and runtime, resulting in
unnecessary firmware calls for the same token values.
Add a caching layer for the opal_check_token() OPAL call to avoid
repeated firmware calls for token availability checks. This reduces
firmware call overhead during boot.
Testing with buildroot images shows OPAL calls reduced from
35578 to 28983, before console bring-up.
Signed-off-by: Shivang Upadhyay <shivangu@linux.ibm.com>
---
Changelog:
* v1: https://lore.kernel.org/all/20260601112520.161605-1-shivangu@linux.ibm.com/
- implemented tri-state check as suggestd by Sourabh.
- made the implementation more clear.
---
arch/powerpc/include/asm/opal.h | 1 +
arch/powerpc/platforms/powernv/opal-call.c | 2 +-
arch/powerpc/platforms/powernv/opal.c | 30 ++++++++++++++++++++++
3 files changed, 32 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 0a398265ba04..e7e11479122b 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -156,6 +156,7 @@ int64_t opal_pci_next_error(uint64_t phb_id, __be64 *first_frozen_pe,
int64_t opal_pci_poll(uint64_t id);
int64_t opal_return_cpu(void);
int64_t opal_check_token(uint64_t token);
+int64_t opal_check_token_call(uint64_t token);
int64_t opal_reinit_cpus(uint64_t flags);
int64_t opal_xscom_read(uint32_t gcid, uint64_t pcb_addr, __be64 *val);
diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c
index 021b0ec29e24..00325c189e69 100644
--- a/arch/powerpc/platforms/powernv/opal-call.c
+++ b/arch/powerpc/platforms/powernv/opal-call.c
@@ -207,7 +207,7 @@ OPAL_CALL(opal_validate_flash, OPAL_FLASH_VALIDATE);
OPAL_CALL(opal_manage_flash, OPAL_FLASH_MANAGE);
OPAL_CALL(opal_update_flash, OPAL_FLASH_UPDATE);
OPAL_CALL(opal_resync_timebase, OPAL_RESYNC_TIMEBASE);
-OPAL_CALL(opal_check_token, OPAL_CHECK_TOKEN);
+OPAL_CALL(opal_check_token_call, OPAL_CHECK_TOKEN);
OPAL_CALL(opal_dump_init, OPAL_DUMP_INIT);
OPAL_CALL(opal_dump_info, OPAL_DUMP_INFO);
OPAL_CALL(opal_dump_info2, OPAL_DUMP_INFO2);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 1946dbdc9fa1..1e9cb5271ee7 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -1125,6 +1125,36 @@ EXPORT_SYMBOL_GPL(opal_flash_read);
EXPORT_SYMBOL_GPL(opal_flash_write);
EXPORT_SYMBOL_GPL(opal_flash_erase);
EXPORT_SYMBOL_GPL(opal_prd_msg);
+
+/**
+ * opal_check_token - Check if an OPAL call token is supported
+ * @token: OPAL token number to check
+ *
+ * Returns 1 if supported, 0 if not.
+ */
+int64_t opal_check_token(uint64_t token)
+{
+ static u8 token_cache[OPAL_LAST];
+ enum {
+ SUPP_UNKNOWN = 0,
+ PRESENT,
+ ABSENT
+ };
+
+ if (token > OPAL_LAST)
+ return 0;
+
+ if (token_cache[token] == SUPP_UNKNOWN) {
+ /* Do the actual opal_call here */
+ if (opal_check_token_call(token)) {
+ token_cache[token] = PRESENT;
+ } else {
+ token_cache[token] = ABSENT;
+ }
+ }
+
+ return (token_cache[token] == PRESENT);
+}
EXPORT_SYMBOL_GPL(opal_check_token);
/* Convert a region of vmalloc memory to an opal sg list */
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v3 4/4] panic: use sys_info_with_filter() to avoid duplicate backtraces
From: Bradley Morgan @ 2026-06-26 12:32 UTC (permalink / raw)
To: Petr Mladek
Cc: Andrew Morton, Feng Tang, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Madhavan Srinivasan, Douglas Anderson,
linux-kernel, linuxppc-dev, stable
In-Reply-To: <85F6E30C-EB1B-4BAF-9204-5174FD066EE0@grrlz.net>
On June 26, 2026 1:17:13 PM GMT+01:00, Bradley Morgan <include@grrlz.net>
wrote:
>On June 26, 2026 1:14:14 PM GMT+01:00, Petr Mladek <pmladek@suse.com>
>wrote:
>>On Fri 2026-06-26 12:23:50, Petr Mladek wrote:
>>> On Thu 2026-06-25 15:25:58, Bradley Morgan wrote:
>>> > panic_other_cpus_shutdown() handles SYS_INFO_ALL_BT before stopping
>>the
>>> > other CPUs. Do not ask sys_info() to handle that bit again later in
>>the
>>> > panic path.
>>> >
>>> > Use sys_info_with_filter() so panic_print=all_bt does not request
>more
>>> > output after the CPUs are stopped.
>>> >
>>> > Fixes: a9af76a78760 ("watchdog: add sys_info sysctls to dump sys info
>>on system lockup")
>>> > Cc: stable@vger.kernel.org
>>> > Signed-off-by: Bradley Morgan <include@grrlz.net>
>>> > ---
>>> > kernel/panic.c | 2 +-
>>> > 1 file changed, 1 insertion(+), 1 deletion(-)
>>> >
>>> > diff --git a/kernel/panic.c b/kernel/panic.c
>>> > index 213725b612aa..eb842823df61 100644
>>> > --- a/kernel/panic.c
>>> > +++ b/kernel/panic.c
>>> > @@ -680,7 +680,7 @@ void vpanic(const char *fmt, va_list args)
>>> > */
>>> > atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
>>> >
>>> > - sys_info(panic_print);
>>> > + sys_info_with_filter(panic_print, SYS_INFO_ALL_BT);
>>>
>>> Hmm, this prevents printing backtraces from all CPUs completely.
>>> But what if they were not printed?
>>>
>>> They might be printed by:
>>>
>>> static void panic_other_cpus_shutdown(bool crash_kexec)
>>> {
>>> if (panic_print & SYS_INFO_ALL_BT)
>>> panic_trigger_all_cpu_backtrace();
>>>
>>> [...]
>>> }
>>>
>>> But it checks only "panic_print" variable. It won't do anything
>>> when (panic_print == 0).
>>>
>>> In this case, we might still want to print the backraces when
>>> SYS_INFO_ALL_BT is set in kernel_si_info.
>>>
>>> > kmsg_dump_desc(KMSG_DUMP_PANIC, buf);
>>>
>>> Of course, we might fix panic_other_cpus_shutdown() to check also
>>> kernel_si_info.
>>>
>>> But it all becomes very hairy. We have several levels:
>>>
>>> + watchdog-all_bt-specific option, e.g.
>>sysctl_hardlockup_all_cpu_backtrace
>>>
>>> + watchdog-specific si_info preferences, e.g. hardlockup_si_mask
>>>
>>> + panic-specific si_info: panic_print
>>>
>>> + universal fallback for any layer: kernel_si_info
>>>
>>> Now, we try to check all these variables back and forth to
>>> trigger all backtraces or to avoid triggering them.
>>> And it clearly does not work well and the code is more and more
>>> hairy.
>>>
>>> I think about another approach. The word "waterfall" comes to my mind.
>>> Instead of checking all the settings back and forth, let's process
>>> each setting one by one and just remember what has been done and
>>> skip this in the next level.
>>>
>>> All the si_info actions seems to dump a global system state.
>>> So, it would make sense to remember the state in a global variable
>>> even when it might be modified by more CPUs in parallel.
>>>
>>> I am going to think more about it.
>>
>>I have created a POC using Gemini. I haven't tested it.
>>But it looks acceptable. And the logic seems to be more
>>straightforward.
>>
>>One drawback is that it requires adding the _reset()
>>call for all sys_info() callers. It is fine in principle
>>but it might complicate back-porting because all changes
>>have to be done in one patch.
>>
>>But honestly, this is a nice to have fix. Most people could
>>live happily without it.
>>
>>From 3c66436d9978030845a96bfaedd6b914536e2ac4 Mon Sep 17 00:00:00 2001
>>From: Petr Mladek <pmladek@suse.com>
>>Date: Fri, 26 Jun 2026 13:55:41 +0200
>>Subject: [POC] sys_info: Introduce state-tracking APIs to prevent
>duplicate
>> backtraces
>>
>>In watchdog, panic, and hung task detection scenarios, sys_info() can
>>be called multiple times or alongside direct backtrace triggers like
>>trigger_allbutcpu_cpu_backtrace(). This results in identical backtraces
>>being dumped repeatedly from all CPUs, cluttering the kernel log and
>>delaying or obscuring critical debug details.
>>
>>Introduce a state tracking bitmask and associated helpers:
>>- sys_info_done(mask): Marks specific sys_info bits as already printed.
>>- sys_info_reset(): Resets the tracking state.
>>- sys_info_is_done(mask): Checks if all bits in the mask have been
>printed.
>>
>>Update sys_info() to automatically filter out already printed bits
>>using this state. Integrate these APIs with the generic hardlockup
>>and softlockup watchdogs, the PowerPC watchdog, the hung task detector,
>>and the panic core. This ensures that each piece of system information
>>and backtrace output is printed at most once per lockup/panic event,
>>and the state is reset cleanly when a lockup does not trigger a panic.
>>
>>Races between sys_info() callers are ignored. It should be acceptable
>>because the output from various watchdogs has never been synchronized.
>>And panic() never returns.
>>
>>Assisted-by: gemini-1.5-flash ?
>
>Why not use gemini 3.5 flash?
>
>I can try if you want.
>
>Could I have the prompt you used? :)
>
>>Signed-off-by: Petr Mladek <pmladek@suse.com>
>>---
>> arch/powerpc/kernel/watchdog.c | 13 ++++++++++---
>> include/linux/sys_info.h | 3 +++
>> kernel/hung_task.c | 2 ++
>> kernel/panic.c | 4 +++-
>> kernel/watchdog.c | 10 ++++++++--
>> lib/sys_info.c | 30 +++++++++++++++++++++++++++++-
>> 6 files changed, 55 insertions(+), 7 deletions(-)
>>
>>diff --git a/arch/powerpc/kernel/watchdog.c
>b/arch/powerpc/kernel/watchdog.c
>>index c40c69368476..0eab7894b9dc 100644
>>--- a/arch/powerpc/kernel/watchdog.c
>>+++ b/arch/powerpc/kernel/watchdog.c
>>@@ -239,6 +239,7 @@ static void watchdog_smp_panic(int cpu)
>> if (sysctl_hardlockup_all_cpu_backtrace ||
>> (hardlockup_si_mask & SYS_INFO_ALL_BT)) {
>> trigger_allbutcpu_cpu_backtrace(cpu);
>>+ sys_info_done(SYS_INFO_ALL_BT);
>> cpumask_clear(&wd_smp_cpus_ipi);
>> } else {
>> /*
>>@@ -251,10 +252,12 @@ static void watchdog_smp_panic(int cpu)
>> }
>> }
>>
>>- sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT);
>>+ sys_info(hardlockup_si_mask);
>> if (hardlockup_panic)
>> nmi_panic(NULL, "Hard LOCKUP");
>>
>>+ sys_info_reset();
>>+
>> wd_end_reporting();
>>
>> return;
>>@@ -419,13 +422,17 @@ DEFINE_INTERRUPT_HANDLER_NMI(soft_nmi_interrupt)
>> xchg(&__wd_nmi_output, 1); // see wd_lockup_ipi
>>
>> if (sysctl_hardlockup_all_cpu_backtrace ||
>>- (hardlockup_si_mask & SYS_INFO_ALL_BT))
>>+ (hardlockup_si_mask & SYS_INFO_ALL_BT)) {
>> trigger_allbutcpu_cpu_backtrace(cpu);
>>+ sys_info_done(SYS_INFO_ALL_BT);
>>+ }
>>
>>- sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT);
>>+ sys_info(hardlockup_si_mask);
>> if (hardlockup_panic)
>> nmi_panic(regs, "Hard LOCKUP");
>>
>>+ sys_info_reset();
>>+
>> wd_end_reporting();
>> }
>> /*
>>diff --git a/include/linux/sys_info.h b/include/linux/sys_info.h
>>index a5bc3ea3d44b..ad43548c75dd 100644
>>--- a/include/linux/sys_info.h
>>+++ b/include/linux/sys_info.h
>>@@ -18,6 +18,9 @@
>> #define SYS_INFO_BLOCKED_TASKS 0x00000080
>>
>> void sys_info(unsigned long si_mask);
>>+void sys_info_done(unsigned long si_mask);
>>+void sys_info_reset(void);
>>+bool sys_info_is_done(unsigned long si_mask);
>> unsigned long sys_info_parse_param(char *str);
>>
>> #ifdef CONFIG_SYSCTL
>>diff --git a/kernel/hung_task.c b/kernel/hung_task.c
>>index 6fcc94ce4ca9..dbb6a27770f5 100644
>>--- a/kernel/hung_task.c
>>+++ b/kernel/hung_task.c
>>@@ -354,6 +354,8 @@ static void check_hung_uninterruptible_tasks(unsigned
>long timeout)
>>
>> if (hung_task_call_panic)
>> panic("hung_task: blocked tasks");
>>+
>>+ sys_info_reset();
>> }
>>
>> static long hung_timeout_jiffies(unsigned long last_checked,
>>diff --git a/kernel/panic.c b/kernel/panic.c
>>index 213725b612aa..86ce17f03da2 100644
>>--- a/kernel/panic.c
>>+++ b/kernel/panic.c
>>@@ -550,8 +550,10 @@ static void panic_trigger_all_cpu_backtrace(void)
>> */
>> static void panic_other_cpus_shutdown(bool crash_kexec)
>> {
>>- if (panic_print & SYS_INFO_ALL_BT)
>>+ if ((panic_print & SYS_INFO_ALL_BT) && !sys_info_is_done(SYS_INFO_ALL_BT)) {
>> panic_trigger_all_cpu_backtrace();
>>+ sys_info_done(SYS_INFO_ALL_BT);
>>+ }
>>
>> /*
>> * Note that smp_send_stop() is the usual SMP shutdown function,
>>diff --git a/kernel/watchdog.c b/kernel/watchdog.c
>>index 87dd5e0f6968..f431087c68a7 100644
>>--- a/kernel/watchdog.c
>>+++ b/kernel/watchdog.c
>>@@ -282,14 +282,17 @@ void watchdog_hardlockup_check(unsigned int cpu,
>struct pt_regs *regs)
>>
>> if (hardlockup_all_cpu_backtrace) {
>> trigger_allbutcpu_cpu_backtrace(cpu);
>>+ sys_info_done(SYS_INFO_ALL_BT);
>> if (!hardlockup_panic)
>> clear_bit_unlock(0, &hard_lockup_nmi_warn);
>> }
>>
>>- sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT);
>>+ sys_info(hardlockup_si_mask);
>> if (hardlockup_panic)
>> nmi_panic(regs, "Hard LOCKUP");
>>
>>+ sys_info_reset();
>>+
>> per_cpu(watchdog_hardlockup_warned, cpu) = true;
>> }
>>
>>@@ -895,16 +898,19 @@ static enum hrtimer_restart
>watchdog_timer_fn(struct hrtimer *hrtimer)
>>
>> if (softlockup_all_cpu_backtrace) {
>> trigger_allbutcpu_cpu_backtrace(smp_processor_id());
>>+ sys_info_done(SYS_INFO_ALL_BT);
>> if (!softlockup_panic)
>> clear_bit_unlock(0, &soft_lockup_nmi_warn);
>> }
>>
>> add_taint(TAINT_SOFTLOCKUP, LOCKDEP_STILL_OK);
>>- sys_info(softlockup_si_mask & ~SYS_INFO_ALL_BT);
>>+ sys_info(softlockup_si_mask);
>> thresh_count = duration / get_softlockup_thresh();
>>
>> if (softlockup_panic && thresh_count >= softlockup_panic)
>> panic("softlockup: hung tasks");
>>+
>>+ sys_info_reset();
>> }
>>
>> return HRTIMER_RESTART;
>>diff --git a/lib/sys_info.c b/lib/sys_info.c
>>index f32a06ec9ed4..f8e6176fae75 100644
>>--- a/lib/sys_info.c
>>+++ b/lib/sys_info.c
>>@@ -160,7 +160,35 @@ static void __sys_info(unsigned long si_mask)
>> show_state_filter(TASK_UNINTERRUPTIBLE);
>> }
>>
>>+static unsigned long sys_info_done_mask;
>>+
>>+void sys_info_done(unsigned long si_mask)
>>+{
>>+ sys_info_done_mask |= si_mask;
>>+}
>>+
>>+void sys_info_reset(void)
>>+{
>>+ sys_info_done_mask = 0;
>>+}
>>+
>>+bool sys_info_is_done(unsigned long si_mask)
>>+{
>>+ return (sys_info_done_mask & si_mask) == si_mask;
>>+}
>>+
>> void sys_info(unsigned long si_mask)
>> {
>>- __sys_info(si_mask ? : kernel_si_mask);
>>+ unsigned long mask;
>>+
>>+ if (si_mask)
>>+ mask = si_mask & ~sys_info_done_mask;
>>+ else
>>+ mask = kernel_si_mask & ~sys_info_done_mask;
>>+
>>+ if (!mask)
>>+ return;
>>+
>>+ __sys_info(mask);
>>+ sys_info_done(mask);
>> }
>>
>
>Thanks!
Hmm.. new idea
kernel/dump_filter.c ?
What this file could do is to handle a generic lockup state machine
so any subsystem can log what it already dumped?
I know it may bloat, but it's better then cramming fixes in.
What do you guys think? Maybe we could start a RFC for this?
Thanks!
^ permalink raw reply
* Re: [PATCH v3 4/4] panic: use sys_info_with_filter() to avoid duplicate backtraces
From: Bradley Morgan @ 2026-06-26 12:17 UTC (permalink / raw)
To: Petr Mladek
Cc: Andrew Morton, Feng Tang, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Madhavan Srinivasan, Douglas Anderson,
linux-kernel, linuxppc-dev, stable
In-Reply-To: <aj5tFiwhRqPkAkqU@pathway.suse.cz>
On June 26, 2026 1:14:14 PM GMT+01:00, Petr Mladek <pmladek@suse.com>
wrote:
>On Fri 2026-06-26 12:23:50, Petr Mladek wrote:
>> On Thu 2026-06-25 15:25:58, Bradley Morgan wrote:
>> > panic_other_cpus_shutdown() handles SYS_INFO_ALL_BT before stopping
>the
>> > other CPUs. Do not ask sys_info() to handle that bit again later in
>the
>> > panic path.
>> >
>> > Use sys_info_with_filter() so panic_print=all_bt does not request more
>> > output after the CPUs are stopped.
>> >
>> > Fixes: a9af76a78760 ("watchdog: add sys_info sysctls to dump sys info
>on system lockup")
>> > Cc: stable@vger.kernel.org
>> > Signed-off-by: Bradley Morgan <include@grrlz.net>
>> > ---
>> > kernel/panic.c | 2 +-
>> > 1 file changed, 1 insertion(+), 1 deletion(-)
>> >
>> > diff --git a/kernel/panic.c b/kernel/panic.c
>> > index 213725b612aa..eb842823df61 100644
>> > --- a/kernel/panic.c
>> > +++ b/kernel/panic.c
>> > @@ -680,7 +680,7 @@ void vpanic(const char *fmt, va_list args)
>> > */
>> > atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
>> >
>> > - sys_info(panic_print);
>> > + sys_info_with_filter(panic_print, SYS_INFO_ALL_BT);
>>
>> Hmm, this prevents printing backtraces from all CPUs completely.
>> But what if they were not printed?
>>
>> They might be printed by:
>>
>> static void panic_other_cpus_shutdown(bool crash_kexec)
>> {
>> if (panic_print & SYS_INFO_ALL_BT)
>> panic_trigger_all_cpu_backtrace();
>>
>> [...]
>> }
>>
>> But it checks only "panic_print" variable. It won't do anything
>> when (panic_print == 0).
>>
>> In this case, we might still want to print the backraces when
>> SYS_INFO_ALL_BT is set in kernel_si_info.
>>
>> > kmsg_dump_desc(KMSG_DUMP_PANIC, buf);
>>
>> Of course, we might fix panic_other_cpus_shutdown() to check also
>> kernel_si_info.
>>
>> But it all becomes very hairy. We have several levels:
>>
>> + watchdog-all_bt-specific option, e.g.
>sysctl_hardlockup_all_cpu_backtrace
>>
>> + watchdog-specific si_info preferences, e.g. hardlockup_si_mask
>>
>> + panic-specific si_info: panic_print
>>
>> + universal fallback for any layer: kernel_si_info
>>
>> Now, we try to check all these variables back and forth to
>> trigger all backtraces or to avoid triggering them.
>> And it clearly does not work well and the code is more and more
>> hairy.
>>
>> I think about another approach. The word "waterfall" comes to my mind.
>> Instead of checking all the settings back and forth, let's process
>> each setting one by one and just remember what has been done and
>> skip this in the next level.
>>
>> All the si_info actions seems to dump a global system state.
>> So, it would make sense to remember the state in a global variable
>> even when it might be modified by more CPUs in parallel.
>>
>> I am going to think more about it.
>
>I have created a POC using Gemini. I haven't tested it.
>But it looks acceptable. And the logic seems to be more
>straightforward.
>
>One drawback is that it requires adding the _reset()
>call for all sys_info() callers. It is fine in principle
>but it might complicate back-porting because all changes
>have to be done in one patch.
>
>But honestly, this is a nice to have fix. Most people could
>live happily without it.
>
>From 3c66436d9978030845a96bfaedd6b914536e2ac4 Mon Sep 17 00:00:00 2001
>From: Petr Mladek <pmladek@suse.com>
>Date: Fri, 26 Jun 2026 13:55:41 +0200
>Subject: [POC] sys_info: Introduce state-tracking APIs to prevent duplicate
> backtraces
>
>In watchdog, panic, and hung task detection scenarios, sys_info() can
>be called multiple times or alongside direct backtrace triggers like
>trigger_allbutcpu_cpu_backtrace(). This results in identical backtraces
>being dumped repeatedly from all CPUs, cluttering the kernel log and
>delaying or obscuring critical debug details.
>
>Introduce a state tracking bitmask and associated helpers:
>- sys_info_done(mask): Marks specific sys_info bits as already printed.
>- sys_info_reset(): Resets the tracking state.
>- sys_info_is_done(mask): Checks if all bits in the mask have been printed.
>
>Update sys_info() to automatically filter out already printed bits
>using this state. Integrate these APIs with the generic hardlockup
>and softlockup watchdogs, the PowerPC watchdog, the hung task detector,
>and the panic core. This ensures that each piece of system information
>and backtrace output is printed at most once per lockup/panic event,
>and the state is reset cleanly when a lockup does not trigger a panic.
>
>Races between sys_info() callers are ignored. It should be acceptable
>because the output from various watchdogs has never been synchronized.
>And panic() never returns.
>
>Assisted-by: gemini-1.5-flash ?
Why not use gemini 3.5 flash?
I can try if you want.
Could I have the prompt you used? :)
>Signed-off-by: Petr Mladek <pmladek@suse.com>
>---
> arch/powerpc/kernel/watchdog.c | 13 ++++++++++---
> include/linux/sys_info.h | 3 +++
> kernel/hung_task.c | 2 ++
> kernel/panic.c | 4 +++-
> kernel/watchdog.c | 10 ++++++++--
> lib/sys_info.c | 30 +++++++++++++++++++++++++++++-
> 6 files changed, 55 insertions(+), 7 deletions(-)
>
>diff --git a/arch/powerpc/kernel/watchdog.c b/arch/powerpc/kernel/watchdog.c
>index c40c69368476..0eab7894b9dc 100644
>--- a/arch/powerpc/kernel/watchdog.c
>+++ b/arch/powerpc/kernel/watchdog.c
>@@ -239,6 +239,7 @@ static void watchdog_smp_panic(int cpu)
> if (sysctl_hardlockup_all_cpu_backtrace ||
> (hardlockup_si_mask & SYS_INFO_ALL_BT)) {
> trigger_allbutcpu_cpu_backtrace(cpu);
>+ sys_info_done(SYS_INFO_ALL_BT);
> cpumask_clear(&wd_smp_cpus_ipi);
> } else {
> /*
>@@ -251,10 +252,12 @@ static void watchdog_smp_panic(int cpu)
> }
> }
>
>- sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT);
>+ sys_info(hardlockup_si_mask);
> if (hardlockup_panic)
> nmi_panic(NULL, "Hard LOCKUP");
>
>+ sys_info_reset();
>+
> wd_end_reporting();
>
> return;
>@@ -419,13 +422,17 @@ DEFINE_INTERRUPT_HANDLER_NMI(soft_nmi_interrupt)
> xchg(&__wd_nmi_output, 1); // see wd_lockup_ipi
>
> if (sysctl_hardlockup_all_cpu_backtrace ||
>- (hardlockup_si_mask & SYS_INFO_ALL_BT))
>+ (hardlockup_si_mask & SYS_INFO_ALL_BT)) {
> trigger_allbutcpu_cpu_backtrace(cpu);
>+ sys_info_done(SYS_INFO_ALL_BT);
>+ }
>
>- sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT);
>+ sys_info(hardlockup_si_mask);
> if (hardlockup_panic)
> nmi_panic(regs, "Hard LOCKUP");
>
>+ sys_info_reset();
>+
> wd_end_reporting();
> }
> /*
>diff --git a/include/linux/sys_info.h b/include/linux/sys_info.h
>index a5bc3ea3d44b..ad43548c75dd 100644
>--- a/include/linux/sys_info.h
>+++ b/include/linux/sys_info.h
>@@ -18,6 +18,9 @@
> #define SYS_INFO_BLOCKED_TASKS 0x00000080
>
> void sys_info(unsigned long si_mask);
>+void sys_info_done(unsigned long si_mask);
>+void sys_info_reset(void);
>+bool sys_info_is_done(unsigned long si_mask);
> unsigned long sys_info_parse_param(char *str);
>
> #ifdef CONFIG_SYSCTL
>diff --git a/kernel/hung_task.c b/kernel/hung_task.c
>index 6fcc94ce4ca9..dbb6a27770f5 100644
>--- a/kernel/hung_task.c
>+++ b/kernel/hung_task.c
>@@ -354,6 +354,8 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
>
> if (hung_task_call_panic)
> panic("hung_task: blocked tasks");
>+
>+ sys_info_reset();
> }
>
> static long hung_timeout_jiffies(unsigned long last_checked,
>diff --git a/kernel/panic.c b/kernel/panic.c
>index 213725b612aa..86ce17f03da2 100644
>--- a/kernel/panic.c
>+++ b/kernel/panic.c
>@@ -550,8 +550,10 @@ static void panic_trigger_all_cpu_backtrace(void)
> */
> static void panic_other_cpus_shutdown(bool crash_kexec)
> {
>- if (panic_print & SYS_INFO_ALL_BT)
>+ if ((panic_print & SYS_INFO_ALL_BT) && !sys_info_is_done(SYS_INFO_ALL_BT)) {
> panic_trigger_all_cpu_backtrace();
>+ sys_info_done(SYS_INFO_ALL_BT);
>+ }
>
> /*
> * Note that smp_send_stop() is the usual SMP shutdown function,
>diff --git a/kernel/watchdog.c b/kernel/watchdog.c
>index 87dd5e0f6968..f431087c68a7 100644
>--- a/kernel/watchdog.c
>+++ b/kernel/watchdog.c
>@@ -282,14 +282,17 @@ void watchdog_hardlockup_check(unsigned int cpu, struct pt_regs *regs)
>
> if (hardlockup_all_cpu_backtrace) {
> trigger_allbutcpu_cpu_backtrace(cpu);
>+ sys_info_done(SYS_INFO_ALL_BT);
> if (!hardlockup_panic)
> clear_bit_unlock(0, &hard_lockup_nmi_warn);
> }
>
>- sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT);
>+ sys_info(hardlockup_si_mask);
> if (hardlockup_panic)
> nmi_panic(regs, "Hard LOCKUP");
>
>+ sys_info_reset();
>+
> per_cpu(watchdog_hardlockup_warned, cpu) = true;
> }
>
>@@ -895,16 +898,19 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
>
> if (softlockup_all_cpu_backtrace) {
> trigger_allbutcpu_cpu_backtrace(smp_processor_id());
>+ sys_info_done(SYS_INFO_ALL_BT);
> if (!softlockup_panic)
> clear_bit_unlock(0, &soft_lockup_nmi_warn);
> }
>
> add_taint(TAINT_SOFTLOCKUP, LOCKDEP_STILL_OK);
>- sys_info(softlockup_si_mask & ~SYS_INFO_ALL_BT);
>+ sys_info(softlockup_si_mask);
> thresh_count = duration / get_softlockup_thresh();
>
> if (softlockup_panic && thresh_count >= softlockup_panic)
> panic("softlockup: hung tasks");
>+
>+ sys_info_reset();
> }
>
> return HRTIMER_RESTART;
>diff --git a/lib/sys_info.c b/lib/sys_info.c
>index f32a06ec9ed4..f8e6176fae75 100644
>--- a/lib/sys_info.c
>+++ b/lib/sys_info.c
>@@ -160,7 +160,35 @@ static void __sys_info(unsigned long si_mask)
> show_state_filter(TASK_UNINTERRUPTIBLE);
> }
>
>+static unsigned long sys_info_done_mask;
>+
>+void sys_info_done(unsigned long si_mask)
>+{
>+ sys_info_done_mask |= si_mask;
>+}
>+
>+void sys_info_reset(void)
>+{
>+ sys_info_done_mask = 0;
>+}
>+
>+bool sys_info_is_done(unsigned long si_mask)
>+{
>+ return (sys_info_done_mask & si_mask) == si_mask;
>+}
>+
> void sys_info(unsigned long si_mask)
> {
>- __sys_info(si_mask ? : kernel_si_mask);
>+ unsigned long mask;
>+
>+ if (si_mask)
>+ mask = si_mask & ~sys_info_done_mask;
>+ else
>+ mask = kernel_si_mask & ~sys_info_done_mask;
>+
>+ if (!mask)
>+ return;
>+
>+ __sys_info(mask);
>+ sys_info_done(mask);
> }
>
Thanks!
^ permalink raw reply
* Re: [PATCH v3 4/4] panic: use sys_info_with_filter() to avoid duplicate backtraces
From: Petr Mladek @ 2026-06-26 12:14 UTC (permalink / raw)
To: Bradley Morgan
Cc: Andrew Morton, Feng Tang, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Madhavan Srinivasan, Douglas Anderson,
linux-kernel, linuxppc-dev, stable
In-Reply-To: <aj5TNB8cRtMNTtIT@pathway.suse.cz>
On Fri 2026-06-26 12:23:50, Petr Mladek wrote:
> On Thu 2026-06-25 15:25:58, Bradley Morgan wrote:
> > panic_other_cpus_shutdown() handles SYS_INFO_ALL_BT before stopping the
> > other CPUs. Do not ask sys_info() to handle that bit again later in the
> > panic path.
> >
> > Use sys_info_with_filter() so panic_print=all_bt does not request more
> > output after the CPUs are stopped.
> >
> > Fixes: a9af76a78760 ("watchdog: add sys_info sysctls to dump sys info on system lockup")
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Bradley Morgan <include@grrlz.net>
> > ---
> > kernel/panic.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/kernel/panic.c b/kernel/panic.c
> > index 213725b612aa..eb842823df61 100644
> > --- a/kernel/panic.c
> > +++ b/kernel/panic.c
> > @@ -680,7 +680,7 @@ void vpanic(const char *fmt, va_list args)
> > */
> > atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
> >
> > - sys_info(panic_print);
> > + sys_info_with_filter(panic_print, SYS_INFO_ALL_BT);
>
> Hmm, this prevents printing backtraces from all CPUs completely.
> But what if they were not printed?
>
> They might be printed by:
>
> static void panic_other_cpus_shutdown(bool crash_kexec)
> {
> if (panic_print & SYS_INFO_ALL_BT)
> panic_trigger_all_cpu_backtrace();
>
> [...]
> }
>
> But it checks only "panic_print" variable. It won't do anything
> when (panic_print == 0).
>
> In this case, we might still want to print the backraces when
> SYS_INFO_ALL_BT is set in kernel_si_info.
>
> > kmsg_dump_desc(KMSG_DUMP_PANIC, buf);
>
> Of course, we might fix panic_other_cpus_shutdown() to check also
> kernel_si_info.
>
> But it all becomes very hairy. We have several levels:
>
> + watchdog-all_bt-specific option, e.g. sysctl_hardlockup_all_cpu_backtrace
>
> + watchdog-specific si_info preferences, e.g. hardlockup_si_mask
>
> + panic-specific si_info: panic_print
>
> + universal fallback for any layer: kernel_si_info
>
> Now, we try to check all these variables back and forth to
> trigger all backtraces or to avoid triggering them.
> And it clearly does not work well and the code is more and more
> hairy.
>
> I think about another approach. The word "waterfall" comes to my mind.
> Instead of checking all the settings back and forth, let's process
> each setting one by one and just remember what has been done and
> skip this in the next level.
>
> All the si_info actions seems to dump a global system state.
> So, it would make sense to remember the state in a global variable
> even when it might be modified by more CPUs in parallel.
>
> I am going to think more about it.
I have created a POC using Gemini. I haven't tested it.
But it looks acceptable. And the logic seems to be more
straightforward.
One drawback is that it requires adding the _reset()
call for all sys_info() callers. It is fine in principle
but it might complicate back-porting because all changes
have to be done in one patch.
But honestly, this is a nice to have fix. Most people could
live happily without it.
From 3c66436d9978030845a96bfaedd6b914536e2ac4 Mon Sep 17 00:00:00 2001
From: Petr Mladek <pmladek@suse.com>
Date: Fri, 26 Jun 2026 13:55:41 +0200
Subject: [POC] sys_info: Introduce state-tracking APIs to prevent duplicate
backtraces
In watchdog, panic, and hung task detection scenarios, sys_info() can
be called multiple times or alongside direct backtrace triggers like
trigger_allbutcpu_cpu_backtrace(). This results in identical backtraces
being dumped repeatedly from all CPUs, cluttering the kernel log and
delaying or obscuring critical debug details.
Introduce a state tracking bitmask and associated helpers:
- sys_info_done(mask): Marks specific sys_info bits as already printed.
- sys_info_reset(): Resets the tracking state.
- sys_info_is_done(mask): Checks if all bits in the mask have been printed.
Update sys_info() to automatically filter out already printed bits
using this state. Integrate these APIs with the generic hardlockup
and softlockup watchdogs, the PowerPC watchdog, the hung task detector,
and the panic core. This ensures that each piece of system information
and backtrace output is printed at most once per lockup/panic event,
and the state is reset cleanly when a lockup does not trigger a panic.
Races between sys_info() callers are ignored. It should be acceptable
because the output from various watchdogs has never been synchronized.
And panic() never returns.
Assisted-by: gemini-1.5-flash
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
arch/powerpc/kernel/watchdog.c | 13 ++++++++++---
include/linux/sys_info.h | 3 +++
kernel/hung_task.c | 2 ++
kernel/panic.c | 4 +++-
kernel/watchdog.c | 10 ++++++++--
lib/sys_info.c | 30 +++++++++++++++++++++++++++++-
6 files changed, 55 insertions(+), 7 deletions(-)
diff --git a/arch/powerpc/kernel/watchdog.c b/arch/powerpc/kernel/watchdog.c
index c40c69368476..0eab7894b9dc 100644
--- a/arch/powerpc/kernel/watchdog.c
+++ b/arch/powerpc/kernel/watchdog.c
@@ -239,6 +239,7 @@ static void watchdog_smp_panic(int cpu)
if (sysctl_hardlockup_all_cpu_backtrace ||
(hardlockup_si_mask & SYS_INFO_ALL_BT)) {
trigger_allbutcpu_cpu_backtrace(cpu);
+ sys_info_done(SYS_INFO_ALL_BT);
cpumask_clear(&wd_smp_cpus_ipi);
} else {
/*
@@ -251,10 +252,12 @@ static void watchdog_smp_panic(int cpu)
}
}
- sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT);
+ sys_info(hardlockup_si_mask);
if (hardlockup_panic)
nmi_panic(NULL, "Hard LOCKUP");
+ sys_info_reset();
+
wd_end_reporting();
return;
@@ -419,13 +422,17 @@ DEFINE_INTERRUPT_HANDLER_NMI(soft_nmi_interrupt)
xchg(&__wd_nmi_output, 1); // see wd_lockup_ipi
if (sysctl_hardlockup_all_cpu_backtrace ||
- (hardlockup_si_mask & SYS_INFO_ALL_BT))
+ (hardlockup_si_mask & SYS_INFO_ALL_BT)) {
trigger_allbutcpu_cpu_backtrace(cpu);
+ sys_info_done(SYS_INFO_ALL_BT);
+ }
- sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT);
+ sys_info(hardlockup_si_mask);
if (hardlockup_panic)
nmi_panic(regs, "Hard LOCKUP");
+ sys_info_reset();
+
wd_end_reporting();
}
/*
diff --git a/include/linux/sys_info.h b/include/linux/sys_info.h
index a5bc3ea3d44b..ad43548c75dd 100644
--- a/include/linux/sys_info.h
+++ b/include/linux/sys_info.h
@@ -18,6 +18,9 @@
#define SYS_INFO_BLOCKED_TASKS 0x00000080
void sys_info(unsigned long si_mask);
+void sys_info_done(unsigned long si_mask);
+void sys_info_reset(void);
+bool sys_info_is_done(unsigned long si_mask);
unsigned long sys_info_parse_param(char *str);
#ifdef CONFIG_SYSCTL
diff --git a/kernel/hung_task.c b/kernel/hung_task.c
index 6fcc94ce4ca9..dbb6a27770f5 100644
--- a/kernel/hung_task.c
+++ b/kernel/hung_task.c
@@ -354,6 +354,8 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
if (hung_task_call_panic)
panic("hung_task: blocked tasks");
+
+ sys_info_reset();
}
static long hung_timeout_jiffies(unsigned long last_checked,
diff --git a/kernel/panic.c b/kernel/panic.c
index 213725b612aa..86ce17f03da2 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -550,8 +550,10 @@ static void panic_trigger_all_cpu_backtrace(void)
*/
static void panic_other_cpus_shutdown(bool crash_kexec)
{
- if (panic_print & SYS_INFO_ALL_BT)
+ if ((panic_print & SYS_INFO_ALL_BT) && !sys_info_is_done(SYS_INFO_ALL_BT)) {
panic_trigger_all_cpu_backtrace();
+ sys_info_done(SYS_INFO_ALL_BT);
+ }
/*
* Note that smp_send_stop() is the usual SMP shutdown function,
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 87dd5e0f6968..f431087c68a7 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -282,14 +282,17 @@ void watchdog_hardlockup_check(unsigned int cpu, struct pt_regs *regs)
if (hardlockup_all_cpu_backtrace) {
trigger_allbutcpu_cpu_backtrace(cpu);
+ sys_info_done(SYS_INFO_ALL_BT);
if (!hardlockup_panic)
clear_bit_unlock(0, &hard_lockup_nmi_warn);
}
- sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT);
+ sys_info(hardlockup_si_mask);
if (hardlockup_panic)
nmi_panic(regs, "Hard LOCKUP");
+ sys_info_reset();
+
per_cpu(watchdog_hardlockup_warned, cpu) = true;
}
@@ -895,16 +898,19 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
if (softlockup_all_cpu_backtrace) {
trigger_allbutcpu_cpu_backtrace(smp_processor_id());
+ sys_info_done(SYS_INFO_ALL_BT);
if (!softlockup_panic)
clear_bit_unlock(0, &soft_lockup_nmi_warn);
}
add_taint(TAINT_SOFTLOCKUP, LOCKDEP_STILL_OK);
- sys_info(softlockup_si_mask & ~SYS_INFO_ALL_BT);
+ sys_info(softlockup_si_mask);
thresh_count = duration / get_softlockup_thresh();
if (softlockup_panic && thresh_count >= softlockup_panic)
panic("softlockup: hung tasks");
+
+ sys_info_reset();
}
return HRTIMER_RESTART;
diff --git a/lib/sys_info.c b/lib/sys_info.c
index f32a06ec9ed4..f8e6176fae75 100644
--- a/lib/sys_info.c
+++ b/lib/sys_info.c
@@ -160,7 +160,35 @@ static void __sys_info(unsigned long si_mask)
show_state_filter(TASK_UNINTERRUPTIBLE);
}
+static unsigned long sys_info_done_mask;
+
+void sys_info_done(unsigned long si_mask)
+{
+ sys_info_done_mask |= si_mask;
+}
+
+void sys_info_reset(void)
+{
+ sys_info_done_mask = 0;
+}
+
+bool sys_info_is_done(unsigned long si_mask)
+{
+ return (sys_info_done_mask & si_mask) == si_mask;
+}
+
void sys_info(unsigned long si_mask)
{
- __sys_info(si_mask ? : kernel_si_mask);
+ unsigned long mask;
+
+ if (si_mask)
+ mask = si_mask & ~sys_info_done_mask;
+ else
+ mask = kernel_si_mask & ~sys_info_done_mask;
+
+ if (!mask)
+ return;
+
+ __sys_info(mask);
+ sys_info_done(mask);
}
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v3 4/4] panic: use sys_info_with_filter() to avoid duplicate backtraces
From: Feng Tang @ 2026-06-26 12:06 UTC (permalink / raw)
To: Petr Mladek
Cc: Bradley Morgan, Andrew Morton, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Madhavan Srinivasan, Douglas Anderson,
linux-kernel, linuxppc-dev, stable
In-Reply-To: <aj5TNB8cRtMNTtIT@pathway.suse.cz>
On Fri, Jun 26, 2026 at 12:23:48PM +0200, Petr Mladek wrote:
> On Thu 2026-06-25 15:25:58, Bradley Morgan wrote:
> > panic_other_cpus_shutdown() handles SYS_INFO_ALL_BT before stopping the
> > other CPUs. Do not ask sys_info() to handle that bit again later in the
> > panic path.
> >
> > Use sys_info_with_filter() so panic_print=all_bt does not request more
> > output after the CPUs are stopped.
> >
> > Fixes: a9af76a78760 ("watchdog: add sys_info sysctls to dump sys info on system lockup")
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Bradley Morgan <include@grrlz.net>
> > ---
> > kernel/panic.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/kernel/panic.c b/kernel/panic.c
> > index 213725b612aa..eb842823df61 100644
> > --- a/kernel/panic.c
> > +++ b/kernel/panic.c
> > @@ -680,7 +680,7 @@ void vpanic(const char *fmt, va_list args)
> > */
> > atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
> >
> > - sys_info(panic_print);
> > + sys_info_with_filter(panic_print, SYS_INFO_ALL_BT);
>
> Hmm, this prevents printing backtraces from all CPUs completely.
> But what if they were not printed?
>
> They might be printed by:
>
> static void panic_other_cpus_shutdown(bool crash_kexec)
> {
> if (panic_print & SYS_INFO_ALL_BT)
> panic_trigger_all_cpu_backtrace();
>
> [...]
> }
>
> But it checks only "panic_print" variable. It won't do anything
> when (panic_print == 0).
>
> In this case, we might still want to print the backraces when
> SYS_INFO_ALL_BT is set in kernel_si_info.
Yep.
>
> > kmsg_dump_desc(KMSG_DUMP_PANIC, buf);
>
> Of course, we might fix panic_other_cpus_shutdown() to check also
> kernel_si_info.
>
> But it all becomes very hairy. We have several levels:
>
> + watchdog-all_bt-specific option, e.g. sysctl_hardlockup_all_cpu_backtrace
>
> + watchdog-specific si_info preferences, e.g. hardlockup_si_mask
>
> + panic-specific si_info: panic_print
>
> + universal fallback for any layer: kernel_si_info
>
> Now, we try to check all these variables back and forth to
> trigger all backtraces or to avoid triggering them.
> And it clearly does not work well and the code is more and more
> hairy.
Agree :)
> I think about another approach. The word "waterfall" comes to my mind.
> Instead of checking all the settings back and forth, let's process
> each setting one by one and just remember what has been done and
> skip this in the next level.
When initially reviewing V2's 4th patch, I thought about the
'panic_this_cpu_backtrace_printed', but it's a local variable which
records the state.
> All the si_info actions seems to dump a global system state.
> So, it would make sense to remember the state in a global variable
> even when it might be modified by more CPUs in parallel.
IIUC, panic case is kind of special, as it has to separate the
'sys_info()' op in different stage. Can we do a merge in the start
of vpanic() by:
panic_print = panic_print ?: kernel_si_mask;
as a addon patch ?
Thanks,
Feng
> I am going to think more about it.
>
> Please, do not send v4 until the discussion settles!
>
> Best Regards,
> Petr
^ permalink raw reply
* [PATCH] powerpc/pseries: Simplify attribute description check in papr_init()
From: Thorsten Blum @ 2026-06-26 11:07 UTC (permalink / raw)
To: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP), Kees Cook
Cc: Thorsten Blum, linuxppc-dev, linux-kernel
Check only the first byte instead of scanning the entire string with
strnlen().
Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
---
arch/powerpc/platforms/pseries/papr_platform_attributes.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/papr_platform_attributes.c b/arch/powerpc/platforms/pseries/papr_platform_attributes.c
index c6159870de0e..ff8adda02341 100644
--- a/arch/powerpc/platforms/pseries/papr_platform_attributes.c
+++ b/arch/powerpc/platforms/pseries/papr_platform_attributes.c
@@ -325,12 +325,8 @@ static int __init papr_init(void)
}
for (idx = 0; idx < num_attrs; idx++) {
- bool show_val_desc = true;
-
/* Do not add the value desc attr if it does not exist */
- if (strnlen(esi_attrs[idx].value_desc,
- sizeof(esi_attrs[idx].value_desc)) == 0)
- show_val_desc = false;
+ bool show_val_desc = *esi_attrs[idx].value_desc != '\0';
if (add_attr_group(be64_to_cpu(esi_attrs[idx].id),
&papr_groups[idx],
^ permalink raw reply related
* [PATCH 1/1] KVM: powerpc/book3s_hv: Use generic xfer to guest work function
From: Vishal Chourasia @ 2026-06-26 10:53 UTC (permalink / raw)
To: maddy
Cc: npiggin, mpe, chleroy, gautam, bigeasy, linuxppc-dev, kvm,
linux-kernel, Vishal Chourasia
In-Reply-To: <20260626105449.2897924-2-vishalc@linux.ibm.com>
Use the generic infrastructure to check for and handle pending work
before transitioning into guest mode, replacing the open-coded
need_resched() and cond_resched() checks.
This picks up handling for TIF_NOTIFY_RESUME, which was previously
ignored, meaning task work will now be correctly handled on every
guest re-entry.
Signed-off-by: Vishal Chourasia <vishalc@linux.ibm.com>
---
arch/powerpc/kvm/Kconfig | 1 +
arch/powerpc/kvm/book3s_hv.c | 58 +++++++++++++++++++++++++++++++-----
2 files changed, 52 insertions(+), 7 deletions(-)
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index 9a0d1c1aca6c..36aec58c5f22 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -81,6 +81,7 @@ config KVM_BOOK3S_64_HV
depends on KVM_BOOK3S_64 && PPC_POWERNV
select KVM_BOOK3S_HV_POSSIBLE
select KVM_BOOK3S_HV_PMU
+ select VIRT_XFER_TO_GUEST_WORK
select CMA
help
Support running unmodified book3s_64 guest kernels in
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 61dbeea317f3..b012512342e6 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -3850,10 +3850,20 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
* and return without going into the guest(s).
* If the mmu_ready flag has been cleared, don't go into the
* guest because that means a HPT resize operation is in progress.
+ *
+ * xfer_to_guest_mode_work_pending() is the IRQs-disabled recheck for
+ * pending guest-mode work (reschedule, signals, and TIF_NOTIFY_RESUME
+ * task_work such as the deferred CFS throttle). It is the pre-POWER9
+ * analog of the final gate in kvmhv_run_single_vcpu(), and a superset
+ * of the old need_resched() check: it catches work that raced in after
+ * the drain in kvmppc_run_vcpu(), so a CPU-bound vCPU is throttled here
+ * instead of running one more guest dispatch past its quota. IRQs are
+ * hard-disabled just above, so the non-__ variant (which asserts that)
+ * is the correct one.
*/
local_irq_disable();
hard_irq_disable();
- if (lazy_irq_pending() || need_resched() ||
+ if (lazy_irq_pending() || xfer_to_guest_mode_work_pending() ||
recheck_signals_and_mmu(&core_info)) {
local_irq_enable();
vc->vcore_state = VCORE_INACTIVE;
@@ -4824,10 +4834,24 @@ static int kvmppc_run_vcpu(struct kvm_vcpu *vcpu)
vc->runner = vcpu;
if (n_ceded == vc->n_runnable) {
kvmppc_vcore_blocked(vc);
- } else if (need_resched()) {
+ } else if (__xfer_to_guest_mode_work_pending()) {
kvmppc_vcore_preempt(vc);
- /* Let something else run */
- cond_resched_lock(&vc->lock);
+ /*
+ * Let something else run, and run pending guest-mode
+ * work (reschedule, and TIF_NOTIFY_RESUME task_work such
+ * as the deferred CFS throttle) before we would re-enter
+ * the guest, so a CPU-bound vCPU is actually throttled
+ * here instead of running past its quota. This is a
+ * superset of the old need_resched() check. Use the raw
+ * helper, not the kvm_ wrapper: signals (KVM_EXIT_INTR
+ * and the signal_exits stat) are accounted by this path's
+ * existing handling below, so going through the wrapper
+ * here would double-count them. The helper may schedule(),
+ * so the vcore lock is dropped around it.
+ */
+ spin_unlock(&vc->lock);
+ xfer_to_guest_mode_handle_work();
+ spin_lock(&vc->lock);
if (vc->vcore_state == VCORE_PREEMPT)
kvmppc_vcore_end_preempt(vc);
} else {
@@ -4899,8 +4923,21 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
}
}
- if (need_resched())
- cond_resched();
+ /*
+ * Run pending work before (re-)entering the guest, most importantly
+ * task_work queued via TWA_RESUME (e.g. the deferred CFS bandwidth
+ * throttle, which only sets TIF_NOTIFY_RESUME). Without this a CPU-bound
+ * vCPU that keeps returning RESUME_GUEST never reaches an exit-to-user
+ * point, so the throttle is never enforced and the task runs far beyond
+ * its quota. The helper also handles reschedule and signals, replacing
+ * the cond_resched() that was here. It may schedule(), so it runs before
+ * preemption and IRQs are disabled, with no vcore/KVM locks held. This
+ * is the per-reentry site shared by the bare-metal and pseries (nested)
+ * paths, so both are covered.
+ */
+ r = kvm_xfer_to_guest_mode_handle_work(vcpu);
+ if (r) /* -EINTR: signal pending, exit to userspace (KVM_EXIT_INTR) */
+ return r;
kvmppc_update_vpas(vcpu);
@@ -4916,7 +4953,14 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
if (signal_pending(current))
goto sigpend;
- if (need_resched() || !kvm->arch.mmu_ready)
+ /*
+ * Re-check for pending guest-mode work with IRQs disabled, to catch
+ * anything (e.g. a TIF_NOTIFY_RESUME task_work such as the deferred CFS
+ * throttle) that raced in after the check above. Bail back to the outer
+ * loop, which re-enters here and runs the work. This is a superset of
+ * the previous need_resched() check.
+ */
+ if (xfer_to_guest_mode_work_pending() || !kvm->arch.mmu_ready)
goto out;
vcpu->cpu = pcpu;
--
2.54.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox