drivers/net/netconsole.c | 109 +++++++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 41 deletions(-)
This series adds support for the nbcon (new buffer console) infrastructure
to netconsole, enabling lock-free, priority-based console operations that
are safer in crash scenarios.
The implementation is introduced in three steps:
1) Refactor the message fragmentation logic into a reusable helper function
2) Extend nbcon support to non-extended (basic) consoles using the same
infrastructure.
The initial discussion about it appeared a while ago in [1], in order to
solve Mike's HARDIRQ-safe -> HARDIRQ-unsafe lock order warning, and the root
cause is that some hosts were calling IRQ unsafe locks from inside console
lock.
At that time, we didn't have the CON_NBCON_ATOMIC_UNSAFE yet. John
kindly implemented CON_NBCON_ATOMIC_UNSAFE in 187de7c212e5 ("printk:
nbcon: Allow unsafe write_atomic() for panic"), and now we can
implement netconsole on top of nbcon.
Important to note that netconsole continues to call netpoll and the
network TX helpers with interrupt disable, given the TX are called with
target_list_lock.
Link:
https://lore.kernel.org/all/b2qps3uywhmjaym4mht2wpxul4yqtuuayeoq4iv4k3zf5wdgh3@tocu6c7mj4lt/
[1]
Signed-off-by: Breno Leitao <leitao@debian.org>
Changes from RFC:
* Removed the extra CONFIG for NBCON, given we don't want to support
both console. Move to nbcon as the only console framework supported
* Incorporated the changes from Petr.
* Some renames to make the code more consistent.
* Link: https://lore.kernel.org/all/20251121-nbcon-v1-0-503d17b2b4af@debian.org/
---
Breno Leitao (2):
netconsole: extract message fragmentation into send_msg_udp()
netconsole: convert to NBCON console infrastructure
drivers/net/netconsole.c | 109 +++++++++++++++++++++++++++++------------------
1 file changed, 68 insertions(+), 41 deletions(-)
---
base-commit: 7b8e9264f55a9c320f398e337d215e68cca50131
change-id: 20251117-nbcon-f24477ca9f3e
Best regards,
--
Breno Leitao <leitao@debian.org>
Hello Petr, John and Marcos, On Mon, Dec 22, 2025 at 06:52:09AM -0800, Breno Leitao wrote: > This series adds support for the nbcon (new buffer console) infrastructure > to netconsole, enabling lock-free, priority-based console operations that > are safer in crash scenarios. I've been reflecting further on this port and encountered a potential roadblock that I'd like to discuss to ensure I'm heading in the right direction. Netconsole appends additional data (sysdata) to messages, specifically the CPU and task_struct->comm fields. Basically, it appends current->comm and raw_smp_processor_id() when sending a message. (For more details, see sysdata_append_cpu_nr() and sysdata_append_taskname()) With nbcon, since netconsole will operate on a separate thread, this sysdata may become inaccurate (the data would reflect the printk thread rather than the original task or CPU that generated the message). Upon reviewing the printk subsystem, I noticed that struct printk_info->caller_id stores similar information, but not exactly the same. It contains either the CPU *or* the task, not both, and this data isn't easily accessible from within the ->write_thread() context. One possible solution that comes to my mind is to pass both the CPU ID and the task_struct/vpid to struct printk_info, and then integrate this into struct nbcon_write_context *wctxt somehow. This way, netconsole could reliably query the original CPU and task that generated the message, regardless of where the netconsole code is executed. How crazy is this approach?
Hi Breno,
On 2026-01-07, Breno Leitao <leitao@debian.org> wrote:
> On Mon, Dec 22, 2025 at 06:52:09AM -0800, Breno Leitao wrote:
>> This series adds support for the nbcon (new buffer console) infrastructure
>> to netconsole, enabling lock-free, priority-based console operations that
>> are safer in crash scenarios.
>
> I've been reflecting further on this port and encountered a potential
> roadblock that I'd like to discuss to ensure I'm heading in the right
> direction.
>
> Netconsole appends additional data (sysdata) to messages, specifically
> the CPU and task_struct->comm fields.
>
> Basically, it appends current->comm and raw_smp_processor_id()
> when sending a message.
> (For more details, see sysdata_append_cpu_nr() and
> sysdata_append_taskname())
I was not aware of this netconsole feature until now.
> With nbcon, since netconsole will operate on a separate thread, this
> sysdata may become inaccurate (the data would reflect the printk thread
> rather than the original task or CPU that generated the message).
Note that even with legacy consoles there was never a guarantee that the
printing context is the same CPU/task as the printk() caller. It was
just much more likely.
> Upon reviewing the printk subsystem, I noticed that struct
> printk_info->caller_id stores similar information, but not exactly the
> same. It contains either the CPU *or* the task, not both, and this data
> isn't easily accessible from within the ->write_thread() context.
>
> One possible solution that comes to my mind is to pass both the CPU ID
> and the task_struct/vpid to struct printk_info, and then integrate this
> into struct nbcon_write_context *wctxt somehow.
>
> This way, netconsole could reliably query the original CPU and task that
> generated the message, regardless of where the netconsole code is
> executed.
But by the time the printer is active, that task may no longer exist,
may have migrated to a different CPU and/or may be sleeping.
IIUC, basically you want to attach console-specific additional
information to ringbuffer records, but only that specific console should
see/use the additional information. In this case it could be up to 4+16
additional bytes (depending on @sysdata_fields).
A while ago we had a discussion[0] about adding custom
information. There I even went so far as to suggest supporting things
like a new boot argument:
printk.format=ts,cpu,comm,pid,in_atomic
(which could also be console-specific)
The result of the discussion was killing off dictionaries (that allowed
variable length custom data) and replacing them with the dev_printk_info
struct.
I am just pointing out that this kind of discussion has existed in the
past and not suggesting that we should reintroduce dictionaries.
A simple fix could be to add an extra 36-byte struct to both
dev_printk_info and nbcon_write_context that exists conditionally on
CONFIG_NETCONSOLE_DYNAMIC.
vprintk_store() would set the extra data to dev_printk_info.
nbcon_emit_next_record() would copy the data to nbcon_write_context.
John Ogness
[0] https://lore.kernel.org/lkml/20200904082438.20707-1-changki.kim@samsung.com
Hi John,
On Wed, Jan 07, 2026 at 04:56:41PM +0106, John Ogness wrote:
> On 2026-01-07, Breno Leitao <leitao@debian.org> wrote:
> > Upon reviewing the printk subsystem, I noticed that struct
> > printk_info->caller_id stores similar information, but not exactly the
> > same. It contains either the CPU *or* the task, not both, and this data
> > isn't easily accessible from within the ->write_thread() context.
> >
> > One possible solution that comes to my mind is to pass both the CPU ID
> > and the task_struct/vpid to struct printk_info, and then integrate this
> > into struct nbcon_write_context *wctxt somehow.
> >
> > This way, netconsole could reliably query the original CPU and task that
> > generated the message, regardless of where the netconsole code is
> > executed.
>
> But by the time the printer is active, that task may no longer exist,
> may have migrated to a different CPU and/or may be sleeping.
>
> IIUC, basically you want to attach console-specific additional
> information to ringbuffer records, but only that specific console should
> see/use the additional information. In this case it could be up to 4+16
> additional bytes (depending on @sysdata_fields).
>
> A while ago we had a discussion[0] about adding custom
Thanks for sharing that discussion link—very helpful context!
> information. There I even went so far as to suggest supporting things
> like a new boot argument:
>
> printk.format=ts,cpu,comm,pid,in_atomic
>
> (which could also be console-specific)
This is essentially what we ended up implementing in netconsole.
Netconsole makes this straightforward and efficient since I don't need to worry
about ring buffer space. The approach is simple: receive the char *msg, copy it
to a bounce buffer, append raw_smp_processor_id(), current->comm, etc., send
the packet, and free the buffer. No impact on the ring buffer or other side
effects.
> The result of the discussion was killing off dictionaries (that allowed
> variable length custom data) and replacing them with the dev_printk_info
> struct.
>
> I am just pointing out that this kind of discussion has existed in the
> past and not suggesting that we should reintroduce dictionaries.
>
> A simple fix could be to add an extra 36-byte struct to both
> dev_printk_info and nbcon_write_context that exists conditionally on
> CONFIG_NETCONSOLE_DYNAMIC.
I believe we can achieve this with less than 36 bytes per entry. Taking
inspiration from printk_caller_id(), we could store both the PID and
smp_processor_id() more compactly, 8 bytes total ?!
Something like the following should address netconsole's needs:
diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h
index eb2094e43050..908cb891af0d 100644
--- a/include/linux/dev_printk.h
+++ b/include/linux/dev_printk.h
@@ -27,6 +27,10 @@ struct device;
struct dev_printk_info {
char subsystem[PRINTK_INFO_SUBSYSTEM_LEN];
char device[PRINTK_INFO_DEVICE_LEN];
+#ifdef CONFIG_DEV_PRINTK_ENRICHED_CTX /* Something that I can select when CONFIG_NETCONSOLE_DYNAMIC is selected */
+ pid_t pid;
+ int cpu;
+#endif
};
> vprintk_store() would set the extra data to dev_printk_info.
>
> nbcon_emit_next_record() would copy the data to nbcon_write_context.
Thanks. Let me prototype this and see how it turns out.
--breno
On Wed, Jan 07, 2026 at 08:58:39AM -0800, Breno Leitao wrote:
> On Wed, Jan 07, 2026 at 04:56:41PM +0106, John Ogness wrote:
>
> Thanks. Let me prototype this and see how it turns out.
This is what I am thinking about. How bad is it?
(I've also implemented the netconsole part as well, so, if you want to
have a tree, you can find it in
https://github.com/leitao/linux/tree/execution_context)
commit fe79961da6cabe42343185cf1a7308162bf6bad3
Author: Breno Leitao <leitao@debian.org>
Date: Thu Jan 8 03:00:46 2026 -0800
printk: Add execution context (PID/CPU) to dev_printk_info
Extend struct dev_printk_info to include the task PID and CPU number
where printk messages originate. This information is captured at
vprintk_store() time and propagated through printk_message to
nbcon_write_context, making it available to nbcon console drivers.
This is useful for consoles like netconsole that want to include
execution context in their output, allowing correlation of messages
with specific tasks and CPUs regardless of where the console driver
actually runs.
The feature is controlled by CONFIG_PRINTK_EXECUTION_CTX, which is
automatically selected by CONFIG_NETCONSOLE_DYNAMIC. When disabled,
the helper functions compile to no-ops with no overhead.
Suggested-by: John Ogness <john.ogness@linutronix.de>
Signed-off-by: Breno Leitao <leitao@debian.org>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index ac12eaf11755..e6a9369be202 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -341,6 +341,7 @@ config NETCONSOLE_DYNAMIC
bool "Dynamic reconfiguration of logging targets"
depends on NETCONSOLE && SYSFS && CONFIGFS_FS && \
!(NETCONSOLE=y && CONFIGFS_FS=m)
+ select PRINTK_EXECUTION_CTX
help
This option enables the ability to dynamically reconfigure target
parameters (interface, IP addresses, port numbers, MAC addresses)
diff --git a/include/linux/console.h b/include/linux/console.h
index fc9f5c5c1b04..c724f59f96e6 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -298,12 +298,18 @@ struct nbcon_context {
* @outbuf: Pointer to the text buffer for output
* @len: Length to write
* @unsafe_takeover: If a hostile takeover in an unsafe state has occurred
+ * @pid: PID of the task that generated the message
+ * @cpu: CPU on which the message was generated
*/
struct nbcon_write_context {
struct nbcon_context __private ctxt;
char *outbuf;
unsigned int len;
bool unsafe_takeover;
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+ pid_t pid;
+ int cpu;
+#endif
};
/**
diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h
index eb2094e43050..42ee778b29dd 100644
--- a/include/linux/dev_printk.h
+++ b/include/linux/dev_printk.h
@@ -27,6 +27,10 @@ struct device;
struct dev_printk_info {
char subsystem[PRINTK_INFO_SUBSYSTEM_LEN];
char device[PRINTK_INFO_DEVICE_LEN];
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+ pid_t pid;
+ int cpu;
+#endif
};
#ifdef CONFIG_PRINTK
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 5f5f626f4279..81e5cd336677 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -287,6 +287,10 @@ struct printk_message {
unsigned int outbuf_len;
u64 seq;
unsigned long dropped;
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+ pid_t pid;
+ int cpu;
+#endif
};
bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 3fa403f9831f..2465fafd7727 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -946,6 +946,18 @@ void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt)
}
EXPORT_SYMBOL_GPL(nbcon_reacquire_nobuf);
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+static inline void wctxt_load_execution_ctx(struct nbcon_write_context *wctxt,
+ struct printk_message *pmsg)
+{
+ wctxt->pid = pmsg->pid;
+ wctxt->cpu = pmsg->cpu;
+}
+#else
+static inline void wctxt_load_execution_ctx(struct nbcon_write_context *wctxt,
+ struct printk_message *pmsg) {}
+#endif
+
/**
* nbcon_emit_next_record - Emit a record in the acquired context
* @wctxt: The write context that will be handed to the write function
@@ -1048,6 +1060,8 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_a
/* Initialize the write context for driver callbacks. */
nbcon_write_context_set_buf(wctxt, &pmsg.pbufs->outbuf[0], pmsg.outbuf_len);
+ wctxt_load_execution_ctx(wctxt, &pmsg);
+
if (use_atomic)
con->write_atomic(con, wctxt);
else
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 1d765ad242b8..ff47b5384f20 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2213,6 +2213,26 @@ static u16 printk_sprint(char *text, u16 size, int facility,
return text_len;
}
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+static inline void printk_save_execution_ctx(struct dev_printk_info *dev_info)
+{
+ dev_info->pid = task_pid_nr(current);
+ dev_info->cpu = smp_processor_id();
+}
+
+static inline void pmsg_load_execution_ctx(struct printk_message *pmsg,
+ const struct dev_printk_info *dev_info)
+{
+ pmsg->pid = dev_info->pid;
+ pmsg->cpu = dev_info->cpu;
+}
+#else
+static inline void printk_save_execution_ctx(struct dev_printk_info *dev_info) {}
+
+static inline void pmsg_load_execution_ctx(struct printk_message *pmsg,
+ const struct dev_printk_info *dev_info) {}
+#endif
+
__printf(4, 0)
int vprintk_store(int facility, int level,
const struct dev_printk_info *dev_info,
@@ -2320,6 +2340,7 @@ int vprintk_store(int facility, int level,
r.info->caller_id = caller_id;
if (dev_info)
memcpy(&r.info->dev_info, dev_info, sizeof(r.info->dev_info));
+ printk_save_execution_ctx(&r.info->dev_info);
/* A message without a trailing newline can be continued. */
if (!(flags & LOG_NEWLINE))
@@ -3002,6 +3023,7 @@ bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
pmsg->seq = r.info->seq;
pmsg->dropped = r.info->seq - seq;
force_con = r.info->flags & LOG_FORCE_CON;
+ pmsg_load_execution_ctx(pmsg, &r.info->dev_info);
/*
* Skip records that are not forced to be printed on consoles and that
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index ba36939fda79..197022099dd8 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -35,6 +35,17 @@ config PRINTK_CALLER
no option to enable/disable at the kernel command line parameter or
sysfs interface.
+config PRINTK_EXECUTION_CTX
+ bool
+ depends on PRINTK
+ help
+ This option extends struct dev_printk_info to include extra execution
+ context in pritnk, such as task PID and CPU number from where the
+ message originated. This is useful for correlating device messages
+ with specific execution contexts.
+
+ One of the main user for this config is netconsole.
+
config STACKTRACE_BUILD_ID
bool "Show build ID information in stacktraces"
depends on PRINTK
On 2026-01-08, Breno Leitao <leitao@debian.org> wrote:
> On Wed, Jan 07, 2026 at 08:58:39AM -0800, Breno Leitao wrote:
> This is what I am thinking about. How bad is it?
>
> (I've also implemented the netconsole part as well, so, if you want to
> have a tree, you can find it in
> https://github.com/leitao/linux/tree/execution_context)
Thanks. It is very helpful to see how you intend to use it.
> commit fe79961da6cabe42343185cf1a7308162bf6bad3
> Author: Breno Leitao <leitao@debian.org>
> Date: Thu Jan 8 03:00:46 2026 -0800
>
> printk: Add execution context (PID/CPU) to dev_printk_info
>
> Extend struct dev_printk_info to include the task PID and CPU number
> where printk messages originate. This information is captured at
> vprintk_store() time and propagated through printk_message to
> nbcon_write_context, making it available to nbcon console drivers.
>
> This is useful for consoles like netconsole that want to include
> execution context in their output, allowing correlation of messages
> with specific tasks and CPUs regardless of where the console driver
> actually runs.
>
> The feature is controlled by CONFIG_PRINTK_EXECUTION_CTX, which is
> automatically selected by CONFIG_NETCONSOLE_DYNAMIC. When disabled,
> the helper functions compile to no-ops with no overhead.
>
> Suggested-by: John Ogness <john.ogness@linutronix.de>
> Signed-off-by: Breno Leitao <leitao@debian.org>
>
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index ac12eaf11755..e6a9369be202 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -341,6 +341,7 @@ config NETCONSOLE_DYNAMIC
> bool "Dynamic reconfiguration of logging targets"
> depends on NETCONSOLE && SYSFS && CONFIGFS_FS && \
> !(NETCONSOLE=y && CONFIGFS_FS=m)
> + select PRINTK_EXECUTION_CTX
> help
> This option enables the ability to dynamically reconfigure target
> parameters (interface, IP addresses, port numbers, MAC addresses)
> diff --git a/include/linux/console.h b/include/linux/console.h
> index fc9f5c5c1b04..c724f59f96e6 100644
> --- a/include/linux/console.h
> +++ b/include/linux/console.h
> @@ -298,12 +298,18 @@ struct nbcon_context {
> * @outbuf: Pointer to the text buffer for output
> * @len: Length to write
> * @unsafe_takeover: If a hostile takeover in an unsafe state has occurred
> + * @pid: PID of the task that generated the message
> + * @cpu: CPU on which the message was generated
> */
> struct nbcon_write_context {
> struct nbcon_context __private ctxt;
> char *outbuf;
> unsigned int len;
> bool unsafe_takeover;
> +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> + pid_t pid;
> + int cpu;
> +#endif
Something like msg_pid/msg_cpu or printk_pid/printk_cpu might be better
to make it clear we are not talking about _this_ context. This struct is
used by code outside of the printk subsystem, which is why I think it
needs to be more obvious what these represent.
@Petr: Any suggestions for names (assuming this is even acceptable)?
> };
>
> /**
> diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h
> index eb2094e43050..42ee778b29dd 100644
> --- a/include/linux/dev_printk.h
> +++ b/include/linux/dev_printk.h
> @@ -27,6 +27,10 @@ struct device;
> struct dev_printk_info {
> char subsystem[PRINTK_INFO_SUBSYSTEM_LEN];
> char device[PRINTK_INFO_DEVICE_LEN];
> +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> + pid_t pid;
I am not happy about this being resolved by the netconsole printer to
get the task name. A lot can happen between now and then. But I also
shudder at the thought of making dev_printk_info much larger. This is
already a horrible waste of memory (which I talked about here[0]).
I also do not think dev_printk_info is the appropriate place to store
this information. These new fields are not related to the dev_printk
API. They belong in printk_info.
> + int cpu;
> +#endif
> };
>
> #ifdef CONFIG_PRINTK
> diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
> index 5f5f626f4279..81e5cd336677 100644
> --- a/kernel/printk/internal.h
> +++ b/kernel/printk/internal.h
> @@ -287,6 +287,10 @@ struct printk_message {
> unsigned int outbuf_len;
> u64 seq;
> unsigned long dropped;
> +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> + pid_t pid;
> + int cpu;
> +#endif
> };
>
> bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
> diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
> index 3fa403f9831f..2465fafd7727 100644
> --- a/kernel/printk/nbcon.c
> +++ b/kernel/printk/nbcon.c
> @@ -946,6 +946,18 @@ void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt)
> }
> EXPORT_SYMBOL_GPL(nbcon_reacquire_nobuf);
>
> +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> +static inline void wctxt_load_execution_ctx(struct nbcon_write_context *wctxt,
> + struct printk_message *pmsg)
> +{
> + wctxt->pid = pmsg->pid;
> + wctxt->cpu = pmsg->cpu;
> +}
> +#else
> +static inline void wctxt_load_execution_ctx(struct nbcon_write_context *wctxt,
> + struct printk_message *pmsg) {}
> +#endif
> +
> /**
> * nbcon_emit_next_record - Emit a record in the acquired context
> * @wctxt: The write context that will be handed to the write function
> @@ -1048,6 +1060,8 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_a
> /* Initialize the write context for driver callbacks. */
> nbcon_write_context_set_buf(wctxt, &pmsg.pbufs->outbuf[0], pmsg.outbuf_len);
>
> + wctxt_load_execution_ctx(wctxt, &pmsg);
> +
> if (use_atomic)
> con->write_atomic(con, wctxt);
> else
> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index 1d765ad242b8..ff47b5384f20 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -2213,6 +2213,26 @@ static u16 printk_sprint(char *text, u16 size, int facility,
> return text_len;
> }
>
> +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> +static inline void printk_save_execution_ctx(struct dev_printk_info *dev_info)
> +{
> + dev_info->pid = task_pid_nr(current);
> + dev_info->cpu = smp_processor_id();
> +}
> +
> +static inline void pmsg_load_execution_ctx(struct printk_message *pmsg,
> + const struct dev_printk_info *dev_info)
> +{
> + pmsg->pid = dev_info->pid;
> + pmsg->cpu = dev_info->cpu;
> +}
> +#else
> +static inline void printk_save_execution_ctx(struct dev_printk_info *dev_info) {}
> +
> +static inline void pmsg_load_execution_ctx(struct printk_message *pmsg,
> + const struct dev_printk_info *dev_info) {}
> +#endif
> +
> __printf(4, 0)
> int vprintk_store(int facility, int level,
> const struct dev_printk_info *dev_info,
> @@ -2320,6 +2340,7 @@ int vprintk_store(int facility, int level,
> r.info->caller_id = caller_id;
> if (dev_info)
> memcpy(&r.info->dev_info, dev_info, sizeof(r.info->dev_info));
> + printk_save_execution_ctx(&r.info->dev_info);
>
> /* A message without a trailing newline can be continued. */
> if (!(flags & LOG_NEWLINE))
> @@ -3002,6 +3023,7 @@ bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
> pmsg->seq = r.info->seq;
> pmsg->dropped = r.info->seq - seq;
> force_con = r.info->flags & LOG_FORCE_CON;
> + pmsg_load_execution_ctx(pmsg, &r.info->dev_info);
>
> /*
> * Skip records that are not forced to be printed on consoles and that
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index ba36939fda79..197022099dd8 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -35,6 +35,17 @@ config PRINTK_CALLER
> no option to enable/disable at the kernel command line parameter or
> sysfs interface.
>
> +config PRINTK_EXECUTION_CTX
> + bool
> + depends on PRINTK
> + help
> + This option extends struct dev_printk_info to include extra execution
It should extend printk_info instead.
> + context in pritnk, such as task PID and CPU number from where the
printk
> + message originated. This is useful for correlating device messages
Rather than "device messages" I suggest "printk messages".
> + with specific execution contexts.
> +
> + One of the main user for this config is netconsole.
Rather than saying which drivers might support this, it would probably
be better to make it explicit. For example introducing a new config
like:
CONFIG_CONSOLE_HAS_EXECUTION_CTX
that can only be selected by the console driver (or in your case, the
console driver option NETCONSOLE_DYNAMIC). Then make
PRINTK_EXECUTION_CTX depend only on CONSOLE_HAS_EXECUTION_CTX. That way
it is only available if the console driver supports it.
> +
> config STACKTRACE_BUILD_ID
> bool "Show build ID information in stacktraces"
> depends on PRINTK
While this patch might be "good enough" to preserve the current
CONFIG_NETCONSOLE_DYNAMIC features for NBCON, I am not happy about it:
1. It relies on the printer context being able to determine context
information about the printk() caller. I would prefer adding the task
name directly to printk_info instead.
2. It adds information to printk records that only netconsole can
use. If we want other consoles to support this, we would need to modify
all the console code. I would prefer it is dynamically added to the
generic printing text. We could do this by extending
msg_print_ext_body() based on some user configuration. But it would
conflict with the current netconsole format.
Despite my concerns, adding the PID and CPU information is generally
useful. So I am not against expanding printk_info. My concerns are more
about how this information is being used by netconsole.
@Petr: I am really curious to hear your thoughts on this.
John Ogness
[0] https://lore.kernel.org/lkml/84y10vz7ty.fsf@jogness.linutronix.de
On Thu 2026-01-08 17:56:44, John Ogness wrote:
> On 2026-01-08, Breno Leitao <leitao@debian.org> wrote:
> > On Wed, Jan 07, 2026 at 08:58:39AM -0800, Breno Leitao wrote:
> > This is what I am thinking about. How bad is it?
> >
> > (I've also implemented the netconsole part as well, so, if you want to
> > have a tree, you can find it in
> > https://github.com/leitao/linux/tree/execution_context)
>
> Thanks. It is very helpful to see how you intend to use it.
>
> > commit fe79961da6cabe42343185cf1a7308162bf6bad3
> > Author: Breno Leitao <leitao@debian.org>
> > Date: Thu Jan 8 03:00:46 2026 -0800
> >
> > printk: Add execution context (PID/CPU) to dev_printk_info
> >
> > Extend struct dev_printk_info to include the task PID and CPU number
> > where printk messages originate. This information is captured at
> > vprintk_store() time and propagated through printk_message to
> > nbcon_write_context, making it available to nbcon console drivers.
> >
> > This is useful for consoles like netconsole that want to include
> > execution context in their output, allowing correlation of messages
> > with specific tasks and CPUs regardless of where the console driver
> > actually runs.
> >
> > The feature is controlled by CONFIG_PRINTK_EXECUTION_CTX, which is
> > automatically selected by CONFIG_NETCONSOLE_DYNAMIC. When disabled,
> > the helper functions compile to no-ops with no overhead.
> >
> > Suggested-by: John Ogness <john.ogness@linutronix.de>
> > Signed-off-by: Breno Leitao <leitao@debian.org>
> >
> > diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> > index ac12eaf11755..e6a9369be202 100644
> > --- a/drivers/net/Kconfig
> > +++ b/drivers/net/Kconfig
> > @@ -341,6 +341,7 @@ config NETCONSOLE_DYNAMIC
> > bool "Dynamic reconfiguration of logging targets"
> > depends on NETCONSOLE && SYSFS && CONFIGFS_FS && \
> > !(NETCONSOLE=y && CONFIGFS_FS=m)
> > + select PRINTK_EXECUTION_CTX
> > help
> > This option enables the ability to dynamically reconfigure target
> > parameters (interface, IP addresses, port numbers, MAC addresses)
> > diff --git a/include/linux/console.h b/include/linux/console.h
> > index fc9f5c5c1b04..c724f59f96e6 100644
> > --- a/include/linux/console.h
> > +++ b/include/linux/console.h
> > @@ -298,12 +298,18 @@ struct nbcon_context {
> > * @outbuf: Pointer to the text buffer for output
> > * @len: Length to write
> > * @unsafe_takeover: If a hostile takeover in an unsafe state has occurred
> > + * @pid: PID of the task that generated the message
> > + * @cpu: CPU on which the message was generated
> > */
> > struct nbcon_write_context {
> > struct nbcon_context __private ctxt;
> > char *outbuf;
> > unsigned int len;
> > bool unsafe_takeover;
> > +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> > + pid_t pid;
> > + int cpu;
> > +#endif
>
> Something like msg_pid/msg_cpu or printk_pid/printk_cpu might be better
> to make it clear we are not talking about _this_ context. This struct is
> used by code outside of the printk subsystem, which is why I think it
> needs to be more obvious what these represent.
>
> @Petr: Any suggestions for names (assuming this is even acceptable)?
>
> > };
> >
> > /**
> > diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h
> > index eb2094e43050..42ee778b29dd 100644
> > --- a/include/linux/dev_printk.h
> > +++ b/include/linux/dev_printk.h
> > @@ -27,6 +27,10 @@ struct device;
> > struct dev_printk_info {
> > char subsystem[PRINTK_INFO_SUBSYSTEM_LEN];
> > char device[PRINTK_INFO_DEVICE_LEN];
> > +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> > + pid_t pid;
>
> I am not happy about this being resolved by the netconsole printer to
> get the task name. A lot can happen between now and then. But I also
> shudder at the thought of making dev_printk_info much larger. This is
> already a horrible waste of memory (which I talked about here[0]).
>
> I also do not think dev_printk_info is the appropriate place to store
> this information. These new fields are not related to the dev_printk
> API. They belong in printk_info.
>
> > + int cpu;
> > +#endif
> > };
> >
> > #ifdef CONFIG_PRINTK
> > diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
> > index 5f5f626f4279..81e5cd336677 100644
> > --- a/kernel/printk/internal.h
> > +++ b/kernel/printk/internal.h
> > @@ -287,6 +287,10 @@ struct printk_message {
> > unsigned int outbuf_len;
> > u64 seq;
> > unsigned long dropped;
> > +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> > + pid_t pid;
> > + int cpu;
> > +#endif
> > };
> >
> > bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
> > diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
> > index 3fa403f9831f..2465fafd7727 100644
> > --- a/kernel/printk/nbcon.c
> > +++ b/kernel/printk/nbcon.c
> > @@ -946,6 +946,18 @@ void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt)
> > }
> > EXPORT_SYMBOL_GPL(nbcon_reacquire_nobuf);
> >
> > +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> > +static inline void wctxt_load_execution_ctx(struct nbcon_write_context *wctxt,
> > + struct printk_message *pmsg)
> > +{
> > + wctxt->pid = pmsg->pid;
> > + wctxt->cpu = pmsg->cpu;
> > +}
> > +#else
> > +static inline void wctxt_load_execution_ctx(struct nbcon_write_context *wctxt,
> > + struct printk_message *pmsg) {}
> > +#endif
> > +
> > /**
> > * nbcon_emit_next_record - Emit a record in the acquired context
> > * @wctxt: The write context that will be handed to the write function
> > @@ -1048,6 +1060,8 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_a
> > /* Initialize the write context for driver callbacks. */
> > nbcon_write_context_set_buf(wctxt, &pmsg.pbufs->outbuf[0], pmsg.outbuf_len);
> >
> > + wctxt_load_execution_ctx(wctxt, &pmsg);
> > +
> > if (use_atomic)
> > con->write_atomic(con, wctxt);
> > else
> > diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> > index 1d765ad242b8..ff47b5384f20 100644
> > --- a/kernel/printk/printk.c
> > +++ b/kernel/printk/printk.c
> > @@ -2213,6 +2213,26 @@ static u16 printk_sprint(char *text, u16 size, int facility,
> > return text_len;
> > }
> >
> > +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> > +static inline void printk_save_execution_ctx(struct dev_printk_info *dev_info)
> > +{
> > + dev_info->pid = task_pid_nr(current);
> > + dev_info->cpu = smp_processor_id();
> > +}
> > +
> > +static inline void pmsg_load_execution_ctx(struct printk_message *pmsg,
> > + const struct dev_printk_info *dev_info)
> > +{
> > + pmsg->pid = dev_info->pid;
> > + pmsg->cpu = dev_info->cpu;
> > +}
> > +#else
> > +static inline void printk_save_execution_ctx(struct dev_printk_info *dev_info) {}
> > +
> > +static inline void pmsg_load_execution_ctx(struct printk_message *pmsg,
> > + const struct dev_printk_info *dev_info) {}
> > +#endif
> > +
> > __printf(4, 0)
> > int vprintk_store(int facility, int level,
> > const struct dev_printk_info *dev_info,
> > @@ -2320,6 +2340,7 @@ int vprintk_store(int facility, int level,
> > r.info->caller_id = caller_id;
> > if (dev_info)
> > memcpy(&r.info->dev_info, dev_info, sizeof(r.info->dev_info));
> > + printk_save_execution_ctx(&r.info->dev_info);
> >
> > /* A message without a trailing newline can be continued. */
> > if (!(flags & LOG_NEWLINE))
> > @@ -3002,6 +3023,7 @@ bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
> > pmsg->seq = r.info->seq;
> > pmsg->dropped = r.info->seq - seq;
> > force_con = r.info->flags & LOG_FORCE_CON;
> > + pmsg_load_execution_ctx(pmsg, &r.info->dev_info);
> >
> > /*
> > * Skip records that are not forced to be printed on consoles and that
> > diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> > index ba36939fda79..197022099dd8 100644
> > --- a/lib/Kconfig.debug
> > +++ b/lib/Kconfig.debug
> > @@ -35,6 +35,17 @@ config PRINTK_CALLER
> > no option to enable/disable at the kernel command line parameter or
> > sysfs interface.
> >
> > +config PRINTK_EXECUTION_CTX
> > + bool
> > + depends on PRINTK
> > + help
> > + This option extends struct dev_printk_info to include extra execution
>
> It should extend printk_info instead.
>
> > + context in pritnk, such as task PID and CPU number from where the
>
> printk
>
> > + message originated. This is useful for correlating device messages
>
> Rather than "device messages" I suggest "printk messages".
>
> > + with specific execution contexts.
> > +
> > + One of the main user for this config is netconsole.
>
> Rather than saying which drivers might support this, it would probably
> be better to make it explicit. For example introducing a new config
> like:
>
> CONFIG_CONSOLE_HAS_EXECUTION_CTX
>
> that can only be selected by the console driver (or in your case, the
> console driver option NETCONSOLE_DYNAMIC). Then make
> PRINTK_EXECUTION_CTX depend only on CONSOLE_HAS_EXECUTION_CTX. That way
> it is only available if the console driver supports it.
>
> > +
> > config STACKTRACE_BUILD_ID
> > bool "Show build ID information in stacktraces"
> > depends on PRINTK
>
> While this patch might be "good enough" to preserve the current
> CONFIG_NETCONSOLE_DYNAMIC features for NBCON, I am not happy about it:
>
> 1. It relies on the printer context being able to determine context
> information about the printk() caller. I would prefer adding the task
> name directly to printk_info instead.
Good question. I think that both appraches might have users.
I see the machines on the opposite sides of a spectrum.
a) Huge machines, with hunderds of CPUs and TBs of RAM, might afford
allocation of more space for kernel messages. And it might be even
useful when they run containers which are quickly comming and
going.
b) Small embeded systems want to keep kernel message buffer as small
as possible. I guess that they mostly run just few processes all
the time. So the mapping PID <-> COMM is stable.
Let's see how complicated it would be to make this configurable.
> 2. It adds information to printk records that only netconsole can
> use. If we want other consoles to support this, we would need to modify
> all the console code. I would prefer it is dynamically added to the
> generic printing text. We could do this by extending
> msg_print_ext_body() based on some user configuration. But it would
> conflict with the current netconsole format.
>
> Despite my concerns, adding the PID and CPU information is generally
> useful. So I am not against expanding printk_info. My concerns are more
> about how this information is being used by netconsole.
I agree. I see how useful is even the current print_caller() which
shows either PID or CPU number depending on the context. And it does
not make sense to store this info twice.
If we were adding this info, I would add it for all users, definitely.
We are going to touch the internal printk ringbuffer format anyway.
Now, the main question is how far we want to go.
I see the following possibilities:
A) caller_id -> pid + cpu + atomic/task context bit
===================================================
Replace the current .caller_id and always save both PID and CPU
number. Something like:
diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h
index 4ef81349d9fb..3c7635ada6dd 100644
--- a/kernel/printk/printk_ringbuffer.h
+++ b/kernel/printk/printk_ringbuffer.h
@@ -9,6 +9,12 @@
#include <linux/stddef.h>
#include <linux/types.h>
+
+struct printk_caller {
+ pid_t pid; /* caller pid */
+ int cpu; /* caller CPU number */
+};
+
/*
* Meta information about each stored message.
*
@@ -22,8 +29,8 @@ struct printk_info {
u8 facility; /* syslog facility */
u8 flags:5; /* internal record flags */
u8 level:3; /* syslog level */
- u32 caller_id; /* thread id or processor id */
+ struct printk_caller caller;
struct dev_printk_info dev_info;
};
Plus the task/interrupt bit might be stored either as the highest bit
in .pid or by adding LOG_CALLER_IN_TASK bit into "enum printk_info_flags".
A) caller_id -> pid + cpu + contex
==================================
Same as above but the caller context info is stored separately and
might allow to distinguish more types. Something like:
diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h
index 4ef81349d9fb..44aa60a3f84c 100644
--- a/kernel/printk/printk_ringbuffer.h
+++ b/kernel/printk/printk_ringbuffer.h
@@ -9,6 +9,19 @@
#include <linux/stddef.h>
#include <linux/types.h>
+#define PRINTK_CALLER_CTXT_PREEMPT_BIT 1
+#define PRINTK_CALLER_CTXT_SOFTIRQ_BIT 2
+#define PRINTK_CALLER_CTXT_HARDIRQ_BIT 3
+#define PRINTK_CALLER_CTXT_NMI 4
+/* This is not supported on all platforms, see irqs_disabled() */
+#define PRINTK_CALLER_CTXT_IRQS_DISABLED 5
+
+struct printk_caller {
+ u8 ctxt; /* caller context: task, irq, ... */
+ pid_t pid; /* caller pid */
+ int cpu; /* caller CPU number */
+};
+
/*
* Meta information about each stored message.
*
@@ -22,8 +35,8 @@ struct printk_info {
u8 facility; /* syslog facility */
u8 flags:5; /* internal record flags */
u8 level:3; /* syslog level */
- u32 caller_id; /* thread id or processor id */
+ struct printk_caller caller;
struct dev_printk_info dev_info;
};
C) caller_id -> pid + cpu + comm + atomic/task context bit
==========================================================
Similar to A and B but add also
char comm[TASK_COMM_LEN];
into struct printk_caller.
D) caller_id -> pid + cpu + comm + atomic/task context bit
and move printk_caller + printk_dev_info into text buffer
as suggested as mentioned at
https://lore.kernel.org/lkml/84y10vz7ty.fsf@jogness.linutronix.de
====================================================================
There are many possibilities how to do it. And it involves two
problems:
a) how to store the data into data buffer
b) how to integrate this in the ring buffer API
I thought about several approaches and realized that it still
would make sense to keep:
+ binary data (pid, cpu, ctxt) in desc ring
+ text data (comm, subsystem, device) in text_data buffer
Something like:
diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h
index 4ef81349d9fb..41232bf2919d 100644
--- a/kernel/printk/printk_ringbuffer.h
+++ b/kernel/printk/printk_ringbuffer.h
@@ -9,6 +9,27 @@
#include <linux/stddef.h>
#include <linux/types.h>
+#define PRINTK_CALLER_CTXT_PREEMPT_BIT 0
+#define PRINTK_CALLER_CTXT_SOFTIRQ_BIT 1
+#define PRINTK_CALLER_CTXT_HARDIRQ_BIT 2
+#define PRINTK_CALLER_CTXT_NMI 3
+/* This is not supported on all platforms, see irqs_disabled() */
+#define PRINTK_CALLER_CTXT_IRQS_DISABLED 4
+
+struct printk_caller {
+ u8 ctxt; /* caller context: task, irq, ... */
+ pid_t pid; /* caller pid */
+ int cpu; /* caller CPU number */
+};
+
+/*
+ * Describe which text information about the caller
+ * is stored in text_data_ring
+ */
+#define PRINTK_CALLER_BITS_COMM_BIT 0
+#define PRINTK_CALLER_BITS_SUBSYSTEM_BIT 1
+#define PRINTK_CALLER_BITS_DEVICE_BIT 2
+
/*
* Meta information about each stored message.
*
@@ -22,9 +43,8 @@ struct printk_info {
u8 facility; /* syslog facility */
u8 flags:5; /* internal record flags */
u8 level:3; /* syslog level */
- u32 caller_id; /* thread id or processor id */
-
- struct dev_printk_info dev_info;
+ u8 caller_bits_size; /* size of the caller info in data buffer */
+ u8 caller_bits; /* bits describing caller in data buffer */
};
/*
The text would be stored in the test_data_ring in the following
format:
[<comm>\0][<subsystem>\0][<device\0]<text>\0
aka, strings separated by '\0'. The information about the caller
would be optional where:
+ .caller_bits_size would contain the size of the optional
pieces, including the trailing '\0's.
+ .caller_bits number would define which particular pieces
are there. It would be even somehow extensible. The crash
tool could ignore parts which are not supported.
My opinion:
===========
I personally think that the approach B) is the best compromise for now
because:
1. We really should distinguish task/interrupt context. IMHO, it is
a very useful information provided by the caller_id now.
The approach A) stores the context a hacky way. The approach B)
is cleaner and provides even more precise info.
2. The mapping between PID and COMM might get lost if we do not store it.
But it should not be problem most of the time because we try
to flush consoles ASAP.
I would keep it simple for now. We could add it later when it
becomes a problem in practice.
BTW: I think that we could detect when the mapping is valid
by comparing task->start_time with current time...
Devil advocate: Adding comm[TASK_COMM_LEN] into struct printk_info
might be acceptable. It is "just" 16 bytes in compare
with 64 bytes for dev_printk.
3. It would be nice to optimize the memory usage and store the
optional and variable strings (comm, subsystem, device) into
data buffer. But it looks like a non-trivial work.
I would do this only when there is a real demand. And I haven't
heard about that the current approach was not acceptable yet.
Best Regards,
Petr
On 2026-01-09, Petr Mladek <pmladek@suse.com> wrote:
> If we were adding this info, I would add it for all users, definitely.
> We are going to touch the internal printk ringbuffer format anyway.
Which could mean we are going to need a round of updating crash/dump
tools. So we should choose wisely.
> Now, the main question is how far we want to go.
>
> I see the following possibilities:
>
> A) caller_id -> pid + cpu + atomic/task context bit
> ===================================================
>
> Replace the current .caller_id and always save both PID and CPU
> number. Something like:
>
> diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h
> index 4ef81349d9fb..3c7635ada6dd 100644
> --- a/kernel/printk/printk_ringbuffer.h
> +++ b/kernel/printk/printk_ringbuffer.h
> @@ -9,6 +9,12 @@
> #include <linux/stddef.h>
> #include <linux/types.h>
>
> +
> +struct printk_caller {
> + pid_t pid; /* caller pid */
> + int cpu; /* caller CPU number */
> +};
> +
> /*
> * Meta information about each stored message.
> *
> @@ -22,8 +29,8 @@ struct printk_info {
> u8 facility; /* syslog facility */
> u8 flags:5; /* internal record flags */
> u8 level:3; /* syslog level */
> - u32 caller_id; /* thread id or processor id */
>
> + struct printk_caller caller;
> struct dev_printk_info dev_info;
> };
>
> Plus the task/interrupt bit might be stored either as the highest bit
> in .pid or by adding LOG_CALLER_IN_TASK bit into "enum printk_info_flags".
The thing I find attractive about this solution is that it could be done
such that crash/dump tools must not be changed. We could leave the
semantics for @caller_id as is and simply add @cpu:
--- a/kernel/printk/printk_ringbuffer.h
+++ b/kernel/printk/printk_ringbuffer.h
@@ -23,6 +23,7 @@ struct printk_info {
u8 flags:5; /* internal record flags */
u8 level:3; /* syslog level */
u32 caller_id; /* thread id or processor id */
+ u32 cpu; /* processor id */
struct dev_printk_info dev_info;
};
After all, if the caller is not in_task() then the new @pid would be
meaningless anyway.
If we are willing to accept printer-resolution of task names, then this
simple addition would be good enough for netconsole, while not requiring
any crash/dump tool updates. This would buy us time to think more
seriously about a significant overhaul.
> B) caller_id -> pid + cpu + contex
> ==================================
>
> Same as above but the caller context info is stored separately and
> might allow to distinguish more types. Something like:
>
> diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h
> index 4ef81349d9fb..44aa60a3f84c 100644
> --- a/kernel/printk/printk_ringbuffer.h
> +++ b/kernel/printk/printk_ringbuffer.h
> @@ -9,6 +9,19 @@
> #include <linux/stddef.h>
> #include <linux/types.h>
>
> +#define PRINTK_CALLER_CTXT_PREEMPT_BIT 1
> +#define PRINTK_CALLER_CTXT_SOFTIRQ_BIT 2
> +#define PRINTK_CALLER_CTXT_HARDIRQ_BIT 3
> +#define PRINTK_CALLER_CTXT_NMI 4
> +/* This is not supported on all platforms, see irqs_disabled() */
> +#define PRINTK_CALLER_CTXT_IRQS_DISABLED 5
> +
> +struct printk_caller {
> + u8 ctxt; /* caller context: task, irq, ... */
> + pid_t pid; /* caller pid */
> + int cpu; /* caller CPU number */
> +};
> +
> /*
> * Meta information about each stored message.
> *
> @@ -22,8 +35,8 @@ struct printk_info {
> u8 facility; /* syslog facility */
> u8 flags:5; /* internal record flags */
> u8 level:3; /* syslog level */
> - u32 caller_id; /* thread id or processor id */
>
> + struct printk_caller caller;
> struct dev_printk_info dev_info;
> };
Just as with A, here we could also preserve @caller_id semantics
(instead of introducing @pid) to avoid crash/dump tool updates.
A new @ctxt field is only useful if it can be seen. I am not sure how
you plan on showing this. By extending the prefix like caller_id does?
Would it be a new kernel config or just use CONFIG_PRINTK_CALLER? Either
way, we are talking about extending visible log data, which is something
that needs a discussion on its own.
> C) caller_id -> pid + cpu + comm + atomic/task context bit
> ==========================================================
>
> Similar to A and B but add also
>
> char comm[TASK_COMM_LEN];
>
> into struct printk_caller.
Just as with A and B, we could preserve @caller_id semantics.
This is the simplest solution since the printer would not need to
perform any resolution at all and it would be 100% accurate (when
in_task).
> D) caller_id -> pid + cpu + comm + atomic/task context bit
> and move printk_caller + printk_dev_info into text buffer
> as suggested as mentioned at
> https://lore.kernel.org/lkml/84y10vz7ty.fsf@jogness.linutronix.de
> ====================================================================
>
> There are many possibilities how to do it. And it involves two
> problems:
>
> a) how to store the data into data buffer
> b) how to integrate this in the ring buffer API
>
> I thought about several approaches and realized that it still
> would make sense to keep:
>
> + binary data (pid, cpu, ctxt) in desc ring
> + text data (comm, subsystem, device) in text_data buffer
>
> Something like:
>
> diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h
> index 4ef81349d9fb..41232bf2919d 100644
> --- a/kernel/printk/printk_ringbuffer.h
> +++ b/kernel/printk/printk_ringbuffer.h
> @@ -9,6 +9,27 @@
> #include <linux/stddef.h>
> #include <linux/types.h>
>
> +#define PRINTK_CALLER_CTXT_PREEMPT_BIT 0
> +#define PRINTK_CALLER_CTXT_SOFTIRQ_BIT 1
> +#define PRINTK_CALLER_CTXT_HARDIRQ_BIT 2
> +#define PRINTK_CALLER_CTXT_NMI 3
> +/* This is not supported on all platforms, see irqs_disabled() */
> +#define PRINTK_CALLER_CTXT_IRQS_DISABLED 4
> +
> +struct printk_caller {
> + u8 ctxt; /* caller context: task, irq, ... */
> + pid_t pid; /* caller pid */
> + int cpu; /* caller CPU number */
> +};
> +
> +/*
> + * Describe which text information about the caller
> + * is stored in text_data_ring
> + */
> +#define PRINTK_CALLER_BITS_COMM_BIT 0
> +#define PRINTK_CALLER_BITS_SUBSYSTEM_BIT 1
> +#define PRINTK_CALLER_BITS_DEVICE_BIT 2
> +
> /*
> * Meta information about each stored message.
> *
> @@ -22,9 +43,8 @@ struct printk_info {
> u8 facility; /* syslog facility */
> u8 flags:5; /* internal record flags */
> u8 level:3; /* syslog level */
> - u32 caller_id; /* thread id or processor id */
> -
> - struct dev_printk_info dev_info;
> + u8 caller_bits_size; /* size of the caller info in data buffer */
> + u8 caller_bits; /* bits describing caller in data buffer */
> };
>
> /*
>
> The text would be stored in the test_data_ring in the following
> format:
>
> [<comm>\0][<subsystem>\0][<device\0]<text>\0
I would prefer:
<text>\0[<subsystem>\0][<device>\0][<comm>\0]
Crash/dump tools that are not updated would at least continue to print
the text at the beginning of the line. Here are a few projects that I
track and how they would react (unmodified):
makedumpfile
- https://github.com/makedumpfile/makedumpfile/blob/master/printk.c#L134
- will print "\x00" between the fields
vmcore-dmesg
- https://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git/tree/util_lib/elf_info.c?h=main#n904
- will print "\x00" between the fields
crash
- https://github.com/crash-utility/crash/blob/master/printk.c#L210
- will print "." between the fields
> aka, strings separated by '\0'. The information about the caller
> would be optional where:
>
> + .caller_bits_size would contain the size of the optional
> pieces, including the trailing '\0's.
I do not know if we would need this. @text_len could include the caller
area as well.
> + .caller_bits number would define which particular pieces
> are there. It would be even somehow extensible. The crash
> tool could ignore parts which are not supported.
Yes, this works well.
> My opinion:
> ===========
>
> I personally think that the approach B) is the best compromise for now
> because:
>
> 1. We really should distinguish task/interrupt context. IMHO, it is
> a very useful information provided by the caller_id now.
>
> The approach A) stores the context a hacky way. The approach B)
> is cleaner and provides even more precise info.
>
>
> 2. The mapping between PID and COMM might get lost if we do not store it.
> But it should not be problem most of the time because we try
> to flush consoles ASAP.
>
> I would keep it simple for now. We could add it later when it
> becomes a problem in practice.
>
> BTW: I think that we could detect when the mapping is valid
> by comparing task->start_time with current time...
>
> Devil advocate: Adding comm[TASK_COMM_LEN] into struct printk_info
> might be acceptable. It is "just" 16 bytes in compare
> with 64 bytes for dev_printk.
I am OK with A, B, or C if we can keep the @caller_id semantics. This
would not require any changes to the LOG_CONT implementation or any
other exists buffer preparation code and it would not require and
changes do crash/dump tools. I.e. it would simply be making new fields
available for netconsole.
I can accept that we want to avoid C for now until we solve the
efficient space issue.
(My official preference list is below...)
> 3. It would be nice to optimize the memory usage and store the
> optional and variable strings (comm, subsystem, device) into
> data buffer. But it looks like a non-trivial work.
>
> I would do this only when there is a real demand. And I haven't
> heard about that the current approach was not acceptable yet.
Well, the whole reason the topic came up is because of a complaint from
Geert. And I think if people knew just how much space was being wasted,
they might speak up. For example, on my Debian distro kernel, I have a
256KB text_data_ring and an 896KB desc_ring. I expect that the total
usage would cut in half if we packed the dev_printk_info data into the
text_data_ring. I can prototype some tests (just to satisfy my
curiousity).
I do not think it would be much work. Whether the strings are copied
from text_data arrays or dev_printk_info structs does not make much
difference. There is only a slightly larger overhead to identify their
existance and offsets. (Currently it is a single memcpy() of
dev_printk_info.)
But we would need to update the crash/dump tools. So I am not in a rush
to implement D right now.
My ordered preferences for right now would be:
1. keeping @caller_id semantics + adding @cpu + adding @comm (similar to
your C)
2. keeping @caller_id semantics + adding @cpu (similar to your A)
These additions would be purely to support netconsole and the additions
would be under CONFIG_NETCONSOLE_DYNAMIC. No crash/dump tools should be
changed due to this.
For the long term I would like to move all strings into the
text_data_ring. We could use that opportunity to add context bits, time
stamps, etc. and then appropriately update the major crash/dump tools.
John
On Fri 2026-01-09 16:19:31, John Ogness wrote:
> On 2026-01-09, Petr Mladek <pmladek@suse.com> wrote:
> > If we were adding this info, I would add it for all users, definitely.
> > We are going to touch the internal printk ringbuffer format anyway.
>
> Which could mean we are going to need a round of updating crash/dump
> tools. So we should choose wisely.
Exactly :-)
> > Now, the main question is how far we want to go.
> >
> > I see the following possibilities:
> >
> > A) caller_id -> pid + cpu + atomic/task context bit
> > ===================================================
> >
> > Replace the current .caller_id and always save both PID and CPU
> > number. Something like:
> >
> > diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h
> > index 4ef81349d9fb..3c7635ada6dd 100644
> > --- a/kernel/printk/printk_ringbuffer.h
> > +++ b/kernel/printk/printk_ringbuffer.h
> > @@ -9,6 +9,12 @@
> > #include <linux/stddef.h>
> > #include <linux/types.h>
> >
> > +
> > +struct printk_caller {
> > + pid_t pid; /* caller pid */
> > + int cpu; /* caller CPU number */
> > +};
> > +
> > /*
> > * Meta information about each stored message.
> > *
> > @@ -22,8 +29,8 @@ struct printk_info {
> > u8 facility; /* syslog facility */
> > u8 flags:5; /* internal record flags */
> > u8 level:3; /* syslog level */
> > - u32 caller_id; /* thread id or processor id */
> >
> > + struct printk_caller caller;
> > struct dev_printk_info dev_info;
> > };
> >
> > Plus the task/interrupt bit might be stored either as the highest bit
> > in .pid or by adding LOG_CALLER_IN_TASK bit into "enum printk_info_flags".
>
> The thing I find attractive about this solution is that it could be done
> such that crash/dump tools must not be changed. We could leave the
> semantics for @caller_id as is and simply add @cpu:
>
> --- a/kernel/printk/printk_ringbuffer.h
> +++ b/kernel/printk/printk_ringbuffer.h
> @@ -23,6 +23,7 @@ struct printk_info {
> u8 flags:5; /* internal record flags */
> u8 level:3; /* syslog level */
> u32 caller_id; /* thread id or processor id */
> + u32 cpu; /* processor id */
>
> struct dev_printk_info dev_info;
> };
>
> After all, if the caller is not in_task() then the new @pid would be
> meaningless anyway.
Or we could use:
u32 caller_id2; /* processor id or thread id,
, where .caller_id2 is a complement to caller_id which is backward
compatible. The highest bit in @caller_id would define what
is stored where.
We could create helpers to encode/decode it:
set_printk_info_cpu(struct printk_info *info, int cpu);
get_printk_info_cpu(struct printk_info *info);
...
It is a bit ugly. But storing CPU twice is kind of ugly as well.
And it will provide all information for netconsole.
> If we are willing to accept printer-resolution of task names, then this
> simple addition would be good enough for netconsole, while not requiring
> any crash/dump tool updates. This would buy us time to think more
> seriously about a significant overhaul.
I am just a bit afraid that this might stay quite a long time
until anyone gets motivation and time to clean it.
> > B) caller_id -> pid + cpu + contex
> > ==================================
> >
> > Same as above but the caller context info is stored separately and
> > might allow to distinguish more types. Something like:
> >
> > diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h
> > index 4ef81349d9fb..44aa60a3f84c 100644
> > --- a/kernel/printk/printk_ringbuffer.h
> > +++ b/kernel/printk/printk_ringbuffer.h
> > @@ -9,6 +9,19 @@
> > #include <linux/stddef.h>
> > #include <linux/types.h>
> >
> > +#define PRINTK_CALLER_CTXT_PREEMPT_BIT 1
> > +#define PRINTK_CALLER_CTXT_SOFTIRQ_BIT 2
> > +#define PRINTK_CALLER_CTXT_HARDIRQ_BIT 3
> > +#define PRINTK_CALLER_CTXT_NMI 4
> > +/* This is not supported on all platforms, see irqs_disabled() */
> > +#define PRINTK_CALLER_CTXT_IRQS_DISABLED 5
> > +
> > +struct printk_caller {
> > + u8 ctxt; /* caller context: task, irq, ... */
> > + pid_t pid; /* caller pid */
> > + int cpu; /* caller CPU number */
> > +};
> > +
> > /*
> > * Meta information about each stored message.
> > *
> > @@ -22,8 +35,8 @@ struct printk_info {
> > u8 facility; /* syslog facility */
> > u8 flags:5; /* internal record flags */
> > u8 level:3; /* syslog level */
> > - u32 caller_id; /* thread id or processor id */
> >
> > + struct printk_caller caller;
> > struct dev_printk_info dev_info;
> > };
>
> Just as with A, here we could also preserve @caller_id semantics
> (instead of introducing @pid) to avoid crash/dump tool updates.
>
> A new @ctxt field is only useful if it can be seen. I am not sure how
> you plan on showing this. By extending the prefix like caller_id does?
I am afraid that we would need to come up with another format.
I wanted to get some inspiration from lockdep. And check other
subystems which might already show this (backtrace, ftrace, ...)
> Would it be a new kernel config or just use CONFIG_PRINTK_CALLER? Either
> way, we are talking about extending visible log data, which is something
> that needs a discussion on its own.
Sure. We should think twice about it.
> > C) caller_id -> pid + cpu + comm + atomic/task context bit
> > ==========================================================
> >
> > Similar to A and B but add also
> >
> > char comm[TASK_COMM_LEN];
> >
> > into struct printk_caller.
>
> Just as with A and B, we could preserve @caller_id semantics.
>
> This is the simplest solution since the printer would not need to
> perform any resolution at all and it would be 100% accurate (when
> in_task).
>
> > D) caller_id -> pid + cpu + comm + atomic/task context bit
> > and move printk_caller + printk_dev_info into text buffer
> > as suggested as mentioned at
> > https://lore.kernel.org/lkml/84y10vz7ty.fsf@jogness.linutronix.de
> > ====================================================================
> >
> > There are many possibilities how to do it. And it involves two
> > problems:
> >
> > a) how to store the data into data buffer
> > b) how to integrate this in the ring buffer API
> >
> > I thought about several approaches and realized that it still
> > would make sense to keep:
> >
> > + binary data (pid, cpu, ctxt) in desc ring
> > + text data (comm, subsystem, device) in text_data buffer
> >
> > Something like:
> >
> > diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h
> > index 4ef81349d9fb..41232bf2919d 100644
> > --- a/kernel/printk/printk_ringbuffer.h
> > +++ b/kernel/printk/printk_ringbuffer.h
> > @@ -9,6 +9,27 @@
> > #include <linux/stddef.h>
> > #include <linux/types.h>
> >
> > +#define PRINTK_CALLER_CTXT_PREEMPT_BIT 0
> > +#define PRINTK_CALLER_CTXT_SOFTIRQ_BIT 1
> > +#define PRINTK_CALLER_CTXT_HARDIRQ_BIT 2
> > +#define PRINTK_CALLER_CTXT_NMI 3
> > +/* This is not supported on all platforms, see irqs_disabled() */
> > +#define PRINTK_CALLER_CTXT_IRQS_DISABLED 4
> > +
> > +struct printk_caller {
> > + u8 ctxt; /* caller context: task, irq, ... */
> > + pid_t pid; /* caller pid */
> > + int cpu; /* caller CPU number */
> > +};
> > +
> > +/*
> > + * Describe which text information about the caller
> > + * is stored in text_data_ring
> > + */
> > +#define PRINTK_CALLER_BITS_COMM_BIT 0
> > +#define PRINTK_CALLER_BITS_SUBSYSTEM_BIT 1
> > +#define PRINTK_CALLER_BITS_DEVICE_BIT 2
> > +
> > /*
> > * Meta information about each stored message.
> > *
> > @@ -22,9 +43,8 @@ struct printk_info {
> > u8 facility; /* syslog facility */
> > u8 flags:5; /* internal record flags */
> > u8 level:3; /* syslog level */
> > - u32 caller_id; /* thread id or processor id */
> > -
> > - struct dev_printk_info dev_info;
> > + u8 caller_bits_size; /* size of the caller info in data buffer */
> > + u8 caller_bits; /* bits describing caller in data buffer */
> > };
> >
> > /*
> >
> > The text would be stored in the test_data_ring in the following
> > format:
> >
> > [<comm>\0][<subsystem>\0][<device\0]<text>\0
>
> I would prefer:
>
> <text>\0[<subsystem>\0][<device>\0][<comm>\0]
We could discuss this when there is some code. IMHO, we should keep
the ordering similar to the console output. It might help when
when people see plain memory dump of the data_ring buffer.
> > My opinion:
> > ===========
> >
> > I personally think that the approach B) is the best compromise for now
> > because:
>
> My ordered preferences for right now would be:
>
> 1. keeping @caller_id semantics + adding @cpu + adding @comm (similar to
> your C)
I am fine with this if the crash tools are really able to handle it
out of box.
> 2. keeping @caller_id semantics + adding @cpu (similar to your A)
>
> These additions would be purely to support netconsole and the additions
> would be under CONFIG_NETCONSOLE_DYNAMIC. No crash/dump tools should be
> changed due to this.
>
> For the long term I would like to move all strings into the
> text_data_ring. We could use that opportunity to add context bits, time
> stamps, etc. and then appropriately update the major crash/dump tools.
That would be great.
Best Regards,
Petr
On Fri, Jan 09, 2026 at 04:19:31PM +0106, John Ogness wrote:
> On 2026-01-09, Petr Mladek <pmladek@suse.com> wrote:
...
> Crash/dump tools that are not updated would at least continue to print
> the text at the beginning of the line. Here are a few projects that I
> track and how they would react (unmodified):
>
> makedumpfile
> - https://github.com/makedumpfile/makedumpfile/blob/master/printk.c#L134
> - will print "\x00" between the fields
>
> vmcore-dmesg
> - https://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git/tree/util_lib/elf_info.c?h=main#n904
> - will print "\x00" between the fields
>
> crash
> - https://github.com/crash-utility/crash/blob/master/printk.c#L210
> - will print "." between the fields
drgn:
I know that drgn also parses it, and has a if depending the kernel
version (before or after commit commit 896fbe20b4e2 ("printk: use the
lockless ringbuffer")
https://github.com/osandov/drgn/blob/44ba3eb43a44f246fe3e65a728aa2594a19f15ee/drgn/helpers/linux/printk.py#L252C1-L255C55
> > My opinion:
> > ===========
> >
> > I personally think that the approach B) is the best compromise for now
> > because:
> >
> > 1. We really should distinguish task/interrupt context. IMHO, it is
> > a very useful information provided by the caller_id now.
Agree. I don't have it in netconsole yet, but, this is I would like to
implement.
> My ordered preferences for right now would be:
>
> 1. keeping @caller_id semantics + adding @cpu + adding @comm (similar to
> your C)
This is similar the PoC I wrote earlier in this thread [0] plus @comm.
Link: https://lore.kernel.org/all/j764nuipx4nvemd3wlqfyx77lkdf7wgs5z452hlacwglvc2e7n@vsko4bq5xb2f/ [0]
Let me hack a new version of it with @comm, and post here to check how
it looks likes.
On Mon, Jan 12, 2026 at 02:55:06AM -0800, Breno Leitao wrote:
> > My ordered preferences for right now would be:
> >
> > 1. keeping @caller_id semantics + adding @cpu + adding @comm (similar to
> > your C)
...
> Let me hack a new version of it with @comm, and post here to check how
> it looks likes.
How does this version look like according to the suggestion above. It is
mostly Petr's option C with a few changes:
a) caller_id continues to be unchanged with (pid and context bit)
b) Append @pid and @comm to printk_info
Author: Breno Leitao <leitao@debian.org>
Date: Thu Jan 8 03:00:46 2026 -0800
printk: Add execution context (task name/CPU) to printk_info
Extend struct printk_info to include the task name and CPU number
where printk messages originate. This information is captured at
vprintk_store() time and propagated through printk_message to
nbcon_write_context, making it available to nbcon console drivers.
This is useful for consoles like netconsole that want to include
execution context in their output, allowing correlation of messages
with specific tasks and CPUs regardless of where the console driver
actually runs.
The feature is controlled by CONFIG_PRINTK_EXECUTION_CTX, which is
automatically selected by CONFIG_NETCONSOLE_DYNAMIC. When disabled,
the helper functions compile to no-ops with no overhead.
Suggested-by: John Ogness <john.ogness@linutronix.de>
Signed-off-by: Breno Leitao <leitao@debian.org>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index ac12eaf11755..12e47cb27ffa 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -341,6 +341,7 @@ config NETCONSOLE_DYNAMIC
bool "Dynamic reconfiguration of logging targets"
depends on NETCONSOLE && SYSFS && CONFIGFS_FS && \
!(NETCONSOLE=y && CONFIGFS_FS=m)
+ select CONSOLE_HAS_EXECUTION_CTX
help
This option enables the ability to dynamically reconfigure target
parameters (interface, IP addresses, port numbers, MAC addresses)
diff --git a/include/linux/console.h b/include/linux/console.h
index fc9f5c5c1b04..4bb97700806e 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -19,6 +19,7 @@
#include <linux/irq_work.h>
#include <linux/rculist.h>
#include <linux/rcuwait.h>
+#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/types.h>
#include <linux/vesa.h>
@@ -298,12 +299,18 @@ struct nbcon_context {
* @outbuf: Pointer to the text buffer for output
* @len: Length to write
* @unsafe_takeover: If a hostile takeover in an unsafe state has occurred
+ * @msg_comm: Name of the task that generated the message
+ * @msg_cpu: CPU on which the message was generated
*/
struct nbcon_write_context {
struct nbcon_context __private ctxt;
char *outbuf;
unsigned int len;
bool unsafe_takeover;
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+ char msg_comm[TASK_COMM_LEN];
+ int msg_cpu;
+#endif
};
/**
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 5f5f626f4279..039eb9b44a66 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -281,12 +281,18 @@ struct printk_buffers {
* nothing to output and this record should be skipped.
* @seq: The sequence number of the record used for @pbufs->outbuf.
* @dropped: The number of dropped records from reading @seq.
+ * @msg_comm: Name of the task that generated the message.
+ * @msg_cpu: CPU on which the message was generated.
*/
struct printk_message {
struct printk_buffers *pbufs;
unsigned int outbuf_len;
u64 seq;
unsigned long dropped;
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+ char msg_comm[TASK_COMM_LEN];
+ int msg_cpu;
+#endif
};
bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 3fa403f9831f..38117b72d0b8 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -946,6 +946,18 @@ void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt)
}
EXPORT_SYMBOL_GPL(nbcon_reacquire_nobuf);
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+static inline void wctxt_load_execution_ctx(struct nbcon_write_context *wctxt,
+ struct printk_message *pmsg)
+{
+ memcpy(wctxt->msg_comm, pmsg->msg_comm, TASK_COMM_LEN);
+ wctxt->msg_cpu = pmsg->msg_cpu;
+}
+#else
+static inline void wctxt_load_execution_ctx(struct nbcon_write_context *wctxt,
+ struct printk_message *pmsg) {}
+#endif
+
/**
* nbcon_emit_next_record - Emit a record in the acquired context
* @wctxt: The write context that will be handed to the write function
@@ -1048,6 +1060,8 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_a
/* Initialize the write context for driver callbacks. */
nbcon_write_context_set_buf(wctxt, &pmsg.pbufs->outbuf[0], pmsg.outbuf_len);
+ wctxt_load_execution_ctx(wctxt, &pmsg);
+
if (use_atomic)
con->write_atomic(con, wctxt);
else
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 1d765ad242b8..76dfa7ee1d23 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2213,6 +2213,26 @@ static u16 printk_sprint(char *text, u16 size, int facility,
return text_len;
}
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+static inline void printk_save_execution_ctx(struct printk_info *info)
+{
+ get_task_comm(info->msg_comm, current);
+ info->msg_cpu = smp_processor_id();
+}
+
+static inline void pmsg_load_execution_ctx(struct printk_message *pmsg,
+ const struct printk_info *info)
+{
+ memcpy(pmsg->msg_comm, info->msg_comm, TASK_COMM_LEN);
+ pmsg->msg_cpu = info->msg_cpu;
+}
+#else
+static inline void printk_save_execution_ctx(struct printk_info *info) {}
+
+static inline void pmsg_load_execution_ctx(struct printk_message *pmsg,
+ const struct printk_info *info) {}
+#endif
+
__printf(4, 0)
int vprintk_store(int facility, int level,
const struct dev_printk_info *dev_info,
@@ -2320,6 +2340,7 @@ int vprintk_store(int facility, int level,
r.info->caller_id = caller_id;
if (dev_info)
memcpy(&r.info->dev_info, dev_info, sizeof(r.info->dev_info));
+ printk_save_execution_ctx(r.info);
/* A message without a trailing newline can be continued. */
if (!(flags & LOG_NEWLINE))
@@ -3002,6 +3023,7 @@ bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
pmsg->seq = r.info->seq;
pmsg->dropped = r.info->seq - seq;
force_con = r.info->flags & LOG_FORCE_CON;
+ pmsg_load_execution_ctx(pmsg, r.info);
/*
* Skip records that are not forced to be printed on consoles and that
diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h
index 4ef81349d9fb..4ecb26d8dc8b 100644
--- a/kernel/printk/printk_ringbuffer.h
+++ b/kernel/printk/printk_ringbuffer.h
@@ -6,6 +6,7 @@
#include <linux/atomic.h>
#include <linux/bits.h>
#include <linux/dev_printk.h>
+#include <linux/sched.h>
#include <linux/stddef.h>
#include <linux/types.h>
@@ -23,6 +24,10 @@ struct printk_info {
u8 flags:5; /* internal record flags */
u8 level:3; /* syslog level */
u32 caller_id; /* thread id or processor id */
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+ char msg_comm[TASK_COMM_LEN]; /* name of the task that generated the message */
+ int msg_cpu; /* CPU where the message was generated */
+#endif
struct dev_printk_info dev_info;
};
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index ba36939fda79..57f91ee10b8e 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -35,6 +35,26 @@ config PRINTK_CALLER
no option to enable/disable at the kernel command line parameter or
sysfs interface.
+config CONSOLE_HAS_EXECUTION_CTX
+ bool
+ help
+ Selected by console drivers that support execution context
+ (task name/CPU) in their output. This enables PRINTK_EXECUTION_CTX
+ to provide the necessary infrastructure.
+
+config PRINTK_EXECUTION_CTX
+ bool "Include execution context (task/CPU) in printk messages"
+ depends on PRINTK && CONSOLE_HAS_EXECUTION_CTX
+ default CONSOLE_HAS_EXECUTION_CTX
+ help
+ This option extends struct printk_info to include extra execution
+ context in printk, such as task name and CPU number from where the
+ message originated. This is useful for correlating printk messages
+ with specific execution contexts.
+
+ This is automatically enabled when a console driver that supports
+ execution context is selected.
+
config STACKTRACE_BUILD_ID
bool "Show build ID information in stacktraces"
depends on PRINTK
On Mon 2026-01-12 04:44:42, Breno Leitao wrote:
> On Mon, Jan 12, 2026 at 02:55:06AM -0800, Breno Leitao wrote:
> > > My ordered preferences for right now would be:
> > >
> > > 1. keeping @caller_id semantics + adding @cpu + adding @comm (similar to
> > > your C)
>
> ...
>
> > Let me hack a new version of it with @comm, and post here to check how
> > it looks likes.
>
> How does this version look like according to the suggestion above. It is
> mostly Petr's option C with a few changes:
>
> a) caller_id continues to be unchanged with (pid and context bit)
> b) Append @pid and @comm to printk_info
>
>
> Author: Breno Leitao <leitao@debian.org>
> Date: Thu Jan 8 03:00:46 2026 -0800
>
> printk: Add execution context (task name/CPU) to printk_info
>
> Extend struct printk_info to include the task name and CPU number
> where printk messages originate. This information is captured at
> vprintk_store() time and propagated through printk_message to
> nbcon_write_context, making it available to nbcon console drivers.
>
> This is useful for consoles like netconsole that want to include
> execution context in their output, allowing correlation of messages
> with specific tasks and CPUs regardless of where the console driver
> actually runs.
>
> The feature is controlled by CONFIG_PRINTK_EXECUTION_CTX, which is
> automatically selected by CONFIG_NETCONSOLE_DYNAMIC. When disabled,
> the helper functions compile to no-ops with no overhead.
>
> Suggested-by: John Ogness <john.ogness@linutronix.de>
> Signed-off-by: Breno Leitao <leitao@debian.org>
>
> --- a/kernel/printk/printk_ringbuffer.h
> +++ b/kernel/printk/printk_ringbuffer.h
> @@ -23,6 +24,10 @@ struct printk_info {
> u8 flags:5; /* internal record flags */
> u8 level:3; /* syslog level */
> u32 caller_id; /* thread id or processor id */
> +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> + char msg_comm[TASK_COMM_LEN]; /* name of the task that generated the message */
> + int msg_cpu; /* CPU where the message was generated */
I would allow to store the caller_id complement so that we
always store both cpu and pid.
Also I would remove the "msg_" prefix. It is not bad. But it is
inconsistent with the existing "caller_" prefix. And the meaning
should be obvious because it is stored in struct printk_info...
Otherwise, it looks good to me.
I tried to update your patch with the above proposal to see how
it looks and I got:
From ac9d7962d478bda9b5c7ef1d42e14c46c9d576fc Mon Sep 17 00:00:00 2001
From: Breno Leitao <leitao@debian.org>
Date: Mon, 12 Jan 2026 04:44:42 -0800
Subject: [PATCH 1/2] printk: Add execution context (task name/CPU) to
printk_info
Extend struct printk_info to include the task name, pid, and CPU
number where printk messages originate. This information is captured
at vprintk_store() time and propagated through printk_message to
nbcon_write_context, making it available to nbcon console drivers.
This is useful for consoles like netconsole that want to include
execution context in their output, allowing correlation of messages
with specific tasks and CPUs regardless of where the console driver
actually runs.
The feature is controlled by CONFIG_PRINTK_EXECUTION_CTX, which is
automatically selected by CONFIG_NETCONSOLE_DYNAMIC. When disabled,
the helper functions compile to no-ops with no overhead.
Suggested-by: John Ogness <john.ogness@linutronix.de>
Signed-off-by: Breno Leitao <leitao@debian.org>
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
drivers/net/Kconfig | 1 +
include/linux/console.h | 8 +++++
kernel/printk/internal.h | 7 ++++
kernel/printk/nbcon.c | 15 +++++++++
kernel/printk/printk.c | 53 ++++++++++++++++++++++++++++++-
kernel/printk/printk_ringbuffer.h | 5 +++
lib/Kconfig.debug | 20 ++++++++++++
7 files changed, 108 insertions(+), 1 deletion(-)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index ac12eaf11755..12e47cb27ffa 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -341,6 +341,7 @@ config NETCONSOLE_DYNAMIC
bool "Dynamic reconfiguration of logging targets"
depends on NETCONSOLE && SYSFS && CONFIGFS_FS && \
!(NETCONSOLE=y && CONFIGFS_FS=m)
+ select CONSOLE_HAS_EXECUTION_CTX
help
This option enables the ability to dynamically reconfigure target
parameters (interface, IP addresses, port numbers, MAC addresses)
diff --git a/include/linux/console.h b/include/linux/console.h
index fc9f5c5c1b04..47477fd05ee8 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -19,6 +19,7 @@
#include <linux/irq_work.h>
#include <linux/rculist.h>
#include <linux/rcuwait.h>
+#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/types.h>
#include <linux/vesa.h>
@@ -298,12 +299,19 @@ struct nbcon_context {
* @outbuf: Pointer to the text buffer for output
* @len: Length to write
* @unsafe_takeover: If a hostile takeover in an unsafe state has occurred
+ * @msg_comm: Name of the task that generated the message
+ * @msg_cpu: CPU on which the message was generated
*/
struct nbcon_write_context {
struct nbcon_context __private ctxt;
char *outbuf;
unsigned int len;
bool unsafe_takeover;
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+ int cpu;
+ pid_t pid;
+ char comm[TASK_COMM_LEN];
+#endif
};
/**
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 5f5f626f4279..cf9c01a02853 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -281,12 +281,19 @@ struct printk_buffers {
* nothing to output and this record should be skipped.
* @seq: The sequence number of the record used for @pbufs->outbuf.
* @dropped: The number of dropped records from reading @seq.
+ * @msg_comm: Name of the task that generated the message.
+ * @msg_cpu: CPU on which the message was generated.
*/
struct printk_message {
struct printk_buffers *pbufs;
unsigned int outbuf_len;
u64 seq;
unsigned long dropped;
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+ int cpu;
+ pid_t pid;
+ char comm[TASK_COMM_LEN];
+#endif
};
bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 3fa403f9831f..c2b3c4d2146e 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -946,6 +946,19 @@ void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt)
}
EXPORT_SYMBOL_GPL(nbcon_reacquire_nobuf);
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+static inline void wctxt_load_execution_ctx(struct nbcon_write_context *wctxt,
+ struct printk_message *pmsg)
+{
+ wctxt->cpu = pmsg->cpu;
+ wctxt->pid = pmsg->pid;
+ memcpy(wctxt->comm, pmsg->comm, TASK_COMM_LEN);
+}
+#else
+static inline void wctxt_load_execution_ctx(struct nbcon_write_context *wctxt,
+ struct printk_message *pmsg) {}
+#endif
+
/**
* nbcon_emit_next_record - Emit a record in the acquired context
* @wctxt: The write context that will be handed to the write function
@@ -1048,6 +1061,8 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_a
/* Initialize the write context for driver callbacks. */
nbcon_write_context_set_buf(wctxt, &pmsg.pbufs->outbuf[0], pmsg.outbuf_len);
+ wctxt_load_execution_ctx(wctxt, &pmsg);
+
if (use_atomic)
con->write_atomic(con, wctxt);
else
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 1d765ad242b8..bc09fb6e33d1 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2131,12 +2131,40 @@ static inline void printk_delay(int level)
}
}
+#define caller_id_mask 0x80000000
+
static inline u32 printk_caller_id(void)
{
return in_task() ? task_pid_nr(current) :
- 0x80000000 + smp_processor_id();
+ caller_id_mask + smp_processor_id();
}
+
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+/* Store the opposite info than caller_id. */
+static inline u32 printk_caller_id2(void)
+{
+ return !in_task() ? task_pid_nr(current) :
+ caller_id_mask + smp_processor_id();
+}
+
+static inline pid_t printk_info_get_pid(const struct printk_info *info)
+{
+ u32 caller_id = info->caller_id;
+ u32 caller_id2 = info->caller_id2;
+
+ return caller_id & caller_id_mask ? caller_id2 : caller_id;
+}
+
+static inline int printk_info_get_cpu(const struct printk_info *info)
+{
+ u32 caller_id = info->caller_id;
+ u32 caller_id2 = info->caller_id2;
+
+ return (caller_id & caller_id_mask ? caller_id : caller_id2) & ~caller_id_mask;
+}
+#endif
+
/**
* printk_parse_prefix - Parse level and control flags.
*
@@ -2213,6 +2241,27 @@ static u16 printk_sprint(char *text, u16 size, int facility,
return text_len;
}
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+static inline void printk_store_execution_ctx(struct printk_info *info)
+{
+ info->caller_id2 = printk_caller_id2();
+ get_task_comm(info->comm, current);
+}
+
+static inline void pmsg_load_execution_ctx(struct printk_message *pmsg,
+ const struct printk_info *info)
+{
+ pmsg->cpu = printk_info_get_cpu(info);
+ pmsg->pid = printk_info_get_pid(info);
+ memcpy(pmsg->comm, info->comm, TASK_COMM_LEN);
+}
+#else
+static inline void printk_store_execution_ctx(struct printk_info *info) {}
+
+static inline void pmsg_load_execution_ctx(struct printk_message *pmsg,
+ const struct printk_info *info) {}
+#endif
+
__printf(4, 0)
int vprintk_store(int facility, int level,
const struct dev_printk_info *dev_info,
@@ -2320,6 +2369,7 @@ int vprintk_store(int facility, int level,
r.info->caller_id = caller_id;
if (dev_info)
memcpy(&r.info->dev_info, dev_info, sizeof(r.info->dev_info));
+ printk_store_execution_ctx(r.info);
/* A message without a trailing newline can be continued. */
if (!(flags & LOG_NEWLINE))
@@ -3002,6 +3052,7 @@ bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
pmsg->seq = r.info->seq;
pmsg->dropped = r.info->seq - seq;
force_con = r.info->flags & LOG_FORCE_CON;
+ pmsg_load_execution_ctx(pmsg, r.info);
/*
* Skip records that are not forced to be printed on consoles and that
diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h
index 4ef81349d9fb..8943c02995af 100644
--- a/kernel/printk/printk_ringbuffer.h
+++ b/kernel/printk/printk_ringbuffer.h
@@ -6,6 +6,7 @@
#include <linux/atomic.h>
#include <linux/bits.h>
#include <linux/dev_printk.h>
+#include <linux/sched.h>
#include <linux/stddef.h>
#include <linux/types.h>
@@ -23,6 +24,10 @@ struct printk_info {
u8 flags:5; /* internal record flags */
u8 level:3; /* syslog level */
u32 caller_id; /* thread id or processor id */
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+ u32 caller_id2; /* caller_id complement */
+ char comm[TASK_COMM_LEN]; /* name of the task that generated the message */
+#endif
struct dev_printk_info dev_info;
};
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index ba36939fda79..57f91ee10b8e 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -35,6 +35,26 @@ config PRINTK_CALLER
no option to enable/disable at the kernel command line parameter or
sysfs interface.
+config CONSOLE_HAS_EXECUTION_CTX
+ bool
+ help
+ Selected by console drivers that support execution context
+ (task name/CPU) in their output. This enables PRINTK_EXECUTION_CTX
+ to provide the necessary infrastructure.
+
+config PRINTK_EXECUTION_CTX
+ bool "Include execution context (task/CPU) in printk messages"
+ depends on PRINTK && CONSOLE_HAS_EXECUTION_CTX
+ default CONSOLE_HAS_EXECUTION_CTX
+ help
+ This option extends struct printk_info to include extra execution
+ context in printk, such as task name and CPU number from where the
+ message originated. This is useful for correlating printk messages
+ with specific execution contexts.
+
+ This is automatically enabled when a console driver that supports
+ execution context is selected.
+
config STACKTRACE_BUILD_ID
bool "Show build ID information in stacktraces"
depends on PRINTK
--
2.52.0
On Fri 2026-01-16 16:51:49, Petr Mladek wrote:
> On Mon 2026-01-12 04:44:42, Breno Leitao wrote:
> > On Mon, Jan 12, 2026 at 02:55:06AM -0800, Breno Leitao wrote:
> >
> > printk: Add execution context (task name/CPU) to printk_info
> >
> >
> > --- a/kernel/printk/printk_ringbuffer.h
> > +++ b/kernel/printk/printk_ringbuffer.h
> > @@ -23,6 +24,10 @@ struct printk_info {
> > u8 flags:5; /* internal record flags */
> > u8 level:3; /* syslog level */
> > u32 caller_id; /* thread id or processor id */
> > +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> > + char msg_comm[TASK_COMM_LEN]; /* name of the task that generated the message */
> > + int msg_cpu; /* CPU where the message was generated */
>
> I would allow to store the caller_id complement so that we
> always store both cpu and pid.
>
> Also I would remove the "msg_" prefix. It is not bad. But it is
> inconsistent with the existing "caller_" prefix. And the meaning
> should be obvious because it is stored in struct printk_info...
>
> Otherwise, it looks good to me.
>
> I tried to update your patch with the above proposal to see how
> it looks and I got:
The change seems to work. I have tested it with the following patch:
From 1966dc35bb19eb3fc13ca41257203819c36cd21b Mon Sep 17 00:00:00 2001
From: Petr Mladek <pmladek@suse.com>
Date: Fri, 16 Jan 2026 16:38:16 +0100
Subject: [PATCH 2/2] printk: Test extended execution context
Compile with
CONFIG_NETCONSOLE=y
CONFIG_NETCONSOLE_EXTENDED_LOG=y
CONFIG_CONSOLE_HAS_EXECUTION_CTX=y
CONFIG_PRINTK_EXECUTION_CTX=y
Then the extended console format should show also:
,cpu=XXX,pid=YYY,comm=ZZZ
For example:
[...]
6,776,2595848,-,caller=T167,cpu=3,pid=167,comm=scsi_eh_4;ata5: SATA link down (SStatus 0 SControl 300)
6,777,2623478,-,caller=T1,cpu=11,pid=1,comm=swapper/0;sched_clock: Marking stable (2420002924, 202869031)->(2789319400, -166447445)
6,778,2626663,-,caller=T159,cpu=2,pid=159,comm=scsi_eh_0;ata1: SATA link down (SStatus 0 SControl 300)
6,779,2671763,-,caller=T1,cpu=7,pid=1,comm=swapper/0;registered taskstats version 1
6,780,2672803,-,caller=T163,cpu=3,pid=163,comm=scsi_eh_2;ata3: SATA link down (SStatus 0 SControl 300)
[...]
4,1210,238099642,-,caller=C11,cpu=11,pid=0,comm=swapper/11; common_startup_64+0x13e/0x141
4,1211,238099651,-,caller=C11,cpu=11,pid=0,comm=swapper/11; </TASK>
4,1212,238099652,-,caller=C7,cpu=7,pid=0,comm=swapper/7;NMI backtrace for cpu 7
4,1213,238099655,-,caller=C7,cpu=7,pid=0,comm=swapper/7;CPU: 7 UID: 0 PID: 0 Comm: swapper/7 Not tainted 6.19.0-rc5-default+ #475 PREEMPT(full) 9097c5ae70fd66490486e279e5273a94d14cd453
[...]
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/printk.c | 84 ++++++++++++++++++++++++------------------
1 file changed, 48 insertions(+), 36 deletions(-)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index bc09fb6e33d1..ac8eccb1d2fc 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -630,6 +630,40 @@ static int check_syslog_permissions(int type, int source)
return security_syslog(type);
}
+#define caller_id_mask 0x80000000
+
+static inline u32 printk_caller_id(void)
+{
+ return in_task() ? task_pid_nr(current) :
+ caller_id_mask + smp_processor_id();
+}
+
+
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+/* Store the opposite info than caller_id. */
+static inline u32 printk_caller_id2(void)
+{
+ return !in_task() ? task_pid_nr(current) :
+ caller_id_mask + smp_processor_id();
+}
+
+static inline pid_t printk_info_get_pid(const struct printk_info *info)
+{
+ u32 caller_id = info->caller_id;
+ u32 caller_id2 = info->caller_id2;
+
+ return caller_id & caller_id_mask ? caller_id2 : caller_id;
+}
+
+static inline int printk_info_get_cpu(const struct printk_info *info)
+{
+ u32 caller_id = info->caller_id;
+ u32 caller_id2 = info->caller_id2;
+
+ return (caller_id & caller_id_mask ? caller_id : caller_id2) & ~caller_id_mask;
+}
+#endif
+
static void append_char(char **pp, char *e, char c)
{
if (*pp < e)
@@ -641,6 +675,7 @@ static ssize_t info_print_ext_header(char *buf, size_t size,
{
u64 ts_usec = info->ts_nsec;
char caller[20];
+ char ext_caller[100];
#ifdef CONFIG_PRINTK_CALLER
u32 id = info->caller_id;
@@ -650,11 +685,22 @@ static ssize_t info_print_ext_header(char *buf, size_t size,
caller[0] = '\0';
#endif
+#ifdef CONFIG_PRINTK_EXECUTION_CTX
+ snprintf(ext_caller, sizeof(ext_caller),
+ ",cpu=%u,pid=%u,comm=%s",
+ printk_info_get_cpu(info),
+ printk_info_get_pid(info),
+ info->comm);
+#else
+ ext_caller[0] = '\0';
+#endif
+
do_div(ts_usec, 1000);
- return scnprintf(buf, size, "%u,%llu,%llu,%c%s;",
+ return scnprintf(buf, size, "%u,%llu,%llu,%c%s%s;",
(info->facility << 3) | info->level, info->seq,
- ts_usec, info->flags & LOG_CONT ? 'c' : '-', caller);
+ ts_usec, info->flags & LOG_CONT ? 'c' : '-',
+ caller, ext_caller);
}
static ssize_t msg_add_ext_text(char *buf, size_t size,
@@ -2131,40 +2177,6 @@ static inline void printk_delay(int level)
}
}
-#define caller_id_mask 0x80000000
-
-static inline u32 printk_caller_id(void)
-{
- return in_task() ? task_pid_nr(current) :
- caller_id_mask + smp_processor_id();
-}
-
-
-#ifdef CONFIG_PRINTK_EXECUTION_CTX
-/* Store the opposite info than caller_id. */
-static inline u32 printk_caller_id2(void)
-{
- return !in_task() ? task_pid_nr(current) :
- caller_id_mask + smp_processor_id();
-}
-
-static inline pid_t printk_info_get_pid(const struct printk_info *info)
-{
- u32 caller_id = info->caller_id;
- u32 caller_id2 = info->caller_id2;
-
- return caller_id & caller_id_mask ? caller_id2 : caller_id;
-}
-
-static inline int printk_info_get_cpu(const struct printk_info *info)
-{
- u32 caller_id = info->caller_id;
- u32 caller_id2 = info->caller_id2;
-
- return (caller_id & caller_id_mask ? caller_id : caller_id2) & ~caller_id_mask;
-}
-#endif
-
/**
* printk_parse_prefix - Parse level and control flags.
*
--
2.52.0
Hello Petr,
On Fri, Jan 16, 2026 at 04:53:48PM +0100, Petr Mladek wrote:
> > Otherwise, it looks good to me.
> >
> > I tried to update your patch with the above proposal to see how
> > it looks and I got:
>
> The change seems to work. I have tested it with the following patch:
First of all, *thank you* so much for spending your time on it, this is
helpful.
> Then the extended console format should show also:
>
> ,cpu=XXX,pid=YYY,comm=ZZZ
Are you using this just for testing, or do you plan to get this output?
Context: netconsole outputs the message in a different way, similarly to the
printk dictionary. I.e, taskname and cpu come after, one entry per line:
<message>
SUBSYSTEM=net
DEVICE=+pci:0000:00:1f.6
cpu=42
taskname=NetworkManager
...
I would like to keep the same format, given users might be used to this format
already, where netconsole grabs teh cpu,pid,comm data and massage it before
outputing. Something as:
static int sysdata_append_taskname(struct netconsole_target *nt, int offset,
struct nbcon_write_context *wctxt)
{
return scnprintf(&nt->sysdata[offset],
MAX_EXTRADATA_ENTRY_LEN, " taskname=%s\n",
- current->comm);
+ wctxt->msg_comm);
}
Here is the full patch I was using to test the integration of netconsole and
the previous printk patch:
https://github.com/leitao/linux/commit/4175dc10719a15844b3a0bd7aa38158a913181a3
On Fri 2026-01-16 10:07:08, Breno Leitao wrote:
> Hello Petr,
>
> On Fri, Jan 16, 2026 at 04:53:48PM +0100, Petr Mladek wrote:
> > > Otherwise, it looks good to me.
> > >
> > > I tried to update your patch with the above proposal to see how
> > > it looks and I got:
> >
> > The change seems to work. I have tested it with the following patch:
>
> First of all, *thank you* so much for spending your time on it, this is
> helpful.
You are welcome.
> > Then the extended console format should show also:
> >
> > ,cpu=XXX,pid=YYY,comm=ZZZ
>
> Are you using this just for testing, or do you plan to get this output?
I used this just for testing. But it looks like a good variant for me.
Note that the above is /dev/kmsg output. It would show dev_printk()
messages the following way:
6,295,1164587,-,caller=T1,cpu=10,pid=1,comm=swapper/0;pci 0000:00:02.1: enabling Extended Tags
SUBSYSTEM=pci
DEVICE=+pci:0000:00:02.1
6,296,1167287,-,caller=T1,cpu=10,pid=1,comm=swapper/0;pci 0000:00:02.2: [1b36:000c] type 01 class 0x060400 PCIe Root Port
SUBSYSTEM=pci
DEVICE=+pci:0000:00:02.2
We would need to use another format for (slow) consoles, for example:
<level>[timestamp][Cxxx][context]comm[pid] message
, where:
+ [Cxxx] would show cpu number like the current context field, e.g [ C123]
+ [context] would show context, ideal in some existing format. But
I know only about lockdep format which looks a bit hard to
understand for me.
For example, it might be, for example [TC,HD] for a task context
with hard irqs disabled.
+ comm[pid] is inspired by the existing messages passed from systemd, e.g.
<30>[ 5.317305][ T1] systemd[1]: Starting Journal Service...
<30>[ 5.349000][ T1] systemd[1]: Starting Load Kernel Modules...
But I guess that this might be long bikesheding about this.
> Context: netconsole outputs the message in a different way, similarly to the
> printk dictionary. I.e, taskname and cpu come after, one entry per line:
>
> <message>
> SUBSYSTEM=net
> DEVICE=+pci:0000:00:1f.6
> cpu=42
> taskname=NetworkManager
> ...
I see. Honestly, I never liked the way how dictionary was printed.
It used another syntax than loglevel, sequence id, and timestamp.
It might be confusing and complicate parsing.
But it is a personal opinion. Others might like it because
it might be easier for human eyes parsing.
IMHO, the information needs some parsing anyway to make it human readable:
+ people do not know the log level meaning out of head
+ message id is there primary to detect lost messages
+ timestamp needs conversion, definitely
Sigh, the use of lower case letters for "cpu" and "taskname" made it
even more inconsistent. I would voted against it if I did the review ;-)
> I would like to keep the same format, given users might be used to this format
> already, where netconsole grabs teh cpu,pid,comm data and massage it before
> outputing. Something as:
>
> static int sysdata_append_taskname(struct netconsole_target *nt, int offset,
> struct nbcon_write_context *wctxt)
> {
> return scnprintf(&nt->sysdata[offset],
> MAX_EXTRADATA_ENTRY_LEN, " taskname=%s\n",
> - current->comm);
> + wctxt->msg_comm);
> }
I see. I think that you could keep it for now. It might take quite
some time until we integrate this for /dev/kmsg, ...
> Here is the full patch I was using to test the integration of netconsole and
> the previous printk patch:
>
> https://github.com/leitao/linux/commit/4175dc10719a15844b3a0bd7aa38158a913181a3
BTW.1: I see that netconsole actually does not show pid. So that we do not
need the trick with caller_id2. But people might want to add it in
the future.
I do not have strong opinion about it. We could change it
anytime later if we did not export the new fields for crash
dump, via the VMCOREINFO_OFFSET() macro.
BTW.2: I also noticed that sysdata_append_msgid() uses netconsole-specific
message counter.
Note that each message has its own sequence number. It is the
.seq member in struct printk_info. It is printed in the extended
console output, see info_print_ext_header(). So it is printed
even on netconsole when this extended format is used.
I wonder if the netconsole-specific counter was added
intentionally.
Best Regards,
Petr
Hello Petr, On Mon, Jan 19, 2026 at 03:00:11PM +0100, Petr Mladek wrote: > > Context: netconsole outputs the message in a different way, similarly to the > > printk dictionary. I.e, taskname and cpu come after, one entry per line: > > > > <message> > > SUBSYSTEM=net > > DEVICE=+pci:0000:00:1f.6 > > cpu=42 > > taskname=NetworkManager > > ... > > I see. Honestly, I never liked the way how dictionary was printed. > It used another syntax than loglevel, sequence id, and timestamp. > It might be confusing and complicate parsing. > > But it is a personal opinion. Others might like it because > it might be easier for human eyes parsing. > > IMHO, the information needs some parsing anyway to make it human readable: > > + people do not know the log level meaning out of head > + message id is there primary to detect lost messages > + timestamp needs conversion, definitely > > Sigh, the use of lower case letters for "cpu" and "taskname" made it > even more inconsistent. I would voted against it if I did the review ;-) Me too. ;-) At least, we can use it to differentiate what is coming from pritnk dictionary and netconsole. > > Here is the full patch I was using to test the integration of netconsole and > > the previous printk patch: > > > > https://github.com/leitao/linux/commit/4175dc10719a15844b3a0bd7aa38158a913181a3 > > BTW.1: I see that netconsole actually does not show pid. So that we do not > need the trick with caller_id2. But people might want to add it in > the future. Correct, I haven't found the pid important when aggregating messages in the a fleet of hosts. > BTW.2: I also noticed that sysdata_append_msgid() uses netconsole-specific > message counter. > > Note that each message has its own sequence number. It is the > .seq member in struct printk_info. It is printed in the extended > console output, see info_print_ext_header(). So it is printed > even on netconsole when this extended format is used. > > I wonder if the netconsole-specific counter was added > intentionally. The addition was intentional. The purpose was to monitor the number of lost netconsole messages. Originally we were using printk seq number to track "lost" message, later we discovered that some message numbers were never sent to netconsole , either due to different loglevel or supressed message. Thus, using .seq was not useful to track lost netconsole message. As a result, netconsole now increments the sequence number only when a packet is sent over the wire. Therefore, any gap in the "sequence" indicates that a packet was lost. Back o this current patch, I've tested it internally and run a test for hours without any current issue in terms of task->comm/cpu. How would you prefer to proceed to get the patch in? Thanks --breno
On Mon 2026-01-19 08:34:42, Breno Leitao wrote: > Hello Petr, > > On Mon, Jan 19, 2026 at 03:00:11PM +0100, Petr Mladek wrote: > > > Context: netconsole outputs the message in a different way, similarly to the > > > printk dictionary. I.e, taskname and cpu come after, one entry per line: > > > > > > <message> > > > SUBSYSTEM=net > > > DEVICE=+pci:0000:00:1f.6 > > > cpu=42 > > > taskname=NetworkManager > > > ... > > > > BTW.1: I see that netconsole actually does not show pid. So that we do not > > need the trick with caller_id2. But people might want to add it in > > the future. > > Correct, I haven't found the pid important when aggregating messages in > the a fleet of hosts. Good to know. > > BTW.2: I also noticed that sysdata_append_msgid() uses netconsole-specific > > message counter. > > > > Note that each message has its own sequence number. It is the > > .seq member in struct printk_info. It is printed in the extended > > console output, see info_print_ext_header(). So it is printed > > even on netconsole when this extended format is used. > > > > I wonder if the netconsole-specific counter was added > > intentionally. > > The addition was intentional. The purpose was to monitor the number of > lost netconsole messages. > > Originally we were using printk seq number to track "lost" message, later > we discovered that some message numbers were never sent to netconsole > , either due to different loglevel or supressed message. Thus, using > .seq was not useful to track lost netconsole message. > > As a result, netconsole now increments the sequence number only when > a packet is sent over the wire. Therefore, any gap in the "sequence" > indicates that a packet was lost. Makes perfect sense. > Back o this current patch, I've tested it internally and run a test for > hours without any current issue in terms of task->comm/cpu. > How would you prefer to proceed to get the patch in? Is the netconsole part ready for mainline? If yes, I would suggest to send the full patchset for review and it might go in via the networking tree. If no, then we could try to get in at least the printk part for 6.20. I would personally use the variant with caller_id2 just to be on the safe side. Note that AFAIK, there are no conflicting changes on the printk side floating around. Best Regards, Petr
On 2026-01-20, Petr Mladek <pmladek@suse.com> wrote: > Is the netconsole part ready for mainline? > > If yes, I would suggest to send the full patchset for review and it > might go in via the networking tree. > > If no, then we could try to get in at least the printk part for > 6.20. I would personally use the variant with caller_id2 just to be on > the safe side. I am also fine with these changes (and caller_id2). Please add me CC when submitting the official patches. John
On Tue, Jan 20, 2026 at 09:59:16AM +0100, Petr Mladek wrote: > On Mon 2026-01-19 08:34:42, Breno Leitao wrote: > > Back o this current patch, I've tested it internally and run a test for > > hours without any current issue in terms of task->comm/cpu. > > How would you prefer to proceed to get the patch in? > > Is the netconsole part ready for mainline? > > If yes, I would suggest to send the full patchset for review and > it might go in via the networking tree. Yes, it is. I will focus on it today, then! Thanks --breno
On Fri 2026-01-09 14:29:54, Petr Mladek wrote:
> On Thu 2026-01-08 17:56:44, John Ogness wrote:
> > On 2026-01-08, Breno Leitao <leitao@debian.org> wrote:
> > > On Wed, Jan 07, 2026 at 08:58:39AM -0800, Breno Leitao wrote:
> > > This is what I am thinking about. How bad is it?
> > >
> > > (I've also implemented the netconsole part as well, so, if you want to
> > > have a tree, you can find it in
> > > https://github.com/leitao/linux/tree/execution_context)
> >
> > Thanks. It is very helpful to see how you intend to use it.
> >
> > > commit fe79961da6cabe42343185cf1a7308162bf6bad3
> > > Author: Breno Leitao <leitao@debian.org>
> > > Date: Thu Jan 8 03:00:46 2026 -0800
> > >
> > > printk: Add execution context (PID/CPU) to dev_printk_info
> > >
> > > Extend struct dev_printk_info to include the task PID and CPU number
> > > where printk messages originate. This information is captured at
> > > vprintk_store() time and propagated through printk_message to
> > > nbcon_write_context, making it available to nbcon console drivers.
> > >
> > > This is useful for consoles like netconsole that want to include
> > > execution context in their output, allowing correlation of messages
> > > with specific tasks and CPUs regardless of where the console driver
> > > actually runs.
> > >
> > > The feature is controlled by CONFIG_PRINTK_EXECUTION_CTX, which is
> > > automatically selected by CONFIG_NETCONSOLE_DYNAMIC. When disabled,
> > > the helper functions compile to no-ops with no overhead.
> > >
> > > Suggested-by: John Ogness <john.ogness@linutronix.de>
> > > Signed-off-by: Breno Leitao <leitao@debian.org>
> > >
> > > diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> > > index ac12eaf11755..e6a9369be202 100644
> > > --- a/drivers/net/Kconfig
> > > +++ b/drivers/net/Kconfig
> > > @@ -341,6 +341,7 @@ config NETCONSOLE_DYNAMIC
> > > bool "Dynamic reconfiguration of logging targets"
> > > depends on NETCONSOLE && SYSFS && CONFIGFS_FS && \
> > > !(NETCONSOLE=y && CONFIGFS_FS=m)
> > > + select PRINTK_EXECUTION_CTX
> > > help
> > > This option enables the ability to dynamically reconfigure target
> > > parameters (interface, IP addresses, port numbers, MAC addresses)
> > > diff --git a/include/linux/console.h b/include/linux/console.h
> > > index fc9f5c5c1b04..c724f59f96e6 100644
> > > --- a/include/linux/console.h
> > > +++ b/include/linux/console.h
> > > @@ -298,12 +298,18 @@ struct nbcon_context {
> > > * @outbuf: Pointer to the text buffer for output
> > > * @len: Length to write
> > > * @unsafe_takeover: If a hostile takeover in an unsafe state has occurred
> > > + * @pid: PID of the task that generated the message
> > > + * @cpu: CPU on which the message was generated
> > > */
> > > struct nbcon_write_context {
> > > struct nbcon_context __private ctxt;
> > > char *outbuf;
> > > unsigned int len;
> > > bool unsafe_takeover;
> > > +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> > > + pid_t pid;
> > > + int cpu;
> > > +#endif
> >
> > Something like msg_pid/msg_cpu or printk_pid/printk_cpu might be better
> > to make it clear we are not talking about _this_ context. This struct is
> > used by code outside of the printk subsystem, which is why I think it
> > needs to be more obvious what these represent.
> >
> > @Petr: Any suggestions for names (assuming this is even acceptable)?
> >
> > > };
> > >
> > > /**
> > > diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h
> > > index eb2094e43050..42ee778b29dd 100644
> > > --- a/include/linux/dev_printk.h
> > > +++ b/include/linux/dev_printk.h
> > > @@ -27,6 +27,10 @@ struct device;
> > > struct dev_printk_info {
> > > char subsystem[PRINTK_INFO_SUBSYSTEM_LEN];
> > > char device[PRINTK_INFO_DEVICE_LEN];
> > > +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> > > + pid_t pid;
> >
> > I am not happy about this being resolved by the netconsole printer to
> > get the task name. A lot can happen between now and then. But I also
> > shudder at the thought of making dev_printk_info much larger. This is
> > already a horrible waste of memory (which I talked about here[0]).
> >
> > I also do not think dev_printk_info is the appropriate place to store
> > this information. These new fields are not related to the dev_printk
> > API. They belong in printk_info.
> >
> > > + int cpu;
> > > +#endif
> > > };
> > >
> > > #ifdef CONFIG_PRINTK
> > > diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
> > > index 5f5f626f4279..81e5cd336677 100644
> > > --- a/kernel/printk/internal.h
> > > +++ b/kernel/printk/internal.h
> > > @@ -287,6 +287,10 @@ struct printk_message {
> > > unsigned int outbuf_len;
> > > u64 seq;
> > > unsigned long dropped;
> > > +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> > > + pid_t pid;
> > > + int cpu;
> > > +#endif
> > > };
> > >
> > > bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
> > > diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
> > > index 3fa403f9831f..2465fafd7727 100644
> > > --- a/kernel/printk/nbcon.c
> > > +++ b/kernel/printk/nbcon.c
> > > @@ -946,6 +946,18 @@ void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt)
> > > }
> > > EXPORT_SYMBOL_GPL(nbcon_reacquire_nobuf);
> > >
> > > +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> > > +static inline void wctxt_load_execution_ctx(struct nbcon_write_context *wctxt,
> > > + struct printk_message *pmsg)
> > > +{
> > > + wctxt->pid = pmsg->pid;
> > > + wctxt->cpu = pmsg->cpu;
> > > +}
> > > +#else
> > > +static inline void wctxt_load_execution_ctx(struct nbcon_write_context *wctxt,
> > > + struct printk_message *pmsg) {}
> > > +#endif
> > > +
> > > /**
> > > * nbcon_emit_next_record - Emit a record in the acquired context
> > > * @wctxt: The write context that will be handed to the write function
> > > @@ -1048,6 +1060,8 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_a
> > > /* Initialize the write context for driver callbacks. */
> > > nbcon_write_context_set_buf(wctxt, &pmsg.pbufs->outbuf[0], pmsg.outbuf_len);
> > >
> > > + wctxt_load_execution_ctx(wctxt, &pmsg);
> > > +
> > > if (use_atomic)
> > > con->write_atomic(con, wctxt);
> > > else
> > > diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> > > index 1d765ad242b8..ff47b5384f20 100644
> > > --- a/kernel/printk/printk.c
> > > +++ b/kernel/printk/printk.c
> > > @@ -2213,6 +2213,26 @@ static u16 printk_sprint(char *text, u16 size, int facility,
> > > return text_len;
> > > }
> > >
> > > +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> > > +static inline void printk_save_execution_ctx(struct dev_printk_info *dev_info)
> > > +{
> > > + dev_info->pid = task_pid_nr(current);
> > > + dev_info->cpu = smp_processor_id();
> > > +}
> > > +
> > > +static inline void pmsg_load_execution_ctx(struct printk_message *pmsg,
> > > + const struct dev_printk_info *dev_info)
> > > +{
> > > + pmsg->pid = dev_info->pid;
> > > + pmsg->cpu = dev_info->cpu;
> > > +}
> > > +#else
> > > +static inline void printk_save_execution_ctx(struct dev_printk_info *dev_info) {}
> > > +
> > > +static inline void pmsg_load_execution_ctx(struct printk_message *pmsg,
> > > + const struct dev_printk_info *dev_info) {}
> > > +#endif
> > > +
> > > __printf(4, 0)
> > > int vprintk_store(int facility, int level,
> > > const struct dev_printk_info *dev_info,
> > > @@ -2320,6 +2340,7 @@ int vprintk_store(int facility, int level,
> > > r.info->caller_id = caller_id;
> > > if (dev_info)
> > > memcpy(&r.info->dev_info, dev_info, sizeof(r.info->dev_info));
> > > + printk_save_execution_ctx(&r.info->dev_info);
> > >
> > > /* A message without a trailing newline can be continued. */
> > > if (!(flags & LOG_NEWLINE))
> > > @@ -3002,6 +3023,7 @@ bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
> > > pmsg->seq = r.info->seq;
> > > pmsg->dropped = r.info->seq - seq;
> > > force_con = r.info->flags & LOG_FORCE_CON;
> > > + pmsg_load_execution_ctx(pmsg, &r.info->dev_info);
> > >
> > > /*
> > > * Skip records that are not forced to be printed on consoles and that
> > > diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> > > index ba36939fda79..197022099dd8 100644
> > > --- a/lib/Kconfig.debug
> > > +++ b/lib/Kconfig.debug
> > > @@ -35,6 +35,17 @@ config PRINTK_CALLER
> > > no option to enable/disable at the kernel command line parameter or
> > > sysfs interface.
> > >
> > > +config PRINTK_EXECUTION_CTX
> > > + bool
> > > + depends on PRINTK
> > > + help
> > > + This option extends struct dev_printk_info to include extra execution
> >
> > It should extend printk_info instead.
> >
> > > + context in pritnk, such as task PID and CPU number from where the
> >
> > printk
> >
> > > + message originated. This is useful for correlating device messages
> >
> > Rather than "device messages" I suggest "printk messages".
> >
> > > + with specific execution contexts.
> > > +
> > > + One of the main user for this config is netconsole.
> >
> > Rather than saying which drivers might support this, it would probably
> > be better to make it explicit. For example introducing a new config
> > like:
> >
> > CONFIG_CONSOLE_HAS_EXECUTION_CTX
> >
> > that can only be selected by the console driver (or in your case, the
> > console driver option NETCONSOLE_DYNAMIC). Then make
> > PRINTK_EXECUTION_CTX depend only on CONSOLE_HAS_EXECUTION_CTX. That way
> > it is only available if the console driver supports it.
> >
> > > +
> > > config STACKTRACE_BUILD_ID
> > > bool "Show build ID information in stacktraces"
> > > depends on PRINTK
> >
> > While this patch might be "good enough" to preserve the current
> > CONFIG_NETCONSOLE_DYNAMIC features for NBCON, I am not happy about it:
> >
> > 1. It relies on the printer context being able to determine context
> > information about the printk() caller. I would prefer adding the task
> > name directly to printk_info instead.
>
> Good question. I think that both appraches might have users.
> I see the machines on the opposite sides of a spectrum.
>
> a) Huge machines, with hunderds of CPUs and TBs of RAM, might afford
> allocation of more space for kernel messages. And it might be even
> useful when they run containers which are quickly comming and
> going.
>
> b) Small embeded systems want to keep kernel message buffer as small
> as possible. I guess that they mostly run just few processes all
> the time. So the mapping PID <-> COMM is stable.
>
> Let's see how complicated it would be to make this configurable.
>
> > 2. It adds information to printk records that only netconsole can
> > use. If we want other consoles to support this, we would need to modify
> > all the console code. I would prefer it is dynamically added to the
> > generic printing text. We could do this by extending
> > msg_print_ext_body() based on some user configuration. But it would
> > conflict with the current netconsole format.
> >
> > Despite my concerns, adding the PID and CPU information is generally
> > useful. So I am not against expanding printk_info. My concerns are more
> > about how this information is being used by netconsole.
>
> I agree. I see how useful is even the current print_caller() which
> shows either PID or CPU number depending on the context. And it does
> not make sense to store this info twice.
>
> If we were adding this info, I would add it for all users, definitely.
> We are going to touch the internal printk ringbuffer format anyway.
> Now, the main question is how far we want to go.
>
> I see the following possibilities:
>
> A) caller_id -> pid + cpu + atomic/task context bit
> ===================================================
>
> A) caller_id -> pid + cpu + contex
^
Should have been B /o\
> ==================================
>
> Same as above but the caller context info is stored separately and
> might allow to distinguish more types. Something like:
>
> diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h
> index 4ef81349d9fb..44aa60a3f84c 100644
> --- a/kernel/printk/printk_ringbuffer.h
> +++ b/kernel/printk/printk_ringbuffer.h
> @@ -9,6 +9,19 @@
> #include <linux/stddef.h>
> #include <linux/types.h>
>
> +#define PRINTK_CALLER_CTXT_PREEMPT_BIT 1
> +#define PRINTK_CALLER_CTXT_SOFTIRQ_BIT 2
> +#define PRINTK_CALLER_CTXT_HARDIRQ_BIT 3
> +#define PRINTK_CALLER_CTXT_NMI 4
> +/* This is not supported on all platforms, see irqs_disabled() */
> +#define PRINTK_CALLER_CTXT_IRQS_DISABLED 5
> +
> +struct printk_caller {
> + u8 ctxt; /* caller context: task, irq, ... */
> + pid_t pid; /* caller pid */
> + int cpu; /* caller CPU number */
> +};
> +
> /*
> * Meta information about each stored message.
> *
> @@ -22,8 +35,8 @@ struct printk_info {
> u8 facility; /* syslog facility */
> u8 flags:5; /* internal record flags */
> u8 level:3; /* syslog level */
> - u32 caller_id; /* thread id or processor id */
>
> + struct printk_caller caller;
> struct dev_printk_info dev_info;
> };
>
>
> C) caller_id -> pid + cpu + comm + atomic/task context bit
> ==========================================================
>
> Similar to A and B but add also
>
> char comm[TASK_COMM_LEN];
>
> into struct printk_caller.
>
>
> D) caller_id -> pid + cpu + comm + atomic/task context bit
> and move printk_caller + printk_dev_info into text buffer
> as suggested as mentioned at
> https://lore.kernel.org/lkml/84y10vz7ty.fsf@jogness.linutronix.de
> ====================================================================
>
> My opinion:
> ===========
>
> I personally think that the approach B) is the best compromise for now
> because:
Note that my proposed code shown only how to store the information
so that it was available for the netconsole.
Once we decide how to store it then we could talk about how to show
it on other consoles and via /dev/kmsg. All the proposals allowed
to keep the output backward compatible for now.
Best Regards,
Petr
On Thu, Jan 08, 2026 at 05:56:44PM +0100, John Ogness wrote:
> On 2026-01-08, Breno Leitao <leitao@debian.org> wrote:
>
> > +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> > + pid_t pid;
> > + int cpu;
> > +#endif
>
> Something like msg_pid/msg_cpu or printk_pid/printk_cpu might be better
> to make it clear we are not talking about _this_ context. This struct is
> used by code outside of the printk subsystem, which is why I think it
> needs to be more obvious what these represent.
Acknowledged.
> @Petr: Any suggestions for names (assuming this is even acceptable)?
>
> > };
> >
> > /**
> > diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h
> > index eb2094e43050..42ee778b29dd 100644
> > --- a/include/linux/dev_printk.h
> > +++ b/include/linux/dev_printk.h
> > @@ -27,6 +27,10 @@ struct device;
> > struct dev_printk_info {
> > char subsystem[PRINTK_INFO_SUBSYSTEM_LEN];
> > char device[PRINTK_INFO_DEVICE_LEN];
> > +#ifdef CONFIG_PRINTK_EXECUTION_CTX
> > + pid_t pid;
>
> I am not happy about this being resolved by the netconsole printer to
> get the task name. A lot can happen between now and then. But I also
> shudder at the thought of making dev_printk_info much larger. This is
> already a horrible waste of memory (which I talked about here[0]).
I encountered the same dilemma. There's also another trade-off: passing
the context from the msg to netconsole requires some string copies.
Instead of simple assignments like "pmsg->msg_pid = info->msg_pid" and
"wctxt->msg_pid = pmsg->msg_pid", we would need to use strcpy.
I'm fine with either approach — happy to defer to your preference.
> I also do not think dev_printk_info is the appropriate place to store
> this information. These new fields are not related to the dev_printk
> API. They belong in printk_info.
Acknowledged.
> > + This option extends struct dev_printk_info to include extra execution
>
> It should extend printk_info instead.
Acknowledged.
>
> > + context in pritnk, such as task PID and CPU number from where the
>
> printk
>
> > + message originated. This is useful for correlating device messages
>
> Rather than "device messages" I suggest "printk messages".
Acknowledged.
>
> > + with specific execution contexts.
> > +
> > + One of the main user for this config is netconsole.
>
> Rather than saying which drivers might support this, it would probably
> be better to make it explicit. For example introducing a new config
> like:
>
> CONFIG_CONSOLE_HAS_EXECUTION_CTX
>
> that can only be selected by the console driver (or in your case, the
> console driver option NETCONSOLE_DYNAMIC). Then make
> PRINTK_EXECUTION_CTX depend only on CONSOLE_HAS_EXECUTION_CTX. That way
> it is only available if the console driver supports it.
Good idea. This creates a transitional layer between the context and
printk's internal configuration: consoles explicitly select
CONSOLE_HAS_EXECUTION_CTX, which in turn enables PRINTK_EXECUTION_CTX.
> > +
> > config STACKTRACE_BUILD_ID
> > bool "Show build ID information in stacktraces"
> > depends on PRINTK
>
> While this patch might be "good enough" to preserve the current
> CONFIG_NETCONSOLE_DYNAMIC features for NBCON, I am not happy about it:
>
> 1. It relies on the printer context being able to determine context
> information about the printk() caller. I would prefer adding the task
> name directly to printk_info instead.
That would be straightforward to implement and would simplify things for
console users like netconsole. The trade-off is increased memory usage
in printk_info, printk_message, and nbcon_write_context, plus some
additional strscpy calls.
I don't have a strong preference here.
> 2. It adds information to printk records that only netconsole can use.
> If we want other consoles to support this, we would need to modify
> all the console code. I would prefer it is dynamically added to the
> generic printing text. We could do this by extending
> msg_print_ext_body() based on some user configuration.
This would address the problem for other consoles, but based on my
understanding of earlier discussions [0], that doesn't seem to be the
direction you guys decided.
Link: https://lore.kernel.org/lkml/20200904082438.20707-1-changki.kim@samsung.com/ [0]
> But it would conflict with the current netconsole format.
Good point. Let me provide some additional context that may help us find
a better solution.
Netconsole's sysdata and userdata append data to printk messages in a
similar fashion to the dictionary/dev_printk_info — essentially an
extension of dev_printk_info data (though with one regrettable
inconsistency: the keys are lowercase).
Here's an example of a netconsole message with dev_printk_info plus sysdata:
<message>
SUBSYSTEM=net
DEVICE=+pci:0000:00:1f.6
cpu=42
taskname=NetworkManager
...
So while the format is similar, the differences are significant enough
that moving cpu/taskname from netconsole to printk/dev_printk_info
wouldn't be trivial.
> Despite my concerns, adding the PID and CPU information is generally
> useful. So I am not against expanding printk_info. My concerns are
> more about how this information is being used by netconsole.
>
> @Petr: I am really curious to hear your thoughts on this.
Thanks for the feedback and for helping me work through this. Let's see
what @Petr has to say, and then we can decide how to proceed.
--breno
On 12/22/25 3:52 PM, Breno Leitao wrote:
> This series adds support for the nbcon (new buffer console) infrastructure
> to netconsole, enabling lock-free, priority-based console operations that
> are safer in crash scenarios.
>
> The implementation is introduced in three steps:
>
> 1) Refactor the message fragmentation logic into a reusable helper function
> 2) Extend nbcon support to non-extended (basic) consoles using the same
> infrastructure.
>
> The initial discussion about it appeared a while ago in [1], in order to
> solve Mike's HARDIRQ-safe -> HARDIRQ-unsafe lock order warning, and the root
> cause is that some hosts were calling IRQ unsafe locks from inside console
> lock.
>
> At that time, we didn't have the CON_NBCON_ATOMIC_UNSAFE yet. John
> kindly implemented CON_NBCON_ATOMIC_UNSAFE in 187de7c212e5 ("printk:
> nbcon: Allow unsafe write_atomic() for panic"), and now we can
> implement netconsole on top of nbcon.
>
> Important to note that netconsole continues to call netpoll and the
> network TX helpers with interrupt disable, given the TX are called with
> target_list_lock.
>
> Link:
> https://lore.kernel.org/all/b2qps3uywhmjaym4mht2wpxul4yqtuuayeoq4iv4k3zf5wdgh3@tocu6c7mj4lt/
> [1]
>
> Signed-off-by: Breno Leitao <leitao@debian.org>
## Form letter - net-next-closed
The net-next tree is closed for new drivers, features, code refactoring
and optimizations due to the merge window and the winter break. We are
currently accepting bug fixes only.
Please repost when net-next reopens after Jan 2nd.
RFC patches sent for review only are obviously welcome at any time.
---
To save me a few moments, I will not send the same messages in reply to
the others pending net-next patches of yours, but this still applies :-P
On Tue, Dec 23, 2025 at 08:12:08AM +0100, Paolo Abeni wrote:
> On 12/22/25 3:52 PM, Breno Leitao wrote:
> > This series adds support for the nbcon (new buffer console) infrastructure
> > to netconsole, enabling lock-free, priority-based console operations that
> > are safer in crash scenarios.
> >
> > The implementation is introduced in three steps:
> >
> > 1) Refactor the message fragmentation logic into a reusable helper function
> > 2) Extend nbcon support to non-extended (basic) consoles using the same
> > infrastructure.
> >
> > The initial discussion about it appeared a while ago in [1], in order to
> > solve Mike's HARDIRQ-safe -> HARDIRQ-unsafe lock order warning, and the root
> > cause is that some hosts were calling IRQ unsafe locks from inside console
> > lock.
> >
> > At that time, we didn't have the CON_NBCON_ATOMIC_UNSAFE yet. John
> > kindly implemented CON_NBCON_ATOMIC_UNSAFE in 187de7c212e5 ("printk:
> > nbcon: Allow unsafe write_atomic() for panic"), and now we can
> > implement netconsole on top of nbcon.
> >
> > Important to note that netconsole continues to call netpoll and the
> > network TX helpers with interrupt disable, given the TX are called with
> > target_list_lock.
> >
> > Link:
> > https://lore.kernel.org/all/b2qps3uywhmjaym4mht2wpxul4yqtuuayeoq4iv4k3zf5wdgh3@tocu6c7mj4lt/
> > [1]
> >
> > Signed-off-by: Breno Leitao <leitao@debian.org>
>
> ## Form letter - net-next-closed
>
> The net-next tree is closed for new drivers, features, code refactoring
> and optimizations due to the merge window and the winter break. We are
> currently accepting bug fixes only.
>
> Please repost when net-next reopens after Jan 2nd.
>
> RFC patches sent for review only are obviously welcome at any time.
> ---
> To save me a few moments, I will not send the same messages in reply to
> the others pending net-next patches of yours, but this still applies :-P
Shame on me! I haven't paid attention to the announcement emails. Fixed
it now.
Sorry for the noise,
--breno
© 2016 - 2026 Red Hat, Inc.