| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * linux/kernel/printk.c |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 16 | 17 | * 01Mar01 Andrew Morton |
|---|
| 17 | 18 | */ |
|---|
| 18 | 19 | |
|---|
| 20 | +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| 21 | + |
|---|
| 19 | 22 | #include <linux/kernel.h> |
|---|
| 20 | 23 | #include <linux/mm.h> |
|---|
| 21 | 24 | #include <linux/tty.h> |
|---|
| .. | .. |
|---|
| 29 | 32 | #include <linux/delay.h> |
|---|
| 30 | 33 | #include <linux/smp.h> |
|---|
| 31 | 34 | #include <linux/security.h> |
|---|
| 32 | | -#include <linux/bootmem.h> |
|---|
| 33 | 35 | #include <linux/memblock.h> |
|---|
| 34 | 36 | #include <linux/syscalls.h> |
|---|
| 35 | 37 | #include <linux/crash_core.h> |
|---|
| 36 | | -#include <linux/kdb.h> |
|---|
| 37 | 38 | #include <linux/ratelimit.h> |
|---|
| 38 | 39 | #include <linux/kmsg_dump.h> |
|---|
| 39 | 40 | #include <linux/syslog.h> |
|---|
| .. | .. |
|---|
| 53 | 54 | #include <trace/events/initcall.h> |
|---|
| 54 | 55 | #define CREATE_TRACE_POINTS |
|---|
| 55 | 56 | #include <trace/events/printk.h> |
|---|
| 57 | +#undef CREATE_TRACE_POINTS |
|---|
| 58 | +#include <trace/hooks/printk.h> |
|---|
| 59 | +#include <trace/hooks/logbuf.h> |
|---|
| 56 | 60 | |
|---|
| 61 | +#include "printk_ringbuffer.h" |
|---|
| 57 | 62 | #include "console_cmdline.h" |
|---|
| 58 | 63 | #include "braille.h" |
|---|
| 59 | 64 | #include "internal.h" |
|---|
| .. | .. |
|---|
| 82 | 87 | CONSOLE_LOGLEVEL_MIN, /* minimum_console_loglevel */ |
|---|
| 83 | 88 | CONSOLE_LOGLEVEL_DEFAULT, /* default_console_loglevel */ |
|---|
| 84 | 89 | }; |
|---|
| 90 | +EXPORT_SYMBOL_GPL(console_printk); |
|---|
| 85 | 91 | |
|---|
| 86 | 92 | atomic_t ignore_console_lock_warning __read_mostly = ATOMIC_INIT(0); |
|---|
| 87 | 93 | EXPORT_SYMBOL(ignore_console_lock_warning); |
|---|
| .. | .. |
|---|
| 101 | 107 | static DEFINE_SEMAPHORE(console_sem); |
|---|
| 102 | 108 | struct console *console_drivers; |
|---|
| 103 | 109 | EXPORT_SYMBOL_GPL(console_drivers); |
|---|
| 110 | + |
|---|
| 111 | +/* |
|---|
| 112 | + * System may need to suppress printk message under certain |
|---|
| 113 | + * circumstances, like after kernel panic happens. |
|---|
| 114 | + */ |
|---|
| 115 | +int __read_mostly suppress_printk; |
|---|
| 104 | 116 | |
|---|
| 105 | 117 | #ifdef CONFIG_LOCKDEP |
|---|
| 106 | 118 | static struct lockdep_map console_lock_dep_map = { |
|---|
| .. | .. |
|---|
| 127 | 139 | |
|---|
| 128 | 140 | static int __control_devkmsg(char *str) |
|---|
| 129 | 141 | { |
|---|
| 142 | + size_t len; |
|---|
| 143 | + |
|---|
| 130 | 144 | if (!str) |
|---|
| 131 | 145 | return -EINVAL; |
|---|
| 132 | 146 | |
|---|
| 133 | | - if (!strncmp(str, "on", 2)) { |
|---|
| 147 | + len = str_has_prefix(str, "on"); |
|---|
| 148 | + if (len) { |
|---|
| 134 | 149 | devkmsg_log = DEVKMSG_LOG_MASK_ON; |
|---|
| 135 | | - return 2; |
|---|
| 136 | | - } else if (!strncmp(str, "off", 3)) { |
|---|
| 137 | | - devkmsg_log = DEVKMSG_LOG_MASK_OFF; |
|---|
| 138 | | - return 3; |
|---|
| 139 | | - } else if (!strncmp(str, "ratelimit", 9)) { |
|---|
| 140 | | - devkmsg_log = DEVKMSG_LOG_MASK_DEFAULT; |
|---|
| 141 | | - return 9; |
|---|
| 150 | + return len; |
|---|
| 142 | 151 | } |
|---|
| 152 | + |
|---|
| 153 | + len = str_has_prefix(str, "off"); |
|---|
| 154 | + if (len) { |
|---|
| 155 | + devkmsg_log = DEVKMSG_LOG_MASK_OFF; |
|---|
| 156 | + return len; |
|---|
| 157 | + } |
|---|
| 158 | + |
|---|
| 159 | + len = str_has_prefix(str, "ratelimit"); |
|---|
| 160 | + if (len) { |
|---|
| 161 | + devkmsg_log = DEVKMSG_LOG_MASK_DEFAULT; |
|---|
| 162 | + return len; |
|---|
| 163 | + } |
|---|
| 164 | + |
|---|
| 143 | 165 | return -EINVAL; |
|---|
| 144 | 166 | } |
|---|
| 145 | 167 | |
|---|
| 146 | 168 | static int __init control_devkmsg(char *str) |
|---|
| 147 | 169 | { |
|---|
| 148 | | - if (__control_devkmsg(str) < 0) |
|---|
| 170 | + if (__control_devkmsg(str) < 0) { |
|---|
| 171 | + pr_warn("printk.devkmsg: bad option string '%s'\n", str); |
|---|
| 149 | 172 | return 1; |
|---|
| 173 | + } |
|---|
| 150 | 174 | |
|---|
| 151 | 175 | /* |
|---|
| 152 | 176 | * Set sysctl string accordingly: |
|---|
| .. | .. |
|---|
| 165 | 189 | */ |
|---|
| 166 | 190 | devkmsg_log |= DEVKMSG_LOG_MASK_LOCK; |
|---|
| 167 | 191 | |
|---|
| 168 | | - return 0; |
|---|
| 192 | + return 1; |
|---|
| 169 | 193 | } |
|---|
| 170 | 194 | __setup("printk.devkmsg=", control_devkmsg); |
|---|
| 171 | 195 | |
|---|
| 172 | 196 | char devkmsg_log_str[DEVKMSG_STR_MAX_SIZE] = "ratelimit"; |
|---|
| 173 | 197 | |
|---|
| 174 | 198 | int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write, |
|---|
| 175 | | - void __user *buffer, size_t *lenp, loff_t *ppos) |
|---|
| 199 | + void *buffer, size_t *lenp, loff_t *ppos) |
|---|
| 176 | 200 | { |
|---|
| 177 | 201 | char old_str[DEVKMSG_STR_MAX_SIZE]; |
|---|
| 178 | 202 | unsigned int old; |
|---|
| .. | .. |
|---|
| 210 | 234 | return 0; |
|---|
| 211 | 235 | } |
|---|
| 212 | 236 | |
|---|
| 213 | | -/* |
|---|
| 214 | | - * Number of registered extended console drivers. |
|---|
| 215 | | - * |
|---|
| 216 | | - * If extended consoles are present, in-kernel cont reassembly is disabled |
|---|
| 217 | | - * and each fragment is stored as a separate log entry with proper |
|---|
| 218 | | - * continuation flag so that every emitted message has full metadata. This |
|---|
| 219 | | - * doesn't change the result for regular consoles or /proc/kmsg. For |
|---|
| 220 | | - * /dev/kmsg, as long as the reader concatenates messages according to |
|---|
| 221 | | - * consecutive continuation flags, the end result should be the same too. |
|---|
| 222 | | - */ |
|---|
| 237 | +/* Number of registered extended console drivers. */ |
|---|
| 223 | 238 | static int nr_ext_console_drivers; |
|---|
| 224 | 239 | |
|---|
| 225 | 240 | /* |
|---|
| .. | .. |
|---|
| 256 | 271 | { |
|---|
| 257 | 272 | unsigned long flags; |
|---|
| 258 | 273 | |
|---|
| 259 | | - mutex_release(&console_lock_dep_map, 1, ip); |
|---|
| 274 | + mutex_release(&console_lock_dep_map, ip); |
|---|
| 260 | 275 | |
|---|
| 261 | 276 | printk_safe_enter_irqsave(flags); |
|---|
| 262 | 277 | up(&console_sem); |
|---|
| .. | .. |
|---|
| 288 | 303 | static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; |
|---|
| 289 | 304 | |
|---|
| 290 | 305 | static int preferred_console = -1; |
|---|
| 306 | +static bool has_preferred_console; |
|---|
| 291 | 307 | int console_set_on_cmdline; |
|---|
| 292 | 308 | EXPORT_SYMBOL(console_set_on_cmdline); |
|---|
| 293 | 309 | |
|---|
| .. | .. |
|---|
| 302 | 318 | static int console_msg_format = MSG_FORMAT_DEFAULT; |
|---|
| 303 | 319 | |
|---|
| 304 | 320 | /* |
|---|
| 305 | | - * The printk log buffer consists of a chain of concatenated variable |
|---|
| 306 | | - * length records. Every record starts with a record header, containing |
|---|
| 307 | | - * the overall length of the record. |
|---|
| 321 | + * The printk log buffer consists of a sequenced collection of records, each |
|---|
| 322 | + * containing variable length message text. Every record also contains its |
|---|
| 323 | + * own meta-data (@info). |
|---|
| 308 | 324 | * |
|---|
| 309 | | - * The heads to the first and last entry in the buffer, as well as the |
|---|
| 310 | | - * sequence numbers of these entries are maintained when messages are |
|---|
| 311 | | - * stored. |
|---|
| 325 | + * Every record meta-data carries the timestamp in microseconds, as well as |
|---|
| 326 | + * the standard userspace syslog level and syslog facility. The usual kernel |
|---|
| 327 | + * messages use LOG_KERN; userspace-injected messages always carry a matching |
|---|
| 328 | + * syslog facility, by default LOG_USER. The origin of every message can be |
|---|
| 329 | + * reliably determined that way. |
|---|
| 312 | 330 | * |
|---|
| 313 | | - * If the heads indicate available messages, the length in the header |
|---|
| 314 | | - * tells the start next message. A length == 0 for the next message |
|---|
| 315 | | - * indicates a wrap-around to the beginning of the buffer. |
|---|
| 331 | + * The human readable log message of a record is available in @text, the |
|---|
| 332 | + * length of the message text in @text_len. The stored message is not |
|---|
| 333 | + * terminated. |
|---|
| 316 | 334 | * |
|---|
| 317 | | - * Every record carries the monotonic timestamp in microseconds, as well as |
|---|
| 318 | | - * the standard userspace syslog level and syslog facility. The usual |
|---|
| 319 | | - * kernel messages use LOG_KERN; userspace-injected messages always carry |
|---|
| 320 | | - * a matching syslog facility, by default LOG_USER. The origin of every |
|---|
| 321 | | - * message can be reliably determined that way. |
|---|
| 322 | | - * |
|---|
| 323 | | - * The human readable log message directly follows the message header. The |
|---|
| 324 | | - * length of the message text is stored in the header, the stored message |
|---|
| 325 | | - * is not terminated. |
|---|
| 326 | | - * |
|---|
| 327 | | - * Optionally, a message can carry a dictionary of properties (key/value pairs), |
|---|
| 328 | | - * to provide userspace with a machine-readable message context. |
|---|
| 335 | + * Optionally, a record can carry a dictionary of properties (key/value |
|---|
| 336 | + * pairs), to provide userspace with a machine-readable message context. |
|---|
| 329 | 337 | * |
|---|
| 330 | 338 | * Examples for well-defined, commonly used property names are: |
|---|
| 331 | 339 | * DEVICE=b12:8 device identifier |
|---|
| .. | .. |
|---|
| 335 | 343 | * +sound:card0 subsystem:devname |
|---|
| 336 | 344 | * SUBSYSTEM=pci driver-core subsystem name |
|---|
| 337 | 345 | * |
|---|
| 338 | | - * Valid characters in property names are [a-zA-Z0-9.-_]. The plain text value |
|---|
| 339 | | - * follows directly after a '=' character. Every property is terminated by |
|---|
| 340 | | - * a '\0' character. The last property is not terminated. |
|---|
| 346 | + * Valid characters in property names are [a-zA-Z0-9.-_]. Property names |
|---|
| 347 | + * and values are terminated by a '\0' character. |
|---|
| 341 | 348 | * |
|---|
| 342 | | - * Example of a message structure: |
|---|
| 343 | | - * 0000 ff 8f 00 00 00 00 00 00 monotonic time in nsec |
|---|
| 344 | | - * 0008 34 00 record is 52 bytes long |
|---|
| 345 | | - * 000a 0b 00 text is 11 bytes long |
|---|
| 346 | | - * 000c 1f 00 dictionary is 23 bytes long |
|---|
| 347 | | - * 000e 03 00 LOG_KERN (facility) LOG_ERR (level) |
|---|
| 348 | | - * 0010 69 74 27 73 20 61 20 6c "it's a l" |
|---|
| 349 | | - * 69 6e 65 "ine" |
|---|
| 350 | | - * 001b 44 45 56 49 43 "DEVIC" |
|---|
| 351 | | - * 45 3d 62 38 3a 32 00 44 "E=b8:2\0D" |
|---|
| 352 | | - * 52 49 56 45 52 3d 62 75 "RIVER=bu" |
|---|
| 353 | | - * 67 "g" |
|---|
| 354 | | - * 0032 00 00 00 padding to next message header |
|---|
| 349 | + * Example of record values: |
|---|
| 350 | + * record.text_buf = "it's a line" (unterminated) |
|---|
| 351 | + * record.info.seq = 56 |
|---|
| 352 | + * record.info.ts_nsec = 36863 |
|---|
| 353 | + * record.info.text_len = 11 |
|---|
| 354 | + * record.info.facility = 0 (LOG_KERN) |
|---|
| 355 | + * record.info.flags = 0 |
|---|
| 356 | + * record.info.level = 3 (LOG_ERR) |
|---|
| 357 | + * record.info.caller_id = 299 (task 299) |
|---|
| 358 | + * record.info.dev_info.subsystem = "pci" (terminated) |
|---|
| 359 | + * record.info.dev_info.device = "+pci:0000:00:01.0" (terminated) |
|---|
| 355 | 360 | * |
|---|
| 356 | | - * The 'struct printk_log' buffer header must never be directly exported to |
|---|
| 361 | + * The 'struct printk_info' buffer must never be directly exported to |
|---|
| 357 | 362 | * userspace, it is a kernel-private implementation detail that might |
|---|
| 358 | 363 | * need to be changed in the future, when the requirements change. |
|---|
| 359 | 364 | * |
|---|
| .. | .. |
|---|
| 370 | 375 | |
|---|
| 371 | 376 | enum log_flags { |
|---|
| 372 | 377 | LOG_NEWLINE = 2, /* text ended with a newline */ |
|---|
| 373 | | - LOG_PREFIX = 4, /* text started with a prefix */ |
|---|
| 374 | 378 | LOG_CONT = 8, /* text is a fragment of a continuation line */ |
|---|
| 375 | 379 | }; |
|---|
| 376 | | - |
|---|
| 377 | | -struct printk_log { |
|---|
| 378 | | - u64 ts_nsec; /* timestamp in nanoseconds */ |
|---|
| 379 | | - u16 len; /* length of entire record */ |
|---|
| 380 | | - u16 text_len; /* length of text buffer */ |
|---|
| 381 | | - u16 dict_len; /* length of dictionary buffer */ |
|---|
| 382 | | - u8 facility; /* syslog facility */ |
|---|
| 383 | | - u8 flags:5; /* internal record flags */ |
|---|
| 384 | | - u8 level:3; /* syslog level */ |
|---|
| 385 | | -#ifdef CONFIG_PRINTK_PROCESS |
|---|
| 386 | | - char process[16]; /* process name */ |
|---|
| 387 | | - pid_t pid; /* process id */ |
|---|
| 388 | | - u8 cpu; /* cpu id */ |
|---|
| 389 | | - u8 in_interrupt; /* interrupt context */ |
|---|
| 390 | | -#endif |
|---|
| 391 | | -} |
|---|
| 392 | | -#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS |
|---|
| 393 | | -__packed __aligned(4) |
|---|
| 394 | | -#endif |
|---|
| 395 | | -; |
|---|
| 396 | 380 | |
|---|
| 397 | 381 | /* |
|---|
| 398 | 382 | * The logbuf_lock protects kmsg buffer, indices, counters. This can be taken |
|---|
| .. | .. |
|---|
| 429 | 413 | printk_safe_exit_irqrestore(flags); \ |
|---|
| 430 | 414 | } while (0) |
|---|
| 431 | 415 | |
|---|
| 432 | | -#ifdef CONFIG_EARLY_PRINTK |
|---|
| 433 | | -struct console *early_console; |
|---|
| 434 | | - |
|---|
| 435 | | -static void early_vprintk(const char *fmt, va_list ap) |
|---|
| 436 | | -{ |
|---|
| 437 | | - if (early_console) { |
|---|
| 438 | | - char buf[512]; |
|---|
| 439 | | - int n = vscnprintf(buf, sizeof(buf), fmt, ap); |
|---|
| 440 | | - |
|---|
| 441 | | - early_console->write(early_console, buf, n); |
|---|
| 442 | | - } |
|---|
| 443 | | -} |
|---|
| 444 | | - |
|---|
| 445 | | -asmlinkage void early_printk(const char *fmt, ...) |
|---|
| 446 | | -{ |
|---|
| 447 | | - va_list ap; |
|---|
| 448 | | - |
|---|
| 449 | | - va_start(ap, fmt); |
|---|
| 450 | | - early_vprintk(fmt, ap); |
|---|
| 451 | | - va_end(ap); |
|---|
| 452 | | -} |
|---|
| 453 | | - |
|---|
| 454 | | -/* |
|---|
| 455 | | - * This is independent of any log levels - a global |
|---|
| 456 | | - * kill switch that turns off all of printk. |
|---|
| 457 | | - * |
|---|
| 458 | | - * Used by the NMI watchdog if early-printk is enabled. |
|---|
| 459 | | - */ |
|---|
| 460 | | -static bool __read_mostly printk_killswitch; |
|---|
| 461 | | - |
|---|
| 462 | | -static int __init force_early_printk_setup(char *str) |
|---|
| 463 | | -{ |
|---|
| 464 | | - printk_killswitch = true; |
|---|
| 465 | | - return 0; |
|---|
| 466 | | -} |
|---|
| 467 | | -early_param("force_early_printk", force_early_printk_setup); |
|---|
| 468 | | - |
|---|
| 469 | | -void printk_kill(void) |
|---|
| 470 | | -{ |
|---|
| 471 | | - printk_killswitch = true; |
|---|
| 472 | | -} |
|---|
| 473 | | - |
|---|
| 474 | | -#ifdef CONFIG_PRINTK |
|---|
| 475 | | -static int forced_early_printk(const char *fmt, va_list ap) |
|---|
| 476 | | -{ |
|---|
| 477 | | - if (!printk_killswitch) |
|---|
| 478 | | - return 0; |
|---|
| 479 | | - early_vprintk(fmt, ap); |
|---|
| 480 | | - return 1; |
|---|
| 481 | | -} |
|---|
| 482 | | -#endif |
|---|
| 483 | | - |
|---|
| 484 | | -#else |
|---|
| 485 | | -static inline int forced_early_printk(const char *fmt, va_list ap) |
|---|
| 486 | | -{ |
|---|
| 487 | | - return 0; |
|---|
| 488 | | -} |
|---|
| 489 | | -#endif |
|---|
| 490 | | - |
|---|
| 491 | 416 | #ifdef CONFIG_PRINTK |
|---|
| 492 | 417 | DECLARE_WAIT_QUEUE_HEAD(log_wait); |
|---|
| 493 | 418 | /* the next printk record to read by syslog(READ) or /proc/kmsg */ |
|---|
| 494 | 419 | static u64 syslog_seq; |
|---|
| 495 | | -static u32 syslog_idx; |
|---|
| 496 | 420 | static size_t syslog_partial; |
|---|
| 497 | | - |
|---|
| 498 | | -/* index and sequence number of the first record stored in the buffer */ |
|---|
| 499 | | -static u64 log_first_seq; |
|---|
| 500 | | -static u32 log_first_idx; |
|---|
| 501 | | - |
|---|
| 502 | | -/* index and sequence number of the next record to store in the buffer */ |
|---|
| 503 | | -static u64 log_next_seq; |
|---|
| 504 | | -static u32 log_next_idx; |
|---|
| 421 | +static bool syslog_time; |
|---|
| 505 | 422 | |
|---|
| 506 | 423 | /* the next printk record to write to the console */ |
|---|
| 507 | 424 | static u64 console_seq; |
|---|
| 508 | | -static u32 console_idx; |
|---|
| 509 | 425 | static u64 exclusive_console_stop_seq; |
|---|
| 426 | +static unsigned long console_dropped; |
|---|
| 510 | 427 | |
|---|
| 511 | 428 | /* the next printk record to read after the last 'clear' command */ |
|---|
| 512 | 429 | static u64 clear_seq; |
|---|
| 513 | | -static u32 clear_idx; |
|---|
| 514 | 430 | |
|---|
| 515 | | -#ifdef CONFIG_PRINTK_PROCESS |
|---|
| 431 | +#ifdef CONFIG_PRINTK_CALLER |
|---|
| 516 | 432 | #define PREFIX_MAX 48 |
|---|
| 517 | 433 | #else |
|---|
| 518 | 434 | #define PREFIX_MAX 32 |
|---|
| .. | .. |
|---|
| 523 | 439 | #define LOG_FACILITY(v) ((v) >> 3 & 0xff) |
|---|
| 524 | 440 | |
|---|
| 525 | 441 | /* record buffer */ |
|---|
| 526 | | -#define LOG_ALIGN __alignof__(struct printk_log) |
|---|
| 442 | +#define LOG_ALIGN __alignof__(unsigned long) |
|---|
| 527 | 443 | #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) |
|---|
| 528 | 444 | #define LOG_BUF_LEN_MAX (u32)(1 << 31) |
|---|
| 529 | 445 | static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN); |
|---|
| 530 | 446 | static char *log_buf = __log_buf; |
|---|
| 531 | 447 | static u32 log_buf_len = __LOG_BUF_LEN; |
|---|
| 448 | + |
|---|
| 449 | +/* |
|---|
| 450 | + * Define the average message size. This only affects the number of |
|---|
| 451 | + * descriptors that will be available. Underestimating is better than |
|---|
| 452 | + * overestimating (too many available descriptors is better than not enough). |
|---|
| 453 | + */ |
|---|
| 454 | +#define PRB_AVGBITS 5 /* 32 character average length */ |
|---|
| 455 | + |
|---|
| 456 | +#if CONFIG_LOG_BUF_SHIFT <= PRB_AVGBITS |
|---|
| 457 | +#error CONFIG_LOG_BUF_SHIFT value too small. |
|---|
| 458 | +#endif |
|---|
| 459 | +_DEFINE_PRINTKRB(printk_rb_static, CONFIG_LOG_BUF_SHIFT - PRB_AVGBITS, |
|---|
| 460 | + PRB_AVGBITS, &__log_buf[0]); |
|---|
| 461 | + |
|---|
| 462 | +static struct printk_ringbuffer printk_rb_dynamic; |
|---|
| 463 | + |
|---|
| 464 | +static struct printk_ringbuffer *prb = &printk_rb_static; |
|---|
| 532 | 465 | |
|---|
| 533 | 466 | /* |
|---|
| 534 | 467 | * We cannot access per-CPU data (e.g. per-CPU flush irq_work) before |
|---|
| .. | .. |
|---|
| 556 | 489 | } |
|---|
| 557 | 490 | EXPORT_SYMBOL_GPL(log_buf_len_get); |
|---|
| 558 | 491 | |
|---|
| 559 | | -/* human readable text of the record */ |
|---|
| 560 | | -static char *log_text(const struct printk_log *msg) |
|---|
| 561 | | -{ |
|---|
| 562 | | - return (char *)msg + sizeof(struct printk_log); |
|---|
| 563 | | -} |
|---|
| 564 | | - |
|---|
| 565 | | -/* optional key/value pair dictionary attached to the record */ |
|---|
| 566 | | -static char *log_dict(const struct printk_log *msg) |
|---|
| 567 | | -{ |
|---|
| 568 | | - return (char *)msg + sizeof(struct printk_log) + msg->text_len; |
|---|
| 569 | | -} |
|---|
| 570 | | - |
|---|
| 571 | | -/* get record by index; idx must point to valid msg */ |
|---|
| 572 | | -static struct printk_log *log_from_idx(u32 idx) |
|---|
| 573 | | -{ |
|---|
| 574 | | - struct printk_log *msg = (struct printk_log *)(log_buf + idx); |
|---|
| 575 | | - |
|---|
| 576 | | - /* |
|---|
| 577 | | - * A length == 0 record is the end of buffer marker. Wrap around and |
|---|
| 578 | | - * read the message at the start of the buffer. |
|---|
| 579 | | - */ |
|---|
| 580 | | - if (!msg->len) |
|---|
| 581 | | - return (struct printk_log *)log_buf; |
|---|
| 582 | | - return msg; |
|---|
| 583 | | -} |
|---|
| 584 | | - |
|---|
| 585 | | -/* get next record; idx must point to valid msg */ |
|---|
| 586 | | -static u32 log_next(u32 idx) |
|---|
| 587 | | -{ |
|---|
| 588 | | - struct printk_log *msg = (struct printk_log *)(log_buf + idx); |
|---|
| 589 | | - |
|---|
| 590 | | - /* length == 0 indicates the end of the buffer; wrap */ |
|---|
| 591 | | - /* |
|---|
| 592 | | - * A length == 0 record is the end of buffer marker. Wrap around and |
|---|
| 593 | | - * read the message at the start of the buffer as *this* one, and |
|---|
| 594 | | - * return the one after that. |
|---|
| 595 | | - */ |
|---|
| 596 | | - if (!msg->len) { |
|---|
| 597 | | - msg = (struct printk_log *)log_buf; |
|---|
| 598 | | - return msg->len; |
|---|
| 599 | | - } |
|---|
| 600 | | - return idx + msg->len; |
|---|
| 601 | | -} |
|---|
| 602 | | - |
|---|
| 603 | | -#ifdef CONFIG_PRINTK_PROCESS |
|---|
| 604 | | -static bool printk_process = true; |
|---|
| 605 | | -static size_t print_process(const struct printk_log *msg, char *buf) |
|---|
| 606 | | -{ |
|---|
| 607 | | - if (!printk_process) |
|---|
| 608 | | - return 0; |
|---|
| 609 | | - |
|---|
| 610 | | - if (!buf) |
|---|
| 611 | | - return snprintf(NULL, 0, "%c[%1d:%15s:%5d] ", ' ', 0, " ", 0); |
|---|
| 612 | | - |
|---|
| 613 | | - return sprintf(buf, "%c[%1d:%15s:%5d] ", |
|---|
| 614 | | - msg->in_interrupt ? 'I' : ' ', |
|---|
| 615 | | - msg->cpu, |
|---|
| 616 | | - msg->process, |
|---|
| 617 | | - msg->pid); |
|---|
| 618 | | -} |
|---|
| 619 | | -module_param_named(process, printk_process, bool, 0644); |
|---|
| 620 | | -#endif |
|---|
| 621 | | - |
|---|
| 622 | | -/* |
|---|
| 623 | | - * Check whether there is enough free space for the given message. |
|---|
| 624 | | - * |
|---|
| 625 | | - * The same values of first_idx and next_idx mean that the buffer |
|---|
| 626 | | - * is either empty or full. |
|---|
| 627 | | - * |
|---|
| 628 | | - * If the buffer is empty, we must respect the position of the indexes. |
|---|
| 629 | | - * They cannot be reset to the beginning of the buffer. |
|---|
| 630 | | - */ |
|---|
| 631 | | -static int logbuf_has_space(u32 msg_size, bool empty) |
|---|
| 632 | | -{ |
|---|
| 633 | | - u32 free; |
|---|
| 634 | | - |
|---|
| 635 | | - if (log_next_idx > log_first_idx || empty) |
|---|
| 636 | | - free = max(log_buf_len - log_next_idx, log_first_idx); |
|---|
| 637 | | - else |
|---|
| 638 | | - free = log_first_idx - log_next_idx; |
|---|
| 639 | | - |
|---|
| 640 | | - /* |
|---|
| 641 | | - * We need space also for an empty header that signalizes wrapping |
|---|
| 642 | | - * of the buffer. |
|---|
| 643 | | - */ |
|---|
| 644 | | - return free >= msg_size + sizeof(struct printk_log); |
|---|
| 645 | | -} |
|---|
| 646 | | - |
|---|
| 647 | | -static int log_make_free_space(u32 msg_size) |
|---|
| 648 | | -{ |
|---|
| 649 | | - while (log_first_seq < log_next_seq && |
|---|
| 650 | | - !logbuf_has_space(msg_size, false)) { |
|---|
| 651 | | - /* drop old messages until we have enough contiguous space */ |
|---|
| 652 | | - log_first_idx = log_next(log_first_idx); |
|---|
| 653 | | - log_first_seq++; |
|---|
| 654 | | - } |
|---|
| 655 | | - |
|---|
| 656 | | - if (clear_seq < log_first_seq) { |
|---|
| 657 | | - clear_seq = log_first_seq; |
|---|
| 658 | | - clear_idx = log_first_idx; |
|---|
| 659 | | - } |
|---|
| 660 | | - |
|---|
| 661 | | - /* sequence numbers are equal, so the log buffer is empty */ |
|---|
| 662 | | - if (logbuf_has_space(msg_size, log_first_seq == log_next_seq)) |
|---|
| 663 | | - return 0; |
|---|
| 664 | | - |
|---|
| 665 | | - return -ENOMEM; |
|---|
| 666 | | -} |
|---|
| 667 | | - |
|---|
| 668 | | -/* compute the message size including the padding bytes */ |
|---|
| 669 | | -static u32 msg_used_size(u16 text_len, u16 dict_len, u32 *pad_len) |
|---|
| 670 | | -{ |
|---|
| 671 | | - u32 size; |
|---|
| 672 | | - |
|---|
| 673 | | - size = sizeof(struct printk_log) + text_len + dict_len; |
|---|
| 674 | | - *pad_len = (-size) & (LOG_ALIGN - 1); |
|---|
| 675 | | - size += *pad_len; |
|---|
| 676 | | - |
|---|
| 677 | | - return size; |
|---|
| 678 | | -} |
|---|
| 679 | | - |
|---|
| 680 | 492 | /* |
|---|
| 681 | 493 | * Define how much of the log buffer we could take at maximum. The value |
|---|
| 682 | 494 | * must be greater than two. Note that only half of the buffer is available |
|---|
| .. | .. |
|---|
| 685 | 497 | #define MAX_LOG_TAKE_PART 4 |
|---|
| 686 | 498 | static const char trunc_msg[] = "<truncated>"; |
|---|
| 687 | 499 | |
|---|
| 688 | | -static u32 truncate_msg(u16 *text_len, u16 *trunc_msg_len, |
|---|
| 689 | | - u16 *dict_len, u32 *pad_len) |
|---|
| 500 | +static void truncate_msg(u16 *text_len, u16 *trunc_msg_len) |
|---|
| 690 | 501 | { |
|---|
| 691 | 502 | /* |
|---|
| 692 | 503 | * The message should not take the whole buffer. Otherwise, it might |
|---|
| 693 | 504 | * get removed too soon. |
|---|
| 694 | 505 | */ |
|---|
| 695 | 506 | u32 max_text_len = log_buf_len / MAX_LOG_TAKE_PART; |
|---|
| 507 | + |
|---|
| 696 | 508 | if (*text_len > max_text_len) |
|---|
| 697 | 509 | *text_len = max_text_len; |
|---|
| 698 | | - /* enable the warning message */ |
|---|
| 510 | + |
|---|
| 511 | + /* enable the warning message (if there is room) */ |
|---|
| 699 | 512 | *trunc_msg_len = strlen(trunc_msg); |
|---|
| 700 | | - /* disable the "dict" completely */ |
|---|
| 701 | | - *dict_len = 0; |
|---|
| 702 | | - /* compute the size again, count also the warning message */ |
|---|
| 703 | | - return msg_used_size(*text_len + *trunc_msg_len, 0, pad_len); |
|---|
| 513 | + if (*text_len >= *trunc_msg_len) |
|---|
| 514 | + *text_len -= *trunc_msg_len; |
|---|
| 515 | + else |
|---|
| 516 | + *trunc_msg_len = 0; |
|---|
| 704 | 517 | } |
|---|
| 705 | 518 | |
|---|
| 706 | 519 | /* insert record into the buffer, discard old ones, update heads */ |
|---|
| 707 | | -static int log_store(int facility, int level, |
|---|
| 520 | +static int log_store(u32 caller_id, int facility, int level, |
|---|
| 708 | 521 | enum log_flags flags, u64 ts_nsec, |
|---|
| 709 | | - const char *dict, u16 dict_len, |
|---|
| 522 | + const struct dev_printk_info *dev_info, |
|---|
| 710 | 523 | const char *text, u16 text_len) |
|---|
| 711 | 524 | { |
|---|
| 712 | | - struct printk_log *msg; |
|---|
| 713 | | - u32 size, pad_len; |
|---|
| 525 | + struct prb_reserved_entry e; |
|---|
| 526 | + struct printk_record r; |
|---|
| 714 | 527 | u16 trunc_msg_len = 0; |
|---|
| 715 | 528 | |
|---|
| 716 | | - /* number of '\0' padding bytes to next message */ |
|---|
| 717 | | - size = msg_used_size(text_len, dict_len, &pad_len); |
|---|
| 529 | + prb_rec_init_wr(&r, text_len); |
|---|
| 718 | 530 | |
|---|
| 719 | | - if (log_make_free_space(size)) { |
|---|
| 531 | + if (!prb_reserve(&e, prb, &r)) { |
|---|
| 720 | 532 | /* truncate the message if it is too long for empty buffer */ |
|---|
| 721 | | - size = truncate_msg(&text_len, &trunc_msg_len, |
|---|
| 722 | | - &dict_len, &pad_len); |
|---|
| 533 | + truncate_msg(&text_len, &trunc_msg_len); |
|---|
| 534 | + prb_rec_init_wr(&r, text_len + trunc_msg_len); |
|---|
| 723 | 535 | /* survive when the log buffer is too small for trunc_msg */ |
|---|
| 724 | | - if (log_make_free_space(size)) |
|---|
| 536 | + if (!prb_reserve(&e, prb, &r)) |
|---|
| 725 | 537 | return 0; |
|---|
| 726 | 538 | } |
|---|
| 727 | 539 | |
|---|
| 728 | | - if (log_next_idx + size + sizeof(struct printk_log) > log_buf_len) { |
|---|
| 729 | | - /* |
|---|
| 730 | | - * This message + an additional empty header does not fit |
|---|
| 731 | | - * at the end of the buffer. Add an empty header with len == 0 |
|---|
| 732 | | - * to signify a wrap around. |
|---|
| 733 | | - */ |
|---|
| 734 | | - memset(log_buf + log_next_idx, 0, sizeof(struct printk_log)); |
|---|
| 735 | | - log_next_idx = 0; |
|---|
| 736 | | - } |
|---|
| 737 | | - |
|---|
| 738 | 540 | /* fill message */ |
|---|
| 739 | | - msg = (struct printk_log *)(log_buf + log_next_idx); |
|---|
| 740 | | - memcpy(log_text(msg), text, text_len); |
|---|
| 741 | | - msg->text_len = text_len; |
|---|
| 742 | | - if (trunc_msg_len) { |
|---|
| 743 | | - memcpy(log_text(msg) + text_len, trunc_msg, trunc_msg_len); |
|---|
| 744 | | - msg->text_len += trunc_msg_len; |
|---|
| 745 | | - } |
|---|
| 746 | | - memcpy(log_dict(msg), dict, dict_len); |
|---|
| 747 | | - msg->dict_len = dict_len; |
|---|
| 748 | | - msg->facility = facility; |
|---|
| 749 | | - msg->level = level & 7; |
|---|
| 750 | | - msg->flags = flags & 0x1f; |
|---|
| 541 | + memcpy(&r.text_buf[0], text, text_len); |
|---|
| 542 | + if (trunc_msg_len) |
|---|
| 543 | + memcpy(&r.text_buf[text_len], trunc_msg, trunc_msg_len); |
|---|
| 544 | + r.info->text_len = text_len + trunc_msg_len; |
|---|
| 545 | + r.info->facility = facility; |
|---|
| 546 | + r.info->level = level & 7; |
|---|
| 547 | + r.info->flags = flags & 0x1f; |
|---|
| 751 | 548 | if (ts_nsec > 0) |
|---|
| 752 | | - msg->ts_nsec = ts_nsec; |
|---|
| 549 | + r.info->ts_nsec = ts_nsec; |
|---|
| 753 | 550 | else |
|---|
| 754 | | - msg->ts_nsec = get_local_clock(); |
|---|
| 755 | | - memset(log_dict(msg) + dict_len, 0, pad_len); |
|---|
| 756 | | - msg->len = size; |
|---|
| 551 | + r.info->ts_nsec = get_local_clock(); |
|---|
| 552 | + r.info->caller_id = caller_id; |
|---|
| 553 | + if (dev_info) |
|---|
| 554 | + memcpy(&r.info->dev_info, dev_info, sizeof(r.info->dev_info)); |
|---|
| 757 | 555 | |
|---|
| 758 | | -#ifdef CONFIG_PRINTK_PROCESS |
|---|
| 759 | | - if (printk_process) { |
|---|
| 760 | | - strncpy(msg->process, current->comm, sizeof(msg->process) - 1); |
|---|
| 761 | | - msg->process[sizeof(msg->process) - 1] = '\0'; |
|---|
| 762 | | - msg->pid = task_pid_nr(current); |
|---|
| 763 | | - msg->cpu = raw_smp_processor_id(); |
|---|
| 764 | | - msg->in_interrupt = in_interrupt() ? 1 : 0; |
|---|
| 765 | | - } |
|---|
| 766 | | -#endif |
|---|
| 556 | + /* A message without a trailing newline can be continued. */ |
|---|
| 557 | + if (!(flags & LOG_NEWLINE)) |
|---|
| 558 | + prb_commit(&e); |
|---|
| 559 | + else |
|---|
| 560 | + prb_final_commit(&e); |
|---|
| 767 | 561 | |
|---|
| 768 | | - /* insert message */ |
|---|
| 769 | | - log_next_idx += msg->len; |
|---|
| 770 | | - log_next_seq++; |
|---|
| 562 | + trace_android_vh_logbuf(prb, &r); |
|---|
| 771 | 563 | |
|---|
| 772 | | - return msg->text_len; |
|---|
| 564 | + return (text_len + trunc_msg_len); |
|---|
| 773 | 565 | } |
|---|
| 774 | 566 | |
|---|
| 775 | 567 | int dmesg_restrict = IS_ENABLED(CONFIG_SECURITY_DMESG_RESTRICT); |
|---|
| .. | .. |
|---|
| 821 | 613 | *(*pp)++ = c; |
|---|
| 822 | 614 | } |
|---|
| 823 | 615 | |
|---|
| 824 | | -static ssize_t msg_print_ext_header(char *buf, size_t size, |
|---|
| 825 | | - struct printk_log *msg, u64 seq) |
|---|
| 616 | +static ssize_t info_print_ext_header(char *buf, size_t size, |
|---|
| 617 | + struct printk_info *info) |
|---|
| 826 | 618 | { |
|---|
| 827 | | - u64 ts_usec = msg->ts_nsec; |
|---|
| 619 | + u64 ts_usec = info->ts_nsec; |
|---|
| 620 | + char caller[20]; |
|---|
| 621 | +#ifdef CONFIG_PRINTK_CALLER |
|---|
| 622 | + u32 id = info->caller_id; |
|---|
| 623 | + |
|---|
| 624 | + snprintf(caller, sizeof(caller), ",caller=%c%u", |
|---|
| 625 | + id & 0x80000000 ? 'C' : 'T', id & ~0x80000000); |
|---|
| 626 | +#else |
|---|
| 627 | + caller[0] = '\0'; |
|---|
| 628 | +#endif |
|---|
| 828 | 629 | |
|---|
| 829 | 630 | do_div(ts_usec, 1000); |
|---|
| 830 | 631 | |
|---|
| 831 | | - return scnprintf(buf, size, "%u,%llu,%llu,%c;", |
|---|
| 832 | | - (msg->facility << 3) | msg->level, seq, ts_usec, |
|---|
| 833 | | - msg->flags & LOG_CONT ? 'c' : '-'); |
|---|
| 632 | + return scnprintf(buf, size, "%u,%llu,%llu,%c%s;", |
|---|
| 633 | + (info->facility << 3) | info->level, info->seq, |
|---|
| 634 | + ts_usec, info->flags & LOG_CONT ? 'c' : '-', caller); |
|---|
| 834 | 635 | } |
|---|
| 835 | 636 | |
|---|
| 836 | | -static ssize_t msg_print_ext_body(char *buf, size_t size, |
|---|
| 837 | | - char *dict, size_t dict_len, |
|---|
| 838 | | - char *text, size_t text_len) |
|---|
| 637 | +static ssize_t msg_add_ext_text(char *buf, size_t size, |
|---|
| 638 | + const char *text, size_t text_len, |
|---|
| 639 | + unsigned char endc) |
|---|
| 839 | 640 | { |
|---|
| 840 | 641 | char *p = buf, *e = buf + size; |
|---|
| 841 | 642 | size_t i; |
|---|
| .. | .. |
|---|
| 849 | 650 | else |
|---|
| 850 | 651 | append_char(&p, e, c); |
|---|
| 851 | 652 | } |
|---|
| 852 | | - append_char(&p, e, '\n'); |
|---|
| 853 | | - |
|---|
| 854 | | - if (dict_len) { |
|---|
| 855 | | - bool line = true; |
|---|
| 856 | | - |
|---|
| 857 | | - for (i = 0; i < dict_len; i++) { |
|---|
| 858 | | - unsigned char c = dict[i]; |
|---|
| 859 | | - |
|---|
| 860 | | - if (line) { |
|---|
| 861 | | - append_char(&p, e, ' '); |
|---|
| 862 | | - line = false; |
|---|
| 863 | | - } |
|---|
| 864 | | - |
|---|
| 865 | | - if (c == '\0') { |
|---|
| 866 | | - append_char(&p, e, '\n'); |
|---|
| 867 | | - line = true; |
|---|
| 868 | | - continue; |
|---|
| 869 | | - } |
|---|
| 870 | | - |
|---|
| 871 | | - if (c < ' ' || c >= 127 || c == '\\') { |
|---|
| 872 | | - p += scnprintf(p, e - p, "\\x%02x", c); |
|---|
| 873 | | - continue; |
|---|
| 874 | | - } |
|---|
| 875 | | - |
|---|
| 876 | | - append_char(&p, e, c); |
|---|
| 877 | | - } |
|---|
| 878 | | - append_char(&p, e, '\n'); |
|---|
| 879 | | - } |
|---|
| 653 | + append_char(&p, e, endc); |
|---|
| 880 | 654 | |
|---|
| 881 | 655 | return p - buf; |
|---|
| 656 | +} |
|---|
| 657 | + |
|---|
| 658 | +static ssize_t msg_add_dict_text(char *buf, size_t size, |
|---|
| 659 | + const char *key, const char *val) |
|---|
| 660 | +{ |
|---|
| 661 | + size_t val_len = strlen(val); |
|---|
| 662 | + ssize_t len; |
|---|
| 663 | + |
|---|
| 664 | + if (!val_len) |
|---|
| 665 | + return 0; |
|---|
| 666 | + |
|---|
| 667 | + len = msg_add_ext_text(buf, size, "", 0, ' '); /* dict prefix */ |
|---|
| 668 | + len += msg_add_ext_text(buf + len, size - len, key, strlen(key), '='); |
|---|
| 669 | + len += msg_add_ext_text(buf + len, size - len, val, val_len, '\n'); |
|---|
| 670 | + |
|---|
| 671 | + return len; |
|---|
| 672 | +} |
|---|
| 673 | + |
|---|
| 674 | +static ssize_t msg_print_ext_body(char *buf, size_t size, |
|---|
| 675 | + char *text, size_t text_len, |
|---|
| 676 | + struct dev_printk_info *dev_info) |
|---|
| 677 | +{ |
|---|
| 678 | + ssize_t len; |
|---|
| 679 | + |
|---|
| 680 | + len = msg_add_ext_text(buf, size, text, text_len, '\n'); |
|---|
| 681 | + |
|---|
| 682 | + if (!dev_info) |
|---|
| 683 | + goto out; |
|---|
| 684 | + |
|---|
| 685 | + len += msg_add_dict_text(buf + len, size - len, "SUBSYSTEM", |
|---|
| 686 | + dev_info->subsystem); |
|---|
| 687 | + len += msg_add_dict_text(buf + len, size - len, "DEVICE", |
|---|
| 688 | + dev_info->device); |
|---|
| 689 | +out: |
|---|
| 690 | + return len; |
|---|
| 882 | 691 | } |
|---|
| 883 | 692 | |
|---|
| 884 | 693 | /* /dev/kmsg - userspace message inject/listen interface */ |
|---|
| 885 | 694 | struct devkmsg_user { |
|---|
| 886 | 695 | u64 seq; |
|---|
| 887 | | - u32 idx; |
|---|
| 888 | 696 | struct ratelimit_state rs; |
|---|
| 889 | 697 | struct mutex lock; |
|---|
| 890 | 698 | char buf[CONSOLE_EXT_LOG_MAX]; |
|---|
| 699 | + |
|---|
| 700 | + struct printk_info info; |
|---|
| 701 | + char text_buf[CONSOLE_EXT_LOG_MAX]; |
|---|
| 702 | + struct printk_record record; |
|---|
| 891 | 703 | }; |
|---|
| 704 | + |
|---|
| 705 | +static __printf(3, 4) __cold |
|---|
| 706 | +int devkmsg_emit(int facility, int level, const char *fmt, ...) |
|---|
| 707 | +{ |
|---|
| 708 | + va_list args; |
|---|
| 709 | + int r; |
|---|
| 710 | + |
|---|
| 711 | + va_start(args, fmt); |
|---|
| 712 | + r = vprintk_emit(facility, level, NULL, fmt, args); |
|---|
| 713 | + va_end(args); |
|---|
| 714 | + |
|---|
| 715 | + return r; |
|---|
| 716 | +} |
|---|
| 892 | 717 | |
|---|
| 893 | 718 | static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from) |
|---|
| 894 | 719 | { |
|---|
| .. | .. |
|---|
| 948 | 773 | } |
|---|
| 949 | 774 | } |
|---|
| 950 | 775 | |
|---|
| 951 | | - printk_emit(facility, level, NULL, 0, "%s", line); |
|---|
| 776 | + devkmsg_emit(facility, level, "%s", line); |
|---|
| 952 | 777 | kfree(buf); |
|---|
| 953 | 778 | return ret; |
|---|
| 954 | 779 | } |
|---|
| .. | .. |
|---|
| 957 | 782 | size_t count, loff_t *ppos) |
|---|
| 958 | 783 | { |
|---|
| 959 | 784 | struct devkmsg_user *user = file->private_data; |
|---|
| 960 | | - struct printk_log *msg; |
|---|
| 785 | + struct printk_record *r = &user->record; |
|---|
| 961 | 786 | size_t len; |
|---|
| 962 | 787 | ssize_t ret; |
|---|
| 963 | 788 | |
|---|
| .. | .. |
|---|
| 969 | 794 | return ret; |
|---|
| 970 | 795 | |
|---|
| 971 | 796 | logbuf_lock_irq(); |
|---|
| 972 | | - while (user->seq == log_next_seq) { |
|---|
| 797 | + if (!prb_read_valid(prb, user->seq, r)) { |
|---|
| 973 | 798 | if (file->f_flags & O_NONBLOCK) { |
|---|
| 974 | 799 | ret = -EAGAIN; |
|---|
| 975 | 800 | logbuf_unlock_irq(); |
|---|
| .. | .. |
|---|
| 978 | 803 | |
|---|
| 979 | 804 | logbuf_unlock_irq(); |
|---|
| 980 | 805 | ret = wait_event_interruptible(log_wait, |
|---|
| 981 | | - user->seq != log_next_seq); |
|---|
| 806 | + prb_read_valid(prb, user->seq, r)); |
|---|
| 982 | 807 | if (ret) |
|---|
| 983 | 808 | goto out; |
|---|
| 984 | 809 | logbuf_lock_irq(); |
|---|
| 985 | 810 | } |
|---|
| 986 | 811 | |
|---|
| 987 | | - if (user->seq < log_first_seq) { |
|---|
| 812 | + if (r->info->seq != user->seq) { |
|---|
| 988 | 813 | /* our last seen message is gone, return error and reset */ |
|---|
| 989 | | - user->idx = log_first_idx; |
|---|
| 990 | | - user->seq = log_first_seq; |
|---|
| 814 | + user->seq = r->info->seq; |
|---|
| 991 | 815 | ret = -EPIPE; |
|---|
| 992 | 816 | logbuf_unlock_irq(); |
|---|
| 993 | 817 | goto out; |
|---|
| 994 | 818 | } |
|---|
| 995 | 819 | |
|---|
| 996 | | - msg = log_from_idx(user->idx); |
|---|
| 997 | | - len = msg_print_ext_header(user->buf, sizeof(user->buf), |
|---|
| 998 | | - msg, user->seq); |
|---|
| 820 | + len = info_print_ext_header(user->buf, sizeof(user->buf), r->info); |
|---|
| 999 | 821 | len += msg_print_ext_body(user->buf + len, sizeof(user->buf) - len, |
|---|
| 1000 | | - log_dict(msg), msg->dict_len, |
|---|
| 1001 | | - log_text(msg), msg->text_len); |
|---|
| 822 | + &r->text_buf[0], r->info->text_len, |
|---|
| 823 | + &r->info->dev_info); |
|---|
| 1002 | 824 | |
|---|
| 1003 | | - user->idx = log_next(user->idx); |
|---|
| 1004 | | - user->seq++; |
|---|
| 825 | + user->seq = r->info->seq + 1; |
|---|
| 1005 | 826 | logbuf_unlock_irq(); |
|---|
| 1006 | 827 | |
|---|
| 1007 | 828 | if (len > count) { |
|---|
| .. | .. |
|---|
| 1019 | 840 | return ret; |
|---|
| 1020 | 841 | } |
|---|
| 1021 | 842 | |
|---|
| 843 | +/* |
|---|
| 844 | + * Be careful when modifying this function!!! |
|---|
| 845 | + * |
|---|
| 846 | + * Only few operations are supported because the device works only with the |
|---|
| 847 | + * entire variable length messages (records). Non-standard values are |
|---|
| 848 | + * returned in the other cases and has been this way for quite some time. |
|---|
| 849 | + * User space applications might depend on this behavior. |
|---|
| 850 | + */ |
|---|
| 1022 | 851 | static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence) |
|---|
| 1023 | 852 | { |
|---|
| 1024 | 853 | struct devkmsg_user *user = file->private_data; |
|---|
| .. | .. |
|---|
| 1033 | 862 | switch (whence) { |
|---|
| 1034 | 863 | case SEEK_SET: |
|---|
| 1035 | 864 | /* the first record */ |
|---|
| 1036 | | - user->idx = log_first_idx; |
|---|
| 1037 | | - user->seq = log_first_seq; |
|---|
| 865 | + user->seq = prb_first_valid_seq(prb); |
|---|
| 1038 | 866 | break; |
|---|
| 1039 | 867 | case SEEK_DATA: |
|---|
| 1040 | 868 | /* |
|---|
| .. | .. |
|---|
| 1042 | 870 | * like issued by 'dmesg -c'. Reading /dev/kmsg itself |
|---|
| 1043 | 871 | * changes no global state, and does not clear anything. |
|---|
| 1044 | 872 | */ |
|---|
| 1045 | | - user->idx = clear_idx; |
|---|
| 1046 | 873 | user->seq = clear_seq; |
|---|
| 1047 | 874 | break; |
|---|
| 1048 | 875 | case SEEK_END: |
|---|
| 1049 | 876 | /* after the last record */ |
|---|
| 1050 | | - user->idx = log_next_idx; |
|---|
| 1051 | | - user->seq = log_next_seq; |
|---|
| 877 | + user->seq = prb_next_seq(prb); |
|---|
| 1052 | 878 | break; |
|---|
| 1053 | 879 | default: |
|---|
| 1054 | 880 | ret = -EINVAL; |
|---|
| .. | .. |
|---|
| 1060 | 886 | static __poll_t devkmsg_poll(struct file *file, poll_table *wait) |
|---|
| 1061 | 887 | { |
|---|
| 1062 | 888 | struct devkmsg_user *user = file->private_data; |
|---|
| 889 | + struct printk_info info; |
|---|
| 1063 | 890 | __poll_t ret = 0; |
|---|
| 1064 | 891 | |
|---|
| 1065 | 892 | if (!user) |
|---|
| .. | .. |
|---|
| 1068 | 895 | poll_wait(file, &log_wait, wait); |
|---|
| 1069 | 896 | |
|---|
| 1070 | 897 | logbuf_lock_irq(); |
|---|
| 1071 | | - if (user->seq < log_next_seq) { |
|---|
| 898 | + if (prb_read_valid_info(prb, user->seq, &info, NULL)) { |
|---|
| 1072 | 899 | /* return error when data has vanished underneath us */ |
|---|
| 1073 | | - if (user->seq < log_first_seq) |
|---|
| 900 | + if (info.seq != user->seq) |
|---|
| 1074 | 901 | ret = EPOLLIN|EPOLLRDNORM|EPOLLERR|EPOLLPRI; |
|---|
| 1075 | 902 | else |
|---|
| 1076 | 903 | ret = EPOLLIN|EPOLLRDNORM; |
|---|
| .. | .. |
|---|
| 1105 | 932 | |
|---|
| 1106 | 933 | mutex_init(&user->lock); |
|---|
| 1107 | 934 | |
|---|
| 935 | + prb_rec_init_rd(&user->record, &user->info, |
|---|
| 936 | + &user->text_buf[0], sizeof(user->text_buf)); |
|---|
| 937 | + |
|---|
| 1108 | 938 | logbuf_lock_irq(); |
|---|
| 1109 | | - user->idx = log_first_idx; |
|---|
| 1110 | | - user->seq = log_first_seq; |
|---|
| 939 | + user->seq = prb_first_valid_seq(prb); |
|---|
| 1111 | 940 | logbuf_unlock_irq(); |
|---|
| 1112 | 941 | |
|---|
| 1113 | 942 | file->private_data = user; |
|---|
| .. | .. |
|---|
| 1148 | 977 | */ |
|---|
| 1149 | 978 | void log_buf_vmcoreinfo_setup(void) |
|---|
| 1150 | 979 | { |
|---|
| 1151 | | - VMCOREINFO_SYMBOL(log_buf); |
|---|
| 1152 | | - VMCOREINFO_SYMBOL(log_buf_len); |
|---|
| 1153 | | - VMCOREINFO_SYMBOL(log_first_idx); |
|---|
| 1154 | | - VMCOREINFO_SYMBOL(clear_idx); |
|---|
| 1155 | | - VMCOREINFO_SYMBOL(log_next_idx); |
|---|
| 980 | + struct dev_printk_info *dev_info = NULL; |
|---|
| 981 | + |
|---|
| 982 | + VMCOREINFO_SYMBOL(prb); |
|---|
| 983 | + VMCOREINFO_SYMBOL(printk_rb_static); |
|---|
| 984 | + VMCOREINFO_SYMBOL(clear_seq); |
|---|
| 985 | + |
|---|
| 1156 | 986 | /* |
|---|
| 1157 | | - * Export struct printk_log size and field offsets. User space tools can |
|---|
| 987 | + * Export struct size and field offsets. User space tools can |
|---|
| 1158 | 988 | * parse it and detect any changes to structure down the line. |
|---|
| 1159 | 989 | */ |
|---|
| 1160 | | - VMCOREINFO_STRUCT_SIZE(printk_log); |
|---|
| 1161 | | - VMCOREINFO_OFFSET(printk_log, ts_nsec); |
|---|
| 1162 | | - VMCOREINFO_OFFSET(printk_log, len); |
|---|
| 1163 | | - VMCOREINFO_OFFSET(printk_log, text_len); |
|---|
| 1164 | | - VMCOREINFO_OFFSET(printk_log, dict_len); |
|---|
| 990 | + |
|---|
| 991 | + VMCOREINFO_STRUCT_SIZE(printk_ringbuffer); |
|---|
| 992 | + VMCOREINFO_OFFSET(printk_ringbuffer, desc_ring); |
|---|
| 993 | + VMCOREINFO_OFFSET(printk_ringbuffer, text_data_ring); |
|---|
| 994 | + VMCOREINFO_OFFSET(printk_ringbuffer, fail); |
|---|
| 995 | + |
|---|
| 996 | + VMCOREINFO_STRUCT_SIZE(prb_desc_ring); |
|---|
| 997 | + VMCOREINFO_OFFSET(prb_desc_ring, count_bits); |
|---|
| 998 | + VMCOREINFO_OFFSET(prb_desc_ring, descs); |
|---|
| 999 | + VMCOREINFO_OFFSET(prb_desc_ring, infos); |
|---|
| 1000 | + VMCOREINFO_OFFSET(prb_desc_ring, head_id); |
|---|
| 1001 | + VMCOREINFO_OFFSET(prb_desc_ring, tail_id); |
|---|
| 1002 | + |
|---|
| 1003 | + VMCOREINFO_STRUCT_SIZE(prb_desc); |
|---|
| 1004 | + VMCOREINFO_OFFSET(prb_desc, state_var); |
|---|
| 1005 | + VMCOREINFO_OFFSET(prb_desc, text_blk_lpos); |
|---|
| 1006 | + |
|---|
| 1007 | + VMCOREINFO_STRUCT_SIZE(prb_data_blk_lpos); |
|---|
| 1008 | + VMCOREINFO_OFFSET(prb_data_blk_lpos, begin); |
|---|
| 1009 | + VMCOREINFO_OFFSET(prb_data_blk_lpos, next); |
|---|
| 1010 | + |
|---|
| 1011 | + VMCOREINFO_STRUCT_SIZE(printk_info); |
|---|
| 1012 | + VMCOREINFO_OFFSET(printk_info, seq); |
|---|
| 1013 | + VMCOREINFO_OFFSET(printk_info, ts_nsec); |
|---|
| 1014 | + VMCOREINFO_OFFSET(printk_info, text_len); |
|---|
| 1015 | + VMCOREINFO_OFFSET(printk_info, caller_id); |
|---|
| 1016 | + VMCOREINFO_OFFSET(printk_info, dev_info); |
|---|
| 1017 | + |
|---|
| 1018 | + VMCOREINFO_STRUCT_SIZE(dev_printk_info); |
|---|
| 1019 | + VMCOREINFO_OFFSET(dev_printk_info, subsystem); |
|---|
| 1020 | + VMCOREINFO_LENGTH(printk_info_subsystem, sizeof(dev_info->subsystem)); |
|---|
| 1021 | + VMCOREINFO_OFFSET(dev_printk_info, device); |
|---|
| 1022 | + VMCOREINFO_LENGTH(printk_info_device, sizeof(dev_info->device)); |
|---|
| 1023 | + |
|---|
| 1024 | + VMCOREINFO_STRUCT_SIZE(prb_data_ring); |
|---|
| 1025 | + VMCOREINFO_OFFSET(prb_data_ring, size_bits); |
|---|
| 1026 | + VMCOREINFO_OFFSET(prb_data_ring, data); |
|---|
| 1027 | + VMCOREINFO_OFFSET(prb_data_ring, head_lpos); |
|---|
| 1028 | + VMCOREINFO_OFFSET(prb_data_ring, tail_lpos); |
|---|
| 1029 | + |
|---|
| 1030 | + VMCOREINFO_SIZE(atomic_long_t); |
|---|
| 1031 | + VMCOREINFO_TYPE_OFFSET(atomic_long_t, counter); |
|---|
| 1165 | 1032 | } |
|---|
| 1166 | 1033 | #endif |
|---|
| 1167 | 1034 | |
|---|
| .. | .. |
|---|
| 1239 | 1106 | __printk_percpu_data_ready = true; |
|---|
| 1240 | 1107 | } |
|---|
| 1241 | 1108 | |
|---|
| 1109 | +static unsigned int __init add_to_rb(struct printk_ringbuffer *rb, |
|---|
| 1110 | + struct printk_record *r) |
|---|
| 1111 | +{ |
|---|
| 1112 | + struct prb_reserved_entry e; |
|---|
| 1113 | + struct printk_record dest_r; |
|---|
| 1114 | + |
|---|
| 1115 | + prb_rec_init_wr(&dest_r, r->info->text_len); |
|---|
| 1116 | + |
|---|
| 1117 | + if (!prb_reserve(&e, rb, &dest_r)) |
|---|
| 1118 | + return 0; |
|---|
| 1119 | + |
|---|
| 1120 | + memcpy(&dest_r.text_buf[0], &r->text_buf[0], r->info->text_len); |
|---|
| 1121 | + dest_r.info->text_len = r->info->text_len; |
|---|
| 1122 | + dest_r.info->facility = r->info->facility; |
|---|
| 1123 | + dest_r.info->level = r->info->level; |
|---|
| 1124 | + dest_r.info->flags = r->info->flags; |
|---|
| 1125 | + dest_r.info->ts_nsec = r->info->ts_nsec; |
|---|
| 1126 | + dest_r.info->caller_id = r->info->caller_id; |
|---|
| 1127 | + memcpy(&dest_r.info->dev_info, &r->info->dev_info, sizeof(dest_r.info->dev_info)); |
|---|
| 1128 | + |
|---|
| 1129 | + prb_final_commit(&e); |
|---|
| 1130 | + |
|---|
| 1131 | + return prb_record_text_space(&e); |
|---|
| 1132 | +} |
|---|
| 1133 | + |
|---|
| 1134 | +static char setup_text_buf[LOG_LINE_MAX] __initdata; |
|---|
| 1135 | + |
|---|
| 1242 | 1136 | void __init setup_log_buf(int early) |
|---|
| 1243 | 1137 | { |
|---|
| 1138 | + struct printk_info *new_infos; |
|---|
| 1139 | + unsigned int new_descs_count; |
|---|
| 1140 | + struct prb_desc *new_descs; |
|---|
| 1141 | + struct printk_info info; |
|---|
| 1142 | + struct printk_record r; |
|---|
| 1143 | + size_t new_descs_size; |
|---|
| 1144 | + size_t new_infos_size; |
|---|
| 1244 | 1145 | unsigned long flags; |
|---|
| 1245 | 1146 | char *new_log_buf; |
|---|
| 1246 | 1147 | unsigned int free; |
|---|
| 1148 | + u64 seq; |
|---|
| 1247 | 1149 | |
|---|
| 1248 | 1150 | /* |
|---|
| 1249 | 1151 | * Some archs call setup_log_buf() multiple times - first is very |
|---|
| .. | .. |
|---|
| 1262 | 1164 | if (!new_log_buf_len) |
|---|
| 1263 | 1165 | return; |
|---|
| 1264 | 1166 | |
|---|
| 1265 | | - if (early) { |
|---|
| 1266 | | - new_log_buf = |
|---|
| 1267 | | - memblock_virt_alloc(new_log_buf_len, LOG_ALIGN); |
|---|
| 1268 | | - } else { |
|---|
| 1269 | | - new_log_buf = memblock_virt_alloc_nopanic(new_log_buf_len, |
|---|
| 1270 | | - LOG_ALIGN); |
|---|
| 1271 | | - } |
|---|
| 1272 | | - |
|---|
| 1273 | | - if (unlikely(!new_log_buf)) { |
|---|
| 1274 | | - pr_err("log_buf_len: %lu bytes not available\n", |
|---|
| 1275 | | - new_log_buf_len); |
|---|
| 1167 | + new_descs_count = new_log_buf_len >> PRB_AVGBITS; |
|---|
| 1168 | + if (new_descs_count == 0) { |
|---|
| 1169 | + pr_err("new_log_buf_len: %lu too small\n", new_log_buf_len); |
|---|
| 1276 | 1170 | return; |
|---|
| 1277 | 1171 | } |
|---|
| 1278 | 1172 | |
|---|
| 1173 | + new_log_buf = memblock_alloc(new_log_buf_len, LOG_ALIGN); |
|---|
| 1174 | + if (unlikely(!new_log_buf)) { |
|---|
| 1175 | + pr_err("log_buf_len: %lu text bytes not available\n", |
|---|
| 1176 | + new_log_buf_len); |
|---|
| 1177 | + return; |
|---|
| 1178 | + } |
|---|
| 1179 | + |
|---|
| 1180 | + new_descs_size = new_descs_count * sizeof(struct prb_desc); |
|---|
| 1181 | + new_descs = memblock_alloc(new_descs_size, LOG_ALIGN); |
|---|
| 1182 | + if (unlikely(!new_descs)) { |
|---|
| 1183 | + pr_err("log_buf_len: %zu desc bytes not available\n", |
|---|
| 1184 | + new_descs_size); |
|---|
| 1185 | + goto err_free_log_buf; |
|---|
| 1186 | + } |
|---|
| 1187 | + |
|---|
| 1188 | + new_infos_size = new_descs_count * sizeof(struct printk_info); |
|---|
| 1189 | + new_infos = memblock_alloc(new_infos_size, LOG_ALIGN); |
|---|
| 1190 | + if (unlikely(!new_infos)) { |
|---|
| 1191 | + pr_err("log_buf_len: %zu info bytes not available\n", |
|---|
| 1192 | + new_infos_size); |
|---|
| 1193 | + goto err_free_descs; |
|---|
| 1194 | + } |
|---|
| 1195 | + |
|---|
| 1196 | + prb_rec_init_rd(&r, &info, &setup_text_buf[0], sizeof(setup_text_buf)); |
|---|
| 1197 | + |
|---|
| 1198 | + prb_init(&printk_rb_dynamic, |
|---|
| 1199 | + new_log_buf, ilog2(new_log_buf_len), |
|---|
| 1200 | + new_descs, ilog2(new_descs_count), |
|---|
| 1201 | + new_infos); |
|---|
| 1202 | + |
|---|
| 1279 | 1203 | logbuf_lock_irqsave(flags); |
|---|
| 1204 | + |
|---|
| 1280 | 1205 | log_buf_len = new_log_buf_len; |
|---|
| 1281 | 1206 | log_buf = new_log_buf; |
|---|
| 1282 | 1207 | new_log_buf_len = 0; |
|---|
| 1283 | | - free = __LOG_BUF_LEN - log_next_idx; |
|---|
| 1284 | | - memcpy(log_buf, __log_buf, __LOG_BUF_LEN); |
|---|
| 1208 | + |
|---|
| 1209 | + free = __LOG_BUF_LEN; |
|---|
| 1210 | + prb_for_each_record(0, &printk_rb_static, seq, &r) |
|---|
| 1211 | + free -= add_to_rb(&printk_rb_dynamic, &r); |
|---|
| 1212 | + |
|---|
| 1213 | + /* |
|---|
| 1214 | + * This is early enough that everything is still running on the |
|---|
| 1215 | + * boot CPU and interrupts are disabled. So no new messages will |
|---|
| 1216 | + * appear during the transition to the dynamic buffer. |
|---|
| 1217 | + */ |
|---|
| 1218 | + prb = &printk_rb_dynamic; |
|---|
| 1219 | + |
|---|
| 1285 | 1220 | logbuf_unlock_irqrestore(flags); |
|---|
| 1221 | + |
|---|
| 1222 | + if (seq != prb_next_seq(&printk_rb_static)) { |
|---|
| 1223 | + pr_err("dropped %llu messages\n", |
|---|
| 1224 | + prb_next_seq(&printk_rb_static) - seq); |
|---|
| 1225 | + } |
|---|
| 1286 | 1226 | |
|---|
| 1287 | 1227 | pr_info("log_buf_len: %u bytes\n", log_buf_len); |
|---|
| 1288 | 1228 | pr_info("early log buf free: %u(%u%%)\n", |
|---|
| 1289 | 1229 | free, (free * 100) / __LOG_BUF_LEN); |
|---|
| 1230 | + return; |
|---|
| 1231 | + |
|---|
| 1232 | +err_free_descs: |
|---|
| 1233 | + memblock_free(__pa(new_descs), new_descs_size); |
|---|
| 1234 | +err_free_log_buf: |
|---|
| 1235 | + memblock_free(__pa(new_log_buf), new_log_buf_len); |
|---|
| 1290 | 1236 | } |
|---|
| 1291 | 1237 | |
|---|
| 1292 | | -#ifdef CONFIG_PSTORE_CONSOLE_FORCE_ON |
|---|
| 1293 | | -static bool __read_mostly ignore_loglevel = true; |
|---|
| 1294 | | -#else |
|---|
| 1295 | 1238 | static bool __read_mostly ignore_loglevel; |
|---|
| 1296 | | -#endif |
|---|
| 1297 | 1239 | |
|---|
| 1298 | 1240 | static int __init ignore_loglevel_setup(char *str) |
|---|
| 1299 | 1241 | { |
|---|
| .. | .. |
|---|
| 1307 | 1249 | module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR); |
|---|
| 1308 | 1250 | MODULE_PARM_DESC(ignore_loglevel, |
|---|
| 1309 | 1251 | "ignore loglevel setting (prints all kernel messages to the console)"); |
|---|
| 1310 | | - |
|---|
| 1311 | | -#ifdef CONFIG_PSTORE_CONSOLE_FORCE |
|---|
| 1312 | | -static bool __read_mostly pstore_con_force = IS_ENABLED(CONFIG_PSTORE_CONSOLE_FORCE_ON); |
|---|
| 1313 | | - |
|---|
| 1314 | | -static int __init pstore_con_force_setup(char *str) |
|---|
| 1315 | | -{ |
|---|
| 1316 | | - bool force; |
|---|
| 1317 | | - int ret = strtobool(str, &force); |
|---|
| 1318 | | - |
|---|
| 1319 | | - if (ret) |
|---|
| 1320 | | - return ret; |
|---|
| 1321 | | - |
|---|
| 1322 | | - ignore_loglevel = force; |
|---|
| 1323 | | - pstore_con_force = force; |
|---|
| 1324 | | - if (force) |
|---|
| 1325 | | - pr_info("debug: pstore console ignoring loglevel setting.\n"); |
|---|
| 1326 | | - |
|---|
| 1327 | | - return 0; |
|---|
| 1328 | | -} |
|---|
| 1329 | | - |
|---|
| 1330 | | -early_param("pstore_con_force", pstore_con_force_setup); |
|---|
| 1331 | | -module_param(pstore_con_force, bool, S_IRUGO | S_IWUSR); |
|---|
| 1332 | | -MODULE_PARM_DESC(pstore_con_force, |
|---|
| 1333 | | - "ignore loglevel setting (prints all kernel messages to the pstore console)"); |
|---|
| 1334 | | - |
|---|
| 1335 | | -static void call_console_drivers_level(int level, const char *ext_text, size_t ext_len, |
|---|
| 1336 | | - const char *text, size_t len) |
|---|
| 1337 | | -{ |
|---|
| 1338 | | - struct console *con; |
|---|
| 1339 | | - |
|---|
| 1340 | | - trace_console_rcuidle(text, len); |
|---|
| 1341 | | - |
|---|
| 1342 | | - if (!console_drivers) |
|---|
| 1343 | | - return; |
|---|
| 1344 | | - |
|---|
| 1345 | | - for_each_console(con) { |
|---|
| 1346 | | - if (pstore_con_force && |
|---|
| 1347 | | - !(con->flags & CON_PSTORE) && level >= console_loglevel) |
|---|
| 1348 | | - continue; |
|---|
| 1349 | | - if (exclusive_console && con != exclusive_console) |
|---|
| 1350 | | - continue; |
|---|
| 1351 | | - if (!(con->flags & CON_ENABLED)) |
|---|
| 1352 | | - continue; |
|---|
| 1353 | | - if (!con->write) |
|---|
| 1354 | | - continue; |
|---|
| 1355 | | - if (!cpu_online(smp_processor_id()) && |
|---|
| 1356 | | - !(con->flags & CON_ANYTIME)) |
|---|
| 1357 | | - continue; |
|---|
| 1358 | | - if (con->flags & CON_EXTENDED) |
|---|
| 1359 | | - con->write(con, ext_text, ext_len); |
|---|
| 1360 | | - else |
|---|
| 1361 | | - con->write(con, text, len); |
|---|
| 1362 | | - } |
|---|
| 1363 | | -} |
|---|
| 1364 | | -#endif |
|---|
| 1365 | 1252 | |
|---|
| 1366 | 1253 | static bool suppress_message_printing(int level) |
|---|
| 1367 | 1254 | { |
|---|
| .. | .. |
|---|
| 1426 | 1313 | static bool printk_time = IS_ENABLED(CONFIG_PRINTK_TIME); |
|---|
| 1427 | 1314 | module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR); |
|---|
| 1428 | 1315 | |
|---|
| 1316 | +static size_t print_syslog(unsigned int level, char *buf) |
|---|
| 1317 | +{ |
|---|
| 1318 | + return sprintf(buf, "<%u>", level); |
|---|
| 1319 | +} |
|---|
| 1320 | + |
|---|
| 1429 | 1321 | static size_t print_time(u64 ts, char *buf) |
|---|
| 1430 | 1322 | { |
|---|
| 1431 | | - unsigned long rem_nsec; |
|---|
| 1323 | + unsigned long rem_nsec = do_div(ts, 1000000000); |
|---|
| 1432 | 1324 | |
|---|
| 1433 | | - if (!printk_time) |
|---|
| 1434 | | - return 0; |
|---|
| 1435 | | - |
|---|
| 1436 | | - rem_nsec = do_div(ts, 1000000000); |
|---|
| 1437 | | - |
|---|
| 1438 | | - if (!buf) |
|---|
| 1439 | | - return snprintf(NULL, 0, "[%5lu.000000] ", (unsigned long)ts); |
|---|
| 1440 | | - |
|---|
| 1441 | | - return sprintf(buf, "[%5lu.%06lu] ", |
|---|
| 1325 | + return sprintf(buf, "[%5lu.%06lu]", |
|---|
| 1442 | 1326 | (unsigned long)ts, rem_nsec / 1000); |
|---|
| 1443 | 1327 | } |
|---|
| 1444 | 1328 | |
|---|
| 1445 | | -static size_t print_prefix(const struct printk_log *msg, bool syslog, char *buf) |
|---|
| 1329 | +#ifdef CONFIG_PRINTK_CALLER |
|---|
| 1330 | +static size_t print_caller(u32 id, char *buf) |
|---|
| 1331 | +{ |
|---|
| 1332 | + char caller[12]; |
|---|
| 1333 | + |
|---|
| 1334 | + snprintf(caller, sizeof(caller), "%c%u", |
|---|
| 1335 | + id & 0x80000000 ? 'C' : 'T', id & ~0x80000000); |
|---|
| 1336 | + return sprintf(buf, "[%6s]", caller); |
|---|
| 1337 | +} |
|---|
| 1338 | +#else |
|---|
| 1339 | +#define print_caller(id, buf) 0 |
|---|
| 1340 | +#endif |
|---|
| 1341 | + |
|---|
| 1342 | +static size_t info_print_prefix(const struct printk_info *info, bool syslog, |
|---|
| 1343 | + bool time, char *buf) |
|---|
| 1446 | 1344 | { |
|---|
| 1447 | 1345 | size_t len = 0; |
|---|
| 1448 | | - unsigned int prefix = (msg->facility << 3) | msg->level; |
|---|
| 1449 | 1346 | |
|---|
| 1450 | | - if (syslog) { |
|---|
| 1451 | | - if (buf) { |
|---|
| 1452 | | - len += sprintf(buf, "<%u>", prefix); |
|---|
| 1453 | | - } else { |
|---|
| 1454 | | - len += 3; |
|---|
| 1455 | | - if (prefix > 999) |
|---|
| 1456 | | - len += 3; |
|---|
| 1457 | | - else if (prefix > 99) |
|---|
| 1458 | | - len += 2; |
|---|
| 1459 | | - else if (prefix > 9) |
|---|
| 1460 | | - len++; |
|---|
| 1461 | | - } |
|---|
| 1347 | + if (syslog) |
|---|
| 1348 | + len = print_syslog((info->facility << 3) | info->level, buf); |
|---|
| 1349 | + |
|---|
| 1350 | + if (time) |
|---|
| 1351 | + len += print_time(info->ts_nsec, buf + len); |
|---|
| 1352 | + |
|---|
| 1353 | + len += print_caller(info->caller_id, buf + len); |
|---|
| 1354 | + |
|---|
| 1355 | + if (IS_ENABLED(CONFIG_PRINTK_CALLER) || time) { |
|---|
| 1356 | + buf[len++] = ' '; |
|---|
| 1357 | + buf[len] = '\0'; |
|---|
| 1462 | 1358 | } |
|---|
| 1463 | 1359 | |
|---|
| 1464 | | - len += print_time(msg->ts_nsec, buf ? buf + len : NULL); |
|---|
| 1465 | | -#ifdef CONFIG_PRINTK_PROCESS |
|---|
| 1466 | | - len += print_process(msg, buf ? buf + len : NULL); |
|---|
| 1467 | | -#endif |
|---|
| 1468 | 1360 | return len; |
|---|
| 1469 | 1361 | } |
|---|
| 1470 | 1362 | |
|---|
| 1471 | | -static size_t msg_print_text(const struct printk_log *msg, bool syslog, char *buf, size_t size) |
|---|
| 1363 | +/* |
|---|
| 1364 | + * Prepare the record for printing. The text is shifted within the given |
|---|
| 1365 | + * buffer to avoid a need for another one. The following operations are |
|---|
| 1366 | + * done: |
|---|
| 1367 | + * |
|---|
| 1368 | + * - Add prefix for each line. |
|---|
| 1369 | + * - Drop truncated lines that no longer fit into the buffer. |
|---|
| 1370 | + * - Add the trailing newline that has been removed in vprintk_store(). |
|---|
| 1371 | + * - Add a string terminator. |
|---|
| 1372 | + * |
|---|
| 1373 | + * Since the produced string is always terminated, the maximum possible |
|---|
| 1374 | + * return value is @r->text_buf_size - 1; |
|---|
| 1375 | + * |
|---|
| 1376 | + * Return: The length of the updated/prepared text, including the added |
|---|
| 1377 | + * prefixes and the newline. The terminator is not counted. The dropped |
|---|
| 1378 | + * line(s) are not counted. |
|---|
| 1379 | + */ |
|---|
| 1380 | +static size_t record_print_text(struct printk_record *r, bool syslog, |
|---|
| 1381 | + bool time) |
|---|
| 1472 | 1382 | { |
|---|
| 1473 | | - const char *text = log_text(msg); |
|---|
| 1474 | | - size_t text_size = msg->text_len; |
|---|
| 1383 | + size_t text_len = r->info->text_len; |
|---|
| 1384 | + size_t buf_size = r->text_buf_size; |
|---|
| 1385 | + char *text = r->text_buf; |
|---|
| 1386 | + char prefix[PREFIX_MAX]; |
|---|
| 1387 | + bool truncated = false; |
|---|
| 1388 | + size_t prefix_len; |
|---|
| 1389 | + size_t line_len; |
|---|
| 1475 | 1390 | size_t len = 0; |
|---|
| 1391 | + char *next; |
|---|
| 1476 | 1392 | |
|---|
| 1477 | | - do { |
|---|
| 1478 | | - const char *next = memchr(text, '\n', text_size); |
|---|
| 1479 | | - size_t text_len; |
|---|
| 1393 | + /* |
|---|
| 1394 | + * If the message was truncated because the buffer was not large |
|---|
| 1395 | + * enough, treat the available text as if it were the full text. |
|---|
| 1396 | + */ |
|---|
| 1397 | + if (text_len > buf_size) |
|---|
| 1398 | + text_len = buf_size; |
|---|
| 1480 | 1399 | |
|---|
| 1400 | + prefix_len = info_print_prefix(r->info, syslog, time, prefix); |
|---|
| 1401 | + |
|---|
| 1402 | + /* |
|---|
| 1403 | + * @text_len: bytes of unprocessed text |
|---|
| 1404 | + * @line_len: bytes of current line _without_ newline |
|---|
| 1405 | + * @text: pointer to beginning of current line |
|---|
| 1406 | + * @len: number of bytes prepared in r->text_buf |
|---|
| 1407 | + */ |
|---|
| 1408 | + for (;;) { |
|---|
| 1409 | + next = memchr(text, '\n', text_len); |
|---|
| 1481 | 1410 | if (next) { |
|---|
| 1482 | | - text_len = next - text; |
|---|
| 1483 | | - next++; |
|---|
| 1484 | | - text_size -= next - text; |
|---|
| 1411 | + line_len = next - text; |
|---|
| 1485 | 1412 | } else { |
|---|
| 1486 | | - text_len = text_size; |
|---|
| 1413 | + /* Drop truncated line(s). */ |
|---|
| 1414 | + if (truncated) |
|---|
| 1415 | + break; |
|---|
| 1416 | + line_len = text_len; |
|---|
| 1487 | 1417 | } |
|---|
| 1488 | 1418 | |
|---|
| 1489 | | - if (buf) { |
|---|
| 1490 | | - if (print_prefix(msg, syslog, NULL) + |
|---|
| 1491 | | - text_len + 1 >= size - len) |
|---|
| 1419 | + /* |
|---|
| 1420 | + * Truncate the text if there is not enough space to add the |
|---|
| 1421 | + * prefix and a trailing newline and a terminator. |
|---|
| 1422 | + */ |
|---|
| 1423 | + if (len + prefix_len + text_len + 1 + 1 > buf_size) { |
|---|
| 1424 | + /* Drop even the current line if no space. */ |
|---|
| 1425 | + if (len + prefix_len + line_len + 1 + 1 > buf_size) |
|---|
| 1492 | 1426 | break; |
|---|
| 1493 | 1427 | |
|---|
| 1494 | | - len += print_prefix(msg, syslog, buf + len); |
|---|
| 1495 | | - memcpy(buf + len, text, text_len); |
|---|
| 1496 | | - len += text_len; |
|---|
| 1497 | | - buf[len++] = '\n'; |
|---|
| 1498 | | - } else { |
|---|
| 1499 | | - /* SYSLOG_ACTION_* buffer size only calculation */ |
|---|
| 1500 | | - len += print_prefix(msg, syslog, NULL); |
|---|
| 1501 | | - len += text_len; |
|---|
| 1502 | | - len++; |
|---|
| 1428 | + text_len = buf_size - len - prefix_len - 1 - 1; |
|---|
| 1429 | + truncated = true; |
|---|
| 1503 | 1430 | } |
|---|
| 1504 | 1431 | |
|---|
| 1505 | | - text = next; |
|---|
| 1506 | | - } while (text); |
|---|
| 1432 | + memmove(text + prefix_len, text, text_len); |
|---|
| 1433 | + memcpy(text, prefix, prefix_len); |
|---|
| 1434 | + |
|---|
| 1435 | + /* |
|---|
| 1436 | + * Increment the prepared length to include the text and |
|---|
| 1437 | + * prefix that were just moved+copied. Also increment for the |
|---|
| 1438 | + * newline at the end of this line. If this is the last line, |
|---|
| 1439 | + * there is no newline, but it will be added immediately below. |
|---|
| 1440 | + */ |
|---|
| 1441 | + len += prefix_len + line_len + 1; |
|---|
| 1442 | + if (text_len == line_len) { |
|---|
| 1443 | + /* |
|---|
| 1444 | + * This is the last line. Add the trailing newline |
|---|
| 1445 | + * removed in vprintk_store(). |
|---|
| 1446 | + */ |
|---|
| 1447 | + text[prefix_len + line_len] = '\n'; |
|---|
| 1448 | + break; |
|---|
| 1449 | + } |
|---|
| 1450 | + |
|---|
| 1451 | + /* |
|---|
| 1452 | + * Advance beyond the added prefix and the related line with |
|---|
| 1453 | + * its newline. |
|---|
| 1454 | + */ |
|---|
| 1455 | + text += prefix_len + line_len + 1; |
|---|
| 1456 | + |
|---|
| 1457 | + /* |
|---|
| 1458 | + * The remaining text has only decreased by the line with its |
|---|
| 1459 | + * newline. |
|---|
| 1460 | + * |
|---|
| 1461 | + * Note that @text_len can become zero. It happens when @text |
|---|
| 1462 | + * ended with a newline (either due to truncation or the |
|---|
| 1463 | + * original string ending with "\n\n"). The loop is correctly |
|---|
| 1464 | + * repeated and (if not truncated) an empty line with a prefix |
|---|
| 1465 | + * will be prepared. |
|---|
| 1466 | + */ |
|---|
| 1467 | + text_len -= line_len + 1; |
|---|
| 1468 | + } |
|---|
| 1469 | + |
|---|
| 1470 | + /* |
|---|
| 1471 | + * If a buffer was provided, it will be terminated. Space for the |
|---|
| 1472 | + * string terminator is guaranteed to be available. The terminator is |
|---|
| 1473 | + * not counted in the return value. |
|---|
| 1474 | + */ |
|---|
| 1475 | + if (buf_size > 0) |
|---|
| 1476 | + r->text_buf[len] = 0; |
|---|
| 1507 | 1477 | |
|---|
| 1508 | 1478 | return len; |
|---|
| 1479 | +} |
|---|
| 1480 | + |
|---|
| 1481 | +static size_t get_record_print_text_size(struct printk_info *info, |
|---|
| 1482 | + unsigned int line_count, |
|---|
| 1483 | + bool syslog, bool time) |
|---|
| 1484 | +{ |
|---|
| 1485 | + char prefix[PREFIX_MAX]; |
|---|
| 1486 | + size_t prefix_len; |
|---|
| 1487 | + |
|---|
| 1488 | + prefix_len = info_print_prefix(info, syslog, time, prefix); |
|---|
| 1489 | + |
|---|
| 1490 | + /* |
|---|
| 1491 | + * Each line will be preceded with a prefix. The intermediate |
|---|
| 1492 | + * newlines are already within the text, but a final trailing |
|---|
| 1493 | + * newline will be added. |
|---|
| 1494 | + */ |
|---|
| 1495 | + return ((prefix_len * line_count) + info->text_len + 1); |
|---|
| 1509 | 1496 | } |
|---|
| 1510 | 1497 | |
|---|
| 1511 | 1498 | static int syslog_print(char __user *buf, int size) |
|---|
| 1512 | 1499 | { |
|---|
| 1500 | + struct printk_info info; |
|---|
| 1501 | + struct printk_record r; |
|---|
| 1513 | 1502 | char *text; |
|---|
| 1514 | | - struct printk_log *msg; |
|---|
| 1515 | 1503 | int len = 0; |
|---|
| 1516 | 1504 | |
|---|
| 1517 | 1505 | text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL); |
|---|
| 1518 | 1506 | if (!text) |
|---|
| 1519 | 1507 | return -ENOMEM; |
|---|
| 1520 | 1508 | |
|---|
| 1509 | + prb_rec_init_rd(&r, &info, text, LOG_LINE_MAX + PREFIX_MAX); |
|---|
| 1510 | + |
|---|
| 1521 | 1511 | while (size > 0) { |
|---|
| 1522 | 1512 | size_t n; |
|---|
| 1523 | 1513 | size_t skip; |
|---|
| 1524 | 1514 | |
|---|
| 1525 | 1515 | logbuf_lock_irq(); |
|---|
| 1526 | | - if (syslog_seq < log_first_seq) { |
|---|
| 1527 | | - /* messages are gone, move to first one */ |
|---|
| 1528 | | - syslog_seq = log_first_seq; |
|---|
| 1529 | | - syslog_idx = log_first_idx; |
|---|
| 1530 | | - syslog_partial = 0; |
|---|
| 1531 | | - } |
|---|
| 1532 | | - if (syslog_seq == log_next_seq) { |
|---|
| 1516 | + if (!prb_read_valid(prb, syslog_seq, &r)) { |
|---|
| 1533 | 1517 | logbuf_unlock_irq(); |
|---|
| 1534 | 1518 | break; |
|---|
| 1535 | 1519 | } |
|---|
| 1520 | + if (r.info->seq != syslog_seq) { |
|---|
| 1521 | + /* message is gone, move to next valid one */ |
|---|
| 1522 | + syslog_seq = r.info->seq; |
|---|
| 1523 | + syslog_partial = 0; |
|---|
| 1524 | + } |
|---|
| 1525 | + |
|---|
| 1526 | + /* |
|---|
| 1527 | + * To keep reading/counting partial line consistent, |
|---|
| 1528 | + * use printk_time value as of the beginning of a line. |
|---|
| 1529 | + */ |
|---|
| 1530 | + if (!syslog_partial) |
|---|
| 1531 | + syslog_time = printk_time; |
|---|
| 1536 | 1532 | |
|---|
| 1537 | 1533 | skip = syslog_partial; |
|---|
| 1538 | | - msg = log_from_idx(syslog_idx); |
|---|
| 1539 | | - n = msg_print_text(msg, true, text, LOG_LINE_MAX + PREFIX_MAX); |
|---|
| 1534 | + n = record_print_text(&r, true, syslog_time); |
|---|
| 1540 | 1535 | if (n - syslog_partial <= size) { |
|---|
| 1541 | 1536 | /* message fits into buffer, move forward */ |
|---|
| 1542 | | - syslog_idx = log_next(syslog_idx); |
|---|
| 1543 | | - syslog_seq++; |
|---|
| 1537 | + syslog_seq = r.info->seq + 1; |
|---|
| 1544 | 1538 | n -= syslog_partial; |
|---|
| 1545 | 1539 | syslog_partial = 0; |
|---|
| 1546 | 1540 | } else if (!len){ |
|---|
| .. | .. |
|---|
| 1571 | 1565 | |
|---|
| 1572 | 1566 | static int syslog_print_all(char __user *buf, int size, bool clear) |
|---|
| 1573 | 1567 | { |
|---|
| 1568 | + struct printk_info info; |
|---|
| 1569 | + unsigned int line_count; |
|---|
| 1570 | + struct printk_record r; |
|---|
| 1574 | 1571 | char *text; |
|---|
| 1575 | 1572 | int len = 0; |
|---|
| 1576 | | - u64 next_seq; |
|---|
| 1577 | 1573 | u64 seq; |
|---|
| 1578 | | - u32 idx; |
|---|
| 1579 | | - int attempts = 0; |
|---|
| 1580 | | - int num_msg; |
|---|
| 1574 | + bool time; |
|---|
| 1581 | 1575 | |
|---|
| 1582 | 1576 | text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL); |
|---|
| 1583 | 1577 | if (!text) |
|---|
| 1584 | 1578 | return -ENOMEM; |
|---|
| 1585 | 1579 | |
|---|
| 1580 | + time = printk_time; |
|---|
| 1586 | 1581 | logbuf_lock_irq(); |
|---|
| 1587 | | - |
|---|
| 1588 | | -try_again: |
|---|
| 1589 | | - attempts++; |
|---|
| 1590 | | - if (attempts > 10) { |
|---|
| 1591 | | - len = -EBUSY; |
|---|
| 1592 | | - goto out; |
|---|
| 1593 | | - } |
|---|
| 1594 | | - num_msg = 0; |
|---|
| 1595 | | - |
|---|
| 1596 | 1582 | /* |
|---|
| 1597 | 1583 | * Find first record that fits, including all following records, |
|---|
| 1598 | 1584 | * into the user-provided buffer for this dump. |
|---|
| 1599 | 1585 | */ |
|---|
| 1600 | | - seq = clear_seq; |
|---|
| 1601 | | - idx = clear_idx; |
|---|
| 1602 | | - while (seq < log_next_seq) { |
|---|
| 1603 | | - struct printk_log *msg = log_from_idx(idx); |
|---|
| 1604 | | - |
|---|
| 1605 | | - len += msg_print_text(msg, true, NULL, 0); |
|---|
| 1606 | | - idx = log_next(idx); |
|---|
| 1607 | | - seq++; |
|---|
| 1608 | | - num_msg++; |
|---|
| 1609 | | - if (num_msg > 5) { |
|---|
| 1610 | | - num_msg = 0; |
|---|
| 1611 | | - logbuf_unlock_irq(); |
|---|
| 1612 | | - logbuf_lock_irq(); |
|---|
| 1613 | | - if (clear_seq < log_first_seq) |
|---|
| 1614 | | - goto try_again; |
|---|
| 1615 | | - } |
|---|
| 1616 | | - } |
|---|
| 1586 | + prb_for_each_info(clear_seq, prb, seq, &info, &line_count) |
|---|
| 1587 | + len += get_record_print_text_size(&info, line_count, true, time); |
|---|
| 1617 | 1588 | |
|---|
| 1618 | 1589 | /* move first record forward until length fits into the buffer */ |
|---|
| 1619 | | - seq = clear_seq; |
|---|
| 1620 | | - idx = clear_idx; |
|---|
| 1621 | | - while (len > size && seq < log_next_seq) { |
|---|
| 1622 | | - struct printk_log *msg = log_from_idx(idx); |
|---|
| 1623 | | - |
|---|
| 1624 | | - len -= msg_print_text(msg, true, NULL, 0); |
|---|
| 1625 | | - idx = log_next(idx); |
|---|
| 1626 | | - seq++; |
|---|
| 1627 | | - num_msg++; |
|---|
| 1628 | | - if (num_msg > 5) { |
|---|
| 1629 | | - num_msg = 0; |
|---|
| 1630 | | - logbuf_unlock_irq(); |
|---|
| 1631 | | - logbuf_lock_irq(); |
|---|
| 1632 | | - if (clear_seq < log_first_seq) |
|---|
| 1633 | | - goto try_again; |
|---|
| 1634 | | - } |
|---|
| 1590 | + prb_for_each_info(clear_seq, prb, seq, &info, &line_count) { |
|---|
| 1591 | + if (len <= size) |
|---|
| 1592 | + break; |
|---|
| 1593 | + len -= get_record_print_text_size(&info, line_count, true, time); |
|---|
| 1635 | 1594 | } |
|---|
| 1636 | 1595 | |
|---|
| 1637 | | - /* last message fitting into this dump */ |
|---|
| 1638 | | - next_seq = log_next_seq; |
|---|
| 1596 | + prb_rec_init_rd(&r, &info, text, LOG_LINE_MAX + PREFIX_MAX); |
|---|
| 1639 | 1597 | |
|---|
| 1640 | 1598 | len = 0; |
|---|
| 1641 | | - while (len >= 0 && seq < next_seq) { |
|---|
| 1642 | | - struct printk_log *msg = log_from_idx(idx); |
|---|
| 1599 | + prb_for_each_record(seq, prb, seq, &r) { |
|---|
| 1643 | 1600 | int textlen; |
|---|
| 1644 | 1601 | |
|---|
| 1645 | | - textlen = msg_print_text(msg, true, text, |
|---|
| 1646 | | - LOG_LINE_MAX + PREFIX_MAX); |
|---|
| 1647 | | - if (textlen < 0) { |
|---|
| 1648 | | - len = textlen; |
|---|
| 1602 | + textlen = record_print_text(&r, true, time); |
|---|
| 1603 | + |
|---|
| 1604 | + if (len + textlen > size) { |
|---|
| 1605 | + seq--; |
|---|
| 1649 | 1606 | break; |
|---|
| 1650 | 1607 | } |
|---|
| 1651 | | - idx = log_next(idx); |
|---|
| 1652 | | - seq++; |
|---|
| 1653 | 1608 | |
|---|
| 1654 | 1609 | logbuf_unlock_irq(); |
|---|
| 1655 | 1610 | if (copy_to_user(buf + len, text, textlen)) |
|---|
| .. | .. |
|---|
| 1658 | 1613 | len += textlen; |
|---|
| 1659 | 1614 | logbuf_lock_irq(); |
|---|
| 1660 | 1615 | |
|---|
| 1661 | | - if (seq < log_first_seq) { |
|---|
| 1662 | | - /* messages are gone, move to next one */ |
|---|
| 1663 | | - seq = log_first_seq; |
|---|
| 1664 | | - idx = log_first_idx; |
|---|
| 1665 | | - } |
|---|
| 1616 | + if (len < 0) |
|---|
| 1617 | + break; |
|---|
| 1666 | 1618 | } |
|---|
| 1667 | 1619 | |
|---|
| 1668 | | - if (clear) { |
|---|
| 1669 | | - clear_seq = log_next_seq; |
|---|
| 1670 | | - clear_idx = log_next_idx; |
|---|
| 1671 | | - } |
|---|
| 1672 | | -out: |
|---|
| 1620 | + if (clear) |
|---|
| 1621 | + clear_seq = seq; |
|---|
| 1673 | 1622 | logbuf_unlock_irq(); |
|---|
| 1674 | 1623 | |
|---|
| 1675 | 1624 | kfree(text); |
|---|
| .. | .. |
|---|
| 1679 | 1628 | static void syslog_clear(void) |
|---|
| 1680 | 1629 | { |
|---|
| 1681 | 1630 | logbuf_lock_irq(); |
|---|
| 1682 | | - clear_seq = log_next_seq; |
|---|
| 1683 | | - clear_idx = log_next_idx; |
|---|
| 1631 | + clear_seq = prb_next_seq(prb); |
|---|
| 1684 | 1632 | logbuf_unlock_irq(); |
|---|
| 1685 | 1633 | } |
|---|
| 1686 | 1634 | |
|---|
| 1687 | 1635 | int do_syslog(int type, char __user *buf, int len, int source) |
|---|
| 1688 | 1636 | { |
|---|
| 1637 | + struct printk_info info; |
|---|
| 1689 | 1638 | bool clear = false; |
|---|
| 1690 | 1639 | static int saved_console_loglevel = LOGLEVEL_DEFAULT; |
|---|
| 1691 | 1640 | int error; |
|---|
| .. | .. |
|---|
| 1704 | 1653 | return -EINVAL; |
|---|
| 1705 | 1654 | if (!len) |
|---|
| 1706 | 1655 | return 0; |
|---|
| 1707 | | - if (!access_ok(VERIFY_WRITE, buf, len)) |
|---|
| 1656 | + if (!access_ok(buf, len)) |
|---|
| 1708 | 1657 | return -EFAULT; |
|---|
| 1709 | 1658 | error = wait_event_interruptible(log_wait, |
|---|
| 1710 | | - syslog_seq != log_next_seq); |
|---|
| 1659 | + prb_read_valid(prb, syslog_seq, NULL)); |
|---|
| 1711 | 1660 | if (error) |
|---|
| 1712 | 1661 | return error; |
|---|
| 1713 | 1662 | error = syslog_print(buf, len); |
|---|
| .. | .. |
|---|
| 1715 | 1664 | /* Read/clear last kernel messages */ |
|---|
| 1716 | 1665 | case SYSLOG_ACTION_READ_CLEAR: |
|---|
| 1717 | 1666 | clear = true; |
|---|
| 1718 | | - /* FALL THRU */ |
|---|
| 1667 | + fallthrough; |
|---|
| 1719 | 1668 | /* Read last kernel messages */ |
|---|
| 1720 | 1669 | case SYSLOG_ACTION_READ_ALL: |
|---|
| 1721 | 1670 | if (!buf || len < 0) |
|---|
| 1722 | 1671 | return -EINVAL; |
|---|
| 1723 | 1672 | if (!len) |
|---|
| 1724 | 1673 | return 0; |
|---|
| 1725 | | - if (!access_ok(VERIFY_WRITE, buf, len)) |
|---|
| 1674 | + if (!access_ok(buf, len)) |
|---|
| 1726 | 1675 | return -EFAULT; |
|---|
| 1727 | 1676 | error = syslog_print_all(buf, len, clear); |
|---|
| 1728 | 1677 | break; |
|---|
| .. | .. |
|---|
| 1756 | 1705 | /* Number of chars in the log buffer */ |
|---|
| 1757 | 1706 | case SYSLOG_ACTION_SIZE_UNREAD: |
|---|
| 1758 | 1707 | logbuf_lock_irq(); |
|---|
| 1759 | | - if (syslog_seq < log_first_seq) { |
|---|
| 1708 | + if (!prb_read_valid_info(prb, syslog_seq, &info, NULL)) { |
|---|
| 1709 | + /* No unread messages. */ |
|---|
| 1710 | + logbuf_unlock_irq(); |
|---|
| 1711 | + return 0; |
|---|
| 1712 | + } |
|---|
| 1713 | + if (info.seq != syslog_seq) { |
|---|
| 1760 | 1714 | /* messages are gone, move to first one */ |
|---|
| 1761 | | - syslog_seq = log_first_seq; |
|---|
| 1762 | | - syslog_idx = log_first_idx; |
|---|
| 1715 | + syslog_seq = info.seq; |
|---|
| 1763 | 1716 | syslog_partial = 0; |
|---|
| 1764 | 1717 | } |
|---|
| 1765 | 1718 | if (source == SYSLOG_FROM_PROC) { |
|---|
| .. | .. |
|---|
| 1768 | 1721 | * for pending data, not the size; return the count of |
|---|
| 1769 | 1722 | * records, not the length. |
|---|
| 1770 | 1723 | */ |
|---|
| 1771 | | - error = log_next_seq - syslog_seq; |
|---|
| 1724 | + error = prb_next_seq(prb) - syslog_seq; |
|---|
| 1772 | 1725 | } else { |
|---|
| 1773 | | - u64 seq = syslog_seq; |
|---|
| 1774 | | - u32 idx = syslog_idx; |
|---|
| 1726 | + bool time = syslog_partial ? syslog_time : printk_time; |
|---|
| 1727 | + unsigned int line_count; |
|---|
| 1728 | + u64 seq; |
|---|
| 1775 | 1729 | |
|---|
| 1776 | | - while (seq < log_next_seq) { |
|---|
| 1777 | | - struct printk_log *msg = log_from_idx(idx); |
|---|
| 1778 | | - |
|---|
| 1779 | | - error += msg_print_text(msg, true, NULL, 0); |
|---|
| 1780 | | - idx = log_next(idx); |
|---|
| 1781 | | - seq++; |
|---|
| 1730 | + prb_for_each_info(syslog_seq, prb, seq, &info, |
|---|
| 1731 | + &line_count) { |
|---|
| 1732 | + error += get_record_print_text_size(&info, line_count, |
|---|
| 1733 | + true, time); |
|---|
| 1734 | + time = printk_time; |
|---|
| 1782 | 1735 | } |
|---|
| 1783 | 1736 | error -= syslog_partial; |
|---|
| 1784 | 1737 | } |
|---|
| .. | .. |
|---|
| 1801 | 1754 | return do_syslog(type, buf, len, SYSLOG_FROM_READER); |
|---|
| 1802 | 1755 | } |
|---|
| 1803 | 1756 | |
|---|
| 1804 | | -#ifndef CONFIG_PREEMPT_RT_FULL |
|---|
| 1805 | 1757 | /* |
|---|
| 1806 | 1758 | * Special console_lock variants that help to reduce the risk of soft-lockups. |
|---|
| 1807 | 1759 | * They allow to pass console_lock to another printk() call using a busy wait. |
|---|
| .. | .. |
|---|
| 1861 | 1813 | raw_spin_unlock(&console_owner_lock); |
|---|
| 1862 | 1814 | |
|---|
| 1863 | 1815 | if (!waiter) { |
|---|
| 1864 | | - spin_release(&console_owner_dep_map, 1, _THIS_IP_); |
|---|
| 1816 | + spin_release(&console_owner_dep_map, _THIS_IP_); |
|---|
| 1865 | 1817 | return 0; |
|---|
| 1866 | 1818 | } |
|---|
| 1867 | 1819 | |
|---|
| 1868 | 1820 | /* The waiter is now free to continue */ |
|---|
| 1869 | 1821 | WRITE_ONCE(console_waiter, false); |
|---|
| 1870 | 1822 | |
|---|
| 1871 | | - spin_release(&console_owner_dep_map, 1, _THIS_IP_); |
|---|
| 1823 | + spin_release(&console_owner_dep_map, _THIS_IP_); |
|---|
| 1872 | 1824 | |
|---|
| 1873 | 1825 | /* |
|---|
| 1874 | 1826 | * Hand off console_lock to waiter. The waiter will perform |
|---|
| 1875 | 1827 | * the up(). After this, the waiter is the console_lock owner. |
|---|
| 1876 | 1828 | */ |
|---|
| 1877 | | - mutex_release(&console_lock_dep_map, 1, _THIS_IP_); |
|---|
| 1829 | + mutex_release(&console_lock_dep_map, _THIS_IP_); |
|---|
| 1878 | 1830 | return 1; |
|---|
| 1879 | 1831 | } |
|---|
| 1880 | 1832 | |
|---|
| .. | .. |
|---|
| 1928 | 1880 | /* Owner will clear console_waiter on hand off */ |
|---|
| 1929 | 1881 | while (READ_ONCE(console_waiter)) |
|---|
| 1930 | 1882 | cpu_relax(); |
|---|
| 1931 | | - spin_release(&console_owner_dep_map, 1, _THIS_IP_); |
|---|
| 1883 | + spin_release(&console_owner_dep_map, _THIS_IP_); |
|---|
| 1932 | 1884 | |
|---|
| 1933 | 1885 | printk_safe_exit_irqrestore(flags); |
|---|
| 1934 | 1886 | /* |
|---|
| .. | .. |
|---|
| 1942 | 1894 | return 1; |
|---|
| 1943 | 1895 | } |
|---|
| 1944 | 1896 | |
|---|
| 1945 | | -#else |
|---|
| 1946 | | - |
|---|
| 1947 | | -static int console_trylock_spinning(void) |
|---|
| 1948 | | -{ |
|---|
| 1949 | | - return console_trylock(); |
|---|
| 1950 | | -} |
|---|
| 1951 | | - |
|---|
| 1952 | | -#endif |
|---|
| 1953 | | - |
|---|
| 1954 | 1897 | /* |
|---|
| 1955 | 1898 | * Call the console drivers, asking them to write out |
|---|
| 1956 | 1899 | * log_buf[start] to log_buf[end - 1]. |
|---|
| 1957 | 1900 | * The console_lock must be held. |
|---|
| 1958 | 1901 | */ |
|---|
| 1959 | | -#ifdef CONFIG_PSTORE_CONSOLE_FORCE |
|---|
| 1960 | | -__maybe_unused |
|---|
| 1961 | | -#endif |
|---|
| 1962 | 1902 | static void call_console_drivers(const char *ext_text, size_t ext_len, |
|---|
| 1963 | 1903 | const char *text, size_t len) |
|---|
| 1964 | 1904 | { |
|---|
| 1905 | + static char dropped_text[64]; |
|---|
| 1906 | + size_t dropped_len = 0; |
|---|
| 1965 | 1907 | struct console *con; |
|---|
| 1966 | 1908 | |
|---|
| 1967 | 1909 | trace_console_rcuidle(text, len); |
|---|
| .. | .. |
|---|
| 1969 | 1911 | if (!console_drivers) |
|---|
| 1970 | 1912 | return; |
|---|
| 1971 | 1913 | |
|---|
| 1972 | | - if (IS_ENABLED(CONFIG_PREEMPT_RT_BASE)) { |
|---|
| 1973 | | - if (in_irq() || in_nmi()) |
|---|
| 1974 | | - return; |
|---|
| 1914 | + if (console_dropped) { |
|---|
| 1915 | + dropped_len = snprintf(dropped_text, sizeof(dropped_text), |
|---|
| 1916 | + "** %lu printk messages dropped **\n", |
|---|
| 1917 | + console_dropped); |
|---|
| 1918 | + console_dropped = 0; |
|---|
| 1975 | 1919 | } |
|---|
| 1976 | 1920 | |
|---|
| 1977 | | - migrate_disable(); |
|---|
| 1978 | 1921 | for_each_console(con) { |
|---|
| 1979 | 1922 | if (exclusive_console && con != exclusive_console) |
|---|
| 1980 | 1923 | continue; |
|---|
| .. | .. |
|---|
| 1987 | 1930 | continue; |
|---|
| 1988 | 1931 | if (con->flags & CON_EXTENDED) |
|---|
| 1989 | 1932 | con->write(con, ext_text, ext_len); |
|---|
| 1990 | | - else |
|---|
| 1933 | + else { |
|---|
| 1934 | + if (dropped_len) |
|---|
| 1935 | + con->write(con, dropped_text, dropped_len); |
|---|
| 1991 | 1936 | con->write(con, text, len); |
|---|
| 1937 | + } |
|---|
| 1992 | 1938 | } |
|---|
| 1993 | | - migrate_enable(); |
|---|
| 1994 | 1939 | } |
|---|
| 1995 | 1940 | |
|---|
| 1996 | 1941 | int printk_delay_msec __read_mostly; |
|---|
| .. | .. |
|---|
| 2007 | 1952 | } |
|---|
| 2008 | 1953 | } |
|---|
| 2009 | 1954 | |
|---|
| 2010 | | -/* |
|---|
| 2011 | | - * Continuation lines are buffered, and not committed to the record buffer |
|---|
| 2012 | | - * until the line is complete, or a race forces it. The line fragments |
|---|
| 2013 | | - * though, are printed immediately to the consoles to ensure everything has |
|---|
| 2014 | | - * reached the console in case of a kernel crash. |
|---|
| 2015 | | - */ |
|---|
| 2016 | | -static struct cont { |
|---|
| 2017 | | - char buf[LOG_LINE_MAX]; |
|---|
| 2018 | | - size_t len; /* length == 0 means unused buffer */ |
|---|
| 2019 | | - struct task_struct *owner; /* task of first print*/ |
|---|
| 2020 | | - u64 ts_nsec; /* time of first print */ |
|---|
| 2021 | | - u8 level; /* log level of first message */ |
|---|
| 2022 | | - u8 facility; /* log facility of first message */ |
|---|
| 2023 | | - enum log_flags flags; /* prefix, newline flags */ |
|---|
| 2024 | | -} cont; |
|---|
| 2025 | | - |
|---|
| 2026 | | -static void cont_flush(void) |
|---|
| 1955 | +static inline u32 printk_caller_id(void) |
|---|
| 2027 | 1956 | { |
|---|
| 2028 | | - if (cont.len == 0) |
|---|
| 2029 | | - return; |
|---|
| 2030 | | - |
|---|
| 2031 | | - log_store(cont.facility, cont.level, cont.flags, cont.ts_nsec, |
|---|
| 2032 | | - NULL, 0, cont.buf, cont.len); |
|---|
| 2033 | | - cont.len = 0; |
|---|
| 1957 | + return in_task() ? task_pid_nr(current) : |
|---|
| 1958 | + 0x80000000 + raw_smp_processor_id(); |
|---|
| 2034 | 1959 | } |
|---|
| 2035 | 1960 | |
|---|
| 2036 | | -static bool cont_add(int facility, int level, enum log_flags flags, const char *text, size_t len) |
|---|
| 1961 | +static size_t log_output(int facility, int level, enum log_flags lflags, |
|---|
| 1962 | + const struct dev_printk_info *dev_info, |
|---|
| 1963 | + char *text, size_t text_len) |
|---|
| 2037 | 1964 | { |
|---|
| 2038 | | - /* |
|---|
| 2039 | | - * If ext consoles are present, flush and skip in-kernel |
|---|
| 2040 | | - * continuation. See nr_ext_console_drivers definition. Also, if |
|---|
| 2041 | | - * the line gets too long, split it up in separate records. |
|---|
| 2042 | | - */ |
|---|
| 2043 | | - if (nr_ext_console_drivers || cont.len + len > sizeof(cont.buf)) { |
|---|
| 2044 | | - cont_flush(); |
|---|
| 2045 | | - return false; |
|---|
| 2046 | | - } |
|---|
| 1965 | + const u32 caller_id = printk_caller_id(); |
|---|
| 2047 | 1966 | |
|---|
| 2048 | | - if (!cont.len) { |
|---|
| 2049 | | - cont.facility = facility; |
|---|
| 2050 | | - cont.level = level; |
|---|
| 2051 | | - cont.owner = current; |
|---|
| 2052 | | - cont.ts_nsec = get_local_clock(); |
|---|
| 2053 | | - cont.flags = flags; |
|---|
| 2054 | | - } |
|---|
| 1967 | + if (lflags & LOG_CONT) { |
|---|
| 1968 | + struct prb_reserved_entry e; |
|---|
| 1969 | + struct printk_record r; |
|---|
| 2055 | 1970 | |
|---|
| 2056 | | - memcpy(cont.buf + cont.len, text, len); |
|---|
| 2057 | | - cont.len += len; |
|---|
| 1971 | + prb_rec_init_wr(&r, text_len); |
|---|
| 1972 | + if (prb_reserve_in_last(&e, prb, &r, caller_id, LOG_LINE_MAX)) { |
|---|
| 1973 | + memcpy(&r.text_buf[r.info->text_len], text, text_len); |
|---|
| 1974 | + r.info->text_len += text_len; |
|---|
| 1975 | + if (lflags & LOG_NEWLINE) { |
|---|
| 1976 | + r.info->flags |= LOG_NEWLINE; |
|---|
| 1977 | + prb_final_commit(&e); |
|---|
| 1978 | + } else { |
|---|
| 1979 | + prb_commit(&e); |
|---|
| 1980 | + } |
|---|
| 2058 | 1981 | |
|---|
| 2059 | | - // The original flags come from the first line, |
|---|
| 2060 | | - // but later continuations can add a newline. |
|---|
| 2061 | | - if (flags & LOG_NEWLINE) { |
|---|
| 2062 | | - cont.flags |= LOG_NEWLINE; |
|---|
| 2063 | | - cont_flush(); |
|---|
| 2064 | | - } |
|---|
| 2065 | | - |
|---|
| 2066 | | - if (cont.len > (sizeof(cont.buf) * 80) / 100) |
|---|
| 2067 | | - cont_flush(); |
|---|
| 2068 | | - |
|---|
| 2069 | | - return true; |
|---|
| 2070 | | -} |
|---|
| 2071 | | - |
|---|
| 2072 | | -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) |
|---|
| 2073 | | -{ |
|---|
| 2074 | | - /* |
|---|
| 2075 | | - * If an earlier line was buffered, and we're a continuation |
|---|
| 2076 | | - * write from the same process, try to add it to the buffer. |
|---|
| 2077 | | - */ |
|---|
| 2078 | | - if (cont.len) { |
|---|
| 2079 | | - if (cont.owner == current && (lflags & LOG_CONT)) { |
|---|
| 2080 | | - if (cont_add(facility, level, lflags, text, text_len)) |
|---|
| 2081 | | - return text_len; |
|---|
| 2082 | | - } |
|---|
| 2083 | | - /* Otherwise, make sure it's flushed */ |
|---|
| 2084 | | - cont_flush(); |
|---|
| 2085 | | - } |
|---|
| 2086 | | - |
|---|
| 2087 | | - /* Skip empty continuation lines that couldn't be added - they just flush */ |
|---|
| 2088 | | - if (!text_len && (lflags & LOG_CONT)) |
|---|
| 2089 | | - return 0; |
|---|
| 2090 | | - |
|---|
| 2091 | | - /* If it doesn't end in a newline, try to buffer the current line */ |
|---|
| 2092 | | - if (!(lflags & LOG_NEWLINE)) { |
|---|
| 2093 | | - if (cont_add(facility, level, lflags, text, text_len)) |
|---|
| 1982 | + trace_android_vh_logbuf_pr_cont(&r, text_len); |
|---|
| 2094 | 1983 | return text_len; |
|---|
| 1984 | + } |
|---|
| 2095 | 1985 | } |
|---|
| 2096 | 1986 | |
|---|
| 2097 | 1987 | /* Store it in the record log */ |
|---|
| 2098 | | - return log_store(facility, level, lflags, 0, dict, dictlen, text, text_len); |
|---|
| 1988 | + return log_store(caller_id, facility, level, lflags, 0, |
|---|
| 1989 | + dev_info, text, text_len); |
|---|
| 2099 | 1990 | } |
|---|
| 2100 | 1991 | |
|---|
| 2101 | 1992 | /* Must be called under logbuf_lock. */ |
|---|
| 2102 | 1993 | int vprintk_store(int facility, int level, |
|---|
| 2103 | | - const char *dict, size_t dictlen, |
|---|
| 1994 | + const struct dev_printk_info *dev_info, |
|---|
| 2104 | 1995 | const char *fmt, va_list args) |
|---|
| 2105 | 1996 | { |
|---|
| 2106 | 1997 | static char textbuf[LOG_LINE_MAX]; |
|---|
| .. | .. |
|---|
| 2129 | 2020 | case '0' ... '7': |
|---|
| 2130 | 2021 | if (level == LOGLEVEL_DEFAULT) |
|---|
| 2131 | 2022 | level = kern_level - '0'; |
|---|
| 2132 | | - /* fallthrough */ |
|---|
| 2133 | | - case 'd': /* KERN_DEFAULT */ |
|---|
| 2134 | | - lflags |= LOG_PREFIX; |
|---|
| 2135 | 2023 | break; |
|---|
| 2136 | 2024 | case 'c': /* KERN_CONT */ |
|---|
| 2137 | 2025 | lflags |= LOG_CONT; |
|---|
| .. | .. |
|---|
| 2145 | 2033 | if (level == LOGLEVEL_DEFAULT) |
|---|
| 2146 | 2034 | level = default_message_loglevel; |
|---|
| 2147 | 2035 | |
|---|
| 2148 | | - if (dict) |
|---|
| 2149 | | - lflags |= LOG_PREFIX|LOG_NEWLINE; |
|---|
| 2036 | + if (dev_info) |
|---|
| 2037 | + lflags |= LOG_NEWLINE; |
|---|
| 2150 | 2038 | |
|---|
| 2151 | | - return log_output(facility, level, lflags, |
|---|
| 2152 | | - dict, dictlen, text, text_len); |
|---|
| 2039 | + return log_output(facility, level, lflags, dev_info, text, text_len); |
|---|
| 2153 | 2040 | } |
|---|
| 2154 | 2041 | |
|---|
| 2155 | 2042 | asmlinkage int vprintk_emit(int facility, int level, |
|---|
| 2156 | | - const char *dict, size_t dictlen, |
|---|
| 2043 | + const struct dev_printk_info *dev_info, |
|---|
| 2157 | 2044 | const char *fmt, va_list args) |
|---|
| 2158 | 2045 | { |
|---|
| 2159 | 2046 | int printed_len; |
|---|
| 2160 | | - bool in_sched = false, pending_output; |
|---|
| 2047 | + bool in_sched = false; |
|---|
| 2161 | 2048 | unsigned long flags; |
|---|
| 2162 | | - u64 curr_log_seq; |
|---|
| 2163 | 2049 | |
|---|
| 2164 | | - /* |
|---|
| 2165 | | - * Fall back to early_printk if a debugging subsystem has |
|---|
| 2166 | | - * killed printk output |
|---|
| 2167 | | - */ |
|---|
| 2168 | | - if (unlikely(forced_early_printk(fmt, args))) |
|---|
| 2169 | | - return 1; |
|---|
| 2050 | + /* Suppress unimportant messages after panic happens */ |
|---|
| 2051 | + if (unlikely(suppress_printk)) |
|---|
| 2052 | + return 0; |
|---|
| 2170 | 2053 | |
|---|
| 2171 | 2054 | if (level == LOGLEVEL_SCHED) { |
|---|
| 2172 | 2055 | level = LOGLEVEL_DEFAULT; |
|---|
| .. | .. |
|---|
| 2178 | 2061 | |
|---|
| 2179 | 2062 | /* This stops the holder of console_sem just where we want him */ |
|---|
| 2180 | 2063 | logbuf_lock_irqsave(flags); |
|---|
| 2181 | | - curr_log_seq = log_next_seq; |
|---|
| 2182 | | - printed_len = vprintk_store(facility, level, dict, dictlen, fmt, args); |
|---|
| 2183 | | - pending_output = (curr_log_seq != log_next_seq); |
|---|
| 2064 | + printed_len = vprintk_store(facility, level, dev_info, fmt, args); |
|---|
| 2184 | 2065 | logbuf_unlock_irqrestore(flags); |
|---|
| 2185 | 2066 | |
|---|
| 2186 | 2067 | /* If called from the scheduler, we can not call up(). */ |
|---|
| 2187 | | - if (!in_sched && pending_output) { |
|---|
| 2188 | | - int may_trylock = 1; |
|---|
| 2189 | | - |
|---|
| 2190 | | -#ifdef CONFIG_PREEMPT_RT_FULL |
|---|
| 2191 | | - /* |
|---|
| 2192 | | - * we can't take a sleeping lock with IRQs or preeption disabled |
|---|
| 2193 | | - * so we can't print in these contexts |
|---|
| 2194 | | - */ |
|---|
| 2195 | | - if (!(preempt_count() == 0 && !irqs_disabled())) |
|---|
| 2196 | | - may_trylock = 0; |
|---|
| 2197 | | -#endif |
|---|
| 2068 | + if (!in_sched) { |
|---|
| 2198 | 2069 | /* |
|---|
| 2199 | 2070 | * Disable preemption to avoid being preempted while holding |
|---|
| 2200 | 2071 | * console_sem which would prevent anyone from printing to |
|---|
| 2201 | 2072 | * console |
|---|
| 2202 | 2073 | */ |
|---|
| 2203 | | - migrate_disable(); |
|---|
| 2074 | + preempt_disable(); |
|---|
| 2204 | 2075 | /* |
|---|
| 2205 | 2076 | * Try to acquire and then immediately release the console |
|---|
| 2206 | 2077 | * semaphore. The release will print out buffers and wake up |
|---|
| 2207 | 2078 | * /dev/kmsg and syslog() users. |
|---|
| 2208 | 2079 | */ |
|---|
| 2209 | | - if (may_trylock && console_trylock_spinning()) |
|---|
| 2080 | + if (console_trylock_spinning()) |
|---|
| 2210 | 2081 | console_unlock(); |
|---|
| 2211 | | - migrate_enable(); |
|---|
| 2082 | + preempt_enable(); |
|---|
| 2212 | 2083 | } |
|---|
| 2213 | 2084 | |
|---|
| 2214 | | - if (pending_output) |
|---|
| 2215 | | - wake_up_klogd(); |
|---|
| 2085 | + wake_up_klogd(); |
|---|
| 2216 | 2086 | return printed_len; |
|---|
| 2217 | 2087 | } |
|---|
| 2218 | 2088 | EXPORT_SYMBOL(vprintk_emit); |
|---|
| .. | .. |
|---|
| 2223 | 2093 | } |
|---|
| 2224 | 2094 | EXPORT_SYMBOL(vprintk); |
|---|
| 2225 | 2095 | |
|---|
| 2226 | | -asmlinkage int printk_emit(int facility, int level, |
|---|
| 2227 | | - const char *dict, size_t dictlen, |
|---|
| 2228 | | - const char *fmt, ...) |
|---|
| 2229 | | -{ |
|---|
| 2230 | | - va_list args; |
|---|
| 2231 | | - int r; |
|---|
| 2232 | | - |
|---|
| 2233 | | - va_start(args, fmt); |
|---|
| 2234 | | - r = vprintk_emit(facility, level, dict, dictlen, fmt, args); |
|---|
| 2235 | | - va_end(args); |
|---|
| 2236 | | - |
|---|
| 2237 | | - return r; |
|---|
| 2238 | | -} |
|---|
| 2239 | | -EXPORT_SYMBOL(printk_emit); |
|---|
| 2240 | | - |
|---|
| 2241 | 2096 | int vprintk_default(const char *fmt, va_list args) |
|---|
| 2242 | 2097 | { |
|---|
| 2243 | | - int r; |
|---|
| 2244 | | - |
|---|
| 2245 | | -#ifdef CONFIG_KGDB_KDB |
|---|
| 2246 | | - /* Allow to pass printk() to kdb but avoid a recursion. */ |
|---|
| 2247 | | - if (unlikely(kdb_trap_printk && kdb_printf_cpu < 0)) { |
|---|
| 2248 | | - r = vkdb_printf(KDB_MSGSRC_PRINTK, fmt, args); |
|---|
| 2249 | | - return r; |
|---|
| 2250 | | - } |
|---|
| 2251 | | -#endif |
|---|
| 2252 | | - r = vprintk_emit(0, LOGLEVEL_DEFAULT, NULL, 0, fmt, args); |
|---|
| 2253 | | - |
|---|
| 2254 | | - return r; |
|---|
| 2098 | + return vprintk_emit(0, LOGLEVEL_DEFAULT, NULL, fmt, args); |
|---|
| 2255 | 2099 | } |
|---|
| 2256 | 2100 | EXPORT_SYMBOL_GPL(vprintk_default); |
|---|
| 2257 | 2101 | |
|---|
| .. | .. |
|---|
| 2293 | 2137 | |
|---|
| 2294 | 2138 | #define LOG_LINE_MAX 0 |
|---|
| 2295 | 2139 | #define PREFIX_MAX 0 |
|---|
| 2140 | +#define printk_time false |
|---|
| 2141 | + |
|---|
| 2142 | +#define prb_read_valid(rb, seq, r) false |
|---|
| 2143 | +#define prb_first_valid_seq(rb) 0 |
|---|
| 2296 | 2144 | |
|---|
| 2297 | 2145 | static u64 syslog_seq; |
|---|
| 2298 | | -static u32 syslog_idx; |
|---|
| 2299 | 2146 | static u64 console_seq; |
|---|
| 2300 | | -static u32 console_idx; |
|---|
| 2301 | 2147 | static u64 exclusive_console_stop_seq; |
|---|
| 2302 | | -static u64 log_first_seq; |
|---|
| 2303 | | -static u32 log_first_idx; |
|---|
| 2304 | | -static u64 log_next_seq; |
|---|
| 2305 | | -static char *log_text(const struct printk_log *msg) { return NULL; } |
|---|
| 2306 | | -static char *log_dict(const struct printk_log *msg) { return NULL; } |
|---|
| 2307 | | -static struct printk_log *log_from_idx(u32 idx) { return NULL; } |
|---|
| 2308 | | -static u32 log_next(u32 idx) { return 0; } |
|---|
| 2309 | | -static ssize_t msg_print_ext_header(char *buf, size_t size, |
|---|
| 2310 | | - struct printk_log *msg, |
|---|
| 2311 | | - u64 seq) { return 0; } |
|---|
| 2148 | +static unsigned long console_dropped; |
|---|
| 2149 | + |
|---|
| 2150 | +static size_t record_print_text(const struct printk_record *r, |
|---|
| 2151 | + bool syslog, bool time) |
|---|
| 2152 | +{ |
|---|
| 2153 | + return 0; |
|---|
| 2154 | +} |
|---|
| 2155 | +static ssize_t info_print_ext_header(char *buf, size_t size, |
|---|
| 2156 | + struct printk_info *info) |
|---|
| 2157 | +{ |
|---|
| 2158 | + return 0; |
|---|
| 2159 | +} |
|---|
| 2312 | 2160 | static ssize_t msg_print_ext_body(char *buf, size_t size, |
|---|
| 2313 | | - char *dict, size_t dict_len, |
|---|
| 2314 | | - char *text, size_t text_len) { return 0; } |
|---|
| 2161 | + char *text, size_t text_len, |
|---|
| 2162 | + struct dev_printk_info *dev_info) { return 0; } |
|---|
| 2315 | 2163 | static void console_lock_spinning_enable(void) { } |
|---|
| 2316 | 2164 | static int console_lock_spinning_disable_and_check(void) { return 0; } |
|---|
| 2317 | 2165 | static void call_console_drivers(const char *ext_text, size_t ext_len, |
|---|
| 2318 | 2166 | const char *text, size_t len) {} |
|---|
| 2319 | | -static size_t msg_print_text(const struct printk_log *msg, |
|---|
| 2320 | | - bool syslog, char *buf, size_t size) { return 0; } |
|---|
| 2321 | 2167 | static bool suppress_message_printing(int level) { return false; } |
|---|
| 2322 | 2168 | |
|---|
| 2323 | 2169 | #endif /* CONFIG_PRINTK */ |
|---|
| 2324 | 2170 | |
|---|
| 2171 | +#ifdef CONFIG_EARLY_PRINTK |
|---|
| 2172 | +struct console *early_console; |
|---|
| 2173 | + |
|---|
| 2174 | +asmlinkage __visible void early_printk(const char *fmt, ...) |
|---|
| 2175 | +{ |
|---|
| 2176 | + va_list ap; |
|---|
| 2177 | + char buf[512]; |
|---|
| 2178 | + int n; |
|---|
| 2179 | + |
|---|
| 2180 | + if (!early_console) |
|---|
| 2181 | + return; |
|---|
| 2182 | + |
|---|
| 2183 | + va_start(ap, fmt); |
|---|
| 2184 | + n = vscnprintf(buf, sizeof(buf), fmt, ap); |
|---|
| 2185 | + va_end(ap); |
|---|
| 2186 | + |
|---|
| 2187 | + early_console->write(early_console, buf, n); |
|---|
| 2188 | +} |
|---|
| 2189 | +#endif |
|---|
| 2190 | + |
|---|
| 2325 | 2191 | static int __add_preferred_console(char *name, int idx, char *options, |
|---|
| 2326 | | - char *brl_options) |
|---|
| 2192 | + char *brl_options, bool user_specified) |
|---|
| 2327 | 2193 | { |
|---|
| 2328 | 2194 | struct console_cmdline *c; |
|---|
| 2329 | 2195 | int i; |
|---|
| .. | .. |
|---|
| 2338 | 2204 | if (strcmp(c->name, name) == 0 && c->index == idx) { |
|---|
| 2339 | 2205 | if (!brl_options) |
|---|
| 2340 | 2206 | preferred_console = i; |
|---|
| 2207 | + if (user_specified) |
|---|
| 2208 | + c->user_specified = true; |
|---|
| 2341 | 2209 | return 0; |
|---|
| 2342 | 2210 | } |
|---|
| 2343 | 2211 | } |
|---|
| .. | .. |
|---|
| 2347 | 2215 | preferred_console = i; |
|---|
| 2348 | 2216 | strlcpy(c->name, name, sizeof(c->name)); |
|---|
| 2349 | 2217 | c->options = options; |
|---|
| 2218 | + c->user_specified = user_specified; |
|---|
| 2350 | 2219 | braille_set_options(c, brl_options); |
|---|
| 2351 | 2220 | |
|---|
| 2352 | 2221 | c->index = idx; |
|---|
| .. | .. |
|---|
| 2379 | 2248 | * for exacly this purpose. |
|---|
| 2380 | 2249 | */ |
|---|
| 2381 | 2250 | if (str[0] == 0 || strcmp(str, "null") == 0) { |
|---|
| 2382 | | - __add_preferred_console("ttynull", 0, NULL, NULL); |
|---|
| 2251 | + __add_preferred_console("ttynull", 0, NULL, NULL, true); |
|---|
| 2383 | 2252 | return 1; |
|---|
| 2384 | 2253 | } |
|---|
| 2385 | 2254 | |
|---|
| .. | .. |
|---|
| 2411 | 2280 | idx = simple_strtoul(s, NULL, 10); |
|---|
| 2412 | 2281 | *s = 0; |
|---|
| 2413 | 2282 | |
|---|
| 2414 | | - __add_preferred_console(buf, idx, options, brl_options); |
|---|
| 2283 | + __add_preferred_console(buf, idx, options, brl_options, true); |
|---|
| 2415 | 2284 | console_set_on_cmdline = 1; |
|---|
| 2416 | 2285 | return 1; |
|---|
| 2417 | 2286 | } |
|---|
| .. | .. |
|---|
| 2432 | 2301 | */ |
|---|
| 2433 | 2302 | int add_preferred_console(char *name, int idx, char *options) |
|---|
| 2434 | 2303 | { |
|---|
| 2435 | | - return __add_preferred_console(name, idx, options, NULL); |
|---|
| 2304 | + return __add_preferred_console(name, idx, options, NULL, false); |
|---|
| 2436 | 2305 | } |
|---|
| 2437 | 2306 | |
|---|
| 2438 | 2307 | bool console_suspend_enabled = true; |
|---|
| .. | .. |
|---|
| 2484 | 2353 | */ |
|---|
| 2485 | 2354 | static int console_cpu_notify(unsigned int cpu) |
|---|
| 2486 | 2355 | { |
|---|
| 2356 | + int flag = 0; |
|---|
| 2357 | + |
|---|
| 2358 | + trace_android_vh_printk_hotplug(&flag); |
|---|
| 2359 | + if (flag) |
|---|
| 2360 | + return 0; |
|---|
| 2361 | + |
|---|
| 2487 | 2362 | if (!cpuhp_tasks_frozen) { |
|---|
| 2488 | 2363 | /* If trylock fails, someone else is doing the printing */ |
|---|
| 2489 | 2364 | if (console_trylock()) |
|---|
| .. | .. |
|---|
| 2588 | 2463 | static char text[LOG_LINE_MAX + PREFIX_MAX]; |
|---|
| 2589 | 2464 | unsigned long flags; |
|---|
| 2590 | 2465 | bool do_cond_resched, retry; |
|---|
| 2466 | + struct printk_info info; |
|---|
| 2467 | + struct printk_record r; |
|---|
| 2591 | 2468 | |
|---|
| 2592 | 2469 | if (console_suspended) { |
|---|
| 2593 | 2470 | up_console_sem(); |
|---|
| 2594 | 2471 | return; |
|---|
| 2595 | 2472 | } |
|---|
| 2473 | + |
|---|
| 2474 | + prb_rec_init_rd(&r, &info, text, sizeof(text)); |
|---|
| 2596 | 2475 | |
|---|
| 2597 | 2476 | /* |
|---|
| 2598 | 2477 | * Console drivers are called with interrupts disabled, so |
|---|
| .. | .. |
|---|
| 2606 | 2485 | * |
|---|
| 2607 | 2486 | * console_trylock() is not able to detect the preemptive |
|---|
| 2608 | 2487 | * context reliably. Therefore the value must be stored before |
|---|
| 2609 | | - * and cleared after the the "again" goto label. |
|---|
| 2488 | + * and cleared after the "again" goto label. |
|---|
| 2610 | 2489 | */ |
|---|
| 2611 | 2490 | do_cond_resched = console_may_schedule; |
|---|
| 2612 | 2491 | again: |
|---|
| .. | .. |
|---|
| 2624 | 2503 | } |
|---|
| 2625 | 2504 | |
|---|
| 2626 | 2505 | for (;;) { |
|---|
| 2627 | | - struct printk_log *msg; |
|---|
| 2628 | 2506 | size_t ext_len = 0; |
|---|
| 2629 | 2507 | size_t len; |
|---|
| 2630 | 2508 | |
|---|
| 2631 | 2509 | printk_safe_enter_irqsave(flags); |
|---|
| 2632 | 2510 | raw_spin_lock(&logbuf_lock); |
|---|
| 2633 | | - if (console_seq < log_first_seq) { |
|---|
| 2634 | | - len = sprintf(text, |
|---|
| 2635 | | - "** %llu printk messages dropped **\n", |
|---|
| 2636 | | - log_first_seq - console_seq); |
|---|
| 2637 | | - |
|---|
| 2638 | | - /* messages are gone, move to first one */ |
|---|
| 2639 | | - console_seq = log_first_seq; |
|---|
| 2640 | | - console_idx = log_first_idx; |
|---|
| 2641 | | - } else { |
|---|
| 2642 | | - len = 0; |
|---|
| 2643 | | - } |
|---|
| 2644 | 2511 | skip: |
|---|
| 2645 | | - if (console_seq == log_next_seq) |
|---|
| 2512 | + if (!prb_read_valid(prb, console_seq, &r)) |
|---|
| 2646 | 2513 | break; |
|---|
| 2647 | 2514 | |
|---|
| 2648 | | - msg = log_from_idx(console_idx); |
|---|
| 2649 | | - if (suppress_message_printing(msg->level)) { |
|---|
| 2515 | + if (console_seq != r.info->seq) { |
|---|
| 2516 | + console_dropped += r.info->seq - console_seq; |
|---|
| 2517 | + console_seq = r.info->seq; |
|---|
| 2518 | + } |
|---|
| 2519 | + |
|---|
| 2520 | + if (suppress_message_printing(r.info->level)) { |
|---|
| 2650 | 2521 | /* |
|---|
| 2651 | 2522 | * Skip record we have buffered and already printed |
|---|
| 2652 | 2523 | * directly to the console when we received it, and |
|---|
| 2653 | 2524 | * record that has level above the console loglevel. |
|---|
| 2654 | 2525 | */ |
|---|
| 2655 | | - console_idx = log_next(console_idx); |
|---|
| 2656 | 2526 | console_seq++; |
|---|
| 2657 | 2527 | goto skip; |
|---|
| 2658 | 2528 | } |
|---|
| .. | .. |
|---|
| 2663 | 2533 | exclusive_console = NULL; |
|---|
| 2664 | 2534 | } |
|---|
| 2665 | 2535 | |
|---|
| 2666 | | - len += msg_print_text(msg, |
|---|
| 2667 | | - console_msg_format & MSG_FORMAT_SYSLOG, |
|---|
| 2668 | | - text + len, |
|---|
| 2669 | | - sizeof(text) - len); |
|---|
| 2536 | + /* |
|---|
| 2537 | + * Handle extended console text first because later |
|---|
| 2538 | + * record_print_text() will modify the record buffer in-place. |
|---|
| 2539 | + */ |
|---|
| 2670 | 2540 | if (nr_ext_console_drivers) { |
|---|
| 2671 | | - ext_len = msg_print_ext_header(ext_text, |
|---|
| 2541 | + ext_len = info_print_ext_header(ext_text, |
|---|
| 2672 | 2542 | sizeof(ext_text), |
|---|
| 2673 | | - msg, console_seq); |
|---|
| 2543 | + r.info); |
|---|
| 2674 | 2544 | ext_len += msg_print_ext_body(ext_text + ext_len, |
|---|
| 2675 | 2545 | sizeof(ext_text) - ext_len, |
|---|
| 2676 | | - log_dict(msg), msg->dict_len, |
|---|
| 2677 | | - log_text(msg), msg->text_len); |
|---|
| 2546 | + &r.text_buf[0], |
|---|
| 2547 | + r.info->text_len, |
|---|
| 2548 | + &r.info->dev_info); |
|---|
| 2678 | 2549 | } |
|---|
| 2679 | | - console_idx = log_next(console_idx); |
|---|
| 2550 | + len = record_print_text(&r, |
|---|
| 2551 | + console_msg_format & MSG_FORMAT_SYSLOG, |
|---|
| 2552 | + printk_time); |
|---|
| 2680 | 2553 | console_seq++; |
|---|
| 2681 | 2554 | raw_spin_unlock(&logbuf_lock); |
|---|
| 2682 | 2555 | |
|---|
| 2683 | | -#ifdef CONFIG_PREEMPT_RT_FULL |
|---|
| 2684 | | - printk_safe_exit_irqrestore(flags); |
|---|
| 2685 | | - call_console_drivers(ext_text, ext_len, text, len); |
|---|
| 2686 | | -#else |
|---|
| 2687 | 2556 | /* |
|---|
| 2688 | 2557 | * While actively printing out messages, if another printk() |
|---|
| 2689 | 2558 | * were to occur on another CPU, it may wait for this one to |
|---|
| .. | .. |
|---|
| 2693 | 2562 | console_lock_spinning_enable(); |
|---|
| 2694 | 2563 | |
|---|
| 2695 | 2564 | stop_critical_timings(); /* don't trace print latency */ |
|---|
| 2696 | | -#ifdef CONFIG_PSTORE_CONSOLE_FORCE |
|---|
| 2697 | | - call_console_drivers_level(msg->level, ext_text, ext_len, text, len); |
|---|
| 2698 | | -#else |
|---|
| 2699 | 2565 | call_console_drivers(ext_text, ext_len, text, len); |
|---|
| 2700 | | -#endif |
|---|
| 2701 | 2566 | start_critical_timings(); |
|---|
| 2702 | 2567 | |
|---|
| 2703 | 2568 | if (console_lock_spinning_disable_and_check()) { |
|---|
| .. | .. |
|---|
| 2706 | 2571 | } |
|---|
| 2707 | 2572 | |
|---|
| 2708 | 2573 | printk_safe_exit_irqrestore(flags); |
|---|
| 2709 | | -#endif |
|---|
| 2710 | 2574 | |
|---|
| 2711 | 2575 | if (do_cond_resched) |
|---|
| 2712 | 2576 | cond_resched(); |
|---|
| .. | .. |
|---|
| 2725 | 2589 | * flush, no worries. |
|---|
| 2726 | 2590 | */ |
|---|
| 2727 | 2591 | raw_spin_lock(&logbuf_lock); |
|---|
| 2728 | | - retry = console_seq != log_next_seq; |
|---|
| 2592 | + retry = prb_read_valid(prb, console_seq, NULL); |
|---|
| 2729 | 2593 | raw_spin_unlock(&logbuf_lock); |
|---|
| 2730 | 2594 | printk_safe_exit_irqrestore(flags); |
|---|
| 2731 | 2595 | |
|---|
| .. | .. |
|---|
| 2754 | 2618 | { |
|---|
| 2755 | 2619 | struct console *c; |
|---|
| 2756 | 2620 | |
|---|
| 2757 | | - if (IS_ENABLED(CONFIG_PREEMPT_RT_BASE)) { |
|---|
| 2758 | | - if (in_irq() || in_nmi()) |
|---|
| 2759 | | - return; |
|---|
| 2760 | | - } |
|---|
| 2761 | | - |
|---|
| 2762 | 2621 | /* |
|---|
| 2763 | 2622 | * console_unblank can no longer be called in interrupt context unless |
|---|
| 2764 | 2623 | * oops_in_progress is set to 1.. |
|---|
| .. | .. |
|---|
| 2779 | 2638 | |
|---|
| 2780 | 2639 | /** |
|---|
| 2781 | 2640 | * console_flush_on_panic - flush console content on panic |
|---|
| 2641 | + * @mode: flush all messages in buffer or just the pending ones |
|---|
| 2782 | 2642 | * |
|---|
| 2783 | 2643 | * Immediately output all pending messages no matter what. |
|---|
| 2784 | 2644 | */ |
|---|
| 2785 | | -void console_flush_on_panic(void) |
|---|
| 2645 | +void console_flush_on_panic(enum con_flush_mode mode) |
|---|
| 2786 | 2646 | { |
|---|
| 2787 | 2647 | /* |
|---|
| 2788 | 2648 | * If someone else is holding the console lock, trylock will fail |
|---|
| .. | .. |
|---|
| 2793 | 2653 | */ |
|---|
| 2794 | 2654 | console_trylock(); |
|---|
| 2795 | 2655 | console_may_schedule = 0; |
|---|
| 2656 | + |
|---|
| 2657 | + if (mode == CONSOLE_REPLAY_ALL) { |
|---|
| 2658 | + unsigned long flags; |
|---|
| 2659 | + |
|---|
| 2660 | + logbuf_lock_irqsave(flags); |
|---|
| 2661 | + console_seq = prb_first_valid_seq(prb); |
|---|
| 2662 | + logbuf_unlock_irqrestore(flags); |
|---|
| 2663 | + } |
|---|
| 2796 | 2664 | console_unlock(); |
|---|
| 2797 | 2665 | } |
|---|
| 2798 | 2666 | |
|---|
| .. | .. |
|---|
| 2850 | 2718 | early_param("keep_bootcon", keep_bootcon_setup); |
|---|
| 2851 | 2719 | |
|---|
| 2852 | 2720 | /* |
|---|
| 2721 | + * This is called by register_console() to try to match |
|---|
| 2722 | + * the newly registered console with any of the ones selected |
|---|
| 2723 | + * by either the command line or add_preferred_console() and |
|---|
| 2724 | + * setup/enable it. |
|---|
| 2725 | + * |
|---|
| 2726 | + * Care need to be taken with consoles that are statically |
|---|
| 2727 | + * enabled such as netconsole |
|---|
| 2728 | + */ |
|---|
| 2729 | +static int try_enable_new_console(struct console *newcon, bool user_specified) |
|---|
| 2730 | +{ |
|---|
| 2731 | + struct console_cmdline *c; |
|---|
| 2732 | + int i, err; |
|---|
| 2733 | + |
|---|
| 2734 | + for (i = 0, c = console_cmdline; |
|---|
| 2735 | + i < MAX_CMDLINECONSOLES && c->name[0]; |
|---|
| 2736 | + i++, c++) { |
|---|
| 2737 | + if (c->user_specified != user_specified) |
|---|
| 2738 | + continue; |
|---|
| 2739 | + if (!newcon->match || |
|---|
| 2740 | + newcon->match(newcon, c->name, c->index, c->options) != 0) { |
|---|
| 2741 | + /* default matching */ |
|---|
| 2742 | + BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name)); |
|---|
| 2743 | + if (strcmp(c->name, newcon->name) != 0) |
|---|
| 2744 | + continue; |
|---|
| 2745 | + if (newcon->index >= 0 && |
|---|
| 2746 | + newcon->index != c->index) |
|---|
| 2747 | + continue; |
|---|
| 2748 | + if (newcon->index < 0) |
|---|
| 2749 | + newcon->index = c->index; |
|---|
| 2750 | + |
|---|
| 2751 | + if (_braille_register_console(newcon, c)) |
|---|
| 2752 | + return 0; |
|---|
| 2753 | + |
|---|
| 2754 | + if (newcon->setup && |
|---|
| 2755 | + (err = newcon->setup(newcon, c->options)) != 0) |
|---|
| 2756 | + return err; |
|---|
| 2757 | + } |
|---|
| 2758 | + newcon->flags |= CON_ENABLED; |
|---|
| 2759 | + if (i == preferred_console) { |
|---|
| 2760 | + newcon->flags |= CON_CONSDEV; |
|---|
| 2761 | + has_preferred_console = true; |
|---|
| 2762 | + } |
|---|
| 2763 | + return 0; |
|---|
| 2764 | + } |
|---|
| 2765 | + |
|---|
| 2766 | + /* |
|---|
| 2767 | + * Some consoles, such as pstore and netconsole, can be enabled even |
|---|
| 2768 | + * without matching. Accept the pre-enabled consoles only when match() |
|---|
| 2769 | + * and setup() had a chance to be called. |
|---|
| 2770 | + */ |
|---|
| 2771 | + if (newcon->flags & CON_ENABLED && c->user_specified == user_specified) |
|---|
| 2772 | + return 0; |
|---|
| 2773 | + |
|---|
| 2774 | + return -ENOENT; |
|---|
| 2775 | +} |
|---|
| 2776 | + |
|---|
| 2777 | +/* |
|---|
| 2853 | 2778 | * The console driver calls this routine during kernel initialization |
|---|
| 2854 | 2779 | * to register the console printing procedure with printk() and to |
|---|
| 2855 | 2780 | * print any messages that were printed by the kernel before the |
|---|
| .. | .. |
|---|
| 2870 | 2795 | */ |
|---|
| 2871 | 2796 | void register_console(struct console *newcon) |
|---|
| 2872 | 2797 | { |
|---|
| 2873 | | - int i; |
|---|
| 2874 | 2798 | unsigned long flags; |
|---|
| 2875 | 2799 | struct console *bcon = NULL; |
|---|
| 2876 | | - struct console_cmdline *c; |
|---|
| 2877 | | - static bool has_preferred; |
|---|
| 2800 | + int err; |
|---|
| 2878 | 2801 | |
|---|
| 2879 | | - if (console_drivers) |
|---|
| 2880 | | - for_each_console(bcon) |
|---|
| 2881 | | - if (WARN(bcon == newcon, |
|---|
| 2882 | | - "console '%s%d' already registered\n", |
|---|
| 2883 | | - bcon->name, bcon->index)) |
|---|
| 2884 | | - return; |
|---|
| 2802 | + for_each_console(bcon) { |
|---|
| 2803 | + if (WARN(bcon == newcon, "console '%s%d' already registered\n", |
|---|
| 2804 | + bcon->name, bcon->index)) |
|---|
| 2805 | + return; |
|---|
| 2806 | + } |
|---|
| 2885 | 2807 | |
|---|
| 2886 | 2808 | /* |
|---|
| 2887 | 2809 | * before we register a new CON_BOOT console, make sure we don't |
|---|
| 2888 | 2810 | * already have a valid console |
|---|
| 2889 | 2811 | */ |
|---|
| 2890 | | - if (console_drivers && newcon->flags & CON_BOOT) { |
|---|
| 2891 | | - /* find the last or real console */ |
|---|
| 2812 | + if (newcon->flags & CON_BOOT) { |
|---|
| 2892 | 2813 | for_each_console(bcon) { |
|---|
| 2893 | 2814 | if (!(bcon->flags & CON_BOOT)) { |
|---|
| 2894 | 2815 | pr_info("Too late to register bootconsole %s%d\n", |
|---|
| .. | .. |
|---|
| 2901 | 2822 | if (console_drivers && console_drivers->flags & CON_BOOT) |
|---|
| 2902 | 2823 | bcon = console_drivers; |
|---|
| 2903 | 2824 | |
|---|
| 2904 | | - if (!has_preferred || bcon || !console_drivers) |
|---|
| 2905 | | - has_preferred = preferred_console >= 0; |
|---|
| 2825 | + if (!has_preferred_console || bcon || !console_drivers) |
|---|
| 2826 | + has_preferred_console = preferred_console >= 0; |
|---|
| 2906 | 2827 | |
|---|
| 2907 | 2828 | /* |
|---|
| 2908 | 2829 | * See if we want to use this console driver. If we |
|---|
| 2909 | 2830 | * didn't select a console we take the first one |
|---|
| 2910 | 2831 | * that registers here. |
|---|
| 2911 | 2832 | */ |
|---|
| 2912 | | - if (!has_preferred) { |
|---|
| 2833 | + if (!has_preferred_console) { |
|---|
| 2913 | 2834 | if (newcon->index < 0) |
|---|
| 2914 | 2835 | newcon->index = 0; |
|---|
| 2915 | 2836 | if (newcon->setup == NULL || |
|---|
| .. | .. |
|---|
| 2917 | 2838 | newcon->flags |= CON_ENABLED; |
|---|
| 2918 | 2839 | if (newcon->device) { |
|---|
| 2919 | 2840 | newcon->flags |= CON_CONSDEV; |
|---|
| 2920 | | - has_preferred = true; |
|---|
| 2841 | + has_preferred_console = true; |
|---|
| 2921 | 2842 | } |
|---|
| 2922 | 2843 | } |
|---|
| 2923 | 2844 | } |
|---|
| 2924 | 2845 | |
|---|
| 2925 | | - /* |
|---|
| 2926 | | - * See if this console matches one we selected on |
|---|
| 2927 | | - * the command line. |
|---|
| 2928 | | - */ |
|---|
| 2929 | | - for (i = 0, c = console_cmdline; |
|---|
| 2930 | | - i < MAX_CMDLINECONSOLES && c->name[0]; |
|---|
| 2931 | | - i++, c++) { |
|---|
| 2932 | | - if (!newcon->match || |
|---|
| 2933 | | - newcon->match(newcon, c->name, c->index, c->options) != 0) { |
|---|
| 2934 | | - /* default matching */ |
|---|
| 2935 | | - BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name)); |
|---|
| 2936 | | - if (strcmp(c->name, newcon->name) != 0) |
|---|
| 2937 | | - continue; |
|---|
| 2938 | | - if (newcon->index >= 0 && |
|---|
| 2939 | | - newcon->index != c->index) |
|---|
| 2940 | | - continue; |
|---|
| 2941 | | - if (newcon->index < 0) |
|---|
| 2942 | | - newcon->index = c->index; |
|---|
| 2846 | + /* See if this console matches one we selected on the command line */ |
|---|
| 2847 | + err = try_enable_new_console(newcon, true); |
|---|
| 2943 | 2848 | |
|---|
| 2944 | | - if (_braille_register_console(newcon, c)) |
|---|
| 2945 | | - return; |
|---|
| 2849 | + /* If not, try to match against the platform default(s) */ |
|---|
| 2850 | + if (err == -ENOENT) |
|---|
| 2851 | + err = try_enable_new_console(newcon, false); |
|---|
| 2946 | 2852 | |
|---|
| 2947 | | - if (newcon->setup && |
|---|
| 2948 | | - newcon->setup(newcon, c->options) != 0) |
|---|
| 2949 | | - break; |
|---|
| 2950 | | - } |
|---|
| 2951 | | - |
|---|
| 2952 | | - newcon->flags |= CON_ENABLED; |
|---|
| 2953 | | - if (i == preferred_console) { |
|---|
| 2954 | | - newcon->flags |= CON_CONSDEV; |
|---|
| 2955 | | - has_preferred = true; |
|---|
| 2956 | | - } |
|---|
| 2957 | | - break; |
|---|
| 2958 | | - } |
|---|
| 2959 | | - |
|---|
| 2960 | | - if (!(newcon->flags & CON_ENABLED)) |
|---|
| 2853 | + /* printk() messages are not printed to the Braille console. */ |
|---|
| 2854 | + if (err || newcon->flags & CON_BRL) |
|---|
| 2961 | 2855 | return; |
|---|
| 2962 | 2856 | |
|---|
| 2963 | 2857 | /* |
|---|
| .. | .. |
|---|
| 2979 | 2873 | console_drivers = newcon; |
|---|
| 2980 | 2874 | if (newcon->next) |
|---|
| 2981 | 2875 | newcon->next->flags &= ~CON_CONSDEV; |
|---|
| 2876 | + /* Ensure this flag is always set for the head of the list */ |
|---|
| 2877 | + newcon->flags |= CON_CONSDEV; |
|---|
| 2982 | 2878 | } else { |
|---|
| 2983 | 2879 | newcon->next = console_drivers->next; |
|---|
| 2984 | 2880 | console_drivers->next = newcon; |
|---|
| 2985 | 2881 | } |
|---|
| 2986 | 2882 | |
|---|
| 2987 | 2883 | if (newcon->flags & CON_EXTENDED) |
|---|
| 2988 | | - if (!nr_ext_console_drivers++) |
|---|
| 2989 | | - pr_info("printk: continuation disabled due to ext consoles, expect more fragments in /dev/kmsg\n"); |
|---|
| 2884 | + nr_ext_console_drivers++; |
|---|
| 2990 | 2885 | |
|---|
| 2991 | 2886 | if (newcon->flags & CON_PRINTBUFFER) { |
|---|
| 2992 | 2887 | /* |
|---|
| .. | .. |
|---|
| 3006 | 2901 | exclusive_console = newcon; |
|---|
| 3007 | 2902 | exclusive_console_stop_seq = console_seq; |
|---|
| 3008 | 2903 | console_seq = syslog_seq; |
|---|
| 3009 | | - console_idx = syslog_idx; |
|---|
| 3010 | 2904 | logbuf_unlock_irqrestore(flags); |
|---|
| 3011 | 2905 | } |
|---|
| 3012 | 2906 | console_unlock(); |
|---|
| .. | .. |
|---|
| 3037 | 2931 | |
|---|
| 3038 | 2932 | int unregister_console(struct console *console) |
|---|
| 3039 | 2933 | { |
|---|
| 3040 | | - struct console *a, *b; |
|---|
| 2934 | + struct console *con; |
|---|
| 3041 | 2935 | int res; |
|---|
| 3042 | 2936 | |
|---|
| 3043 | 2937 | pr_info("%sconsole [%s%d] disabled\n", |
|---|
| .. | .. |
|---|
| 3045 | 2939 | console->name, console->index); |
|---|
| 3046 | 2940 | |
|---|
| 3047 | 2941 | res = _braille_unregister_console(console); |
|---|
| 3048 | | - if (res) |
|---|
| 2942 | + if (res < 0) |
|---|
| 3049 | 2943 | return res; |
|---|
| 2944 | + if (res > 0) |
|---|
| 2945 | + return 0; |
|---|
| 3050 | 2946 | |
|---|
| 3051 | | - res = 1; |
|---|
| 2947 | + res = -ENODEV; |
|---|
| 3052 | 2948 | console_lock(); |
|---|
| 3053 | 2949 | if (console_drivers == console) { |
|---|
| 3054 | 2950 | console_drivers=console->next; |
|---|
| 3055 | 2951 | res = 0; |
|---|
| 3056 | | - } else if (console_drivers) { |
|---|
| 3057 | | - for (a=console_drivers->next, b=console_drivers ; |
|---|
| 3058 | | - a; b=a, a=b->next) { |
|---|
| 3059 | | - if (a == console) { |
|---|
| 3060 | | - b->next = a->next; |
|---|
| 2952 | + } else { |
|---|
| 2953 | + for_each_console(con) { |
|---|
| 2954 | + if (con->next == console) { |
|---|
| 2955 | + con->next = console->next; |
|---|
| 3061 | 2956 | res = 0; |
|---|
| 3062 | 2957 | break; |
|---|
| 3063 | 2958 | } |
|---|
| 3064 | 2959 | } |
|---|
| 3065 | 2960 | } |
|---|
| 3066 | 2961 | |
|---|
| 3067 | | - if (!res && (console->flags & CON_EXTENDED)) |
|---|
| 2962 | + if (res) |
|---|
| 2963 | + goto out_disable_unlock; |
|---|
| 2964 | + |
|---|
| 2965 | + if (console->flags & CON_EXTENDED) |
|---|
| 3068 | 2966 | nr_ext_console_drivers--; |
|---|
| 3069 | 2967 | |
|---|
| 3070 | 2968 | /* |
|---|
| .. | .. |
|---|
| 3077 | 2975 | console->flags &= ~CON_ENABLED; |
|---|
| 3078 | 2976 | console_unlock(); |
|---|
| 3079 | 2977 | console_sysfs_notify(); |
|---|
| 2978 | + |
|---|
| 2979 | + if (console->exit) |
|---|
| 2980 | + res = console->exit(console); |
|---|
| 2981 | + |
|---|
| 2982 | + return res; |
|---|
| 2983 | + |
|---|
| 2984 | +out_disable_unlock: |
|---|
| 2985 | + console->flags &= ~CON_ENABLED; |
|---|
| 2986 | + console_unlock(); |
|---|
| 2987 | + |
|---|
| 3080 | 2988 | return res; |
|---|
| 3081 | 2989 | } |
|---|
| 3082 | 2990 | EXPORT_SYMBOL(unregister_console); |
|---|
| .. | .. |
|---|
| 3185 | 3093 | |
|---|
| 3186 | 3094 | static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = { |
|---|
| 3187 | 3095 | .func = wake_up_klogd_work_func, |
|---|
| 3188 | | - .flags = IRQ_WORK_LAZY, |
|---|
| 3096 | + .flags = ATOMIC_INIT(IRQ_WORK_LAZY), |
|---|
| 3189 | 3097 | }; |
|---|
| 3190 | 3098 | |
|---|
| 3191 | 3099 | void wake_up_klogd(void) |
|---|
| .. | .. |
|---|
| 3216 | 3124 | { |
|---|
| 3217 | 3125 | int r; |
|---|
| 3218 | 3126 | |
|---|
| 3219 | | - r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args); |
|---|
| 3127 | + r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, fmt, args); |
|---|
| 3220 | 3128 | defer_console_output(); |
|---|
| 3221 | 3129 | |
|---|
| 3222 | 3130 | return r; |
|---|
| .. | .. |
|---|
| 3233 | 3141 | |
|---|
| 3234 | 3142 | return r; |
|---|
| 3235 | 3143 | } |
|---|
| 3144 | +EXPORT_SYMBOL_GPL(printk_deferred); |
|---|
| 3236 | 3145 | |
|---|
| 3237 | 3146 | /* |
|---|
| 3238 | 3147 | * printk rate limiting, lifted from the networking subsystem. |
|---|
| .. | .. |
|---|
| 3331 | 3240 | static bool always_kmsg_dump; |
|---|
| 3332 | 3241 | module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR); |
|---|
| 3333 | 3242 | |
|---|
| 3243 | +const char *kmsg_dump_reason_str(enum kmsg_dump_reason reason) |
|---|
| 3244 | +{ |
|---|
| 3245 | + switch (reason) { |
|---|
| 3246 | + case KMSG_DUMP_PANIC: |
|---|
| 3247 | + return "Panic"; |
|---|
| 3248 | + case KMSG_DUMP_OOPS: |
|---|
| 3249 | + return "Oops"; |
|---|
| 3250 | + case KMSG_DUMP_EMERG: |
|---|
| 3251 | + return "Emergency"; |
|---|
| 3252 | + case KMSG_DUMP_SHUTDOWN: |
|---|
| 3253 | + return "Shutdown"; |
|---|
| 3254 | + default: |
|---|
| 3255 | + return "Unknown"; |
|---|
| 3256 | + } |
|---|
| 3257 | +} |
|---|
| 3258 | +EXPORT_SYMBOL_GPL(kmsg_dump_reason_str); |
|---|
| 3259 | + |
|---|
| 3334 | 3260 | /** |
|---|
| 3335 | 3261 | * kmsg_dump - dump kernel log to kernel message dumpers. |
|---|
| 3336 | 3262 | * @reason: the reason (oops, panic etc) for dumping |
|---|
| .. | .. |
|---|
| 3344 | 3270 | struct kmsg_dumper *dumper; |
|---|
| 3345 | 3271 | unsigned long flags; |
|---|
| 3346 | 3272 | |
|---|
| 3347 | | - if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump) |
|---|
| 3348 | | - return; |
|---|
| 3349 | | - |
|---|
| 3350 | 3273 | rcu_read_lock(); |
|---|
| 3351 | 3274 | list_for_each_entry_rcu(dumper, &dump_list, list) { |
|---|
| 3352 | | - if (dumper->max_reason && reason > dumper->max_reason) |
|---|
| 3275 | + enum kmsg_dump_reason max_reason = dumper->max_reason; |
|---|
| 3276 | + |
|---|
| 3277 | + /* |
|---|
| 3278 | + * If client has not provided a specific max_reason, default |
|---|
| 3279 | + * to KMSG_DUMP_OOPS, unless always_kmsg_dump was set. |
|---|
| 3280 | + */ |
|---|
| 3281 | + if (max_reason == KMSG_DUMP_UNDEF) { |
|---|
| 3282 | + max_reason = always_kmsg_dump ? KMSG_DUMP_MAX : |
|---|
| 3283 | + KMSG_DUMP_OOPS; |
|---|
| 3284 | + } |
|---|
| 3285 | + if (reason > max_reason) |
|---|
| 3353 | 3286 | continue; |
|---|
| 3354 | 3287 | |
|---|
| 3355 | 3288 | /* initialize iterator with data about the stored records */ |
|---|
| .. | .. |
|---|
| 3357 | 3290 | |
|---|
| 3358 | 3291 | logbuf_lock_irqsave(flags); |
|---|
| 3359 | 3292 | dumper->cur_seq = clear_seq; |
|---|
| 3360 | | - dumper->cur_idx = clear_idx; |
|---|
| 3361 | | - dumper->next_seq = log_next_seq; |
|---|
| 3362 | | - dumper->next_idx = log_next_idx; |
|---|
| 3293 | + dumper->next_seq = prb_next_seq(prb); |
|---|
| 3363 | 3294 | logbuf_unlock_irqrestore(flags); |
|---|
| 3364 | 3295 | |
|---|
| 3365 | 3296 | /* invoke dumper which will iterate over records */ |
|---|
| .. | .. |
|---|
| 3393 | 3324 | bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog, |
|---|
| 3394 | 3325 | char *line, size_t size, size_t *len) |
|---|
| 3395 | 3326 | { |
|---|
| 3396 | | - struct printk_log *msg; |
|---|
| 3327 | + struct printk_info info; |
|---|
| 3328 | + unsigned int line_count; |
|---|
| 3329 | + struct printk_record r; |
|---|
| 3397 | 3330 | size_t l = 0; |
|---|
| 3398 | 3331 | bool ret = false; |
|---|
| 3332 | + |
|---|
| 3333 | + prb_rec_init_rd(&r, &info, line, size); |
|---|
| 3399 | 3334 | |
|---|
| 3400 | 3335 | if (!dumper->active) |
|---|
| 3401 | 3336 | goto out; |
|---|
| 3402 | 3337 | |
|---|
| 3403 | | - if (dumper->cur_seq < log_first_seq) { |
|---|
| 3404 | | - /* messages are gone, move to first available one */ |
|---|
| 3405 | | - dumper->cur_seq = log_first_seq; |
|---|
| 3406 | | - dumper->cur_idx = log_first_idx; |
|---|
| 3338 | + /* Read text or count text lines? */ |
|---|
| 3339 | + if (line) { |
|---|
| 3340 | + if (!prb_read_valid(prb, dumper->cur_seq, &r)) |
|---|
| 3341 | + goto out; |
|---|
| 3342 | + l = record_print_text(&r, syslog, printk_time); |
|---|
| 3343 | + } else { |
|---|
| 3344 | + if (!prb_read_valid_info(prb, dumper->cur_seq, |
|---|
| 3345 | + &info, &line_count)) { |
|---|
| 3346 | + goto out; |
|---|
| 3347 | + } |
|---|
| 3348 | + l = get_record_print_text_size(&info, line_count, syslog, |
|---|
| 3349 | + printk_time); |
|---|
| 3350 | + |
|---|
| 3407 | 3351 | } |
|---|
| 3408 | 3352 | |
|---|
| 3409 | | - /* last entry */ |
|---|
| 3410 | | - if (dumper->cur_seq >= log_next_seq) |
|---|
| 3411 | | - goto out; |
|---|
| 3412 | | - |
|---|
| 3413 | | - msg = log_from_idx(dumper->cur_idx); |
|---|
| 3414 | | - l = msg_print_text(msg, syslog, line, size); |
|---|
| 3415 | | - |
|---|
| 3416 | | - dumper->cur_idx = log_next(dumper->cur_idx); |
|---|
| 3417 | | - dumper->cur_seq++; |
|---|
| 3353 | + dumper->cur_seq = r.info->seq + 1; |
|---|
| 3418 | 3354 | ret = true; |
|---|
| 3419 | 3355 | out: |
|---|
| 3420 | 3356 | if (len) |
|---|
| .. | .. |
|---|
| 3462 | 3398 | * @len: length of line placed into buffer |
|---|
| 3463 | 3399 | * |
|---|
| 3464 | 3400 | * Start at the end of the kmsg buffer and fill the provided buffer |
|---|
| 3465 | | - * with as many of the the *youngest* kmsg records that fit into it. |
|---|
| 3401 | + * with as many of the *youngest* kmsg records that fit into it. |
|---|
| 3466 | 3402 | * If the buffer is large enough, all available kmsg records will be |
|---|
| 3467 | 3403 | * copied with a single call. |
|---|
| 3468 | 3404 | * |
|---|
| .. | .. |
|---|
| 3475 | 3411 | bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, |
|---|
| 3476 | 3412 | char *buf, size_t size, size_t *len) |
|---|
| 3477 | 3413 | { |
|---|
| 3414 | + struct printk_info info; |
|---|
| 3415 | + unsigned int line_count; |
|---|
| 3416 | + struct printk_record r; |
|---|
| 3478 | 3417 | unsigned long flags; |
|---|
| 3479 | 3418 | u64 seq; |
|---|
| 3480 | | - u32 idx; |
|---|
| 3481 | 3419 | u64 next_seq; |
|---|
| 3482 | | - u32 next_idx; |
|---|
| 3483 | 3420 | size_t l = 0; |
|---|
| 3484 | 3421 | bool ret = false; |
|---|
| 3422 | + bool time = printk_time; |
|---|
| 3485 | 3423 | |
|---|
| 3486 | | - if (!dumper->active) |
|---|
| 3424 | + prb_rec_init_rd(&r, &info, buf, size); |
|---|
| 3425 | + |
|---|
| 3426 | + if (!dumper->active || !buf || !size) |
|---|
| 3487 | 3427 | goto out; |
|---|
| 3488 | 3428 | |
|---|
| 3489 | 3429 | logbuf_lock_irqsave(flags); |
|---|
| 3490 | | - if (dumper->cur_seq < log_first_seq) { |
|---|
| 3491 | | - /* messages are gone, move to first available one */ |
|---|
| 3492 | | - dumper->cur_seq = log_first_seq; |
|---|
| 3493 | | - dumper->cur_idx = log_first_idx; |
|---|
| 3430 | + if (prb_read_valid_info(prb, dumper->cur_seq, &info, NULL)) { |
|---|
| 3431 | + if (info.seq != dumper->cur_seq) { |
|---|
| 3432 | + /* messages are gone, move to first available one */ |
|---|
| 3433 | + dumper->cur_seq = info.seq; |
|---|
| 3434 | + } |
|---|
| 3494 | 3435 | } |
|---|
| 3495 | 3436 | |
|---|
| 3496 | 3437 | /* last entry */ |
|---|
| .. | .. |
|---|
| 3501 | 3442 | |
|---|
| 3502 | 3443 | /* calculate length of entire buffer */ |
|---|
| 3503 | 3444 | seq = dumper->cur_seq; |
|---|
| 3504 | | - idx = dumper->cur_idx; |
|---|
| 3505 | | - while (seq < dumper->next_seq) { |
|---|
| 3506 | | - struct printk_log *msg = log_from_idx(idx); |
|---|
| 3507 | | - |
|---|
| 3508 | | - l += msg_print_text(msg, true, NULL, 0); |
|---|
| 3509 | | - idx = log_next(idx); |
|---|
| 3510 | | - seq++; |
|---|
| 3445 | + while (prb_read_valid_info(prb, seq, &info, &line_count)) { |
|---|
| 3446 | + if (r.info->seq >= dumper->next_seq) |
|---|
| 3447 | + break; |
|---|
| 3448 | + l += get_record_print_text_size(&info, line_count, syslog, time); |
|---|
| 3449 | + seq = r.info->seq + 1; |
|---|
| 3511 | 3450 | } |
|---|
| 3512 | 3451 | |
|---|
| 3513 | 3452 | /* move first record forward until length fits into the buffer */ |
|---|
| 3514 | 3453 | seq = dumper->cur_seq; |
|---|
| 3515 | | - idx = dumper->cur_idx; |
|---|
| 3516 | | - while (l >= size && seq < dumper->next_seq) { |
|---|
| 3517 | | - struct printk_log *msg = log_from_idx(idx); |
|---|
| 3518 | | - |
|---|
| 3519 | | - l -= msg_print_text(msg, true, NULL, 0); |
|---|
| 3520 | | - idx = log_next(idx); |
|---|
| 3521 | | - seq++; |
|---|
| 3454 | + while (l >= size && prb_read_valid_info(prb, seq, |
|---|
| 3455 | + &info, &line_count)) { |
|---|
| 3456 | + if (r.info->seq >= dumper->next_seq) |
|---|
| 3457 | + break; |
|---|
| 3458 | + l -= get_record_print_text_size(&info, line_count, syslog, time); |
|---|
| 3459 | + seq = r.info->seq + 1; |
|---|
| 3522 | 3460 | } |
|---|
| 3523 | 3461 | |
|---|
| 3524 | 3462 | /* last message in next interation */ |
|---|
| 3525 | 3463 | next_seq = seq; |
|---|
| 3526 | | - next_idx = idx; |
|---|
| 3527 | 3464 | |
|---|
| 3465 | + /* actually read text into the buffer now */ |
|---|
| 3528 | 3466 | l = 0; |
|---|
| 3529 | | - while (seq < dumper->next_seq) { |
|---|
| 3530 | | - struct printk_log *msg = log_from_idx(idx); |
|---|
| 3467 | + while (prb_read_valid(prb, seq, &r)) { |
|---|
| 3468 | + if (r.info->seq >= dumper->next_seq) |
|---|
| 3469 | + break; |
|---|
| 3531 | 3470 | |
|---|
| 3532 | | - l += msg_print_text(msg, syslog, buf + l, size - l); |
|---|
| 3533 | | - idx = log_next(idx); |
|---|
| 3534 | | - seq++; |
|---|
| 3471 | + l += record_print_text(&r, syslog, time); |
|---|
| 3472 | + |
|---|
| 3473 | + /* adjust record to store to remaining buffer space */ |
|---|
| 3474 | + prb_rec_init_rd(&r, &info, buf + l, size - l); |
|---|
| 3475 | + |
|---|
| 3476 | + seq = r.info->seq + 1; |
|---|
| 3535 | 3477 | } |
|---|
| 3536 | 3478 | |
|---|
| 3537 | 3479 | dumper->next_seq = next_seq; |
|---|
| 3538 | | - dumper->next_idx = next_idx; |
|---|
| 3539 | 3480 | ret = true; |
|---|
| 3540 | 3481 | logbuf_unlock_irqrestore(flags); |
|---|
| 3541 | 3482 | out: |
|---|
| .. | .. |
|---|
| 3546 | 3487 | EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); |
|---|
| 3547 | 3488 | |
|---|
| 3548 | 3489 | /** |
|---|
| 3549 | | - * kmsg_dump_rewind_nolock - reset the interator (unlocked version) |
|---|
| 3490 | + * kmsg_dump_rewind_nolock - reset the iterator (unlocked version) |
|---|
| 3550 | 3491 | * @dumper: registered kmsg dumper |
|---|
| 3551 | 3492 | * |
|---|
| 3552 | 3493 | * Reset the dumper's iterator so that kmsg_dump_get_line() and |
|---|
| .. | .. |
|---|
| 3558 | 3499 | void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper) |
|---|
| 3559 | 3500 | { |
|---|
| 3560 | 3501 | dumper->cur_seq = clear_seq; |
|---|
| 3561 | | - dumper->cur_idx = clear_idx; |
|---|
| 3562 | | - dumper->next_seq = log_next_seq; |
|---|
| 3563 | | - dumper->next_idx = log_next_idx; |
|---|
| 3502 | + dumper->next_seq = prb_next_seq(prb); |
|---|
| 3564 | 3503 | } |
|---|
| 3565 | 3504 | |
|---|
| 3566 | 3505 | /** |
|---|
| 3567 | | - * kmsg_dump_rewind - reset the interator |
|---|
| 3506 | + * kmsg_dump_rewind - reset the iterator |
|---|
| 3568 | 3507 | * @dumper: registered kmsg dumper |
|---|
| 3569 | 3508 | * |
|---|
| 3570 | 3509 | * Reset the dumper's iterator so that kmsg_dump_get_line() and |
|---|