diff options
| -rw-r--r-- | Documentation/core-api/printk-formats.rst | 8 | ||||
| -rw-r--r-- | include/linux/kern_levels.h | 2 | ||||
| -rw-r--r-- | include/linux/printk.h | 1 | ||||
| -rw-r--r-- | kernel/printk/printk.c | 90 | ||||
| -rw-r--r-- | lib/Kconfig.debug | 17 | ||||
| -rw-r--r-- | lib/vsprintf.c | 1 |
6 files changed, 96 insertions, 23 deletions
diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index a7fae4538946..c37ec7cd9c06 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst | |||
| @@ -13,6 +13,10 @@ Integer types | |||
| 13 | 13 | ||
| 14 | If variable is of Type, use printk format specifier: | 14 | If variable is of Type, use printk format specifier: |
| 15 | ------------------------------------------------------------ | 15 | ------------------------------------------------------------ |
| 16 | char %hhd or %hhx | ||
| 17 | unsigned char %hhu or %hhx | ||
| 18 | short int %hd or %hx | ||
| 19 | unsigned short int %hu or %hx | ||
| 16 | int %d or %x | 20 | int %d or %x |
| 17 | unsigned int %u or %x | 21 | unsigned int %u or %x |
| 18 | long %ld or %lx | 22 | long %ld or %lx |
| @@ -21,6 +25,10 @@ Integer types | |||
| 21 | unsigned long long %llu or %llx | 25 | unsigned long long %llu or %llx |
| 22 | size_t %zu or %zx | 26 | size_t %zu or %zx |
| 23 | ssize_t %zd or %zx | 27 | ssize_t %zd or %zx |
| 28 | s8 %hhd or %hhx | ||
| 29 | u8 %hhu or %hhx | ||
| 30 | s16 %hd or %hx | ||
| 31 | u16 %hu or %hx | ||
| 24 | s32 %d or %x | 32 | s32 %d or %x |
| 25 | u32 %u or %x | 33 | u32 %u or %x |
| 26 | s64 %lld or %llx | 34 | s64 %lld or %llx |
diff --git a/include/linux/kern_levels.h b/include/linux/kern_levels.h index d237fe854ad9..bf2389c26ae3 100644 --- a/include/linux/kern_levels.h +++ b/include/linux/kern_levels.h | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | #define KERN_INFO KERN_SOH "6" /* informational */ | 14 | #define KERN_INFO KERN_SOH "6" /* informational */ |
| 15 | #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */ | 15 | #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */ |
| 16 | 16 | ||
| 17 | #define KERN_DEFAULT KERN_SOH "d" /* the default kernel loglevel */ | 17 | #define KERN_DEFAULT "" /* the default kernel loglevel */ |
| 18 | 18 | ||
| 19 | /* | 19 | /* |
| 20 | * Annotation for a "continued" line of log printout (only done after a | 20 | * Annotation for a "continued" line of log printout (only done after a |
diff --git a/include/linux/printk.h b/include/linux/printk.h index 02b5c115d89b..d7c77ed1a4cb 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h | |||
| @@ -18,7 +18,6 @@ static inline int printk_get_level(const char *buffer) | |||
| 18 | if (buffer[0] == KERN_SOH_ASCII && buffer[1]) { | 18 | if (buffer[0] == KERN_SOH_ASCII && buffer[1]) { |
| 19 | switch (buffer[1]) { | 19 | switch (buffer[1]) { |
| 20 | case '0' ... '7': | 20 | case '0' ... '7': |
| 21 | case 'd': /* KERN_DEFAULT */ | ||
| 22 | case 'c': /* KERN_CONT */ | 21 | case 'c': /* KERN_CONT */ |
| 23 | return buffer[1]; | 22 | return buffer[1]; |
| 24 | } | 23 | } |
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index d3d170374ceb..8eee85bb2687 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c | |||
| @@ -344,7 +344,6 @@ static int console_msg_format = MSG_FORMAT_DEFAULT; | |||
| 344 | 344 | ||
| 345 | enum log_flags { | 345 | enum log_flags { |
| 346 | LOG_NEWLINE = 2, /* text ended with a newline */ | 346 | LOG_NEWLINE = 2, /* text ended with a newline */ |
| 347 | LOG_PREFIX = 4, /* text started with a prefix */ | ||
| 348 | LOG_CONT = 8, /* text is a fragment of a continuation line */ | 347 | LOG_CONT = 8, /* text is a fragment of a continuation line */ |
| 349 | }; | 348 | }; |
| 350 | 349 | ||
| @@ -356,6 +355,9 @@ struct printk_log { | |||
| 356 | u8 facility; /* syslog facility */ | 355 | u8 facility; /* syslog facility */ |
| 357 | u8 flags:5; /* internal record flags */ | 356 | u8 flags:5; /* internal record flags */ |
| 358 | u8 level:3; /* syslog level */ | 357 | u8 level:3; /* syslog level */ |
| 358 | #ifdef CONFIG_PRINTK_CALLER | ||
| 359 | u32 caller_id; /* thread id or processor id */ | ||
| 360 | #endif | ||
| 359 | } | 361 | } |
| 360 | #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | 362 | #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS |
| 361 | __packed __aligned(4) | 363 | __packed __aligned(4) |
| @@ -422,7 +424,11 @@ static u64 exclusive_console_stop_seq; | |||
| 422 | static u64 clear_seq; | 424 | static u64 clear_seq; |
| 423 | static u32 clear_idx; | 425 | static u32 clear_idx; |
| 424 | 426 | ||
| 427 | #ifdef CONFIG_PRINTK_CALLER | ||
| 428 | #define PREFIX_MAX 48 | ||
| 429 | #else | ||
| 425 | #define PREFIX_MAX 32 | 430 | #define PREFIX_MAX 32 |
| 431 | #endif | ||
| 426 | #define LOG_LINE_MAX (1024 - PREFIX_MAX) | 432 | #define LOG_LINE_MAX (1024 - PREFIX_MAX) |
| 427 | 433 | ||
| 428 | #define LOG_LEVEL(v) ((v) & 0x07) | 434 | #define LOG_LEVEL(v) ((v) & 0x07) |
| @@ -577,7 +583,7 @@ static u32 truncate_msg(u16 *text_len, u16 *trunc_msg_len, | |||
| 577 | } | 583 | } |
| 578 | 584 | ||
| 579 | /* insert record into the buffer, discard old ones, update heads */ | 585 | /* insert record into the buffer, discard old ones, update heads */ |
| 580 | static int log_store(int facility, int level, | 586 | static int log_store(u32 caller_id, int facility, int level, |
| 581 | enum log_flags flags, u64 ts_nsec, | 587 | enum log_flags flags, u64 ts_nsec, |
| 582 | const char *dict, u16 dict_len, | 588 | const char *dict, u16 dict_len, |
| 583 | const char *text, u16 text_len) | 589 | const char *text, u16 text_len) |
| @@ -625,6 +631,9 @@ static int log_store(int facility, int level, | |||
| 625 | msg->ts_nsec = ts_nsec; | 631 | msg->ts_nsec = ts_nsec; |
| 626 | else | 632 | else |
| 627 | msg->ts_nsec = local_clock(); | 633 | msg->ts_nsec = local_clock(); |
| 634 | #ifdef CONFIG_PRINTK_CALLER | ||
| 635 | msg->caller_id = caller_id; | ||
| 636 | #endif | ||
| 628 | memset(log_dict(msg) + dict_len, 0, pad_len); | 637 | memset(log_dict(msg) + dict_len, 0, pad_len); |
| 629 | msg->len = size; | 638 | msg->len = size; |
| 630 | 639 | ||
| @@ -688,12 +697,21 @@ static ssize_t msg_print_ext_header(char *buf, size_t size, | |||
| 688 | struct printk_log *msg, u64 seq) | 697 | struct printk_log *msg, u64 seq) |
| 689 | { | 698 | { |
| 690 | u64 ts_usec = msg->ts_nsec; | 699 | u64 ts_usec = msg->ts_nsec; |
| 700 | char caller[20]; | ||
| 701 | #ifdef CONFIG_PRINTK_CALLER | ||
| 702 | u32 id = msg->caller_id; | ||
| 703 | |||
| 704 | snprintf(caller, sizeof(caller), ",caller=%c%u", | ||
| 705 | id & 0x80000000 ? 'C' : 'T', id & ~0x80000000); | ||
| 706 | #else | ||
| 707 | caller[0] = '\0'; | ||
| 708 | #endif | ||
| 691 | 709 | ||
| 692 | do_div(ts_usec, 1000); | 710 | do_div(ts_usec, 1000); |
| 693 | 711 | ||
| 694 | return scnprintf(buf, size, "%u,%llu,%llu,%c;", | 712 | return scnprintf(buf, size, "%u,%llu,%llu,%c%s;", |
| 695 | (msg->facility << 3) | msg->level, seq, ts_usec, | 713 | (msg->facility << 3) | msg->level, seq, ts_usec, |
| 696 | msg->flags & LOG_CONT ? 'c' : '-'); | 714 | msg->flags & LOG_CONT ? 'c' : '-', caller); |
| 697 | } | 715 | } |
| 698 | 716 | ||
| 699 | static ssize_t msg_print_ext_body(char *buf, size_t size, | 717 | static ssize_t msg_print_ext_body(char *buf, size_t size, |
| @@ -1038,6 +1056,9 @@ void log_buf_vmcoreinfo_setup(void) | |||
| 1038 | VMCOREINFO_OFFSET(printk_log, len); | 1056 | VMCOREINFO_OFFSET(printk_log, len); |
| 1039 | VMCOREINFO_OFFSET(printk_log, text_len); | 1057 | VMCOREINFO_OFFSET(printk_log, text_len); |
| 1040 | VMCOREINFO_OFFSET(printk_log, dict_len); | 1058 | VMCOREINFO_OFFSET(printk_log, dict_len); |
| 1059 | #ifdef CONFIG_PRINTK_CALLER | ||
| 1060 | VMCOREINFO_OFFSET(printk_log, caller_id); | ||
| 1061 | #endif | ||
| 1041 | } | 1062 | } |
| 1042 | #endif | 1063 | #endif |
| 1043 | 1064 | ||
| @@ -1236,10 +1257,23 @@ static size_t print_time(u64 ts, char *buf) | |||
| 1236 | { | 1257 | { |
| 1237 | unsigned long rem_nsec = do_div(ts, 1000000000); | 1258 | unsigned long rem_nsec = do_div(ts, 1000000000); |
| 1238 | 1259 | ||
| 1239 | return sprintf(buf, "[%5lu.%06lu] ", | 1260 | return sprintf(buf, "[%5lu.%06lu]", |
| 1240 | (unsigned long)ts, rem_nsec / 1000); | 1261 | (unsigned long)ts, rem_nsec / 1000); |
| 1241 | } | 1262 | } |
| 1242 | 1263 | ||
| 1264 | #ifdef CONFIG_PRINTK_CALLER | ||
| 1265 | static size_t print_caller(u32 id, char *buf) | ||
| 1266 | { | ||
| 1267 | char caller[12]; | ||
| 1268 | |||
| 1269 | snprintf(caller, sizeof(caller), "%c%u", | ||
| 1270 | id & 0x80000000 ? 'C' : 'T', id & ~0x80000000); | ||
| 1271 | return sprintf(buf, "[%6s]", caller); | ||
| 1272 | } | ||
| 1273 | #else | ||
| 1274 | #define print_caller(id, buf) 0 | ||
| 1275 | #endif | ||
| 1276 | |||
| 1243 | static size_t print_prefix(const struct printk_log *msg, bool syslog, | 1277 | static size_t print_prefix(const struct printk_log *msg, bool syslog, |
| 1244 | bool time, char *buf) | 1278 | bool time, char *buf) |
| 1245 | { | 1279 | { |
| @@ -1247,8 +1281,17 @@ static size_t print_prefix(const struct printk_log *msg, bool syslog, | |||
| 1247 | 1281 | ||
| 1248 | if (syslog) | 1282 | if (syslog) |
| 1249 | len = print_syslog((msg->facility << 3) | msg->level, buf); | 1283 | len = print_syslog((msg->facility << 3) | msg->level, buf); |
| 1284 | |||
| 1250 | if (time) | 1285 | if (time) |
| 1251 | len += print_time(msg->ts_nsec, buf + len); | 1286 | len += print_time(msg->ts_nsec, buf + len); |
| 1287 | |||
| 1288 | len += print_caller(msg->caller_id, buf + len); | ||
| 1289 | |||
| 1290 | if (IS_ENABLED(CONFIG_PRINTK_CALLER) || time) { | ||
| 1291 | buf[len++] = ' '; | ||
| 1292 | buf[len] = '\0'; | ||
| 1293 | } | ||
| 1294 | |||
| 1252 | return len; | 1295 | return len; |
| 1253 | } | 1296 | } |
| 1254 | 1297 | ||
| @@ -1752,6 +1795,12 @@ static inline void printk_delay(void) | |||
| 1752 | } | 1795 | } |
| 1753 | } | 1796 | } |
| 1754 | 1797 | ||
| 1798 | static inline u32 printk_caller_id(void) | ||
| 1799 | { | ||
| 1800 | return in_task() ? task_pid_nr(current) : | ||
| 1801 | 0x80000000 + raw_smp_processor_id(); | ||
| 1802 | } | ||
| 1803 | |||
| 1755 | /* | 1804 | /* |
| 1756 | * Continuation lines are buffered, and not committed to the record buffer | 1805 | * Continuation lines are buffered, and not committed to the record buffer |
| 1757 | * until the line is complete, or a race forces it. The line fragments | 1806 | * until the line is complete, or a race forces it. The line fragments |
| @@ -1761,7 +1810,7 @@ static inline void printk_delay(void) | |||
| 1761 | static struct cont { | 1810 | static struct cont { |
| 1762 | char buf[LOG_LINE_MAX]; | 1811 | char buf[LOG_LINE_MAX]; |
| 1763 | size_t len; /* length == 0 means unused buffer */ | 1812 | size_t len; /* length == 0 means unused buffer */ |
| 1764 | struct task_struct *owner; /* task of first print*/ | 1813 | u32 caller_id; /* printk_caller_id() of first print */ |
| 1765 | u64 ts_nsec; /* time of first print */ | 1814 | u64 ts_nsec; /* time of first print */ |
| 1766 | u8 level; /* log level of first message */ | 1815 | u8 level; /* log level of first message */ |
| 1767 | u8 facility; /* log facility of first message */ | 1816 | u8 facility; /* log facility of first message */ |
| @@ -1773,12 +1822,13 @@ static void cont_flush(void) | |||
| 1773 | if (cont.len == 0) | 1822 | if (cont.len == 0) |
| 1774 | return; | 1823 | return; |
| 1775 | 1824 | ||
| 1776 | log_store(cont.facility, cont.level, cont.flags, cont.ts_nsec, | 1825 | log_store(cont.caller_id, cont.facility, cont.level, cont.flags, |
| 1777 | NULL, 0, cont.buf, cont.len); | 1826 | cont.ts_nsec, NULL, 0, cont.buf, cont.len); |
| 1778 | cont.len = 0; | 1827 | cont.len = 0; |
| 1779 | } | 1828 | } |
| 1780 | 1829 | ||
| 1781 | static bool cont_add(int facility, int level, enum log_flags flags, const char *text, size_t len) | 1830 | static bool cont_add(u32 caller_id, int facility, int level, |
| 1831 | enum log_flags flags, const char *text, size_t len) | ||
| 1782 | { | 1832 | { |
| 1783 | /* If the line gets too long, split it up in separate records. */ | 1833 | /* If the line gets too long, split it up in separate records. */ |
| 1784 | if (cont.len + len > sizeof(cont.buf)) { | 1834 | 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 | if (!cont.len) { | 1839 | if (!cont.len) { |
| 1790 | cont.facility = facility; | 1840 | cont.facility = facility; |
| 1791 | cont.level = level; | 1841 | cont.level = level; |
| 1792 | cont.owner = current; | 1842 | cont.caller_id = caller_id; |
| 1793 | cont.ts_nsec = local_clock(); | 1843 | cont.ts_nsec = local_clock(); |
| 1794 | cont.flags = flags; | 1844 | cont.flags = flags; |
| 1795 | } | 1845 | } |
| @@ -1809,13 +1859,15 @@ static bool cont_add(int facility, int level, enum log_flags flags, const char * | |||
| 1809 | 1859 | ||
| 1810 | 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) | 1860 | 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) |
| 1811 | { | 1861 | { |
| 1862 | const u32 caller_id = printk_caller_id(); | ||
| 1863 | |||
| 1812 | /* | 1864 | /* |
| 1813 | * If an earlier line was buffered, and we're a continuation | 1865 | * If an earlier line was buffered, and we're a continuation |
| 1814 | * write from the same process, try to add it to the buffer. | 1866 | * write from the same context, try to add it to the buffer. |
| 1815 | */ | 1867 | */ |
| 1816 | if (cont.len) { | 1868 | if (cont.len) { |
| 1817 | if (cont.owner == current && (lflags & LOG_CONT)) { | 1869 | if (cont.caller_id == caller_id && (lflags & LOG_CONT)) { |
| 1818 | if (cont_add(facility, level, lflags, text, text_len)) | 1870 | if (cont_add(caller_id, facility, level, lflags, text, text_len)) |
| 1819 | return text_len; | 1871 | return text_len; |
| 1820 | } | 1872 | } |
| 1821 | /* Otherwise, make sure it's flushed */ | 1873 | /* 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 | 1880 | ||
| 1829 | /* If it doesn't end in a newline, try to buffer the current line */ | 1881 | /* If it doesn't end in a newline, try to buffer the current line */ |
| 1830 | if (!(lflags & LOG_NEWLINE)) { | 1882 | if (!(lflags & LOG_NEWLINE)) { |
| 1831 | if (cont_add(facility, level, lflags, text, text_len)) | 1883 | if (cont_add(caller_id, facility, level, lflags, text, text_len)) |
| 1832 | return text_len; | 1884 | return text_len; |
| 1833 | } | 1885 | } |
| 1834 | 1886 | ||
| 1835 | /* Store it in the record log */ | 1887 | /* Store it in the record log */ |
| 1836 | return log_store(facility, level, lflags, 0, dict, dictlen, text, text_len); | 1888 | return log_store(caller_id, facility, level, lflags, 0, |
| 1889 | dict, dictlen, text, text_len); | ||
| 1837 | } | 1890 | } |
| 1838 | 1891 | ||
| 1839 | /* Must be called under logbuf_lock. */ | 1892 | /* Must be called under logbuf_lock. */ |
| @@ -1867,9 +1920,6 @@ int vprintk_store(int facility, int level, | |||
| 1867 | case '0' ... '7': | 1920 | case '0' ... '7': |
| 1868 | if (level == LOGLEVEL_DEFAULT) | 1921 | if (level == LOGLEVEL_DEFAULT) |
| 1869 | level = kern_level - '0'; | 1922 | level = kern_level - '0'; |
| 1870 | /* fallthrough */ | ||
| 1871 | case 'd': /* KERN_DEFAULT */ | ||
| 1872 | lflags |= LOG_PREFIX; | ||
| 1873 | break; | 1923 | break; |
| 1874 | case 'c': /* KERN_CONT */ | 1924 | case 'c': /* KERN_CONT */ |
| 1875 | lflags |= LOG_CONT; | 1925 | lflags |= LOG_CONT; |
| @@ -1884,7 +1934,7 @@ int vprintk_store(int facility, int level, | |||
| 1884 | level = default_message_loglevel; | 1934 | level = default_message_loglevel; |
| 1885 | 1935 | ||
| 1886 | if (dict) | 1936 | if (dict) |
| 1887 | lflags |= LOG_PREFIX|LOG_NEWLINE; | 1937 | lflags |= LOG_NEWLINE; |
| 1888 | 1938 | ||
| 1889 | return log_output(facility, level, lflags, | 1939 | return log_output(facility, level, lflags, |
| 1890 | dict, dictlen, text, text_len); | 1940 | dict, dictlen, text, text_len); |
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index e718487c97c3..91ed81250fb3 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
| @@ -17,6 +17,23 @@ config PRINTK_TIME | |||
| 17 | The behavior is also controlled by the kernel command line | 17 | The behavior is also controlled by the kernel command line |
| 18 | parameter printk.time=1. See Documentation/admin-guide/kernel-parameters.rst | 18 | parameter printk.time=1. See Documentation/admin-guide/kernel-parameters.rst |
| 19 | 19 | ||
| 20 | config PRINTK_CALLER | ||
| 21 | bool "Show caller information on printks" | ||
| 22 | depends on PRINTK | ||
| 23 | help | ||
| 24 | Selecting this option causes printk() to add a caller "thread id" (if | ||
| 25 | in task context) or a caller "processor id" (if not in task context) | ||
| 26 | to every message. | ||
| 27 | |||
| 28 | This option is intended for environments where multiple threads | ||
| 29 | concurrently call printk() for many times, for it is difficult to | ||
| 30 | interpret without knowing where these lines (or sometimes individual | ||
| 31 | line which was divided into multiple lines due to race) came from. | ||
| 32 | |||
| 33 | Since toggling after boot makes the code racy, currently there is | ||
| 34 | no option to enable/disable at the kernel command line parameter or | ||
| 35 | sysfs interface. | ||
| 36 | |||
| 20 | config CONSOLE_LOGLEVEL_DEFAULT | 37 | config CONSOLE_LOGLEVEL_DEFAULT |
| 21 | int "Default console loglevel (1-15)" | 38 | int "Default console loglevel (1-15)" |
| 22 | range 1 15 | 39 | range 1 15 |
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 30b00de4f321..791b6fa36905 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
| @@ -1931,7 +1931,6 @@ char *device_node_string(char *buf, char *end, struct device_node *dn, | |||
| 1931 | * (legacy clock framework) of the clock | 1931 | * (legacy clock framework) of the clock |
| 1932 | * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address | 1932 | * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address |
| 1933 | * (legacy clock framework) of the clock | 1933 | * (legacy clock framework) of the clock |
| 1934 | * - 'Cr' For a clock, it prints the current rate of the clock | ||
| 1935 | * - 'G' For flags to be printed as a collection of symbolic strings that would | 1934 | * - 'G' For flags to be printed as a collection of symbolic strings that would |
| 1936 | * construct the specific value. Supported flags given by option: | 1935 | * construct the specific value. Supported flags given by option: |
| 1937 | * p page flags (see struct page) given as pointer to unsigned long | 1936 | * p page flags (see struct page) given as pointer to unsigned long |
