[printk,v3,5/6] printk: introduce console_get_next_message() and console_message

Message ID 20221221202704.857925-6-john.ogness@linutronix.de
State New
Headers
Series printk: cleanup buffer handling |

Commit Message

John Ogness Dec. 21, 2022, 8:27 p.m. UTC
  Code for performing the console output is intermixed with code
that is formatting the output for that console. Introduce a new
helper function console_get_next_message() to handle the reading
and formatting of the console text. The helper does not require
any locking so that in the future it can be used for other console
printing contexts as well.

This also introduces a new struct console_message to wrap the
struct console_buffers adding meta-data about its contents. This
allows users of console_get_next_message() to receive all relevant
information about the message that was read and formatted.

The reason a wrapper struct is introduced instead of adding the
meta-data to struct console_buffers is because the upcoming atomic
consoles will need per-cpu and per-context console_buffers. It
would not make sense to make the meta-data also per-cpu and
per-context as that data can be easily stored on the stack of the
console printing context.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
 kernel/printk/internal.h |  16 ++++++
 kernel/printk/printk.c   | 118 +++++++++++++++++++++++++++------------
 2 files changed, 97 insertions(+), 37 deletions(-)
  

Comments

John Ogness Dec. 22, 2022, 3:41 p.m. UTC | #1
On 2022-12-21, John Ogness <john.ogness@linutronix.de> wrote:
> +static bool console_emit_next_record(struct console *con, bool *handover, int cookie)
> +{
> +	bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
> +	static char dropped_text[DROPPED_TEXT_MAX];
> +	static struct console_buffers cbufs;
> +	static struct console_message cmsg = {
> +		.cbufs = &cbufs,
> +	};

@cmsg should not be static. The whole point of the console_message
wrapper struct is so that it can sit on the stack.

John Ogness
  
Petr Mladek Jan. 2, 2023, 3:52 p.m. UTC | #2
On Wed 2022-12-21 21:33:03, John Ogness wrote:
> Code for performing the console output is intermixed with code
> that is formatting the output for that console. Introduce a new
> helper function console_get_next_message() to handle the reading
> and formatting of the console text. The helper does not require
> any locking so that in the future it can be used for other console
> printing contexts as well.
> 
> This also introduces a new struct console_message to wrap the
> struct console_buffers adding meta-data about its contents. This
> allows users of console_get_next_message() to receive all relevant
> information about the message that was read and formatted.
> 
> The reason a wrapper struct is introduced instead of adding the
> meta-data to struct console_buffers is because the upcoming atomic
> consoles will need per-cpu and per-context console_buffers. It
> would not make sense to make the meta-data also per-cpu and
> per-context as that data can be easily stored on the stack of the
> console printing context.
> 
> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index 2e5e2eda1fa1..7cac636600f8 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -2725,34 +2725,34 @@ 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.
> + * Read and format the specified record (or a later record if the specified
> + * record is not available).
>   *
> - * @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
> - * console_lock and the SRCU read lock. Otherwise it is set to false.
> + * @cmsg will contain the formatted result. @cmsg->cbufs must point to a
> + * struct console_buffers.
>   *
> - * @cookie is the cookie from the SRCU read lock.
> + * @seq is the record to read and format. If it is not available, the next
> + * valid record is read.
>   *
> - * Returns false if the given console has no next record to print, otherwise
> - * true.
> + * @is_extended specifies the message should be formatted for extended
> + * console output.
>   *
> - * Requires the console_lock and the SRCU read lock.
> + * Returns false if no record is available. Otherwise true and all fields
> + * of @cmsg are valid. (See the documentation of struct console_message
> + * for information about the @cmsg fields.)
>   */
> -static bool console_emit_next_record(struct console *con, bool *handover, int cookie)
> -{
> -	bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
> -	static char dropped_text[DROPPED_TEXT_MAX];
> -	static struct console_buffers cbufs;
> -	const size_t scratchbuf_sz = sizeof(cbufs.scratchbuf);
> -	const size_t outbuf_sz = sizeof(cbufs.outbuf);
> -	char *scratchbuf = &cbufs.scratchbuf[0];
> -	char *outbuf = &cbufs.outbuf[0];
> +static bool console_get_next_message(struct console_message *cmsg, u64 seq,
> +				     bool is_extended)
> +{
> +	struct console_buffers *cbufs = cmsg->cbufs;
> +	const size_t scratchbuf_sz = sizeof(cbufs->scratchbuf);
> +	const size_t outbuf_sz = sizeof(cbufs->outbuf);
> +	char *scratchbuf = &cbufs->scratchbuf[0];
> +	char *outbuf = &cbufs->outbuf[0];
>  	static int panic_console_dropped;
>  	struct printk_info info;
>  	struct printk_record r;
> -	unsigned long flags;
> -	size_t len;
> +	size_t len = 0;
>  
>  	/*
>  	 * Formatting extended messages requires a separate buffer, so use the
> @@ -2766,33 +2766,77 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
>  	else
>  		prb_rec_init_rd(&r, &info, outbuf, outbuf_sz);
>  
> -	*handover = false;
> -
> -	if (!prb_read_valid(prb, con->seq, &r))
> +	if (!prb_read_valid(prb, seq, &r))
>  		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");
> -		}
> +	cmsg->outbuf_seq = r.info->seq;
> +	cmsg->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 (cmsg->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 (suppress_message_printing(r.info->level)) {
> -		con->seq++;
> -		goto skip;
> -	}
> +	if (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);
> +					  r.text_buf, r.info->text_len, &r.info->dev_info);

This probably was not intended.

If you agree then I could revert this change when pushing.
Or feel free to send respin of this patch.


>  	} else {
>  		len = record_print_text(&r, console_msg_format & MSG_FORMAT_SYSLOG, printk_time);
>  	}
> +out:
> +	cmsg->outbuf_len = len;
> +	return true;
> +}

Otherwise, it looks good:

Reviewed-by: Petr Mladek <pmladek@suse.com>

Best Regards,
Petr
  
John Ogness Jan. 3, 2023, 10:02 a.m. UTC | #3
On 2022-12-21, John Ogness <john.ogness@linutronix.de> wrote:
> +/**
> + * console_message - Container for a prepared console message.

This documentation is not included in the kerneldocs, but it should at
least be proper kerneldoc format. It should be:

 * struct console_message - Container for a prepared console message.

John
  
Petr Mladek Jan. 3, 2023, 2:04 p.m. UTC | #4
On Thu 2022-12-22 16:47:39, John Ogness wrote:
> On 2022-12-21, John Ogness <john.ogness@linutronix.de> wrote:
> > +static bool console_emit_next_record(struct console *con, bool *handover, int cookie)
> > +{
> > +	bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
> > +	static char dropped_text[DROPPED_TEXT_MAX];
> > +	static struct console_buffers cbufs;
> > +	static struct console_message cmsg = {
> > +		.cbufs = &cbufs,
> > +	};
> 
> @cmsg should not be static. The whole point of the console_message
> wrapper struct is so that it can sit on the stack.

Well, it might actually be better to keep it static for now.
It always points to static struct console_buffers cbufs anyway.

It would make sense to have it on stack only when it uses
different buffers.

Which brings the question. Does it makes sense to use
the same buffers by different struct console_message?
Will it be safe in any situation?

I did not want to complicate it yesterday. I think that
I have already proposed this. But this brings back
the question whether it makes sense to have two structures
at all.

I still think that it would be easier and even more safe
to put everything into struct console_message.

I mean to have:

struct console_message {
	char			buf[CONSOLE_EXT_LOG_MAX];
	char			scratch_buf[LOG_LINE_MAX];
	unsigned int		len;
	u64			seq;
	unsigned long		dropped;
};

Best Regards,
Petr
  
Petr Mladek Jan. 3, 2023, 2:05 p.m. UTC | #5
On Tue 2023-01-03 11:08:27, John Ogness wrote:
> On 2022-12-21, John Ogness <john.ogness@linutronix.de> wrote:
> > +/**
> > + * console_message - Container for a prepared console message.
> 
> This documentation is not included in the kerneldocs, but it should at
> least be proper kerneldoc format. It should be:
> 
>  * struct console_message - Container for a prepared console message.

Great catch!

Best Regards,
Petr
  
John Ogness Jan. 3, 2023, 2:57 p.m. UTC | #6
On 2023-01-03, Petr Mladek <pmladek@suse.com> wrote:
> On Thu 2022-12-22 16:47:39, John Ogness wrote:
>> On 2022-12-21, John Ogness <john.ogness@linutronix.de> wrote:
>> > +static bool console_emit_next_record(struct console *con, bool *handover, int cookie)
>> > +{
>> > +	bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
>> > +	static char dropped_text[DROPPED_TEXT_MAX];
>> > +	static struct console_buffers cbufs;
>> > +	static struct console_message cmsg = {
>> > +		.cbufs = &cbufs,
>> > +	};
>> 
>> @cmsg should not be static. The whole point of the console_message
>> wrapper struct is so that it can sit on the stack.
>
> Well, it might actually be better to keep it static for now.
> It always points to static struct console_buffers cbufs anyway.
>
> It would make sense to have it on stack only when it uses
> different buffers.

I think we should avoid making things static when it serves no purpose.

> Which brings the question. Does it makes sense to use
> the same buffers by different struct console_message?
> Will it be safe in any situation?
>
> I did not want to complicate it yesterday. I think that
> I have already proposed this. But this brings back
> the question whether it makes sense to have two structures
> at all.
>
> I still think that it would be easier and even more safe
> to put everything into struct console_message.
>
> I mean to have:
>
> struct console_message {
> 	char			buf[CONSOLE_EXT_LOG_MAX];
> 	char			scratch_buf[LOG_LINE_MAX];
> 	unsigned int		len;
> 	u64			seq;
> 	unsigned long		dropped;
> };

The current atomic console proposal allocates 1x cbuf per-cpu and 4x
meta-data per-cpu. Different contexts of a cpu will have different
meta-data, but all the contexts of a cpu will share the same cbuf.

If cbufs become embedded in cmsg, then we would allocate 1x cmsg
per-cpu. But the atomic consoles would still need their own 4x per-cpu
meta-data.

When looking at the proposal code, it looks wrong to have meta-data
fields in the cmsg struct that are not being used. But maybe that is
acceptable during the "transition phase" until all legacy consoles are
gone.

For v4 I will drop the console_buffers struct. I will use your
suggestion.

John
  
John Ogness Jan. 3, 2023, 3:41 p.m. UTC | #7
On 2023-01-02, Petr Mladek <pmladek@suse.com> wrote:
>>  	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);
>> +					  r.text_buf, r.info->text_len, &r.info->dev_info);
>
> This probably was not intended.

Actually it was. But such a style change is not appropriate here. Sorry
for trying to slip it in.

John
  
Petr Mladek Jan. 3, 2023, 3:55 p.m. UTC | #8
On Tue 2023-01-03 16:03:17, John Ogness wrote:
> On 2023-01-03, Petr Mladek <pmladek@suse.com> wrote:
> > On Thu 2022-12-22 16:47:39, John Ogness wrote:
> >> On 2022-12-21, John Ogness <john.ogness@linutronix.de> wrote:
> >> > +static bool console_emit_next_record(struct console *con, bool *handover, int cookie)
> >> > +{
> >> > +	bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
> >> > +	static char dropped_text[DROPPED_TEXT_MAX];
> >> > +	static struct console_buffers cbufs;
> >> > +	static struct console_message cmsg = {
> >> > +		.cbufs = &cbufs,
> >> > +	};
> >> 
> >> @cmsg should not be static. The whole point of the console_message
> >> wrapper struct is so that it can sit on the stack.
> >
> > Well, it might actually be better to keep it static for now.
> > It always points to static struct console_buffers cbufs anyway.
> >
> > It would make sense to have it on stack only when it uses
> > different buffers.
> 
> I think we should avoid making things static when it serves no purpose.

I agree. Well, I still feel that both structures are tightly
connected and there should be 1:1 relation. See below.

> > Which brings the question. Does it makes sense to use
> > the same buffers by different struct console_message?
> > Will it be safe in any situation?
> >
> > I did not want to complicate it yesterday. I think that
> > I have already proposed this. But this brings back
> > the question whether it makes sense to have two structures
> > at all.
> >
> > I still think that it would be easier and even more safe
> > to put everything into struct console_message.
> >
> > I mean to have:
> >
> > struct console_message {
> > 	char			buf[CONSOLE_EXT_LOG_MAX];
> > 	char			scratch_buf[LOG_LINE_MAX];
> > 	unsigned int		len;
> > 	u64			seq;
> > 	unsigned long		dropped;
> > };
> 
> The current atomic console proposal allocates 1x cbuf per-cpu and 4x
> meta-data per-cpu. Different contexts of a cpu will have different
> meta-data, but all the contexts of a cpu will share the same cbuf.
>
> If cbufs become embedded in cmsg, then we would allocate 1x cmsg
> per-cpu. But the atomic consoles would still need their own 4x per-cpu
> meta-data.

Do we really need 4x the meta data?

The metadata describe the state of the buffer. Using the buffer in one
context invalidates the metadata in the other context.

By other words, if one context reuses the buffer it might also
reuse the metadata. We just need to inform the original context
that it would need to break or re-start the operation.  But we would
need to do this anyway.

This is my intuitive view. It is possible that I miss some
important detail.

> When looking at the proposal code, it looks wrong to have meta-data
> fields in the cmsg struct that are not being used. But maybe that is
> acceptable during the "transition phase" until all legacy consoles are
> gone.

I am not sure what you mean by "not being used".

When I try to find "struct console_buffers" with cscope
than I see it in:

	+ struct console_message definition:
	    + part of the structure

	+ console_prepend_dropped()
	+ console_get_next_message()
	    + both read the pointer from the given struct message

	+ console_emit_next_record()
	    + static definition
	    + the pointer is stored into struct console_message

In all situations, struct console_message is needed when
struct console_buffers is manipulated. By other words,
the metadata are always needed when the buffers are used.

> For v4 I will drop the console_buffers struct. I will use your
> suggestion.

Please, do not do it just to make me happy. My intention
is to keep things simple. And keeping the two structures
synced needs an extra code.

If you are sure that the separation will really be needed
in the future then feel free to keep the two structures.

Best Regards,
Petr
  
John Ogness Jan. 4, 2023, 10:26 a.m. UTC | #9
On 2023-01-03, Petr Mladek <pmladek@suse.com> wrote:
>> The current atomic console proposal allocates 1x cbuf per-cpu and 4x
>> meta-data per-cpu. Different contexts of a cpu will have different
>> meta-data, but all the contexts of a cpu will share the same cbuf.
>>
>> If cbufs become embedded in cmsg, then we would allocate 1x cmsg
>> per-cpu. But the atomic consoles would still need their own 4x per-cpu
>> meta-data.
>
> Do we really need 4x the meta data?

Having per-context meta-data helps minimize data clobbering. For
example, the message-formatting functions would not need to worry about
@cmsg->len changing underneath them. This can be solved with a
READ_ONCE() to a local variable and the function only using the local
copy, but it will mean more copying of variables.

> The metadata describe the state of the buffer. Using the buffer in one
> context invalidates the metadata in the other context.

Yes, but the message-formatting functions are the ones preparing that
meta-data. They must then be able to handle an interrupting context
changing that meta-data.

>> For v4 I will drop the console_buffers struct. I will use your
>> suggestion.
>
> Please, do not do it just to make me happy. My intention
> is to keep things simple. And keeping the two structures
> synced needs an extra code.
>
> If you are sure that the separation will really be needed
> in the future then feel free to keep the two structures.

Currently the message-formatting functions do not care about clobbering
of the text buffers. They blindly just move things around using the
meta-data as safety boundaries. This can lead to a formatted-buffer that
contains garbage, but an interrupted context will not print that buffer
in the end. The important thing is that the garbage was created safely.

Avoiding a separate console_buffers structure may simplify the
structures, but it requires robustifying the message-formatting
functions to be tolerant for meta-data clobbering.

I am currently implementing such changes to see if it is feasible.

John
  
Petr Mladek Jan. 4, 2023, 10:42 a.m. UTC | #10
On Wed 2023-01-04 11:32:30, John Ogness wrote:
> On 2023-01-03, Petr Mladek <pmladek@suse.com> wrote:
> >> The current atomic console proposal allocates 1x cbuf per-cpu and 4x
> >> meta-data per-cpu. Different contexts of a cpu will have different
> >> meta-data, but all the contexts of a cpu will share the same cbuf.
> >>
> >> If cbufs become embedded in cmsg, then we would allocate 1x cmsg
> >> per-cpu. But the atomic consoles would still need their own 4x per-cpu
> >> meta-data.
> >
> > Do we really need 4x the meta data?
> 
> Having per-context meta-data helps minimize data clobbering. For
> example, the message-formatting functions would not need to worry about
> @cmsg->len changing underneath them. This can be solved with a
> READ_ONCE() to a local variable and the function only using the local
> copy, but it will mean more copying of variables.

I see. I agree that a separate structure would avoid these problems.

> > The metadata describe the state of the buffer. Using the buffer in one
> > context invalidates the metadata in the other context.
> 
> Yes, but the message-formatting functions are the ones preparing that
> meta-data. They must then be able to handle an interrupting context
> changing that meta-data.
> 
> >> For v4 I will drop the console_buffers struct. I will use your
> >> suggestion.
> >
> > Please, do not do it just to make me happy. My intention
> > is to keep things simple. And keeping the two structures
> > synced needs an extra code.
> >
> > If you are sure that the separation will really be needed
> > in the future then feel free to keep the two structures.
> 
> Currently the message-formatting functions do not care about clobbering
> of the text buffers. They blindly just move things around using the
> meta-data as safety boundaries. This can lead to a formatted-buffer that
> contains garbage, but an interrupted context will not print that buffer
> in the end. The important thing is that the garbage was created safely.

Right.

> Avoiding a separate console_buffers structure may simplify the
> structures, but it requires robustifying the message-formatting
> functions to be tolerant for meta-data clobbering.
> 
> I am currently implementing such changes to see if it is feasible.

Please, do not spend too much time on this.

I think that the two structures make sense in the end. Just please
mention the metadata clobbering as the motivation in the commit
message.

Best Regards,
Petr
  

Patch

diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index f5ebbd392fee..4f2eb8c470bc 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -91,3 +91,19 @@  struct console_buffers {
 	char	outbuf[CONSOLE_EXT_LOG_MAX];
 	char	scratchbuf[LOG_LINE_MAX];
 };
+
+/**
+ * console_message - Container for a prepared console message.
+ * @cbufs:	Console buffers used to prepare the message.
+ * @outbuf_len:	The length of prepared text in @cbufs->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.
+ * @outbuf_seq:	The sequence number of the record used for @cbufs->outbuf.
+ * @dropped:	The number of dropped records from reading @outbuf_seq.
+ */
+struct console_message {
+	struct console_buffers	*cbufs;
+	unsigned int		outbuf_len;
+	u64			outbuf_seq;
+	unsigned long		dropped;
+};
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 2e5e2eda1fa1..7cac636600f8 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2725,34 +2725,34 @@  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.
+ * Read and format the specified record (or a later record if the specified
+ * record is not available).
  *
- * @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
- * console_lock and the SRCU read lock. Otherwise it is set to false.
+ * @cmsg will contain the formatted result. @cmsg->cbufs must point to a
+ * struct console_buffers.
  *
- * @cookie is the cookie from the SRCU read lock.
+ * @seq is the record to read and format. If it is not available, the next
+ * valid record is read.
  *
- * Returns false if the given console has no next record to print, otherwise
- * true.
+ * @is_extended specifies the message should be formatted for extended
+ * console output.
  *
- * Requires the console_lock and the SRCU read lock.
+ * Returns false if no record is available. Otherwise true and all fields
+ * of @cmsg are valid. (See the documentation of struct console_message
+ * for information about the @cmsg fields.)
  */
-static bool console_emit_next_record(struct console *con, bool *handover, int cookie)
-{
-	bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
-	static char dropped_text[DROPPED_TEXT_MAX];
-	static struct console_buffers cbufs;
-	const size_t scratchbuf_sz = sizeof(cbufs.scratchbuf);
-	const size_t outbuf_sz = sizeof(cbufs.outbuf);
-	char *scratchbuf = &cbufs.scratchbuf[0];
-	char *outbuf = &cbufs.outbuf[0];
+static bool console_get_next_message(struct console_message *cmsg, u64 seq,
+				     bool is_extended)
+{
+	struct console_buffers *cbufs = cmsg->cbufs;
+	const size_t scratchbuf_sz = sizeof(cbufs->scratchbuf);
+	const size_t outbuf_sz = sizeof(cbufs->outbuf);
+	char *scratchbuf = &cbufs->scratchbuf[0];
+	char *outbuf = &cbufs->outbuf[0];
 	static int panic_console_dropped;
 	struct printk_info info;
 	struct printk_record r;
-	unsigned long flags;
-	size_t len;
+	size_t len = 0;
 
 	/*
 	 * Formatting extended messages requires a separate buffer, so use the
@@ -2766,33 +2766,77 @@  static bool console_emit_next_record(struct console *con, bool *handover, int co
 	else
 		prb_rec_init_rd(&r, &info, outbuf, outbuf_sz);
 
-	*handover = false;
-
-	if (!prb_read_valid(prb, con->seq, &r))
+	if (!prb_read_valid(prb, seq, &r))
 		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");
-		}
+	cmsg->outbuf_seq = r.info->seq;
+	cmsg->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 (cmsg->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 (suppress_message_printing(r.info->level)) {
-		con->seq++;
-		goto skip;
-	}
+	if (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);
+					  r.text_buf, r.info->text_len, &r.info->dev_info);
 	} else {
 		len = record_print_text(&r, console_msg_format & MSG_FORMAT_SYSLOG, printk_time);
 	}
+out:
+	cmsg->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
+ * console_lock and the SRCU read lock. Otherwise it is set to false.
+ *
+ * @cookie is the cookie from the SRCU read lock.
+ *
+ * Returns false if the given console has no next record to print, otherwise
+ * true.
+ *
+ * Requires the console_lock and the SRCU read lock.
+ */
+static bool console_emit_next_record(struct console *con, bool *handover, int cookie)
+{
+	bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
+	static char dropped_text[DROPPED_TEXT_MAX];
+	static struct console_buffers cbufs;
+	static struct console_message cmsg = {
+		.cbufs = &cbufs,
+	};
+	char *outbuf = &cbufs.outbuf[0];
+	unsigned long flags;
+
+	*handover = false;
+
+	if (!console_get_next_message(&cmsg, con->seq, is_extended))
+		return false;
+
+	con->dropped += cmsg.dropped;
+
+	/* Skip messages of formatted length 0. */
+	if (cmsg.outbuf_len == 0) {
+		con->seq = cmsg.outbuf_seq + 1;
+		goto skip;
+	}
 
 	/*
 	 * While actively printing out messages, if another printk()
@@ -2808,11 +2852,11 @@  static bool console_emit_next_record(struct console *con, bool *handover, int co
 	console_lock_spinning_enable();
 
 	stop_critical_timings();	/* don't trace print latency */
-	call_console_driver(con, outbuf, len,
+	call_console_driver(con, outbuf, cmsg.outbuf_len,
 			    is_extended ? NULL : dropped_text);
 	start_critical_timings();
 
-	con->seq++;
+	con->seq = cmsg.outbuf_seq + 1;
 
 	*handover = console_lock_spinning_disable_and_check(cookie);
 	printk_safe_exit_irqrestore(flags);