···3134313431353135#endif /* CONFIG_PRINTK */3136313631373137+31383138+/*31393139+ * Print out one record for each console.31403140+ *31413141+ * @do_cond_resched is set by the caller. It can be true only in schedulable31423142+ * context.31433143+ *31443144+ * @next_seq is set to the sequence number after the last available record.31453145+ * The value is valid only when all usable consoles were flushed. It is31463146+ * when the function returns true (can do the job) and @try_again parameter31473147+ * is set to false, see below.31483148+ *31493149+ * @handover will be set to true if a printk waiter has taken over the31503150+ * console_lock, in which case the caller is no longer holding the31513151+ * console_lock. Otherwise it is set to false.31523152+ *31533153+ * @try_again will be set to true when it still makes sense to call this31543154+ * function again. The function could do the job, see the return value.31553155+ * And some consoles still make progress.31563156+ *31573157+ * Returns true when the function could do the job. Some consoles are usable,31583158+ * and there was no takeover and no panic_on_other_cpu().31593159+ *31603160+ * Requires the console_lock.31613161+ */31623162+static bool console_flush_one_record(bool do_cond_resched, u64 *next_seq, bool *handover,31633163+ bool *try_again)31643164+{31653165+ struct console_flush_type ft;31663166+ bool any_usable = false;31673167+ struct console *con;31683168+ int cookie;31693169+31703170+ *try_again = false;31713171+31723172+ printk_get_console_flush_type(&ft);31733173+31743174+ cookie = console_srcu_read_lock();31753175+ for_each_console_srcu(con) {31763176+ short flags = console_srcu_read_flags(con);31773177+ u64 printk_seq;31783178+ bool progress;31793179+31803180+ /*31813181+ * console_flush_one_record() is only responsible for31823182+ * nbcon consoles when the nbcon consoles cannot print via31833183+ * their atomic or threaded flushing.31843184+ */31853185+ if ((flags & CON_NBCON) && (ft.nbcon_atomic || ft.nbcon_offload))31863186+ continue;31873187+31883188+ if (!console_is_usable(con, flags, !do_cond_resched))31893189+ continue;31903190+ any_usable = true;31913191+31923192+ if (flags & CON_NBCON) {31933193+ progress = nbcon_legacy_emit_next_record(con, handover, cookie,31943194+ !do_cond_resched);31953195+ printk_seq = nbcon_seq_read(con);31963196+ } else {31973197+ progress = console_emit_next_record(con, handover, cookie);31983198+ printk_seq = con->seq;31993199+ }32003200+32013201+ /*32023202+ * If a handover has occurred, the SRCU read lock32033203+ * is already released.32043204+ */32053205+ if (*handover)32063206+ goto fail;32073207+32083208+ /* Track the next of the highest seq flushed. */32093209+ if (printk_seq > *next_seq)32103210+ *next_seq = printk_seq;32113211+32123212+ if (!progress)32133213+ continue;32143214+32153215+ /*32163216+ * An usable console made a progress. There might still be32173217+ * pending messages.32183218+ */32193219+ *try_again = true;32203220+32213221+ /* Allow panic_cpu to take over the consoles safely. */32223222+ if (panic_on_other_cpu())32233223+ goto fail_srcu;32243224+32253225+ if (do_cond_resched)32263226+ cond_resched();32273227+ }32283228+ console_srcu_read_unlock(cookie);32293229+32303230+ return any_usable;32313231+32323232+fail_srcu:32333233+ console_srcu_read_unlock(cookie);32343234+fail:32353235+ *try_again = false;32363236+ return false;32373237+}32383238+31373239/*31383240 * Print out all remaining records to all consoles.31393241 *···32613159 */32623160static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handover)32633161{32643264- struct console_flush_type ft;32653265- bool any_usable = false;32663266- struct console *con;32673267- bool any_progress;32683268- int cookie;31623162+ bool try_again;31633163+ bool ret;3269316432703165 *next_seq = 0;32713166 *handover = false;3272316732733168 do {32743274- any_progress = false;31693169+ ret = console_flush_one_record(do_cond_resched, next_seq,31703170+ handover, &try_again);31713171+ } while (try_again);3275317232763276- printk_get_console_flush_type(&ft);32773277-32783278- cookie = console_srcu_read_lock();32793279- for_each_console_srcu(con) {32803280- short flags = console_srcu_read_flags(con);32813281- u64 printk_seq;32823282- bool progress;32833283-32843284- /*32853285- * console_flush_all() is only responsible for nbcon32863286- * consoles when the nbcon consoles cannot print via32873287- * their atomic or threaded flushing.32883288- */32893289- if ((flags & CON_NBCON) && (ft.nbcon_atomic || ft.nbcon_offload))32903290- continue;32913291-32923292- if (!console_is_usable(con, flags, !do_cond_resched))32933293- continue;32943294- any_usable = true;32953295-32963296- if (flags & CON_NBCON) {32973297- progress = nbcon_legacy_emit_next_record(con, handover, cookie,32983298- !do_cond_resched);32993299- printk_seq = nbcon_seq_read(con);33003300- } else {33013301- progress = console_emit_next_record(con, handover, cookie);33023302- printk_seq = con->seq;33033303- }33043304-33053305- /*33063306- * If a handover has occurred, the SRCU read lock33073307- * is already released.33083308- */33093309- if (*handover)33103310- return false;33113311-33123312- /* Track the next of the highest seq flushed. */33133313- if (printk_seq > *next_seq)33143314- *next_seq = printk_seq;33153315-33163316- if (!progress)33173317- continue;33183318- any_progress = true;33193319-33203320- /* Allow panic_cpu to take over the consoles safely. */33213321- if (panic_on_other_cpu())33223322- goto abandon;33233323-33243324- if (do_cond_resched)33253325- cond_resched();33263326- }33273327- console_srcu_read_unlock(cookie);33283328- } while (any_progress);33293329-33303330- return any_usable;33313331-33323332-abandon:33333333- console_srcu_read_unlock(cookie);33343334- return false;31733173+ return ret;33353174}3336317533373176static void __console_flush_and_unlock(void)···3640359736413598static int legacy_kthread_func(void *unused)36423599{36433643- for (;;) {36443644- wait_event_interruptible(legacy_wait, legacy_kthread_should_wakeup());36003600+ bool try_again;36013601+36023602+wait_for_event:36033603+ wait_event_interruptible(legacy_wait, legacy_kthread_should_wakeup());36043604+36053605+ do {36063606+ bool handover = false;36073607+ u64 next_seq = 0;3645360836463609 if (kthread_should_stop())36473647- break;36103610+ return 0;3648361136493612 console_lock();36503650- __console_flush_and_unlock();36513651- }36133613+ console_flush_one_record(true, &next_seq, &handover, &try_again);36143614+ if (!handover)36153615+ __console_unlock();3652361636533653- return 0;36173617+ } while (try_again);36183618+36193619+ goto wait_for_event;36543620}3655362136563622static bool legacy_kthread_create(void)