mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-03-03 18:28:01 +01:00
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: Petr Mladek <pmladek@suse.com> Reviewed-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Breno Leitao <leitao@debian.org> Reviewed-by: John Ogness <john.ogness@linutronix.de> Link: https://patch.msgid.link/20260206-nbcon-v7-1-62bda69b1b41@debian.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
ad1f18e985
commit
60325c27d3
@@ -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)
|
||||
|
||||
@@ -298,12 +298,20 @@ 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
|
||||
* @cpu: CPU on which the message was generated
|
||||
* @pid: PID of the task that generated the message
|
||||
* @comm: Name of the task that generated the message
|
||||
*/
|
||||
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
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -281,12 +281,20 @@ 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.
|
||||
* @cpu: CPU on which the message was generated.
|
||||
* @pid: PID of the task that generated the message
|
||||
* @comm: Name of the task that generated the message.
|
||||
*/
|
||||
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,
|
||||
|
||||
@@ -946,6 +946,20 @@ void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nbcon_reacquire_nobuf);
|
||||
|
||||
#ifdef CONFIG_PRINTK_EXECUTION_CTX
|
||||
static 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, sizeof(wctxt->comm));
|
||||
static_assert(sizeof(wctxt->comm) == sizeof(pmsg->comm));
|
||||
}
|
||||
#else
|
||||
static 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 +1062,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
|
||||
|
||||
@@ -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 u32 printk_caller_id2(void)
|
||||
{
|
||||
return !in_task() ? task_pid_nr(current) :
|
||||
CALLER_ID_MASK + smp_processor_id();
|
||||
}
|
||||
|
||||
static 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 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,28 @@ static u16 printk_sprint(char *text, u16 size, int facility,
|
||||
return text_len;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PRINTK_EXECUTION_CTX
|
||||
static void printk_store_execution_ctx(struct printk_info *info)
|
||||
{
|
||||
info->caller_id2 = printk_caller_id2();
|
||||
get_task_comm(info->comm, current);
|
||||
}
|
||||
|
||||
static 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, sizeof(pmsg->comm));
|
||||
static_assert(sizeof(pmsg->comm) == sizeof(info->comm));
|
||||
}
|
||||
#else
|
||||
static void printk_store_execution_ctx(struct printk_info *info) {}
|
||||
|
||||
static 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 +2370,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 +3053,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
|
||||
|
||||
@@ -23,6 +23,11 @@ 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 */
|
||||
/* name of the task that generated the message */
|
||||
char comm[TASK_COMM_LEN];
|
||||
#endif
|
||||
|
||||
struct dev_printk_info dev_info;
|
||||
};
|
||||
|
||||
@@ -35,6 +35,18 @@ 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 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
|
||||
|
||||
Reference in New Issue
Block a user