···186186 * printing callbacks must not be called.187187 * @CON_NBCON: Console can operate outside of the legacy style console_lock188188 * constraints.189189+ * @CON_NBCON_ATOMIC_UNSAFE: The write_atomic() callback is not safe and is190190+ * therefore only used by nbcon_atomic_flush_unsafe().189191 */190192enum cons_flags {191193 CON_PRINTBUFFER = BIT(0),···199197 CON_EXTENDED = BIT(6),200198 CON_SUSPENDED = BIT(7),201199 CON_NBCON = BIT(8),200200+ CON_NBCON_ATOMIC_UNSAFE = BIT(9),202201};203202204203/**···611608extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt);612609extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt);613610extern void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt);611611+extern bool nbcon_allow_unsafe_takeover(void);614612extern bool nbcon_kdb_try_acquire(struct console *con,615613 struct nbcon_write_context *wctxt);616614extern void nbcon_kdb_release(struct nbcon_write_context *wctxt);···631627 return false;632628633629 if (flags & CON_NBCON) {634634- /* The write_atomic() callback is optional. */635635- if (use_atomic && !con->write_atomic)636636- return false;630630+ if (use_atomic) {631631+ /* The write_atomic() callback is optional. */632632+ if (!con->write_atomic)633633+ return false;634634+635635+ /*636636+ * An unsafe write_atomic() callback is only usable637637+ * when unsafe takeovers are allowed.638638+ */639639+ if ((flags & CON_NBCON_ATOMIC_UNSAFE) && !nbcon_allow_unsafe_takeover())640640+ return false;641641+ }637642638643 /*639644 * For the !use_atomic case, @printk_kthreads_running is not
+32-15
kernel/printk/nbcon.c
···14371437 return NBCON_PRIO_NORMAL;14381438}1439143914401440+/*14411441+ * Track if it is allowed to perform unsafe hostile takeovers of console14421442+ * ownership. When true, console drivers might perform unsafe actions while14431443+ * printing. It is externally available via nbcon_allow_unsafe_takeover().14441444+ */14451445+static bool panic_nbcon_allow_unsafe_takeover;14461446+14471447+/**14481448+ * nbcon_allow_unsafe_takeover - Check if unsafe console takeovers are allowed14491449+ *14501450+ * Return: True, when it is permitted to perform unsafe console printing14511451+ *14521452+ * This is also used by console_is_usable() to determine if it is allowed to14531453+ * call write_atomic() callbacks flagged as unsafe (CON_NBCON_ATOMIC_UNSAFE).14541454+ */14551455+bool nbcon_allow_unsafe_takeover(void)14561456+{14571457+ return panic_on_this_cpu() && panic_nbcon_allow_unsafe_takeover;14581458+}14591459+14401460/**14411461 * nbcon_legacy_emit_next_record - Print one record for an nbcon console14421462 * in legacy contexts···15271507 * write_atomic() callback15281508 * @con: The nbcon console to flush15291509 * @stop_seq: Flush up until this record15301530- * @allow_unsafe_takeover: True, to allow unsafe hostile takeovers15311510 *15321511 * Return: 0 if @con was flushed up to @stop_seq Otherwise, error code on15331512 * failure.···15451526 * returned, it cannot be expected that the unfinalized record will become15461527 * available.15471528 */15481548-static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,15491549- bool allow_unsafe_takeover)15291529+static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)15501530{15511531 struct nbcon_write_context wctxt = { };15521532 struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);···15541536 ctxt->console = con;15551537 ctxt->spinwait_max_us = 2000;15561538 ctxt->prio = nbcon_get_default_prio();15571557- ctxt->allow_unsafe_takeover = allow_unsafe_takeover;15391539+ ctxt->allow_unsafe_takeover = nbcon_allow_unsafe_takeover();1558154015591541 while (nbcon_seq_read(con) < stop_seq) {15601542 if (!nbcon_context_try_acquire(ctxt, false))···15861568 * write_atomic() callback15871569 * @con: The nbcon console to flush15881570 * @stop_seq: Flush up until this record15891589- * @allow_unsafe_takeover: True, to allow unsafe hostile takeovers15901571 *15911572 * This will stop flushing before @stop_seq if another context has ownership.15921573 * That context is then responsible for the flushing. Likewise, if new records15931574 * are added while this context was flushing and there is no other context15941575 * to handle the printing, this context must also flush those records.15951576 */15961596-static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,15971597- bool allow_unsafe_takeover)15771577+static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)15981578{15991579 struct console_flush_type ft;16001580 unsigned long flags;···16071591 */16081592 local_irq_save(flags);1609159316101610- err = __nbcon_atomic_flush_pending_con(con, stop_seq, allow_unsafe_takeover);15941594+ err = __nbcon_atomic_flush_pending_con(con, stop_seq);1611159516121596 local_irq_restore(flags);16131597···16391623 * __nbcon_atomic_flush_pending - Flush all nbcon consoles using their16401624 * write_atomic() callback16411625 * @stop_seq: Flush up until this record16421642- * @allow_unsafe_takeover: True, to allow unsafe hostile takeovers16431626 */16441644-static void __nbcon_atomic_flush_pending(u64 stop_seq, bool allow_unsafe_takeover)16271627+static void __nbcon_atomic_flush_pending(u64 stop_seq)16451628{16461629 struct console *con;16471630 int cookie;···16581643 if (nbcon_seq_read(con) >= stop_seq)16591644 continue;1660164516611661- nbcon_atomic_flush_pending_con(con, stop_seq, allow_unsafe_takeover);16461646+ nbcon_atomic_flush_pending_con(con, stop_seq);16621647 }16631648 console_srcu_read_unlock(cookie);16641649}···16741659 */16751660void nbcon_atomic_flush_pending(void)16761661{16771677- __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), false);16621662+ __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb));16781663}1679166416801665/**···16861671 */16871672void nbcon_atomic_flush_unsafe(void)16881673{16891689- __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), true);16741674+ panic_nbcon_allow_unsafe_takeover = true;16751675+ __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb));16761676+ panic_nbcon_allow_unsafe_takeover = false;16901677}1691167816921679/**···19111894 * using the legacy loop.19121895 */19131896 if (ft.nbcon_atomic) {19141914- __nbcon_atomic_flush_pending_con(con, prb_next_reserve_seq(prb), false);18971897+ __nbcon_atomic_flush_pending_con(con, prb_next_reserve_seq(prb));19151898 } else if (ft.legacy_direct) {19161899 if (console_trylock())19171900 console_unlock();···19811964 * The console was locked only when the write_atomic() callback19821965 * was usable.19831966 */19841984- __nbcon_atomic_flush_pending_con(ctxt->console, prb_next_reserve_seq(prb), false);19671967+ __nbcon_atomic_flush_pending_con(ctxt->console, prb_next_reserve_seq(prb));19851968}