summaryrefslogtreecommitdiff
path: root/patches/printk__introduce_kernel_sync_mode.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/printk__introduce_kernel_sync_mode.patch')
-rw-r--r--patches/printk__introduce_kernel_sync_mode.patch374
1 files changed, 0 insertions, 374 deletions
diff --git a/patches/printk__introduce_kernel_sync_mode.patch b/patches/printk__introduce_kernel_sync_mode.patch
deleted file mode 100644
index c4a6812c190c..000000000000
--- a/patches/printk__introduce_kernel_sync_mode.patch
+++ /dev/null
@@ -1,374 +0,0 @@
-Subject: printk: introduce kernel sync mode
-From: John Ogness <john.ogness@linutronix.de>
-Date: Mon Nov 30 01:42:06 2020 +0106
-
-From: John Ogness <john.ogness@linutronix.de>
-
-When the kernel performs an OOPS, enter into "sync mode":
-
-- only atomic consoles (write_atomic() callback) will print
-- printing occurs within vprintk_store() instead of console_unlock()
-
-CONSOLE_LOG_MAX is moved to printk.h to support the per-console
-buffer used in sync mode.
-
-Signed-off-by: John Ogness <john.ogness@linutronix.de>
-Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-
----
- include/linux/console.h | 4 +
- include/linux/printk.h | 6 +
- kernel/printk/printk.c | 178 +++++++++++++++++++++++++++++++++++++++++++++---
- 3 files changed, 178 insertions(+), 10 deletions(-)
----
---- a/include/linux/console.h
-+++ b/include/linux/console.h
-@@ -16,6 +16,7 @@
-
- #include <linux/atomic.h>
- #include <linux/types.h>
-+#include <linux/printk.h>
-
- struct vc_data;
- struct console_font_op;
-@@ -150,6 +151,9 @@ struct console {
- short flags;
- short index;
- int cflag;
-+#ifdef CONFIG_PRINTK
-+ char sync_buf[CONSOLE_LOG_MAX];
-+#endif
- uint ispeed;
- uint ospeed;
- void *data;
---- a/include/linux/printk.h
-+++ b/include/linux/printk.h
-@@ -47,6 +47,12 @@ static inline const char *printk_skip_he
-
- #define CONSOLE_EXT_LOG_MAX 8192
-
-+/*
-+ * The maximum size of a record formatted for console printing
-+ * (i.e. with the prefix prepended to every line).
-+ */
-+#define CONSOLE_LOG_MAX 1024
-+
- /* printk's without a loglevel use this.. */
- #define MESSAGE_LOGLEVEL_DEFAULT CONFIG_MESSAGE_LOGLEVEL_DEFAULT
-
---- a/kernel/printk/printk.c
-+++ b/kernel/printk/printk.c
-@@ -45,6 +45,7 @@
- #include <linux/ctype.h>
- #include <linux/uio.h>
- #include <linux/kgdb.h>
-+#include <linux/clocksource.h>
- #include <linux/sched/clock.h>
- #include <linux/sched/debug.h>
- #include <linux/sched/task_stack.h>
-@@ -355,6 +356,9 @@ static int console_msg_format = MSG_FORM
- static DEFINE_MUTEX(syslog_lock);
-
- #ifdef CONFIG_PRINTK
-+/* Set to enable sync mode. Once set, it is never cleared. */
-+static bool sync_mode;
-+
- DECLARE_WAIT_QUEUE_HEAD(log_wait);
- /* All 3 protected by @syslog_lock. */
- /* the next printk record to read by syslog(READ) or /proc/kmsg */
-@@ -382,6 +386,20 @@ static struct latched_seq console_seq =
- .val[1] = 0,
- };
-
-+static struct latched_seq console_sync_seq = {
-+ .latch = SEQCNT_LATCH_ZERO(console_sync_seq.latch),
-+ .val[0] = 0,
-+ .val[1] = 0,
-+};
-+
-+#ifdef CONFIG_HAVE_NMI
-+static struct latched_seq console_sync_nmi_seq = {
-+ .latch = SEQCNT_LATCH_ZERO(console_sync_nmi_seq.latch),
-+ .val[0] = 0,
-+ .val[1] = 0,
-+};
-+#endif
-+
- /*
- * The next printk record to read after the last 'clear' command. There are
- * two copies (updated with seqcount_latch) so that reads can locklessly
-@@ -399,9 +417,6 @@ static struct latched_seq clear_seq = {
- #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 allowed to be reserved for a record */
- #define LOG_LINE_MAX (CONSOLE_LOG_MAX - PREFIX_MAX)
-
-@@ -1773,6 +1788,116 @@ static inline void printk_delay(int leve
- }
- }
-
-+static bool kernel_sync_mode(void)
-+{
-+ return (oops_in_progress || sync_mode);
-+}
-+
-+static bool console_may_sync(struct console *con)
-+{
-+ if (!(con->flags & CON_ENABLED))
-+ return false;
-+ if (con->write_atomic && kernel_sync_mode())
-+ return true;
-+ return false;
-+}
-+
-+static bool call_sync_console_driver(struct console *con, const char *text, size_t text_len)
-+{
-+ if (!(con->flags & CON_ENABLED))
-+ return false;
-+ if (con->write_atomic && kernel_sync_mode())
-+ con->write_atomic(con, text, text_len);
-+ else
-+ return false;
-+
-+ return true;
-+}
-+
-+static bool have_atomic_console(void)
-+{
-+ struct console *con;
-+
-+ for_each_console(con) {
-+ if (!(con->flags & CON_ENABLED))
-+ continue;
-+ if (con->write_atomic)
-+ return true;
-+ }
-+ return false;
-+}
-+
-+static bool print_sync(struct console *con, u64 *seq)
-+{
-+ struct printk_info info;
-+ struct printk_record r;
-+ size_t text_len;
-+
-+ prb_rec_init_rd(&r, &info, &con->sync_buf[0], sizeof(con->sync_buf));
-+
-+ if (!prb_read_valid(prb, *seq, &r))
-+ return false;
-+
-+ text_len = record_print_text(&r, console_msg_format & MSG_FORMAT_SYSLOG, printk_time);
-+
-+ if (!call_sync_console_driver(con, &con->sync_buf[0], text_len))
-+ return false;
-+
-+ *seq = r.info->seq;
-+
-+ touch_softlockup_watchdog_sync();
-+ clocksource_touch_watchdog();
-+ rcu_cpu_stall_reset();
-+ touch_nmi_watchdog();
-+
-+ if (text_len)
-+ printk_delay(r.info->level);
-+
-+ return true;
-+}
-+
-+static u64 read_console_seq(void)
-+{
-+ u64 seq2;
-+ u64 seq;
-+
-+ seq = latched_seq_read_nolock(&console_seq);
-+ seq2 = latched_seq_read_nolock(&console_sync_seq);
-+ if (seq2 > seq)
-+ seq = seq2;
-+#ifdef CONFIG_HAVE_NMI
-+ seq2 = latched_seq_read_nolock(&console_sync_nmi_seq);
-+ if (seq2 > seq)
-+ seq = seq2;
-+#endif
-+ return seq;
-+}
-+
-+static void print_sync_until(struct console *con, u64 seq)
-+{
-+ u64 printk_seq;
-+
-+ while (!__printk_cpu_trylock())
-+ cpu_relax();
-+
-+ for (;;) {
-+ printk_seq = read_console_seq();
-+ if (printk_seq >= seq)
-+ break;
-+ if (!print_sync(con, &printk_seq))
-+ break;
-+#ifdef CONFIG_PRINTK_NMI
-+ if (in_nmi()) {
-+ latched_seq_write(&console_sync_nmi_seq, printk_seq + 1);
-+ continue;
-+ }
-+#endif
-+ latched_seq_write(&console_sync_seq, printk_seq + 1);
-+ }
-+
-+ __printk_cpu_unlock();
-+}
-+
- /*
- * Special console_lock variants that help to reduce the risk of soft-lockups.
- * They allow to pass console_lock to another printk() call using a busy wait.
-@@ -1947,6 +2072,8 @@ static void call_console_drivers(const c
- if (!cpu_online(smp_processor_id()) &&
- !(con->flags & CON_ANYTIME))
- continue;
-+ if (kernel_sync_mode())
-+ continue;
- if (con->flags & CON_EXTENDED)
- con->write(con, ext_text, ext_len);
- else {
-@@ -2115,6 +2242,7 @@ int vprintk_store(int facility, int leve
- const u32 caller_id = printk_caller_id();
- struct prb_reserved_entry e;
- enum printk_info_flags flags = 0;
-+ bool final_commit = false;
- struct printk_record r;
- unsigned long irqflags;
- u16 trunc_msg_len = 0;
-@@ -2125,6 +2253,7 @@ int vprintk_store(int facility, int leve
- u16 text_len;
- int ret = 0;
- u64 ts_nsec;
-+ u64 seq;
-
- /*
- * Since the duration of printk() can vary depending on the message
-@@ -2163,6 +2292,7 @@ int vprintk_store(int facility, int leve
- if (flags & LOG_CONT) {
- prb_rec_init_wr(&r, reserve_size);
- if (prb_reserve_in_last(&e, prb, &r, caller_id, LOG_LINE_MAX)) {
-+ seq = r.info->seq;
- text_len = printk_sprint(&r.text_buf[r.info->text_len], reserve_size,
- facility, &flags, fmt, args);
- r.info->text_len += text_len;
-@@ -2170,6 +2300,7 @@ int vprintk_store(int facility, int leve
- if (flags & LOG_NEWLINE) {
- r.info->flags |= LOG_NEWLINE;
- prb_final_commit(&e);
-+ final_commit = true;
- } else {
- prb_commit(&e);
- }
-@@ -2193,6 +2324,7 @@ int vprintk_store(int facility, int leve
- if (!prb_reserve(&e, prb, &r))
- goto out;
- }
-+ seq = r.info->seq;
-
- /* fill message */
- text_len = printk_sprint(&r.text_buf[0], reserve_size, facility, &flags, fmt, args);
-@@ -2208,13 +2340,25 @@ int vprintk_store(int facility, int leve
- memcpy(&r.info->dev_info, dev_info, sizeof(r.info->dev_info));
-
- /* A message without a trailing newline can be continued. */
-- if (!(flags & LOG_NEWLINE))
-+ if (!(flags & LOG_NEWLINE)) {
- prb_commit(&e);
-- else
-+ } else {
- prb_final_commit(&e);
-+ final_commit = true;
-+ }
-
- ret = text_len + trunc_msg_len;
- out:
-+ /* only the kernel may perform synchronous printing */
-+ if (facility == 0 && final_commit) {
-+ struct console *con;
-+
-+ for_each_console(con) {
-+ if (console_may_sync(con))
-+ print_sync_until(con, seq + 1);
-+ }
-+ }
-+
- printk_exit_irqrestore(recursion_ptr, irqflags);
- return ret;
- }
-@@ -2283,13 +2427,13 @@ EXPORT_SYMBOL(_printk);
-
- #else /* CONFIG_PRINTK */
-
--#define CONSOLE_LOG_MAX 0
- #define printk_time false
-
- #define prb_read_valid(rb, seq, r) false
- #define prb_first_valid_seq(rb) 0
--#define latched_seq_read_nolock(seq) 0
-+#define read_console_seq() 0
- #define latched_seq_write(dst, src)
-+#define kernel_sync_mode() false
-
- static u64 exclusive_console_stop_seq;
- static unsigned long console_dropped;
-@@ -2593,6 +2737,8 @@ static int have_callable_console(void)
- */
- static inline int can_use_console(void)
- {
-+ if (kernel_sync_mode())
-+ return false;
- return cpu_online(raw_smp_processor_id()) || have_callable_console();
- }
-
-@@ -2662,7 +2808,7 @@ void console_unlock(void)
- size_t len;
-
- skip:
-- seq = latched_seq_read_nolock(&console_seq);
-+ seq = read_console_seq();
- if (!prb_read_valid(prb, seq, &r))
- break;
-
-@@ -2742,7 +2888,7 @@ void console_unlock(void)
- * there's a new owner and the console_unlock() from them will do the
- * flush, no worries.
- */
-- retry = prb_read_valid(prb, latched_seq_read_nolock(&console_seq), NULL);
-+ retry = prb_read_valid(prb, read_console_seq(), NULL);
- if (retry && console_trylock())
- goto again;
- }
-@@ -3042,7 +3188,7 @@ void register_console(struct console *ne
- * ignores console_lock.
- */
- exclusive_console = newcon;
-- exclusive_console_stop_seq = latched_seq_read_nolock(&console_seq);
-+ exclusive_console_stop_seq = read_console_seq();
-
- /* Get a consistent copy of @syslog_seq. */
- mutex_lock(&syslog_lock);
-@@ -3417,6 +3563,18 @@ void kmsg_dump(enum kmsg_dump_reason rea
- {
- struct kmsg_dumper *dumper;
-
-+ if (!oops_in_progress) {
-+ /*
-+ * If atomic consoles are available, activate kernel sync mode
-+ * to make sure any final messages are visible. The trailing
-+ * printk message is important to flush any pending messages.
-+ */
-+ if (have_atomic_console()) {
-+ sync_mode = true;
-+ pr_info("enabled sync mode\n");
-+ }
-+ }
-+
- rcu_read_lock();
- list_for_each_entry_rcu(dumper, &dump_list, list) {
- enum kmsg_dump_reason max_reason = dumper->max_reason;