diff --git a/include/linux/console.h b/include/linux/console.h
index 641c1ca7fb67..32614011a950 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -188,6 +188,21 @@ struct console_buffers {
 	char	text[CONSOLE_LOG_MAX];
 };
 
+/**
+ * struct console_message - console output buffer descriptor
+ * @cbufs:		Pointer to console buffers storing the record text
+ * @outbuf:		Pointer to the text buffer to be used for writing out
+ *			to the device
+ * @outbuf_len:		Length of text at @outbuf
+ * @is_extmsg:		True if this is an extended format message
+ */
+struct console_message {
+	struct console_buffers	*cbufs;
+	char			*outbuf;
+	unsigned int		outbuf_len;
+	bool			is_extmsg;
+};
+
 /**
  * struct console - The console descriptor structure
  * @name:		The name of the console driver
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 750559171e30..dd1d8599ce5a 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2741,11 +2741,76 @@ static void __console_unlock(void)
 	up_console_sem();
 }
 
+/**
+ * console_get_next_message - Fill the output buffer with the next record
+ * @con:	The console to print on
+ * @cmsg:	Pointer to the output buffer descriptor
+ *
+ * Return: False if there is no pending record in the ringbuffer.
+ *	   True if there is a pending record in the ringbuffer.
+ *
+ * When the return value is true, then the caller must check
+ * @cmsg->outbuf. If not NULL it points to the first character to write
+ * to the device and @cmsg->outbuf_len contains the length of the message.
+ * If it is NULL then the record will be skipped.
+ */
+static bool console_get_next_message(struct console *con, struct console_message *cmsg)
+{
+	struct console_buffers *cbufs = cmsg->cbufs;
+	static int panic_console_dropped;
+	struct printk_info info;
+	struct printk_record r;
+	size_t write_text_size;
+	char *write_text;
+	size_t len;
+
+	cmsg->outbuf = NULL;
+	cmsg->outbuf_len = 0;
+
+	prb_rec_init_rd(&r, &info, &cbufs->text[0], sizeof(cbufs->text));
+
+	if (!prb_read_valid(prb, con->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");
+		}
+	}
+
+	/*
+	 * Skip record that has level above the console loglevel.
+	 * Return true so the caller knows a record exists and
+	 * leave cmsg->outbuf NULL so the caller knows the record
+	 * is being skipped.
+	 */
+	if (suppress_message_printing(r.info->level))
+		return true;
+
+	if (cmsg->is_extmsg) {
+		write_text = &cbufs->ext_text[0];
+		write_text_size = sizeof(cbufs->ext_text);
+		len = info_print_ext_header(write_text, write_text_size, r.info);
+		len += msg_print_ext_body(write_text + len, write_text_size - len,
+					  &r.text_buf[0], r.info->text_len, &r.info->dev_info);
+	} else {
+		write_text = &cbufs->text[0];
+		len = record_print_text(&r, console_msg_format & MSG_FORMAT_SYSLOG, printk_time);
+	}
+
+	cmsg->outbuf = write_text;
+	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.
  *
- * @cbufs is the console buffers used to string-print the formatted messages.
+ * @cbufs is the console buffers to use for string-printing the message.
  *
  * @cookie is the cookie from entering the SRCU read-side critical section.
  *
@@ -2761,52 +2826,30 @@ static void __console_unlock(void)
 static bool console_emit_next_record(struct console *con, struct console_buffers *cbufs,
 				     int cookie, bool *handover)
 {
-	static int panic_console_dropped;
-	struct printk_info info;
-	struct printk_record r;
-	size_t write_text_size;
+	struct console_message cmsg = {
+		.cbufs		= cbufs,
+		.is_extmsg	= console_srcu_read_flags(con) & CON_EXTENDED,
+	};
 	unsigned long flags;
 	char *dropped_text;
-	char *write_text;
-	size_t len;
-
-	prb_rec_init_rd(&r, &info, &cbufs->text[0], sizeof(cbufs->text));
 
 	*handover = false;
 
-	if (!prb_read_valid(prb, con->seq, &r))
+	if (!console_get_next_message(con, &cmsg))
 		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");
-		}
-	}
-
-	/* Skip record that has level above the console loglevel. */
-	if (suppress_message_printing(r.info->level)) {
+	if (!cmsg.outbuf) {
+		/* Skipping this record. */
 		con->seq++;
 		goto skip;
 	}
 
-	if (console_srcu_read_flags(con) & CON_EXTENDED) {
+	if (cmsg.is_extmsg) {
 		/* Extended consoles do not print "dropped messages". */
 		dropped_text = NULL;
-
-		write_text = &cbufs->ext_text[0];
-		write_text_size = sizeof(cbufs->ext_text);
-		len = info_print_ext_header(write_text, write_text_size, r.info);
-		len += msg_print_ext_body(write_text + len, write_text_size - len,
-					  &r.text_buf[0], r.info->text_len, &r.info->dev_info);
 	} else {
 		/* @ext_text is unused. Use it for "dropped messages". */
 		dropped_text = &cbufs->ext_text[0];
-
-		write_text = &cbufs->text[0];
-		len = record_print_text(&r, console_msg_format & MSG_FORMAT_SYSLOG, printk_time);
 	}
 
 	/*
@@ -2823,7 +2866,7 @@ static bool console_emit_next_record(struct console *con, struct console_buffers
 	console_lock_spinning_enable();
 
 	stop_critical_timings();	/* don't trace print latency */
-	call_console_driver(con, write_text, len, dropped_text);
+	call_console_driver(con, cmsg.outbuf, cmsg.outbuf_len, dropped_text);
 	start_critical_timings();
 
 	con->seq++;
