diff options
Diffstat (limited to 'kernel/printk/printk.c')
| -rw-r--r-- | kernel/printk/printk.c | 158 |
1 files changed, 99 insertions, 59 deletions
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 5aee9ffb16b9..1c048c66d099 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -3134,6 +3134,99 @@ static inline void printk_kthreads_check_locked(void) { } #endif /* CONFIG_PRINTK */ + +/* + * Print out one record for each console. + * + * @do_cond_resched is set by the caller. It can be true only in schedulable + * context. + * + * @next_seq is set to the sequence number after the last available record. + * The value is valid only when there is at least one usable console and all + * usable consoles were flushed. + * + * @handover will be set to true if a printk waiter has taken over the + * console_lock, in which case the caller is no longer holding the + * console_lock. Otherwise it is set to false. + * + * @any_usable will be set to true if there are any usable consoles. + * + * Returns true when there was at least one usable console and a record was + * flushed. A returned false indicates there were no records to flush for any + * of the consoles. It may also indicate that there were no usable consoles, + * the context has been lost or there is a panic suitation. Regardless the + * reason, the caller should assume it is not useful to immediately try again. + * + * Requires the console_lock. + */ +static bool console_flush_one_record(bool do_cond_resched, u64 *next_seq, bool *handover, + bool *any_usable) +{ + struct console_flush_type ft; + bool any_progress = false; + struct console *con; + int cookie; + + printk_get_console_flush_type(&ft); + + cookie = console_srcu_read_lock(); + for_each_console_srcu(con) { + short flags = console_srcu_read_flags(con); + u64 printk_seq; + bool progress; + + /* + * console_flush_one_record() is only responsible for + * nbcon consoles when the nbcon consoles cannot print via + * their atomic or threaded flushing. + */ + if ((flags & CON_NBCON) && (ft.nbcon_atomic || ft.nbcon_offload)) + continue; + + if (!console_is_usable(con, flags, !do_cond_resched)) + continue; + *any_usable = true; + + if (flags & CON_NBCON) { + progress = nbcon_legacy_emit_next_record(con, handover, cookie, + !do_cond_resched); + printk_seq = nbcon_seq_read(con); + } else { + progress = console_emit_next_record(con, handover, cookie); + printk_seq = con->seq; + } + + /* + * If a handover has occurred, the SRCU read lock + * is already released. + */ + if (*handover) + return false; + + /* Track the next of the highest seq flushed. */ + if (printk_seq > *next_seq) + *next_seq = printk_seq; + + if (!progress) + continue; + any_progress = true; + + /* Allow panic_cpu to take over the consoles safely. */ + if (panic_on_other_cpu()) + goto abandon; + + if (do_cond_resched) + cond_resched(); + } + console_srcu_read_unlock(cookie); + + return any_progress; + +abandon: + console_srcu_read_unlock(cookie); + return false; +} + /* * Print out all remaining records to all consoles. * @@ -3159,77 +3252,24 @@ static inline void printk_kthreads_check_locked(void) { } */ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handover) { - struct console_flush_type ft; bool any_usable = false; - struct console *con; bool any_progress; - int cookie; *next_seq = 0; *handover = false; do { - any_progress = false; + any_progress = console_flush_one_record(do_cond_resched, next_seq, handover, + &any_usable); - printk_get_console_flush_type(&ft); - - cookie = console_srcu_read_lock(); - for_each_console_srcu(con) { - short flags = console_srcu_read_flags(con); - u64 printk_seq; - bool progress; + if (*handover) + return false; - /* - * console_flush_all() is only responsible for nbcon - * consoles when the nbcon consoles cannot print via - * their atomic or threaded flushing. - */ - if ((flags & CON_NBCON) && (ft.nbcon_atomic || ft.nbcon_offload)) - continue; - - if (!console_is_usable(con, flags, !do_cond_resched)) - continue; - any_usable = true; - - if (flags & CON_NBCON) { - progress = nbcon_legacy_emit_next_record(con, handover, cookie, - !do_cond_resched); - printk_seq = nbcon_seq_read(con); - } else { - progress = console_emit_next_record(con, handover, cookie); - printk_seq = con->seq; - } - - /* - * If a handover has occurred, the SRCU read lock - * is already released. - */ - if (*handover) - return false; - - /* Track the next of the highest seq flushed. */ - if (printk_seq > *next_seq) - *next_seq = printk_seq; - - if (!progress) - continue; - any_progress = true; - - /* Allow panic_cpu to take over the consoles safely. */ - if (panic_on_other_cpu()) - goto abandon; - - if (do_cond_resched) - cond_resched(); - } - console_srcu_read_unlock(cookie); + if (panic_on_other_cpu()) + return false; } while (any_progress); return any_usable; - -abandon: - console_srcu_read_unlock(cookie); - return false; } static void __console_flush_and_unlock(void) |