Commit c4703acd authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'printk-for-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk

Pull printk updates from Petr Mladek:

 - Allow to sort mixed lines by an extra information about the caller

 - Remove no longer used LOG_PREFIX.

 - Some clean up and documentation update.

* tag 'printk-for-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk:
  printk/docs: Add extra integer types to printk-formats
  printk: Remove no longer used LOG_PREFIX.
  lib/vsprintf: Remove %pCr remnant in comment
  printk: Pass caller information to log_store().
  printk: Add caller information to printk() output.
parents a448c643 943ca6ad
...@@ -13,6 +13,10 @@ Integer types ...@@ -13,6 +13,10 @@ Integer types
If variable is of Type, use printk format specifier: If variable is of Type, use printk format specifier:
------------------------------------------------------------ ------------------------------------------------------------
char %hhd or %hhx
unsigned char %hhu or %hhx
short int %hd or %hx
unsigned short int %hu or %hx
int %d or %x int %d or %x
unsigned int %u or %x unsigned int %u or %x
long %ld or %lx long %ld or %lx
...@@ -21,6 +25,10 @@ Integer types ...@@ -21,6 +25,10 @@ Integer types
unsigned long long %llu or %llx unsigned long long %llu or %llx
size_t %zu or %zx size_t %zu or %zx
ssize_t %zd or %zx ssize_t %zd or %zx
s8 %hhd or %hhx
u8 %hhu or %hhx
s16 %hd or %hx
u16 %hu or %hx
s32 %d or %x s32 %d or %x
u32 %u or %x u32 %u or %x
s64 %lld or %llx s64 %lld or %llx
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#define KERN_INFO KERN_SOH "6" /* informational */ #define KERN_INFO KERN_SOH "6" /* informational */
#define KERN_DEBUG KERN_SOH "7" /* debug-level messages */ #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
#define KERN_DEFAULT KERN_SOH "d" /* the default kernel loglevel */ #define KERN_DEFAULT "" /* the default kernel loglevel */
/* /*
* Annotation for a "continued" line of log printout (only done after a * Annotation for a "continued" line of log printout (only done after a
......
...@@ -18,7 +18,6 @@ static inline int printk_get_level(const char *buffer) ...@@ -18,7 +18,6 @@ static inline int printk_get_level(const char *buffer)
if (buffer[0] == KERN_SOH_ASCII && buffer[1]) { if (buffer[0] == KERN_SOH_ASCII && buffer[1]) {
switch (buffer[1]) { switch (buffer[1]) {
case '0' ... '7': case '0' ... '7':
case 'd': /* KERN_DEFAULT */
case 'c': /* KERN_CONT */ case 'c': /* KERN_CONT */
return buffer[1]; return buffer[1];
} }
......
...@@ -344,7 +344,6 @@ static int console_msg_format = MSG_FORMAT_DEFAULT; ...@@ -344,7 +344,6 @@ static int console_msg_format = MSG_FORMAT_DEFAULT;
enum log_flags { enum log_flags {
LOG_NEWLINE = 2, /* text ended with a newline */ LOG_NEWLINE = 2, /* text ended with a newline */
LOG_PREFIX = 4, /* text started with a prefix */
LOG_CONT = 8, /* text is a fragment of a continuation line */ LOG_CONT = 8, /* text is a fragment of a continuation line */
}; };
...@@ -356,6 +355,9 @@ struct printk_log { ...@@ -356,6 +355,9 @@ struct printk_log {
u8 facility; /* syslog facility */ u8 facility; /* syslog facility */
u8 flags:5; /* internal record flags */ u8 flags:5; /* internal record flags */
u8 level:3; /* syslog level */ u8 level:3; /* syslog level */
#ifdef CONFIG_PRINTK_CALLER
u32 caller_id; /* thread id or processor id */
#endif
} }
#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
__packed __aligned(4) __packed __aligned(4)
...@@ -422,7 +424,11 @@ static u64 exclusive_console_stop_seq; ...@@ -422,7 +424,11 @@ static u64 exclusive_console_stop_seq;
static u64 clear_seq; static u64 clear_seq;
static u32 clear_idx; static u32 clear_idx;
#ifdef CONFIG_PRINTK_CALLER
#define PREFIX_MAX 48
#else
#define PREFIX_MAX 32 #define PREFIX_MAX 32
#endif
#define LOG_LINE_MAX (1024 - PREFIX_MAX) #define LOG_LINE_MAX (1024 - PREFIX_MAX)
#define LOG_LEVEL(v) ((v) & 0x07) #define LOG_LEVEL(v) ((v) & 0x07)
...@@ -577,7 +583,7 @@ static u32 truncate_msg(u16 *text_len, u16 *trunc_msg_len, ...@@ -577,7 +583,7 @@ static u32 truncate_msg(u16 *text_len, u16 *trunc_msg_len,
} }
/* insert record into the buffer, discard old ones, update heads */ /* insert record into the buffer, discard old ones, update heads */
static int log_store(int facility, int level, static int log_store(u32 caller_id, int facility, int level,
enum log_flags flags, u64 ts_nsec, enum log_flags flags, u64 ts_nsec,
const char *dict, u16 dict_len, const char *dict, u16 dict_len,
const char *text, u16 text_len) const char *text, u16 text_len)
...@@ -625,6 +631,9 @@ static int log_store(int facility, int level, ...@@ -625,6 +631,9 @@ static int log_store(int facility, int level,
msg->ts_nsec = ts_nsec; msg->ts_nsec = ts_nsec;
else else
msg->ts_nsec = local_clock(); msg->ts_nsec = local_clock();
#ifdef CONFIG_PRINTK_CALLER
msg->caller_id = caller_id;
#endif
memset(log_dict(msg) + dict_len, 0, pad_len); memset(log_dict(msg) + dict_len, 0, pad_len);
msg->len = size; msg->len = size;
...@@ -688,12 +697,21 @@ static ssize_t msg_print_ext_header(char *buf, size_t size, ...@@ -688,12 +697,21 @@ static ssize_t msg_print_ext_header(char *buf, size_t size,
struct printk_log *msg, u64 seq) struct printk_log *msg, u64 seq)
{ {
u64 ts_usec = msg->ts_nsec; u64 ts_usec = msg->ts_nsec;
char caller[20];
#ifdef CONFIG_PRINTK_CALLER
u32 id = msg->caller_id;
snprintf(caller, sizeof(caller), ",caller=%c%u",
id & 0x80000000 ? 'C' : 'T', id & ~0x80000000);
#else
caller[0] = '\0';
#endif
do_div(ts_usec, 1000); do_div(ts_usec, 1000);
return scnprintf(buf, size, "%u,%llu,%llu,%c;", return scnprintf(buf, size, "%u,%llu,%llu,%c%s;",
(msg->facility << 3) | msg->level, seq, ts_usec, (msg->facility << 3) | msg->level, seq, ts_usec,
msg->flags & LOG_CONT ? 'c' : '-'); msg->flags & LOG_CONT ? 'c' : '-', caller);
} }
static ssize_t msg_print_ext_body(char *buf, size_t size, static ssize_t msg_print_ext_body(char *buf, size_t size,
...@@ -1038,6 +1056,9 @@ void log_buf_vmcoreinfo_setup(void) ...@@ -1038,6 +1056,9 @@ void log_buf_vmcoreinfo_setup(void)
VMCOREINFO_OFFSET(printk_log, len); VMCOREINFO_OFFSET(printk_log, len);
VMCOREINFO_OFFSET(printk_log, text_len); VMCOREINFO_OFFSET(printk_log, text_len);
VMCOREINFO_OFFSET(printk_log, dict_len); VMCOREINFO_OFFSET(printk_log, dict_len);
#ifdef CONFIG_PRINTK_CALLER
VMCOREINFO_OFFSET(printk_log, caller_id);
#endif
} }
#endif #endif
...@@ -1236,10 +1257,23 @@ static size_t print_time(u64 ts, char *buf) ...@@ -1236,10 +1257,23 @@ static size_t print_time(u64 ts, char *buf)
{ {
unsigned long rem_nsec = do_div(ts, 1000000000); unsigned long rem_nsec = do_div(ts, 1000000000);
return sprintf(buf, "[%5lu.%06lu] ", return sprintf(buf, "[%5lu.%06lu]",
(unsigned long)ts, rem_nsec / 1000); (unsigned long)ts, rem_nsec / 1000);
} }
#ifdef CONFIG_PRINTK_CALLER
static size_t print_caller(u32 id, char *buf)
{
char caller[12];
snprintf(caller, sizeof(caller), "%c%u",
id & 0x80000000 ? 'C' : 'T', id & ~0x80000000);
return sprintf(buf, "[%6s]", caller);
}
#else
#define print_caller(id, buf) 0
#endif
static size_t print_prefix(const struct printk_log *msg, bool syslog, static size_t print_prefix(const struct printk_log *msg, bool syslog,
bool time, char *buf) bool time, char *buf)
{ {
...@@ -1247,8 +1281,17 @@ static size_t print_prefix(const struct printk_log *msg, bool syslog, ...@@ -1247,8 +1281,17 @@ static size_t print_prefix(const struct printk_log *msg, bool syslog,
if (syslog) if (syslog)
len = print_syslog((msg->facility << 3) | msg->level, buf); len = print_syslog((msg->facility << 3) | msg->level, buf);
if (time) if (time)
len += print_time(msg->ts_nsec, buf + len); len += print_time(msg->ts_nsec, buf + len);
len += print_caller(msg->caller_id, buf + len);
if (IS_ENABLED(CONFIG_PRINTK_CALLER) || time) {
buf[len++] = ' ';
buf[len] = '\0';
}
return len; return len;
} }
...@@ -1752,6 +1795,12 @@ static inline void printk_delay(void) ...@@ -1752,6 +1795,12 @@ static inline void printk_delay(void)
} }
} }
static inline u32 printk_caller_id(void)
{
return in_task() ? task_pid_nr(current) :
0x80000000 + raw_smp_processor_id();
}
/* /*
* Continuation lines are buffered, and not committed to the record buffer * Continuation lines are buffered, and not committed to the record buffer
* until the line is complete, or a race forces it. The line fragments * until the line is complete, or a race forces it. The line fragments
...@@ -1761,7 +1810,7 @@ static inline void printk_delay(void) ...@@ -1761,7 +1810,7 @@ static inline void printk_delay(void)
static struct cont { static struct cont {
char buf[LOG_LINE_MAX]; char buf[LOG_LINE_MAX];
size_t len; /* length == 0 means unused buffer */ size_t len; /* length == 0 means unused buffer */
struct task_struct *owner; /* task of first print*/ u32 caller_id; /* printk_caller_id() of first print */
u64 ts_nsec; /* time of first print */ u64 ts_nsec; /* time of first print */
u8 level; /* log level of first message */ u8 level; /* log level of first message */
u8 facility; /* log facility of first message */ u8 facility; /* log facility of first message */
...@@ -1773,12 +1822,13 @@ static void cont_flush(void) ...@@ -1773,12 +1822,13 @@ static void cont_flush(void)
if (cont.len == 0) if (cont.len == 0)
return; return;
log_store(cont.facility, cont.level, cont.flags, cont.ts_nsec, log_store(cont.caller_id, cont.facility, cont.level, cont.flags,
NULL, 0, cont.buf, cont.len); cont.ts_nsec, NULL, 0, cont.buf, cont.len);
cont.len = 0; cont.len = 0;
} }
static bool cont_add(int facility, int level, enum log_flags flags, const char *text, size_t len) static bool cont_add(u32 caller_id, int facility, int level,
enum log_flags flags, const char *text, size_t len)
{ {
/* If the line gets too long, split it up in separate records. */ /* If the line gets too long, split it up in separate records. */
if (cont.len + len > sizeof(cont.buf)) { if (cont.len + len > sizeof(cont.buf)) {
...@@ -1789,7 +1839,7 @@ static bool cont_add(int facility, int level, enum log_flags flags, const char * ...@@ -1789,7 +1839,7 @@ static bool cont_add(int facility, int level, enum log_flags flags, const char *
if (!cont.len) { if (!cont.len) {
cont.facility = facility; cont.facility = facility;
cont.level = level; cont.level = level;
cont.owner = current; cont.caller_id = caller_id;
cont.ts_nsec = local_clock(); cont.ts_nsec = local_clock();
cont.flags = flags; cont.flags = flags;
} }
...@@ -1809,13 +1859,15 @@ static bool cont_add(int facility, int level, enum log_flags flags, const char * ...@@ -1809,13 +1859,15 @@ static bool cont_add(int facility, int level, enum log_flags flags, const char *
static size_t log_output(int facility, int level, enum log_flags lflags, const char *dict, size_t dictlen, char *text, size_t text_len) static size_t log_output(int facility, int level, enum log_flags lflags, const char *dict, size_t dictlen, char *text, size_t text_len)
{ {
const u32 caller_id = printk_caller_id();
/* /*
* If an earlier line was buffered, and we're a continuation * If an earlier line was buffered, and we're a continuation
* write from the same process, try to add it to the buffer. * write from the same context, try to add it to the buffer.
*/ */
if (cont.len) { if (cont.len) {
if (cont.owner == current && (lflags & LOG_CONT)) { if (cont.caller_id == caller_id && (lflags & LOG_CONT)) {
if (cont_add(facility, level, lflags, text, text_len)) if (cont_add(caller_id, facility, level, lflags, text, text_len))
return text_len; return text_len;
} }
/* Otherwise, make sure it's flushed */ /* Otherwise, make sure it's flushed */
...@@ -1828,12 +1880,13 @@ static size_t log_output(int facility, int level, enum log_flags lflags, const c ...@@ -1828,12 +1880,13 @@ static size_t log_output(int facility, int level, enum log_flags lflags, const c
/* If it doesn't end in a newline, try to buffer the current line */ /* If it doesn't end in a newline, try to buffer the current line */
if (!(lflags & LOG_NEWLINE)) { if (!(lflags & LOG_NEWLINE)) {
if (cont_add(facility, level, lflags, text, text_len)) if (cont_add(caller_id, facility, level, lflags, text, text_len))
return text_len; return text_len;
} }
/* Store it in the record log */ /* Store it in the record log */
return log_store(facility, level, lflags, 0, dict, dictlen, text, text_len); return log_store(caller_id, facility, level, lflags, 0,
dict, dictlen, text, text_len);
} }
/* Must be called under logbuf_lock. */ /* Must be called under logbuf_lock. */
...@@ -1867,9 +1920,6 @@ int vprintk_store(int facility, int level, ...@@ -1867,9 +1920,6 @@ int vprintk_store(int facility, int level,
case '0' ... '7': case '0' ... '7':
if (level == LOGLEVEL_DEFAULT) if (level == LOGLEVEL_DEFAULT)
level = kern_level - '0'; level = kern_level - '0';
/* fallthrough */
case 'd': /* KERN_DEFAULT */
lflags |= LOG_PREFIX;
break; break;
case 'c': /* KERN_CONT */ case 'c': /* KERN_CONT */
lflags |= LOG_CONT; lflags |= LOG_CONT;
...@@ -1884,7 +1934,7 @@ int vprintk_store(int facility, int level, ...@@ -1884,7 +1934,7 @@ int vprintk_store(int facility, int level,
level = default_message_loglevel; level = default_message_loglevel;
if (dict) if (dict)
lflags |= LOG_PREFIX|LOG_NEWLINE; lflags |= LOG_NEWLINE;
return log_output(facility, level, lflags, return log_output(facility, level, lflags,
dict, dictlen, text, text_len); dict, dictlen, text, text_len);
......
...@@ -17,6 +17,23 @@ config PRINTK_TIME ...@@ -17,6 +17,23 @@ config PRINTK_TIME
The behavior is also controlled by the kernel command line The behavior is also controlled by the kernel command line
parameter printk.time=1. See Documentation/admin-guide/kernel-parameters.rst parameter printk.time=1. See Documentation/admin-guide/kernel-parameters.rst
config PRINTK_CALLER
bool "Show caller information on printks"
depends on PRINTK
help
Selecting this option causes printk() to add a caller "thread id" (if
in task context) or a caller "processor id" (if not in task context)
to every message.
This option is intended for environments where multiple threads
concurrently call printk() for many times, for it is difficult to
interpret without knowing where these lines (or sometimes individual
line which was divided into multiple lines due to race) came from.
Since toggling after boot makes the code racy, currently there is
no option to enable/disable at the kernel command line parameter or
sysfs interface.
config CONSOLE_LOGLEVEL_DEFAULT config CONSOLE_LOGLEVEL_DEFAULT
int "Default console loglevel (1-15)" int "Default console loglevel (1-15)"
range 1 15 range 1 15
......
...@@ -1931,7 +1931,6 @@ char *device_node_string(char *buf, char *end, struct device_node *dn, ...@@ -1931,7 +1931,6 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
* (legacy clock framework) of the clock * (legacy clock framework) of the clock
* - 'Cn' For a clock, it prints the name (Common Clock Framework) or address * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address
* (legacy clock framework) of the clock * (legacy clock framework) of the clock
* - 'Cr' For a clock, it prints the current rate of the clock
* - 'G' For flags to be printed as a collection of symbolic strings that would * - 'G' For flags to be printed as a collection of symbolic strings that would
* construct the specific value. Supported flags given by option: * construct the specific value. Supported flags given by option:
* p page flags (see struct page) given as pointer to unsigned long * p page flags (see struct page) given as pointer to unsigned long
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment