2830eec14a
Code for performing the console output is intermixed with code that is formatting the output for that console. Introduce a new helper function printk_get_next_message() to handle the reading and formatting of the printk text. The helper does not require any locking so that in the future it can be used for other printing contexts as well. This also introduces a new struct printk_message to wrap the struct printk_buffers, adding metadata about its contents. This allows users of printk_get_next_message() to receive all relevant information about the message that was read and formatted. Why is struct printk_message a wrapper struct? It is intentional that a wrapper struct is introduced instead of adding the metadata directly to struct printk_buffers. The upcoming atomic consoles support multiple printing contexts per CPU. This means that while a CPU is formatting a message, it can be interrupted and the interrupting context may also format a (possibly different) message. Since the printk buffers are rather large, there will only be one struct printk_buffers per CPU and it must be shared by the possible contexts of that CPU. If the metadata was part of struct printk_buffers, interrupting contexts would clobber the metadata being prepared by the interrupted context. This could be handled by robustifying the message formatting functions to cope with metadata unexpectedly changing. However, this would require significant amounts of extra data copying, also adding significant complexity to the code. Instead, the metadata can live on the stack of the formatting context and the message formatting functions do not need to be concerned about the metadata changing underneath them. Note that the message formatting functions can handle unexpected text buffer changes. So it is perfectly OK if a shared text buffer is clobbered by an interrupting context. The atomic console implementation will recognize the interruption and avoid printing the (probably garbage) text buffer. Signed-off-by: John Ogness <john.ogness@linutronix.de> Reviewed-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Petr Mladek <pmladek@suse.com> Link: https://lore.kernel.org/r/20230109100800.1085541-6-john.ogness@linutronix.de
111 lines
3.1 KiB
C
111 lines
3.1 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* internal.h - printk internal definitions
|
|
*/
|
|
#include <linux/percpu.h>
|
|
|
|
#if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL)
|
|
void __init printk_sysctl_init(void);
|
|
int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write,
|
|
void *buffer, size_t *lenp, loff_t *ppos);
|
|
#else
|
|
#define printk_sysctl_init() do { } while (0)
|
|
#endif
|
|
|
|
#ifdef CONFIG_PRINTK
|
|
|
|
#ifdef CONFIG_PRINTK_CALLER
|
|
#define PREFIX_MAX 48
|
|
#else
|
|
#define PREFIX_MAX 32
|
|
#endif
|
|
|
|
/* the maximum size of a formatted record (i.e. with prefix added per line) */
|
|
#define CONSOLE_LOG_MAX 1024
|
|
|
|
/* the maximum size of a formatted extended record */
|
|
#define CONSOLE_EXT_LOG_MAX 8192
|
|
|
|
/* the maximum size for a dropped text message */
|
|
#define DROPPED_TEXT_MAX 64
|
|
|
|
/* the maximum size allowed to be reserved for a record */
|
|
#define LOG_LINE_MAX (CONSOLE_LOG_MAX - PREFIX_MAX)
|
|
|
|
/* Flags for a single printk record. */
|
|
enum printk_info_flags {
|
|
LOG_NEWLINE = 2, /* text ended with a newline */
|
|
LOG_CONT = 8, /* text is a fragment of a continuation line */
|
|
};
|
|
|
|
__printf(4, 0)
|
|
int vprintk_store(int facility, int level,
|
|
const struct dev_printk_info *dev_info,
|
|
const char *fmt, va_list args);
|
|
|
|
__printf(1, 0) int vprintk_default(const char *fmt, va_list args);
|
|
__printf(1, 0) int vprintk_deferred(const char *fmt, va_list args);
|
|
|
|
bool printk_percpu_data_ready(void);
|
|
|
|
#define printk_safe_enter_irqsave(flags) \
|
|
do { \
|
|
local_irq_save(flags); \
|
|
__printk_safe_enter(); \
|
|
} while (0)
|
|
|
|
#define printk_safe_exit_irqrestore(flags) \
|
|
do { \
|
|
__printk_safe_exit(); \
|
|
local_irq_restore(flags); \
|
|
} while (0)
|
|
|
|
void defer_console_output(void);
|
|
|
|
u16 printk_parse_prefix(const char *text, int *level,
|
|
enum printk_info_flags *flags);
|
|
#else
|
|
|
|
#define PREFIX_MAX 0
|
|
#define CONSOLE_LOG_MAX 0
|
|
#define CONSOLE_EXT_LOG_MAX 0
|
|
#define DROPPED_TEXT_MAX 0
|
|
#define LOG_LINE_MAX 0
|
|
|
|
/*
|
|
* In !PRINTK builds we still export console_sem
|
|
* semaphore and some of console functions (console_unlock()/etc.), so
|
|
* printk-safe must preserve the existing local IRQ guarantees.
|
|
*/
|
|
#define printk_safe_enter_irqsave(flags) local_irq_save(flags)
|
|
#define printk_safe_exit_irqrestore(flags) local_irq_restore(flags)
|
|
|
|
static inline bool printk_percpu_data_ready(void) { return false; }
|
|
#endif /* CONFIG_PRINTK */
|
|
|
|
/**
|
|
* struct printk_buffers - Buffers to read/format/output printk messages.
|
|
* @outbuf: After formatting, contains text to output.
|
|
* @scratchbuf: Used as temporary ringbuffer reading and string-print space.
|
|
*/
|
|
struct printk_buffers {
|
|
char outbuf[CONSOLE_EXT_LOG_MAX];
|
|
char scratchbuf[LOG_LINE_MAX];
|
|
};
|
|
|
|
/**
|
|
* struct printk_message - Container for a prepared printk message.
|
|
* @pbufs: printk buffers used to prepare the message.
|
|
* @outbuf_len: The length of prepared text in @pbufs->outbuf to output. This
|
|
* does not count the terminator. A value of 0 means there is
|
|
* nothing to output and this record should be skipped.
|
|
* @seq: The sequence number of the record used for @pbufs->outbuf.
|
|
* @dropped: The number of dropped records from reading @seq.
|
|
*/
|
|
struct printk_message {
|
|
struct printk_buffers *pbufs;
|
|
unsigned int outbuf_len;
|
|
u64 seq;
|
|
unsigned long dropped;
|
|
};
|