Commit 392143c9 authored by Petr Mladek's avatar Petr Mladek
Browse files

Merge branch 'rework/buffers-cleanup' into for-linus

parents 0c2baf65 d551afc2
Loading
Loading
Loading
Loading
+73 −27
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#define _LINUX_CONSOLE_H_ 1

#include <linux/atomic.h>
#include <linux/bits.h>
#include <linux/rculist.h>
#include <linux/types.h>

@@ -125,28 +126,73 @@ static inline int con_debug_leave(void)
/*
 * The interface for a console, or any other device that wants to capture
 * console messages (printer driver?)
 *
 * If a console driver is marked CON_BOOT then it will be auto-unregistered
 * when the first real console is registered.  This is for early-printk drivers.
 */

#define CON_PRINTBUFFER	(1)
#define CON_CONSDEV	(2) /* Preferred console, /dev/console */
#define CON_ENABLED	(4)
#define CON_BOOT	(8)
#define CON_ANYTIME	(16) /* Safe to call when cpu is offline */
#define CON_BRL		(32) /* Used for a braille device */
#define CON_EXTENDED	(64) /* Use the extended output format a la /dev/kmsg */
/**
 * cons_flags - General console flags
 * @CON_PRINTBUFFER:	Used by newly registered consoles to avoid duplicate
 *			output of messages that were already shown by boot
 *			consoles or read by userspace via syslog() syscall.
 * @CON_CONSDEV:	Indicates that the console driver is backing
 *			/dev/console.
 * @CON_ENABLED:	Indicates if a console is allowed to print records. If
 *			false, the console also will not advance to later
 *			records.
 * @CON_BOOT:		Marks the console driver as early console driver which
 *			is used during boot before the real driver becomes
 *			available. It will be automatically unregistered
 *			when the real console driver is registered unless
 *			"keep_bootcon" parameter is used.
 * @CON_ANYTIME:	A misnomed historical flag which tells the core code
 *			that the legacy @console::write callback can be invoked
 *			on a CPU which is marked OFFLINE. That is misleading as
 *			it suggests that there is no contextual limit for
 *			invoking the callback. The original motivation was
 *			readiness of the per-CPU areas.
 * @CON_BRL:		Indicates a braille device which is exempt from
 *			receiving the printk spam for obvious reasons.
 * @CON_EXTENDED:	The console supports the extended output format of
 *			/dev/kmesg which requires a larger output buffer.
 */
enum cons_flags {
	CON_PRINTBUFFER		= BIT(0),
	CON_CONSDEV		= BIT(1),
	CON_ENABLED		= BIT(2),
	CON_BOOT		= BIT(3),
	CON_ANYTIME		= BIT(4),
	CON_BRL			= BIT(5),
	CON_EXTENDED		= BIT(6),
};

/**
 * struct console - The console descriptor structure
 * @name:		The name of the console driver
 * @write:		Write callback to output messages (Optional)
 * @read:		Read callback for console input (Optional)
 * @device:		The underlying TTY device driver (Optional)
 * @unblank:		Callback to unblank the console (Optional)
 * @setup:		Callback for initializing the console (Optional)
 * @exit:		Callback for teardown of the console (Optional)
 * @match:		Callback for matching a console (Optional)
 * @flags:		Console flags. See enum cons_flags
 * @index:		Console index, e.g. port number
 * @cflag:		TTY control mode flags
 * @ispeed:		TTY input speed
 * @ospeed:		TTY output speed
 * @seq:		Sequence number of the next ringbuffer record to print
 * @dropped:		Number of unreported dropped ringbuffer records
 * @data:		Driver private data
 * @node:		hlist node for the console list
 */
struct console {
	char			name[16];
	void	(*write)(struct console *, const char *, unsigned);
	int	(*read)(struct console *, char *, unsigned);
	struct tty_driver *(*device)(struct console *, int *);
	void			(*write)(struct console *co, const char *s, unsigned int count);
	int			(*read)(struct console *co, char *s, unsigned int count);
	struct tty_driver	*(*device)(struct console *co, int *index);
	void			(*unblank)(void);
	int	(*setup)(struct console *, char *);
	int	(*exit)(struct console *);
	int	(*match)(struct console *, char *name, int idx, char *options);
	int			(*setup)(struct console *co, char *options);
	int			(*exit)(struct console *co);
	int			(*match)(struct console *co, char *name, int idx, char *options);
	short			flags;
	short			index;
	int			cflag;
+0 −2
Original line number Diff line number Diff line
@@ -44,8 +44,6 @@ static inline const char *printk_skip_headers(const char *buffer)
	return buffer;
}

#define CONSOLE_EXT_LOG_MAX	8192

/* printk's without a loglevel use this.. */
#define MESSAGE_LOGLEVEL_DEFAULT CONFIG_MESSAGE_LOGLEVEL_DEFAULT

+45 −0
Original line number Diff line number Diff line
@@ -14,6 +14,21 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write,

#ifdef CONFIG_PRINTK

#ifdef CONFIG_PRINTK_CALLER
#define PRINTK_PREFIX_MAX	48
#else
#define PRINTK_PREFIX_MAX	32
#endif

/*
 * the maximum size of a formatted record (i.e. with prefix added
 * per line and dropped messages or in extended message format)
 */
#define PRINTK_MESSAGE_MAX	2048

/* the maximum size allowed to be reserved for a record */
#define PRINTKRB_RECORD_MAX	1024

/* Flags for a single printk record. */
enum printk_info_flags {
	LOG_NEWLINE	= 2,	/* text ended with a newline */
@@ -48,6 +63,10 @@ u16 printk_parse_prefix(const char *text, int *level,
			enum printk_info_flags *flags);
#else

#define PRINTK_PREFIX_MAX	0
#define PRINTK_MESSAGE_MAX	0
#define PRINTKRB_RECORD_MAX	0

/*
 * In !PRINTK builds we still export console_sem
 * semaphore and some of console functions (console_unlock()/etc.), so
@@ -58,3 +77,29 @@ u16 printk_parse_prefix(const char *text, int *level,

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[PRINTK_MESSAGE_MAX];
	char	scratchbuf[PRINTKRB_RECORD_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;
};
+179 −129
Original line number Diff line number Diff line
@@ -465,21 +465,6 @@ static struct latched_seq clear_seq = {
	.val[1]		= 0,
};

#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 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)

#define LOG_LEVEL(v)		((v) & 0x07)
#define LOG_FACILITY(v)		((v) >> 3 & 0xff)

@@ -710,16 +695,15 @@ static ssize_t msg_print_ext_body(char *buf, size_t size,
	return len;
}

static bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
				    bool is_extended, bool may_supress);

/* /dev/kmsg - userspace message inject/listen interface */
struct devkmsg_user {
	atomic64_t seq;
	struct ratelimit_state rs;
	struct mutex lock;
	char buf[CONSOLE_EXT_LOG_MAX];

	struct printk_info info;
	char text_buf[CONSOLE_EXT_LOG_MAX];
	struct printk_record record;
	struct printk_buffers pbufs;
};

static __printf(3, 4) __cold
@@ -745,7 +729,7 @@ static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from)
	size_t len = iov_iter_count(from);
	ssize_t ret = len;

	if (!user || len > LOG_LINE_MAX)
	if (!user || len > PRINTKRB_RECORD_MAX)
		return -EINVAL;

	/* Ignore when user logging is disabled. */
@@ -801,8 +785,10 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
			    size_t count, loff_t *ppos)
{
	struct devkmsg_user *user = file->private_data;
	struct printk_record *r = &user->record;
	size_t len;
	char *outbuf = &user->pbufs.outbuf[0];
	struct printk_message pmsg = {
		.pbufs = &user->pbufs,
	};
	ssize_t ret;

	if (!user)
@@ -812,7 +798,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
	if (ret)
		return ret;

	if (!prb_read_valid(prb, atomic64_read(&user->seq), r)) {
	if (!printk_get_next_message(&pmsg, atomic64_read(&user->seq), true, false)) {
		if (file->f_flags & O_NONBLOCK) {
			ret = -EAGAIN;
			goto out;
@@ -829,36 +815,31 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
		 * This pairs with __wake_up_klogd:A.
		 */
		ret = wait_event_interruptible(log_wait,
				prb_read_valid(prb,
					atomic64_read(&user->seq), r)); /* LMM(devkmsg_read:A) */
				printk_get_next_message(&pmsg, atomic64_read(&user->seq), true,
							false)); /* LMM(devkmsg_read:A) */
		if (ret)
			goto out;
	}

	if (r->info->seq != atomic64_read(&user->seq)) {
	if (pmsg.dropped) {
		/* our last seen message is gone, return error and reset */
		atomic64_set(&user->seq, r->info->seq);
		atomic64_set(&user->seq, pmsg.seq);
		ret = -EPIPE;
		goto out;
	}

	len = info_print_ext_header(user->buf, sizeof(user->buf), r->info);
	len += msg_print_ext_body(user->buf + len, sizeof(user->buf) - len,
				  &r->text_buf[0], r->info->text_len,
				  &r->info->dev_info);

	atomic64_set(&user->seq, r->info->seq + 1);
	atomic64_set(&user->seq, pmsg.seq + 1);

	if (len > count) {
	if (pmsg.outbuf_len > count) {
		ret = -EINVAL;
		goto out;
	}

	if (copy_to_user(buf, user->buf, len)) {
	if (copy_to_user(buf, outbuf, pmsg.outbuf_len)) {
		ret = -EFAULT;
		goto out;
	}
	ret = len;
	ret = pmsg.outbuf_len;
out:
	mutex_unlock(&user->lock);
	return ret;
@@ -952,9 +933,6 @@ static int devkmsg_open(struct inode *inode, struct file *file)

	mutex_init(&user->lock);

	prb_rec_init_rd(&user->record, &user->info,
			&user->text_buf[0], sizeof(user->text_buf));

	atomic64_set(&user->seq, prb_first_valid_seq(prb));

	file->private_data = user;
@@ -1149,7 +1127,7 @@ static unsigned int __init add_to_rb(struct printk_ringbuffer *rb,
	return prb_record_text_space(&e);
}

static char setup_text_buf[LOG_LINE_MAX] __initdata;
static char setup_text_buf[PRINTKRB_RECORD_MAX] __initdata;

void __init setup_log_buf(int early)
{
@@ -1415,7 +1393,7 @@ static size_t record_print_text(struct printk_record *r, bool syslog,
	size_t text_len = r->info->text_len;
	size_t buf_size = r->text_buf_size;
	char *text = r->text_buf;
	char prefix[PREFIX_MAX];
	char prefix[PRINTK_PREFIX_MAX];
	bool truncated = false;
	size_t prefix_len;
	size_t line_len;
@@ -1514,7 +1492,7 @@ static size_t get_record_print_text_size(struct printk_info *info,
					 unsigned int line_count,
					 bool syslog, bool time)
{
	char prefix[PREFIX_MAX];
	char prefix[PRINTK_PREFIX_MAX];
	size_t prefix_len;

	prefix_len = info_print_prefix(info, syslog, time, prefix);
@@ -1580,11 +1558,11 @@ static int syslog_print(char __user *buf, int size)
	int len = 0;
	u64 seq;

	text = kmalloc(CONSOLE_LOG_MAX, GFP_KERNEL);
	text = kmalloc(PRINTK_MESSAGE_MAX, GFP_KERNEL);
	if (!text)
		return -ENOMEM;

	prb_rec_init_rd(&r, &info, text, CONSOLE_LOG_MAX);
	prb_rec_init_rd(&r, &info, text, PRINTK_MESSAGE_MAX);

	mutex_lock(&syslog_lock);

@@ -1685,7 +1663,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
	u64 seq;
	bool time;

	text = kmalloc(CONSOLE_LOG_MAX, GFP_KERNEL);
	text = kmalloc(PRINTK_MESSAGE_MAX, GFP_KERNEL);
	if (!text)
		return -ENOMEM;

@@ -1697,7 +1675,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
	seq = find_first_fitting_seq(latched_seq_read_nolock(&clear_seq), -1,
				     size, true, time);

	prb_rec_init_rd(&r, &info, text, CONSOLE_LOG_MAX);
	prb_rec_init_rd(&r, &info, text, PRINTK_MESSAGE_MAX);

	len = 0;
	prb_for_each_record(seq, prb, seq, &r) {
@@ -2010,27 +1988,6 @@ static int console_trylock_spinning(void)
	return 1;
}

/*
 * Call the specified console driver, asking it to write out the specified
 * text and length. If @dropped_text is non-NULL and any records have been
 * dropped, a dropped message will be written out first.
 */
static void call_console_driver(struct console *con, const char *text, size_t len,
				char *dropped_text)
{
	size_t dropped_len;

	if (con->dropped && dropped_text) {
		dropped_len = snprintf(dropped_text, DROPPED_TEXT_MAX,
				       "** %lu printk messages dropped **\n",
				       con->dropped);
		con->dropped = 0;
		con->write(con, dropped_text, dropped_len);
	}

	con->write(con, text, len);
}

/*
 * Recursion is tracked separately on each CPU. If NMIs are supported, an
 * additional NMI context per CPU is also separately tracked. Until per-CPU
@@ -2241,8 +2198,8 @@ int vprintk_store(int facility, int level,
	reserve_size = vsnprintf(&prefix_buf[0], sizeof(prefix_buf), fmt, args2) + 1;
	va_end(args2);

	if (reserve_size > LOG_LINE_MAX)
		reserve_size = LOG_LINE_MAX;
	if (reserve_size > PRINTKRB_RECORD_MAX)
		reserve_size = PRINTKRB_RECORD_MAX;

	/* Extract log level or control flags. */
	if (facility == 0)
@@ -2256,7 +2213,7 @@ int vprintk_store(int facility, int level,

	if (flags & LOG_CONT) {
		prb_rec_init_wr(&r, reserve_size);
		if (prb_reserve_in_last(&e, prb, &r, caller_id, LOG_LINE_MAX)) {
		if (prb_reserve_in_last(&e, prb, &r, caller_id, PRINTKRB_RECORD_MAX)) {
			text_len = printk_sprint(&r.text_buf[r.info->text_len], reserve_size,
						 facility, &flags, fmt, args);
			r.info->text_len += text_len;
@@ -2387,8 +2344,6 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre

#else /* CONFIG_PRINTK */

#define CONSOLE_LOG_MAX		0
#define DROPPED_TEXT_MAX	0
#define printk_time		false

#define prb_read_valid(rb, seq, r)	false
@@ -2412,10 +2367,6 @@ static ssize_t msg_print_ext_body(char *buf, size_t size,
				  struct dev_printk_info *dev_info) { return 0; }
static void console_lock_spinning_enable(void) { }
static int console_lock_spinning_disable_and_check(int cookie) { return 0; }
static void call_console_driver(struct console *con, const char *text, size_t len,
				char *dropped_text)
{
}
static bool suppress_message_printing(int level) { return false; }
static bool pr_flush(int timeout_ms, bool reset_on_progress) { return true; }
static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress) { return true; }
@@ -2742,16 +2693,136 @@ static void __console_unlock(void)
}

/*
 * Print one record for the given console. The record printed is whatever
 * record is the next available record for the given console.
 * Prepend the message in @pmsg->pbufs->outbuf with a "dropped message". This
 * is achieved by shifting the existing message over and inserting the dropped
 * message.
 *
 * @text is a buffer of size CONSOLE_LOG_MAX.
 * @pmsg is the printk message to prepend.
 *
 * If extended messages should be printed, @ext_text is a buffer of size
 * CONSOLE_EXT_LOG_MAX. Otherwise @ext_text must be NULL.
 * @dropped is the dropped count to report in the dropped message.
 *
 * If the message text in @pmsg->pbufs->outbuf does not have enough space for
 * the dropped message, the message text will be sufficiently truncated.
 *
 * If @pmsg->pbufs->outbuf is modified, @pmsg->outbuf_len is updated.
 */
#ifdef CONFIG_PRINTK
static void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped)
{
	struct printk_buffers *pbufs = pmsg->pbufs;
	const size_t scratchbuf_sz = sizeof(pbufs->scratchbuf);
	const size_t outbuf_sz = sizeof(pbufs->outbuf);
	char *scratchbuf = &pbufs->scratchbuf[0];
	char *outbuf = &pbufs->outbuf[0];
	size_t len;

	len = scnprintf(scratchbuf, scratchbuf_sz,
		       "** %lu printk messages dropped **\n", dropped);

	/*
	 * Make sure outbuf is sufficiently large before prepending.
	 * Keep at least the prefix when the message must be truncated.
	 * It is a rather theoretical problem when someone tries to
	 * use a minimalist buffer.
	 */
	if (WARN_ON_ONCE(len + PRINTK_PREFIX_MAX >= outbuf_sz))
		return;

	if (pmsg->outbuf_len + len >= outbuf_sz) {
		/* Truncate the message, but keep it terminated. */
		pmsg->outbuf_len = outbuf_sz - (len + 1);
		outbuf[pmsg->outbuf_len] = 0;
	}

	memmove(outbuf + len, outbuf, pmsg->outbuf_len + 1);
	memcpy(outbuf, scratchbuf, len);
	pmsg->outbuf_len += len;
}
#else
#define console_prepend_dropped(pmsg, dropped)
#endif /* CONFIG_PRINTK */

/*
 * Read and format the specified record (or a later record if the specified
 * record is not available).
 *
 * @pmsg will contain the formatted result. @pmsg->pbufs must point to a
 * struct printk_buffers.
 *
 * @seq is the record to read and format. If it is not available, the next
 * valid record is read.
 *
 * @is_extended specifies if the message should be formatted for extended
 * console output.
 *
 * @may_supress specifies if records may be skipped based on loglevel.
 *
 * Returns false if no record is available. Otherwise true and all fields
 * of @pmsg are valid. (See the documentation of struct printk_message
 * for information about the @pmsg fields.)
 */
static bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
				    bool is_extended, bool may_suppress)
{
	static int panic_console_dropped;

	struct printk_buffers *pbufs = pmsg->pbufs;
	const size_t scratchbuf_sz = sizeof(pbufs->scratchbuf);
	const size_t outbuf_sz = sizeof(pbufs->outbuf);
	char *scratchbuf = &pbufs->scratchbuf[0];
	char *outbuf = &pbufs->outbuf[0];
	struct printk_info info;
	struct printk_record r;
	size_t len = 0;

	/*
	 * Formatting extended messages requires a separate buffer, so use the
	 * scratch buffer to read in the ringbuffer text.
	 *
 * If dropped messages should be printed, @dropped_text is a buffer of size
 * DROPPED_TEXT_MAX. Otherwise @dropped_text must be NULL.
	 * Formatting normal messages is done in-place, so read the ringbuffer
	 * text directly into the output buffer.
	 */
	if (is_extended)
		prb_rec_init_rd(&r, &info, scratchbuf, scratchbuf_sz);
	else
		prb_rec_init_rd(&r, &info, outbuf, outbuf_sz);

	if (!prb_read_valid(prb, seq, &r))
		return false;

	pmsg->seq = r.info->seq;
	pmsg->dropped = r.info->seq - seq;

	/*
	 * Check for dropped messages in panic here so that printk
	 * suppression can occur as early as possible if necessary.
	 */
	if (pmsg->dropped &&
	    panic_in_progress() &&
	    panic_console_dropped++ > 10) {
		suppress_panic_printk = 1;
		pr_warn_once("Too many dropped messages. Suppress messages on non-panic CPUs to prevent livelock.\n");
	}

	/* Skip record that has level above the console loglevel. */
	if (may_suppress && suppress_message_printing(r.info->level))
		goto out;

	if (is_extended) {
		len = info_print_ext_header(outbuf, outbuf_sz, r.info);
		len += msg_print_ext_body(outbuf + len, outbuf_sz - len,
					  &r.text_buf[0], r.info->text_len, &r.info->dev_info);
	} else {
		len = record_print_text(&r, console_msg_format & MSG_FORMAT_SYSLOG, printk_time);
	}
out:
	pmsg->outbuf_len = len;
	return true;
}

/*
 * Print one record for the given console. The record printed is whatever
 * record is the next available record for the given console.
 *
 * @handover will be set to true if a printk waiter has taken over the
 * console_lock, in which case the caller is no longer holding both the
@@ -2764,46 +2835,33 @@ static void __console_unlock(void)
 *
 * Requires the console_lock and the SRCU read lock.
 */
static bool console_emit_next_record(struct console *con, char *text, char *ext_text,
				     char *dropped_text, bool *handover, int cookie)
static bool console_emit_next_record(struct console *con, bool *handover, int cookie)
{
	static int panic_console_dropped;
	struct printk_info info;
	struct printk_record r;
	unsigned long flags;
	char *write_text;
	size_t len;
	static struct printk_buffers pbufs;

	prb_rec_init_rd(&r, &info, text, CONSOLE_LOG_MAX);
	bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
	char *outbuf = &pbufs.outbuf[0];
	struct printk_message pmsg = {
		.pbufs = &pbufs,
	};
	unsigned long flags;

	*handover = false;

	if (!prb_read_valid(prb, con->seq, &r))
	if (!printk_get_next_message(&pmsg, con->seq, is_extended, true))
		return false;

	if (con->seq != r.info->seq) {
		con->dropped += r.info->seq - con->seq;
		con->seq = r.info->seq;
		if (panic_in_progress() && panic_console_dropped++ > 10) {
			suppress_panic_printk = 1;
			pr_warn_once("Too many dropped messages. Suppress messages on non-panic CPUs to prevent livelock.\n");
		}
	}
	con->dropped += pmsg.dropped;

	/* Skip record that has level above the console loglevel. */
	if (suppress_message_printing(r.info->level)) {
		con->seq++;
	/* Skip messages of formatted length 0. */
	if (pmsg.outbuf_len == 0) {
		con->seq = pmsg.seq + 1;
		goto skip;
	}

	if (ext_text) {
		write_text = ext_text;
		len = info_print_ext_header(ext_text, CONSOLE_EXT_LOG_MAX, r.info);
		len += msg_print_ext_body(ext_text + len, CONSOLE_EXT_LOG_MAX - len,
					  &r.text_buf[0], r.info->text_len, &r.info->dev_info);
	} else {
		write_text = text;
		len = record_print_text(&r, console_msg_format & MSG_FORMAT_SYSLOG, printk_time);
	if (con->dropped && !is_extended) {
		console_prepend_dropped(&pmsg, con->dropped);
		con->dropped = 0;
	}

	/*
@@ -2819,11 +2877,15 @@ static bool console_emit_next_record(struct console *con, char *text, char *ext_
	printk_safe_enter_irqsave(flags);
	console_lock_spinning_enable();

	stop_critical_timings();	/* don't trace print latency */
	call_console_driver(con, write_text, len, dropped_text);
	/* Do not trace print latency. */
	stop_critical_timings();

	/* Write everything out to the hardware. */
	con->write(con, outbuf, pmsg.outbuf_len);

	start_critical_timings();

	con->seq++;
	con->seq = pmsg.seq + 1;

	*handover = console_lock_spinning_disable_and_check(cookie);
	printk_safe_exit_irqrestore(flags);
@@ -2856,9 +2918,6 @@ static bool console_emit_next_record(struct console *con, char *text, char *ext_
 */
static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handover)
{
	static char dropped_text[DROPPED_TEXT_MAX];
	static char ext_text[CONSOLE_EXT_LOG_MAX];
	static char text[CONSOLE_LOG_MAX];
	bool any_usable = false;
	struct console *con;
	bool any_progress;
@@ -2878,16 +2937,7 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
				continue;
			any_usable = true;

			if (console_srcu_read_flags(con) & CON_EXTENDED) {
				/* Extended consoles do not print "dropped messages". */
				progress = console_emit_next_record(con, &text[0],
								    &ext_text[0], NULL,
								    handover, cookie);
			} else {
				progress = console_emit_next_record(con, &text[0],
								    NULL, &dropped_text[0],
								    handover, cookie);
			}
			progress = console_emit_next_record(con, handover, cookie);

			/*
			 * If a handover has occurred, the SRCU read lock