···1919#include <linux/irq_work.h>2020#include <linux/rculist.h>2121#include <linux/rcuwait.h>2222+#include <linux/smp.h>2223#include <linux/types.h>2324#include <linux/vesa.h>2425···603602extern void nbcon_cpu_emergency_enter(void);604603extern void nbcon_cpu_emergency_exit(void);605604extern bool nbcon_can_proceed(struct nbcon_write_context *wctxt);605605+extern void nbcon_write_context_set_buf(struct nbcon_write_context *wctxt,606606+ char *buf, unsigned int len);606607extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt);607608extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt);608609extern void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt);610610+extern bool nbcon_kdb_try_acquire(struct console *con,611611+ struct nbcon_write_context *wctxt);612612+extern void nbcon_kdb_release(struct nbcon_write_context *wctxt);613613+614614+/*615615+ * Check if the given console is currently capable and allowed to print616616+ * records. Note that this function does not consider the current context,617617+ * which can also play a role in deciding if @con can be used to print618618+ * records.619619+ */620620+static inline bool console_is_usable(struct console *con, short flags, bool use_atomic)621621+{622622+ if (!(flags & CON_ENABLED))623623+ return false;624624+625625+ if ((flags & CON_SUSPENDED))626626+ return false;627627+628628+ if (flags & CON_NBCON) {629629+ /* The write_atomic() callback is optional. */630630+ if (use_atomic && !con->write_atomic)631631+ return false;632632+633633+ /*634634+ * For the !use_atomic case, @printk_kthreads_running is not635635+ * checked because the write_thread() callback is also used636636+ * via the legacy loop when the printer threads are not637637+ * available.638638+ */639639+ } else {640640+ if (!con->write)641641+ return false;642642+ }643643+644644+ /*645645+ * Console drivers may assume that per-cpu resources have been646646+ * allocated. So unless they're explicitly marked as being able to647647+ * cope (CON_ANYTIME) don't call them until this CPU is officially up.648648+ */649649+ if (!cpu_online(raw_smp_processor_id()) && !(flags & CON_ANYTIME))650650+ return false;651651+652652+ return true;653653+}654654+609655#else610656static inline void nbcon_cpu_emergency_enter(void) { }611657static inline void nbcon_cpu_emergency_exit(void) { }612658static inline bool nbcon_can_proceed(struct nbcon_write_context *wctxt) { return false; }659659+static inline void nbcon_write_context_set_buf(struct nbcon_write_context *wctxt,660660+ char *buf, unsigned int len) { }613661static inline bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) { return false; }614662static inline bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) { return false; }615663static inline void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt) { }664664+static inline bool nbcon_kdb_try_acquire(struct console *con,665665+ struct nbcon_write_context *wctxt) { return false; }666666+static inline void nbcon_kdb_release(struct nbcon_write_context *wctxt) { }667667+static inline bool console_is_usable(struct console *con, short flags,668668+ bool use_atomic) { return false; }616669#endif617670618671extern int console_set_on_cmdline;
+16
include/linux/kdb.h
···1414 */15151616#include <linux/list.h>1717+#include <linux/smp.h>17181819/* Shifted versions of the command enable bits are be used if the command1920 * has no arguments (see kdb_check_flags). This allows commands, such as···208207/* Dynamic kdb shell command registration */209208extern int kdb_register(kdbtab_t *cmd);210209extern void kdb_unregister(kdbtab_t *cmd);210210+211211+/* Return true when KDB as locked for printing a message on this CPU. */212212+static inline213213+bool kdb_printf_on_this_cpu(void)214214+{215215+ /*216216+ * We can use raw_smp_processor_id() here because the task could217217+ * not get migrated when KDB has locked for printing on this CPU.218218+ */219219+ return unlikely(READ_ONCE(kdb_printf_cpu) == raw_smp_processor_id());220220+}221221+211222#else /* ! CONFIG_KGDB_KDB */212223static inline __printf(1, 2) int kdb_printf(const char *fmt, ...) { return 0; }213224static inline void kdb_init(int level) {}214225static inline int kdb_register(kdbtab_t *cmd) { return 0; }215226static inline void kdb_unregister(kdbtab_t *cmd) {}227227+228228+static inline bool kdb_printf_on_this_cpu(void) { return false; }229229+216230#endif /* CONFIG_KGDB_KDB */217231enum {218232 KDB_NOT_INITIALIZED,
+32-15
kernel/debug/kdb/kdb_io.c
···589589 */590590 cookie = console_srcu_read_lock();591591 for_each_console_srcu(c) {592592- if (!(console_srcu_read_flags(c) & CON_ENABLED))592592+ short flags = console_srcu_read_flags(c);593593+594594+ if (!console_is_usable(c, flags, true))593595 continue;594596 if (c == dbg_io_ops->cons)595597 continue;596596- if (!c->write)597597- continue;598598- /*599599- * Set oops_in_progress to encourage the console drivers to600600- * disregard their internal spin locks: in the current calling601601- * context the risk of deadlock is a bigger problem than risks602602- * due to re-entering the console driver. We operate directly on603603- * oops_in_progress rather than using bust_spinlocks() because604604- * the calls bust_spinlocks() makes on exit are not appropriate605605- * for this calling context.606606- */607607- ++oops_in_progress;608608- c->write(c, msg, msg_len);609609- --oops_in_progress;598598+599599+ if (flags & CON_NBCON) {600600+ struct nbcon_write_context wctxt = { };601601+602602+ /*603603+ * Do not continue if the console is NBCON and the context604604+ * can't be acquired.605605+ */606606+ if (!nbcon_kdb_try_acquire(c, &wctxt))607607+ continue;608608+609609+ nbcon_write_context_set_buf(&wctxt, (char *)msg, msg_len);610610+611611+ c->write_atomic(c, &wctxt);612612+ nbcon_kdb_release(&wctxt);613613+ } else {614614+ /*615615+ * Set oops_in_progress to encourage the console drivers to616616+ * disregard their internal spin locks: in the current calling617617+ * context the risk of deadlock is a bigger problem than risks618618+ * due to re-entering the console driver. We operate directly on619619+ * oops_in_progress rather than using bust_spinlocks() because620620+ * the calls bust_spinlocks() makes on exit are not appropriate621621+ * for this calling context.622622+ */623623+ ++oops_in_progress;624624+ c->write(c, msg, msg_len);625625+ --oops_in_progress;626626+ }610627 touch_nmi_watchdog();611628 }612629 console_srcu_read_unlock(cookie);
-45
kernel/printk/internal.h
···33 * internal.h - printk internal definitions44 */55#include <linux/console.h>66-#include <linux/percpu.h>76#include <linux/types.h>8798#if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL)···111112void nbcon_kthread_stop(struct console *con);112113void nbcon_kthreads_wake(void);113114114114-/*115115- * Check if the given console is currently capable and allowed to print116116- * records. Note that this function does not consider the current context,117117- * which can also play a role in deciding if @con can be used to print118118- * records.119119- */120120-static inline bool console_is_usable(struct console *con, short flags, bool use_atomic)121121-{122122- if (!(flags & CON_ENABLED))123123- return false;124124-125125- if ((flags & CON_SUSPENDED))126126- return false;127127-128128- if (flags & CON_NBCON) {129129- /* The write_atomic() callback is optional. */130130- if (use_atomic && !con->write_atomic)131131- return false;132132-133133- /*134134- * For the !use_atomic case, @printk_kthreads_running is not135135- * checked because the write_thread() callback is also used136136- * via the legacy loop when the printer threads are not137137- * available.138138- */139139- } else {140140- if (!con->write)141141- return false;142142- }143143-144144- /*145145- * Console drivers may assume that per-cpu resources have been146146- * allocated. So unless they're explicitly marked as being able to147147- * cope (CON_ANYTIME) don't call them until this CPU is officially up.148148- */149149- if (!cpu_online(raw_smp_processor_id()) && !(flags & CON_ANYTIME))150150- return false;151151-152152- return true;153153-}154154-155115/**156116 * nbcon_kthread_wake - Wake up a console printing thread157117 * @con: Console to operate on···161203 int cookie, bool use_atomic) { return false; }162204static inline void nbcon_kthread_wake(struct console *con) { }163205static inline void nbcon_kthreads_wake(void) { }164164-165165-static inline bool console_is_usable(struct console *con, short flags,166166- bool use_atomic) { return false; }167206168207#endif /* CONFIG_PRINTK */169208
+68-3
kernel/printk/nbcon.c
···1010#include <linux/export.h>1111#include <linux/init.h>1212#include <linux/irqflags.h>1313+#include <linux/kdb.h>1314#include <linux/kthread.h>1415#include <linux/minmax.h>1516#include <linux/panic.h>···253252 * since all non-panic CPUs are stopped during panic(), it254253 * is safer to have them avoid gaining console ownership.255254 *256256- * If this acquire is a reacquire (and an unsafe takeover255255+ * One exception is when kdb has locked for printing on this CPU.256256+ *257257+ * Second exception is a reacquire (and an unsafe takeover257258 * has not previously occurred) then it is allowed to attempt258259 * a direct acquire in panic. This gives console drivers an259260 * opportunity to perform any necessary cleanup if they were260261 * interrupted by the panic CPU while printing.261262 */262263 if (panic_on_other_cpu() &&264264+ !kdb_printf_on_this_cpu() &&263265 (!is_reacquire || cur->unsafe_takeover)) {264266 return -EPERM;265267 }···857853 return nbcon_context_can_proceed(ctxt, &cur);858854}859855860860-static void nbcon_write_context_set_buf(struct nbcon_write_context *wctxt,861861- char *buf, unsigned int len)856856+void nbcon_write_context_set_buf(struct nbcon_write_context *wctxt,857857+ char *buf, unsigned int len)862858{863859 struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);864860 struct console *con = ctxt->console;···18981894 console_srcu_read_unlock(cookie);18991895}19001896EXPORT_SYMBOL_GPL(nbcon_device_release);18971897+18981898+/**18991899+ * nbcon_kdb_try_acquire - Try to acquire nbcon console and enter unsafe19001900+ * section19011901+ * @con: The nbcon console to acquire19021902+ * @wctxt: The nbcon write context to be used on success19031903+ *19041904+ * Context: Under console_srcu_read_lock() for emitting a single kdb message19051905+ * using the given con->write_atomic() callback. Can be called19061906+ * only when the console is usable at the moment.19071907+ *19081908+ * Return: True if the console was acquired. False otherwise.19091909+ *19101910+ * kdb emits messages on consoles registered for printk() without19111911+ * storing them into the ring buffer. It has to acquire the console19121912+ * ownerhip so that it could call con->write_atomic() callback a safe way.19131913+ *19141914+ * This function acquires the nbcon console using priority NBCON_PRIO_EMERGENCY19151915+ * and marks it unsafe for handover/takeover.19161916+ */19171917+bool nbcon_kdb_try_acquire(struct console *con,19181918+ struct nbcon_write_context *wctxt)19191919+{19201920+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);19211921+19221922+ memset(ctxt, 0, sizeof(*ctxt));19231923+ ctxt->console = con;19241924+ ctxt->prio = NBCON_PRIO_EMERGENCY;19251925+19261926+ if (!nbcon_context_try_acquire(ctxt, false))19271927+ return false;19281928+19291929+ if (!nbcon_context_enter_unsafe(ctxt))19301930+ return false;19311931+19321932+ return true;19331933+}19341934+19351935+/**19361936+ * nbcon_kdb_release - Exit unsafe section and release the nbcon console19371937+ *19381938+ * @wctxt: The nbcon write context initialized by a successful19391939+ * nbcon_kdb_try_acquire()19401940+ */19411941+void nbcon_kdb_release(struct nbcon_write_context *wctxt)19421942+{19431943+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);19441944+19451945+ if (!nbcon_context_exit_unsafe(ctxt))19461946+ return;19471947+19481948+ nbcon_context_release(ctxt);19491949+19501950+ /*19511951+ * Flush any new printk() messages added when the console was blocked.19521952+ * Only the console used by the given write context was blocked.19531953+ * The console was locked only when the write_atomic() callback19541954+ * was usable.19551955+ */19561956+ __nbcon_atomic_flush_pending_con(ctxt->console, prb_next_reserve_seq(prb), false);19571957+}
+4-8
kernel/printk/printk.c
···33313331 */33323332 cookie = console_srcu_read_lock();33333333 for_each_console_srcu(c) {33343334- short flags = console_srcu_read_flags(c);33353335-33363336- if (flags & CON_SUSPENDED)33343334+ if (!console_is_usable(c, console_srcu_read_flags(c), true))33373335 continue;3338333633393339- if ((flags & CON_ENABLED) && c->unblank) {33373337+ if (c->unblank) {33403338 found_unblank = true;33413339 break;33423340 }···3371337333723374 cookie = console_srcu_read_lock();33733375 for_each_console_srcu(c) {33743374- short flags = console_srcu_read_flags(c);33753375-33763376- if (flags & CON_SUSPENDED)33763376+ if (!console_is_usable(c, console_srcu_read_flags(c), true))33773377 continue;3378337833793379- if ((flags & CON_ENABLED) && c->unblank)33793379+ if (c->unblank)33803380 c->unblank();33813381 }33823382 console_srcu_read_unlock(cookie);