Prepare for per-console atomic flushing policies by introducing
enum pr_flush_reason to classify various reasons for performing a
printk backlog flush using printk_trigger_flush().

Propagate the reason down to __nbcon_atomic_flush_pending_con(),
where the actually atomic flushing is executed.

Update all printk_trigger_flush() call sites as well as an
explicit lower-level atomic flush calls to specify the reason.

Note that PR_FLUSH_RUNTIME is used for cases where the reason for
the flush is not clearly defined.

No functional change.

Signed-off-by: John Ogness <[email protected]>
---
 arch/powerpc/kernel/watchdog.c |  2 +-
 include/linux/printk.h         | 22 ++++++++++++++++++++--
 kernel/printk/internal.h       |  4 ++--
 kernel/printk/nbcon.c          | 28 ++++++++++++++++++----------
 kernel/printk/printk.c         | 16 ++++++++--------
 kernel/reboot.c                |  2 +-
 lib/nmi_backtrace.c            |  2 +-
 7 files changed, 51 insertions(+), 25 deletions(-)

diff --git a/arch/powerpc/kernel/watchdog.c b/arch/powerpc/kernel/watchdog.c
index 582ee3fd71c1b..3d4f9dcb82866 100644
--- a/arch/powerpc/kernel/watchdog.c
+++ b/arch/powerpc/kernel/watchdog.c
@@ -365,7 +365,7 @@ static void watchdog_timer_interrupt(int cpu)
                 *
                 * See wd_lockup_ipi.
                 */
-               printk_trigger_flush();
+               printk_trigger_flush(PR_FLUSH_RUNTIME);
        }
 }
 
diff --git a/include/linux/printk.h b/include/linux/printk.h
index f594c1266bfd4..c669497bd3378 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -145,6 +145,24 @@ void early_printk(const char *s, ...) { }
 
 struct dev_printk_info;
 
+/**
+ * enum pr_flush_reason - Reason for a flush
+ * @PR_FLUSH_RUNTIME:  A flush while the kernel is running
+ * @PR_FLUSH_RESTART:  The kernel is ending, but another instance should
+ *                     follow (reboot, kexec)
+ * @PR_FLUSH_HANG:     The kernel is ending and will enter an infinite loop
+ * @PR_FLUSH_KDB:      Printing while KDB is active
+ *
+ * Flush reasons are used to determine if unsafe atomic flushing should be
+ * performed, based on individual console policies.
+ */
+enum pr_flush_reason {
+       PR_FLUSH_RUNTIME,
+       PR_FLUSH_RESTART,
+       PR_FLUSH_HANG,
+       PR_FLUSH_KDB,
+};
+
 #ifdef CONFIG_PRINTK
 asmlinkage __printf(4, 0)
 int vprintk_emit(int facility, int level,
@@ -202,7 +220,7 @@ void dump_stack_print_info(const char *log_lvl);
 void show_regs_print_info(const char *log_lvl);
 extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold;
 extern asmlinkage void dump_stack(void) __cold;
-void printk_trigger_flush(void);
+void printk_trigger_flush(enum pr_flush_reason reason);
 void console_try_replay_all(void);
 void printk_legacy_allow_panic_sync(void);
 extern bool nbcon_device_try_acquire(struct console *con);
@@ -298,7 +316,7 @@ static inline void dump_stack_lvl(const char *log_lvl)
 static inline void dump_stack(void)
 {
 }
-static inline void printk_trigger_flush(void)
+static inline void printk_trigger_flush(enum pr_flush_reason reason)
 {
 }
 static inline void console_try_replay_all(void)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 85fbf1801cbe0..7f1f4677609da 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -104,7 +104,7 @@ void nbcon_seq_force(struct console *con, u64 seq);
 bool nbcon_alloc(struct console *con);
 void nbcon_free(struct console *con);
 enum nbcon_prio nbcon_get_default_prio(void);
-void nbcon_atomic_flush_pending(void);
+void nbcon_atomic_flush_pending(enum pr_flush_reason reason);
 bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
                                   int cookie, bool use_atomic);
 bool nbcon_kthread_create(struct console *con);
@@ -156,7 +156,7 @@ static inline void nbcon_seq_force(struct console *con, u64 
seq) { }
 static inline bool nbcon_alloc(struct console *con) { return false; }
 static inline void nbcon_free(struct console *con) { }
 static inline enum nbcon_prio nbcon_get_default_prio(void) { return 
NBCON_PRIO_NONE; }
-static inline void nbcon_atomic_flush_pending(void) { }
+static inline void nbcon_atomic_flush_pending(enum pr_flush_reason reason) { }
 static inline bool nbcon_legacy_emit_next_record(struct console *con, bool 
*handover,
                                                 int cookie, bool use_atomic) { 
return false; }
 static inline void nbcon_kthread_wake(struct console *con) { }
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 5f8afaca88665..935fd6b86bac7 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1542,6 +1542,7 @@ bool nbcon_legacy_emit_next_record(struct console *con, 
bool *handover,
  * __nbcon_atomic_flush_pending_con - Flush specified nbcon console using its
  *                                     write_atomic() callback
  * @con:                       The nbcon console to flush
+ * @reason:                    The reason for the flush
  * @stop_seq:                  Flush up until this record
  *
  * Return:     0 if @con was flushed up to @stop_seq Otherwise, error code on
@@ -1561,7 +1562,8 @@ bool nbcon_legacy_emit_next_record(struct console *con, 
bool *handover,
  * returned, it cannot be expected that the unfinalized record will become
  * available.
  */
-static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
+static int __nbcon_atomic_flush_pending_con(struct console *con, enum 
pr_flush_reason reason,
+                                           u64 stop_seq)
 {
        struct nbcon_write_context wctxt = { };
        struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
@@ -1610,6 +1612,7 @@ static int __nbcon_atomic_flush_pending_con(struct 
console *con, u64 stop_seq)
  * nbcon_atomic_flush_pending_con - Flush specified nbcon console using its
  *                                     write_atomic() callback
  * @con:                       The nbcon console to flush
+ * @reason:                    The reason for the flush
  * @stop_seq:                  Flush up until this record
  *
  * This will stop flushing before @stop_seq if another context has ownership.
@@ -1617,13 +1620,14 @@ static int __nbcon_atomic_flush_pending_con(struct 
console *con, u64 stop_seq)
  * are added while this context was flushing and there is no other context
  * to handle the printing, this context must also flush those records.
  */
-static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
+static void nbcon_atomic_flush_pending_con(struct console *con, enum 
pr_flush_reason reason,
+                                          u64 stop_seq)
 {
        struct console_flush_type ft;
        int err;
 
 again:
-       err = __nbcon_atomic_flush_pending_con(con, stop_seq);
+       err = __nbcon_atomic_flush_pending_con(con, reason, stop_seq);
 
        /*
         * If there was a new owner (-EPERM, -EAGAIN), that context is
@@ -1652,9 +1656,10 @@ static void nbcon_atomic_flush_pending_con(struct 
console *con, u64 stop_seq)
 /**
  * __nbcon_atomic_flush_pending - Flush all nbcon consoles using their
  *                                     write_atomic() callback
+ * @reason:                    The reason for the flush
  * @stop_seq:                  Flush up until this record
  */
-static void __nbcon_atomic_flush_pending(u64 stop_seq)
+static void __nbcon_atomic_flush_pending(enum pr_flush_reason reason, u64 
stop_seq)
 {
        struct console *con;
        int cookie;
@@ -1672,7 +1677,7 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq)
                if (nbcon_seq_read(con) >= stop_seq)
                        continue;
 
-               nbcon_atomic_flush_pending_con(con, stop_seq);
+               nbcon_atomic_flush_pending_con(con, reason, stop_seq);
        }
        console_srcu_read_unlock(cookie);
 }
@@ -1681,14 +1686,16 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq)
  * nbcon_atomic_flush_pending - Flush all nbcon consoles using their
  *                             write_atomic() callback
  *
+ * @reason:    The reason for the flush
+ *
  * Flush the backlog up through the currently newest record. Any new
  * records added while flushing will not be flushed if there is another
  * context available to handle the flushing. This is to avoid one CPU
  * printing unbounded because other CPUs continue to add records.
  */
-void nbcon_atomic_flush_pending(void)
+void nbcon_atomic_flush_pending(enum pr_flush_reason reason)
 {
-       __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb));
+       __nbcon_atomic_flush_pending(reason, prb_next_reserve_seq(prb));
 }
 
 /**
@@ -1701,7 +1708,7 @@ void nbcon_atomic_flush_pending(void)
 void nbcon_atomic_flush_unsafe(void)
 {
        panic_nbcon_allow_unsafe_takeover = true;
-       __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb));
+       __nbcon_atomic_flush_pending(PR_FLUSH_HANG, prb_next_reserve_seq(prb));
        panic_nbcon_allow_unsafe_takeover = false;
 }
 
@@ -1931,7 +1938,8 @@ void nbcon_device_release(struct console *con)
                 * using the legacy loop.
                 */
                if (ft.nbcon_atomic) {
-                       __nbcon_atomic_flush_pending_con(con, 
prb_next_reserve_seq(prb));
+                       __nbcon_atomic_flush_pending_con(con, PR_FLUSH_RUNTIME,
+                                                        
prb_next_reserve_seq(prb));
                } else if (ft.legacy_direct) {
                        if (console_trylock())
                                console_unlock();
@@ -2001,7 +2009,7 @@ void nbcon_kdb_release(struct nbcon_write_context *wctxt)
         * The console was locked only when the write_atomic() callback
         * was usable.
         */
-       __nbcon_atomic_flush_pending_con(ctxt->console, 
prb_next_reserve_seq(prb));
+       __nbcon_atomic_flush_pending_con(ctxt->console, PR_FLUSH_KDB, 
prb_next_reserve_seq(prb));
 }
 
 /**
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 5dbcf8a9909bb..ab9f2d6a6526a 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2455,7 +2455,7 @@ asmlinkage int vprintk_emit(int facility, int level,
        printed_len = vprintk_store(facility, level, dev_info, fmt, args);
 
        if (ft.nbcon_atomic)
-               nbcon_atomic_flush_pending();
+               nbcon_atomic_flush_pending(PR_FLUSH_RUNTIME);
 
        if (ft.nbcon_offload)
                nbcon_kthreads_wake();
@@ -2870,7 +2870,7 @@ static int console_cpu_notify(unsigned int cpu)
        if (!cpuhp_tasks_frozen) {
                printk_get_console_flush_type(&ft);
                if (ft.nbcon_atomic)
-                       nbcon_atomic_flush_pending();
+                       nbcon_atomic_flush_pending(PR_FLUSH_RUNTIME);
                if (ft.legacy_direct) {
                        if (console_trylock())
                                console_unlock();
@@ -3561,7 +3561,7 @@ void console_flush_on_panic(enum con_flush_mode mode)
 
        printk_get_console_flush_type(&ft);
        if (ft.nbcon_atomic)
-               nbcon_atomic_flush_pending();
+               nbcon_atomic_flush_pending(PR_FLUSH_RUNTIME);
 
        /* Flush legacy consoles once allowed, even when dangerous. */
        if (legacy_allow_panic_sync)
@@ -3775,7 +3775,7 @@ static void printk_kthreads_shutdown(void *data)
                 * The threads may have been stopped while printing a
                 * backlog. Flush any records left over.
                 */
-               nbcon_atomic_flush_pending();
+               nbcon_atomic_flush_pending(PR_FLUSH_RUNTIME);
        }
        console_list_unlock();
 }
@@ -4537,7 +4537,7 @@ static bool __pr_flush(struct console *con, int 
timeout_ms, bool reset_on_progre
        /* Flush the consoles so that records up to @seq are printed. */
        printk_get_console_flush_type(&ft);
        if (ft.nbcon_atomic)
-               nbcon_atomic_flush_pending();
+               nbcon_atomic_flush_pending(PR_FLUSH_RUNTIME);
        if (ft.legacy_direct) {
                console_lock();
                console_unlock();
@@ -4732,13 +4732,13 @@ void defer_console_output(void)
  * This is best effort. Depending on the system state, console states,
  * and caller context, no actual flushing may result from this call.
  */
-void printk_trigger_flush(void)
+void printk_trigger_flush(enum pr_flush_reason reason)
 {
        struct console_flush_type ft;
 
        printk_get_console_flush_type(&ft);
        if (ft.nbcon_atomic)
-               nbcon_atomic_flush_pending();
+               nbcon_atomic_flush_pending(reason);
        if (ft.nbcon_offload)
                nbcon_kthreads_wake();
        if (ft.legacy_direct) {
@@ -5090,7 +5090,7 @@ void console_try_replay_all(void)
        if (console_trylock()) {
                __console_rewind_all();
                if (ft.nbcon_atomic)
-                       nbcon_atomic_flush_pending();
+                       nbcon_atomic_flush_pending(PR_FLUSH_RUNTIME);
                if (ft.nbcon_offload)
                        nbcon_kthreads_wake();
                if (ft.legacy_offload)
diff --git a/kernel/reboot.c b/kernel/reboot.c
index a93c23b9e1948..f2f5dfa8e33ce 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -101,7 +101,7 @@ void emergency_restart(void)
         * the emergency restart. Move them to the atomic mode.
         */
        nbcon_cpu_emergency_enter();
-       printk_trigger_flush();
+       printk_trigger_flush(PR_FLUSH_RESTART);
 
        machine_emergency_restart();
 }
diff --git a/lib/nmi_backtrace.c b/lib/nmi_backtrace.c
index f39c9eca88885..925276113d3a0 100644
--- a/lib/nmi_backtrace.c
+++ b/lib/nmi_backtrace.c
@@ -91,7 +91,7 @@ void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
         * Force flush any remote buffers that might be stuck in IRQ context
         * and therefore could not run their irq_work.
         */
-       printk_trigger_flush();
+       printk_trigger_flush(PR_FLUSH_RUNTIME);
 
        clear_bit_unlock(0, &backtrace_flag);
        put_cpu();
-- 
2.47.3


Reply via email to