Printk changes for 5.1
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABAgAGBQJcf9djAAoJEFKgDEdIgJTyVGYP/REwDqjU7HrHCWdB0XJqens5 OLkCnsnqRyhGUBJX6tc9dnY507FjEFS6DEAZDAPK14T/a50/57xWyXRNObzs7qud sP0otc/Gm7rWOP96ucEbMcPgzhixbC8fO3kvdQhc2HtxMQs4sotXqxDxVDHrbwNt 7hvboTPLbiD7IFmqsQhtNWpGAXGhGzE8RwzltcWP+PcdI4oZVLW5lc4CUPG89AoX Fwd+7TAyH1X0/1QH/RQdOoUadiGIPucMC2HPbk+rDWF6+7zA83W9r28bYvuQemtZ myhRTj6Y46HfngJm5UFCZ56F3mLhs7V7Nc+bGNh6sU2xepCnzcAy5aBwl8xqnftZ hCxzyCdd8JrlcyMKRS4nq8dV0gsJKARRg0S3ZOdKElU4s7ep5dDJ0Ca9lq3K012I nPXrFgC6ZWp1i1aAWV2g5F9i6vB6rvbzqg+MGiuGijEOe0Lz80Humm/Rc4+0KQd2 kT0AOZnpknYMXVs+vbkhntx1Pv1ubzER3B9aysB0hM1NLmZWs2lQgU6sLZnJie3i pEaFeCW+t52p+fkMJjYuirdjK4+zRYyeSqbSECdPCCjSjQcC2SX97hh/qyShtVxc EFjkEKCtHrquFmeGYzCyMk4/rlGtmOJRYchqJi9J/lULW9wHA4zpAyRa1FZkmBzl Zus2Kbmy2oilqsPdpAqt =dXuJ -----END PGP SIGNATURE----- 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.
This commit is contained in:
commit
c4703acd6d
|
@ -13,6 +13,10 @@ Integer types
|
|||
|
||||
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
|
||||
unsigned int %u or %x
|
||||
long %ld or %lx
|
||||
|
@ -21,6 +25,10 @@ Integer types
|
|||
unsigned long long %llu or %llx
|
||||
size_t %zu 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
|
||||
u32 %u or %x
|
||||
s64 %lld or %llx
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#define KERN_INFO KERN_SOH "6" /* informational */
|
||||
#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
|
||||
|
|
|
@ -18,7 +18,6 @@ static inline int printk_get_level(const char *buffer)
|
|||
if (buffer[0] == KERN_SOH_ASCII && buffer[1]) {
|
||||
switch (buffer[1]) {
|
||||
case '0' ... '7':
|
||||
case 'd': /* KERN_DEFAULT */
|
||||
case 'c': /* KERN_CONT */
|
||||
return buffer[1];
|
||||
}
|
||||
|
|
|
@ -344,7 +344,6 @@ static int console_msg_format = MSG_FORMAT_DEFAULT;
|
|||
|
||||
enum log_flags {
|
||||
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 */
|
||||
};
|
||||
|
||||
|
@ -356,6 +355,9 @@ struct printk_log {
|
|||
u8 facility; /* syslog facility */
|
||||
u8 flags:5; /* internal record flags */
|
||||
u8 level:3; /* syslog level */
|
||||
#ifdef CONFIG_PRINTK_CALLER
|
||||
u32 caller_id; /* thread id or processor id */
|
||||
#endif
|
||||
}
|
||||
#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
||||
__packed __aligned(4)
|
||||
|
@ -422,7 +424,11 @@ static u64 exclusive_console_stop_seq;
|
|||
static u64 clear_seq;
|
||||
static u32 clear_idx;
|
||||
|
||||
#ifdef CONFIG_PRINTK_CALLER
|
||||
#define PREFIX_MAX 48
|
||||
#else
|
||||
#define PREFIX_MAX 32
|
||||
#endif
|
||||
#define LOG_LINE_MAX (1024 - PREFIX_MAX)
|
||||
|
||||
#define LOG_LEVEL(v) ((v) & 0x07)
|
||||
|
@ -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 */
|
||||
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,
|
||||
const char *dict, u16 dict_len,
|
||||
const char *text, u16 text_len)
|
||||
|
@ -625,6 +631,9 @@ static int log_store(int facility, int level,
|
|||
msg->ts_nsec = ts_nsec;
|
||||
else
|
||||
msg->ts_nsec = local_clock();
|
||||
#ifdef CONFIG_PRINTK_CALLER
|
||||
msg->caller_id = caller_id;
|
||||
#endif
|
||||
memset(log_dict(msg) + dict_len, 0, pad_len);
|
||||
msg->len = size;
|
||||
|
||||
|
@ -688,12 +697,21 @@ static ssize_t msg_print_ext_header(char *buf, size_t size,
|
|||
struct printk_log *msg, u64 seq)
|
||||
{
|
||||
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);
|
||||
|
||||
return scnprintf(buf, size, "%u,%llu,%llu,%c;",
|
||||
(msg->facility << 3) | msg->level, seq, ts_usec,
|
||||
msg->flags & LOG_CONT ? 'c' : '-');
|
||||
return scnprintf(buf, size, "%u,%llu,%llu,%c%s;",
|
||||
(msg->facility << 3) | msg->level, seq, ts_usec,
|
||||
msg->flags & LOG_CONT ? 'c' : '-', caller);
|
||||
}
|
||||
|
||||
static ssize_t msg_print_ext_body(char *buf, size_t size,
|
||||
|
@ -1038,6 +1056,9 @@ void log_buf_vmcoreinfo_setup(void)
|
|||
VMCOREINFO_OFFSET(printk_log, len);
|
||||
VMCOREINFO_OFFSET(printk_log, text_len);
|
||||
VMCOREINFO_OFFSET(printk_log, dict_len);
|
||||
#ifdef CONFIG_PRINTK_CALLER
|
||||
VMCOREINFO_OFFSET(printk_log, caller_id);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1236,10 +1257,23 @@ static size_t print_time(u64 ts, char *buf)
|
|||
{
|
||||
unsigned long rem_nsec = do_div(ts, 1000000000);
|
||||
|
||||
return sprintf(buf, "[%5lu.%06lu] ",
|
||||
return sprintf(buf, "[%5lu.%06lu]",
|
||||
(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,
|
||||
bool time, char *buf)
|
||||
{
|
||||
|
@ -1247,8 +1281,17 @@ static size_t print_prefix(const struct printk_log *msg, bool syslog,
|
|||
|
||||
if (syslog)
|
||||
len = print_syslog((msg->facility << 3) | msg->level, buf);
|
||||
|
||||
if (time)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
* until the line is complete, or a race forces it. The line fragments
|
||||
|
@ -1761,7 +1810,7 @@ static inline void printk_delay(void)
|
|||
static struct cont {
|
||||
char buf[LOG_LINE_MAX];
|
||||
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 */
|
||||
u8 level; /* log level of first message */
|
||||
u8 facility; /* log facility of first message */
|
||||
|
@ -1773,12 +1822,13 @@ static void cont_flush(void)
|
|||
if (cont.len == 0)
|
||||
return;
|
||||
|
||||
log_store(cont.facility, cont.level, cont.flags, cont.ts_nsec,
|
||||
NULL, 0, cont.buf, cont.len);
|
||||
log_store(cont.caller_id, cont.facility, cont.level, cont.flags,
|
||||
cont.ts_nsec, NULL, 0, cont.buf, cont.len);
|
||||
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 (cont.len + len > sizeof(cont.buf)) {
|
||||
|
@ -1789,7 +1839,7 @@ static bool cont_add(int facility, int level, enum log_flags flags, const char *
|
|||
if (!cont.len) {
|
||||
cont.facility = facility;
|
||||
cont.level = level;
|
||||
cont.owner = current;
|
||||
cont.caller_id = caller_id;
|
||||
cont.ts_nsec = local_clock();
|
||||
cont.flags = flags;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
const u32 caller_id = printk_caller_id();
|
||||
|
||||
/*
|
||||
* 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.owner == current && (lflags & LOG_CONT)) {
|
||||
if (cont_add(facility, level, lflags, text, text_len))
|
||||
if (cont.caller_id == caller_id && (lflags & LOG_CONT)) {
|
||||
if (cont_add(caller_id, facility, level, lflags, text, text_len))
|
||||
return text_len;
|
||||
}
|
||||
/* 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
|
|||
|
||||
/* If it doesn't end in a newline, try to buffer the current line */
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
@ -1867,9 +1920,6 @@ int vprintk_store(int facility, int level,
|
|||
case '0' ... '7':
|
||||
if (level == LOGLEVEL_DEFAULT)
|
||||
level = kern_level - '0';
|
||||
/* fallthrough */
|
||||
case 'd': /* KERN_DEFAULT */
|
||||
lflags |= LOG_PREFIX;
|
||||
break;
|
||||
case 'c': /* KERN_CONT */
|
||||
lflags |= LOG_CONT;
|
||||
|
@ -1884,7 +1934,7 @@ int vprintk_store(int facility, int level,
|
|||
level = default_message_loglevel;
|
||||
|
||||
if (dict)
|
||||
lflags |= LOG_PREFIX|LOG_NEWLINE;
|
||||
lflags |= LOG_NEWLINE;
|
||||
|
||||
return log_output(facility, level, lflags,
|
||||
dict, dictlen, text, text_len);
|
||||
|
|
|
@ -17,6 +17,23 @@ config PRINTK_TIME
|
|||
The behavior is also controlled by the kernel command line
|
||||
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
|
||||
int "Default console loglevel (1-15)"
|
||||
range 1 15
|
||||
|
|
|
@ -1931,7 +1931,6 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
|
|||
* (legacy clock framework) of the clock
|
||||
* - 'Cn' For a clock, it prints the name (Common Clock Framework) or address
|
||||
* (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
|
||||
* construct the specific value. Supported flags given by option:
|
||||
* p page flags (see struct page) given as pointer to unsigned long
|
||||
|
|
Loading…
Reference in New Issue