Commit 2966bd36 authored by Petr Mladek's avatar Petr Mladek

Merge branch 'rework/nbcon-base' into for-linus

parents 86098bcd 98a04655
...@@ -156,6 +156,8 @@ static inline int con_debug_leave(void) ...@@ -156,6 +156,8 @@ static inline int con_debug_leave(void)
* /dev/kmesg which requires a larger output buffer. * /dev/kmesg which requires a larger output buffer.
* @CON_SUSPENDED: Indicates if a console is suspended. If true, the * @CON_SUSPENDED: Indicates if a console is suspended. If true, the
* printing callbacks must not be called. * printing callbacks must not be called.
* @CON_NBCON: Console can operate outside of the legacy style console_lock
* constraints.
*/ */
enum cons_flags { enum cons_flags {
CON_PRINTBUFFER = BIT(0), CON_PRINTBUFFER = BIT(0),
...@@ -166,6 +168,111 @@ enum cons_flags { ...@@ -166,6 +168,111 @@ enum cons_flags {
CON_BRL = BIT(5), CON_BRL = BIT(5),
CON_EXTENDED = BIT(6), CON_EXTENDED = BIT(6),
CON_SUSPENDED = BIT(7), CON_SUSPENDED = BIT(7),
CON_NBCON = BIT(8),
};
/**
* struct nbcon_state - console state for nbcon consoles
* @atom: Compound of the state fields for atomic operations
*
* @req_prio: The priority of a handover request
* @prio: The priority of the current owner
* @unsafe: Console is busy in a non takeover region
* @unsafe_takeover: A hostile takeover in an unsafe state happened in the
* past. The console cannot be safe until re-initialized.
* @cpu: The CPU on which the owner runs
*
* To be used for reading and preparing of the value stored in the nbcon
* state variable @console::nbcon_state.
*
* The @prio and @req_prio fields are particularly important to allow
* spin-waiting to timeout and give up without the risk of a waiter being
* assigned the lock after giving up.
*/
struct nbcon_state {
union {
unsigned int atom;
struct {
unsigned int prio : 2;
unsigned int req_prio : 2;
unsigned int unsafe : 1;
unsigned int unsafe_takeover : 1;
unsigned int cpu : 24;
};
};
};
/*
* The nbcon_state struct is used to easily create and interpret values that
* are stored in the @console::nbcon_state variable. Ensure this struct stays
* within the size boundaries of the atomic variable's underlying type in
* order to avoid any accidental truncation.
*/
static_assert(sizeof(struct nbcon_state) <= sizeof(int));
/**
* nbcon_prio - console owner priority for nbcon consoles
* @NBCON_PRIO_NONE: Unused
* @NBCON_PRIO_NORMAL: Normal (non-emergency) usage
* @NBCON_PRIO_EMERGENCY: Emergency output (WARN/OOPS...)
* @NBCON_PRIO_PANIC: Panic output
* @NBCON_PRIO_MAX: The number of priority levels
*
* A higher priority context can takeover the console when it is
* in the safe state. The final attempt to flush consoles in panic()
* can be allowed to do so even in an unsafe state (Hope and pray).
*/
enum nbcon_prio {
NBCON_PRIO_NONE = 0,
NBCON_PRIO_NORMAL,
NBCON_PRIO_EMERGENCY,
NBCON_PRIO_PANIC,
NBCON_PRIO_MAX,
};
struct console;
struct printk_buffers;
/**
* struct nbcon_context - Context for console acquire/release
* @console: The associated console
* @spinwait_max_us: Limit for spin-wait acquire
* @prio: Priority of the context
* @allow_unsafe_takeover: Allow performing takeover even if unsafe. Can
* be used only with NBCON_PRIO_PANIC @prio. It
* might cause a system freeze when the console
* is used later.
* @backlog: Ringbuffer has pending records
* @pbufs: Pointer to the text buffer for this context
* @seq: The sequence number to print for this context
*/
struct nbcon_context {
/* members set by caller */
struct console *console;
unsigned int spinwait_max_us;
enum nbcon_prio prio;
unsigned int allow_unsafe_takeover : 1;
/* members set by emit */
unsigned int backlog : 1;
/* members set by acquire */
struct printk_buffers *pbufs;
u64 seq;
};
/**
* struct nbcon_write_context - Context handed to the nbcon write callbacks
* @ctxt: The core console context
* @outbuf: Pointer to the text buffer for output
* @len: Length to write
* @unsafe_takeover: If a hostile takeover in an unsafe state has occurred
*/
struct nbcon_write_context {
struct nbcon_context __private ctxt;
char *outbuf;
unsigned int len;
bool unsafe_takeover;
}; };
/** /**
...@@ -187,6 +294,11 @@ enum cons_flags { ...@@ -187,6 +294,11 @@ enum cons_flags {
* @dropped: Number of unreported dropped ringbuffer records * @dropped: Number of unreported dropped ringbuffer records
* @data: Driver private data * @data: Driver private data
* @node: hlist node for the console list * @node: hlist node for the console list
*
* @write_atomic: Write callback for atomic context
* @nbcon_state: State for nbcon consoles
* @nbcon_seq: Sequence number of the next record for nbcon to print
* @pbufs: Pointer to nbcon private buffer
*/ */
struct console { struct console {
char name[16]; char name[16];
...@@ -206,6 +318,13 @@ struct console { ...@@ -206,6 +318,13 @@ struct console {
unsigned long dropped; unsigned long dropped;
void *data; void *data;
struct hlist_node node; struct hlist_node node;
/* nbcon console specific members */
bool (*write_atomic)(struct console *con,
struct nbcon_write_context *wctxt);
atomic_t __private nbcon_state;
atomic_long_t __private nbcon_seq;
struct printk_buffers *pbufs;
}; };
#ifdef CONFIG_LOCKDEP #ifdef CONFIG_LOCKDEP
...@@ -332,6 +451,16 @@ static inline bool console_is_registered(const struct console *con) ...@@ -332,6 +451,16 @@ static inline bool console_is_registered(const struct console *con)
lockdep_assert_console_list_lock_held(); \ lockdep_assert_console_list_lock_held(); \
hlist_for_each_entry(con, &console_list, node) hlist_for_each_entry(con, &console_list, node)
#ifdef CONFIG_PRINTK
extern bool nbcon_can_proceed(struct nbcon_write_context *wctxt);
extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt);
extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt);
#else
static inline bool nbcon_can_proceed(struct nbcon_write_context *wctxt) { return false; }
static inline bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) { return false; }
static inline bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) { return false; }
#endif
extern int console_set_on_cmdline; extern int console_set_on_cmdline;
extern struct console *early_console; extern struct console *early_console;
......
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
obj-y = printk.o obj-y = printk.o
obj-$(CONFIG_PRINTK) += printk_safe.o obj-$(CONFIG_PRINTK) += printk_safe.o nbcon.o
obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o
obj-$(CONFIG_PRINTK_INDEX) += index.o obj-$(CONFIG_PRINTK_INDEX) += index.o
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
* internal.h - printk internal definitions * internal.h - printk internal definitions
*/ */
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/console.h>
#include "printk_ringbuffer.h"
#if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL) #if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL)
void __init printk_sysctl_init(void); void __init printk_sysctl_init(void);
...@@ -12,6 +14,12 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write, ...@@ -12,6 +14,12 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write,
#define printk_sysctl_init() do { } while (0) #define printk_sysctl_init() do { } while (0)
#endif #endif
#define con_printk(lvl, con, fmt, ...) \
printk(lvl pr_fmt("%s%sconsole [%s%d] " fmt), \
(con->flags & CON_NBCON) ? "" : "legacy ", \
(con->flags & CON_BOOT) ? "boot" : "", \
con->name, con->index, ##__VA_ARGS__)
#ifdef CONFIG_PRINTK #ifdef CONFIG_PRINTK
#ifdef CONFIG_PRINTK_CALLER #ifdef CONFIG_PRINTK_CALLER
...@@ -35,6 +43,8 @@ enum printk_info_flags { ...@@ -35,6 +43,8 @@ enum printk_info_flags {
LOG_CONT = 8, /* text is a fragment of a continuation line */ LOG_CONT = 8, /* text is a fragment of a continuation line */
}; };
extern struct printk_ringbuffer *prb;
__printf(4, 0) __printf(4, 0)
int vprintk_store(int facility, int level, int vprintk_store(int facility, int level,
const struct dev_printk_info *dev_info, const struct dev_printk_info *dev_info,
...@@ -61,6 +71,13 @@ void defer_console_output(void); ...@@ -61,6 +71,13 @@ void defer_console_output(void);
u16 printk_parse_prefix(const char *text, int *level, u16 printk_parse_prefix(const char *text, int *level,
enum printk_info_flags *flags); enum printk_info_flags *flags);
u64 nbcon_seq_read(struct console *con);
void nbcon_seq_force(struct console *con, u64 seq);
bool nbcon_alloc(struct console *con);
void nbcon_init(struct console *con);
void nbcon_free(struct console *con);
#else #else
#define PRINTK_PREFIX_MAX 0 #define PRINTK_PREFIX_MAX 0
...@@ -76,8 +93,16 @@ u16 printk_parse_prefix(const char *text, int *level, ...@@ -76,8 +93,16 @@ u16 printk_parse_prefix(const char *text, int *level,
#define printk_safe_exit_irqrestore(flags) local_irq_restore(flags) #define printk_safe_exit_irqrestore(flags) local_irq_restore(flags)
static inline bool printk_percpu_data_ready(void) { return false; } static inline bool printk_percpu_data_ready(void) { return false; }
static inline u64 nbcon_seq_read(struct console *con) { return 0; }
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_init(struct console *con) { }
static inline void nbcon_free(struct console *con) { }
#endif /* CONFIG_PRINTK */ #endif /* CONFIG_PRINTK */
extern struct printk_buffers printk_shared_pbufs;
/** /**
* struct printk_buffers - Buffers to read/format/output printk messages. * struct printk_buffers - Buffers to read/format/output printk messages.
* @outbuf: After formatting, contains text to output. * @outbuf: After formatting, contains text to output.
...@@ -105,3 +130,9 @@ struct printk_message { ...@@ -105,3 +130,9 @@ struct printk_message {
}; };
bool other_cpu_in_panic(void); bool other_cpu_in_panic(void);
bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
bool is_extended, bool may_supress);
#ifdef CONFIG_PRINTK
void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped);
#endif
This diff is collapsed.
...@@ -102,12 +102,6 @@ DEFINE_STATIC_SRCU(console_srcu); ...@@ -102,12 +102,6 @@ DEFINE_STATIC_SRCU(console_srcu);
*/ */
int __read_mostly suppress_printk; int __read_mostly suppress_printk;
/*
* During panic, heavy printk by other CPUs can delay the
* panic and risk deadlock on console resources.
*/
static int __read_mostly suppress_panic_printk;
#ifdef CONFIG_LOCKDEP #ifdef CONFIG_LOCKDEP
static struct lockdep_map console_lock_dep_map = { static struct lockdep_map console_lock_dep_map = {
.name = "console_lock" .name = "console_lock"
...@@ -445,6 +439,12 @@ static int console_msg_format = MSG_FORMAT_DEFAULT; ...@@ -445,6 +439,12 @@ static int console_msg_format = MSG_FORMAT_DEFAULT;
static DEFINE_MUTEX(syslog_lock); static DEFINE_MUTEX(syslog_lock);
#ifdef CONFIG_PRINTK #ifdef CONFIG_PRINTK
/*
* During panic, heavy printk by other CPUs can delay the
* panic and risk deadlock on console resources.
*/
static int __read_mostly suppress_panic_printk;
DECLARE_WAIT_QUEUE_HEAD(log_wait); DECLARE_WAIT_QUEUE_HEAD(log_wait);
/* All 3 protected by @syslog_lock. */ /* All 3 protected by @syslog_lock. */
/* the next printk record to read by syslog(READ) or /proc/kmsg */ /* the next printk record to read by syslog(READ) or /proc/kmsg */
...@@ -494,7 +494,7 @@ _DEFINE_PRINTKRB(printk_rb_static, CONFIG_LOG_BUF_SHIFT - PRB_AVGBITS, ...@@ -494,7 +494,7 @@ _DEFINE_PRINTKRB(printk_rb_static, CONFIG_LOG_BUF_SHIFT - PRB_AVGBITS,
static struct printk_ringbuffer printk_rb_dynamic; static struct printk_ringbuffer printk_rb_dynamic;
static struct printk_ringbuffer *prb = &printk_rb_static; struct printk_ringbuffer *prb = &printk_rb_static;
/* /*
* We cannot access per-CPU data (e.g. per-CPU flush irq_work) before * We cannot access per-CPU data (e.g. per-CPU flush irq_work) before
...@@ -698,9 +698,6 @@ static ssize_t msg_print_ext_body(char *buf, size_t size, ...@@ -698,9 +698,6 @@ static ssize_t msg_print_ext_body(char *buf, size_t size,
return len; return len;
} }
static bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
bool is_extended, bool may_supress);
/* /dev/kmsg - userspace message inject/listen interface */ /* /dev/kmsg - userspace message inject/listen interface */
struct devkmsg_user { struct devkmsg_user {
atomic64_t seq; atomic64_t seq;
...@@ -2348,22 +2345,6 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre ...@@ -2348,22 +2345,6 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
static u64 syslog_seq; static u64 syslog_seq;
static size_t record_print_text(const struct printk_record *r,
bool syslog, bool time)
{
return 0;
}
static ssize_t info_print_ext_header(char *buf, size_t size,
struct printk_info *info)
{
return 0;
}
static ssize_t msg_print_ext_body(char *buf, size_t size,
char *text, size_t text_len,
struct dev_printk_info *dev_info) { return 0; }
static void console_lock_spinning_enable(void) { }
static int console_lock_spinning_disable_and_check(int cookie) { return 0; }
static bool suppress_message_printing(int level) { return false; }
static bool pr_flush(int timeout_ms, bool reset_on_progress) { return true; } static bool pr_flush(int timeout_ms, bool reset_on_progress) { return true; }
static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress) { return true; } static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress) { return true; }
...@@ -2717,6 +2698,8 @@ static void __console_unlock(void) ...@@ -2717,6 +2698,8 @@ static void __console_unlock(void)
up_console_sem(); up_console_sem();
} }
#ifdef CONFIG_PRINTK
/* /*
* Prepend the message in @pmsg->pbufs->outbuf with a "dropped message". This * Prepend the message in @pmsg->pbufs->outbuf with a "dropped message". This
* is achieved by shifting the existing message over and inserting the dropped * is achieved by shifting the existing message over and inserting the dropped
...@@ -2731,8 +2714,7 @@ static void __console_unlock(void) ...@@ -2731,8 +2714,7 @@ static void __console_unlock(void)
* *
* If @pmsg->pbufs->outbuf is modified, @pmsg->outbuf_len is updated. * If @pmsg->pbufs->outbuf is modified, @pmsg->outbuf_len is updated.
*/ */
#ifdef CONFIG_PRINTK void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped)
static void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped)
{ {
struct printk_buffers *pbufs = pmsg->pbufs; struct printk_buffers *pbufs = pmsg->pbufs;
const size_t scratchbuf_sz = sizeof(pbufs->scratchbuf); const size_t scratchbuf_sz = sizeof(pbufs->scratchbuf);
...@@ -2763,9 +2745,6 @@ static void console_prepend_dropped(struct printk_message *pmsg, unsigned long d ...@@ -2763,9 +2745,6 @@ static void console_prepend_dropped(struct printk_message *pmsg, unsigned long d
memcpy(outbuf, scratchbuf, len); memcpy(outbuf, scratchbuf, len);
pmsg->outbuf_len += len; pmsg->outbuf_len += len;
} }
#else
#define console_prepend_dropped(pmsg, dropped)
#endif /* CONFIG_PRINTK */
/* /*
* Read and format the specified record (or a later record if the specified * Read and format the specified record (or a later record if the specified
...@@ -2786,8 +2765,8 @@ static void console_prepend_dropped(struct printk_message *pmsg, unsigned long d ...@@ -2786,8 +2765,8 @@ static void console_prepend_dropped(struct printk_message *pmsg, unsigned long d
* of @pmsg are valid. (See the documentation of struct printk_message * of @pmsg are valid. (See the documentation of struct printk_message
* for information about the @pmsg fields.) * for information about the @pmsg fields.)
*/ */
static bool printk_get_next_message(struct printk_message *pmsg, u64 seq, bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
bool is_extended, bool may_suppress) bool is_extended, bool may_suppress)
{ {
static int panic_console_dropped; static int panic_console_dropped;
...@@ -2845,6 +2824,13 @@ static bool printk_get_next_message(struct printk_message *pmsg, u64 seq, ...@@ -2845,6 +2824,13 @@ static bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
return true; return true;
} }
/*
* Used as the printk buffers for non-panic, serialized console printing.
* This is for legacy (!CON_NBCON) as well as all boot (CON_BOOT) consoles.
* Its usage requires the console_lock held.
*/
struct printk_buffers printk_shared_pbufs;
/* /*
* Print one record for the given console. The record printed is whatever * Print one record for the given console. The record printed is whatever
* record is the next available record for the given console. * record is the next available record for the given console.
...@@ -2862,12 +2848,10 @@ static bool printk_get_next_message(struct printk_message *pmsg, u64 seq, ...@@ -2862,12 +2848,10 @@ static bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
*/ */
static bool console_emit_next_record(struct console *con, bool *handover, int cookie) static bool console_emit_next_record(struct console *con, bool *handover, int cookie)
{ {
static struct printk_buffers pbufs;
bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED; bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
char *outbuf = &pbufs.outbuf[0]; char *outbuf = &printk_shared_pbufs.outbuf[0];
struct printk_message pmsg = { struct printk_message pmsg = {
.pbufs = &pbufs, .pbufs = &printk_shared_pbufs,
}; };
unsigned long flags; unsigned long flags;
...@@ -2918,6 +2902,16 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co ...@@ -2918,6 +2902,16 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
return true; return true;
} }
#else
static bool console_emit_next_record(struct console *con, bool *handover, int cookie)
{
*handover = false;
return false;
}
#endif /* CONFIG_PRINTK */
/* /*
* Print out all remaining records to all consoles. * Print out all remaining records to all consoles.
* *
...@@ -3162,6 +3156,7 @@ void console_flush_on_panic(enum con_flush_mode mode) ...@@ -3162,6 +3156,7 @@ void console_flush_on_panic(enum con_flush_mode mode)
if (mode == CONSOLE_REPLAY_ALL) { if (mode == CONSOLE_REPLAY_ALL) {
struct console *c; struct console *c;
short flags;
int cookie; int cookie;
u64 seq; u64 seq;
...@@ -3169,11 +3164,17 @@ void console_flush_on_panic(enum con_flush_mode mode) ...@@ -3169,11 +3164,17 @@ void console_flush_on_panic(enum con_flush_mode mode)
cookie = console_srcu_read_lock(); cookie = console_srcu_read_lock();
for_each_console_srcu(c) { for_each_console_srcu(c) {
/* flags = console_srcu_read_flags(c);
* This is an unsynchronized assignment, but the
* kernel is in "hope and pray" mode anyway. if (flags & CON_NBCON) {
*/ nbcon_seq_force(c, seq);
c->seq = seq; } else {
/*
* This is an unsynchronized assignment. On
* panic legacy consoles are only best effort.
*/
c->seq = seq;
}
} }
console_srcu_read_unlock(cookie); console_srcu_read_unlock(cookie);
} }
...@@ -3325,11 +3326,6 @@ static void try_enable_default_console(struct console *newcon) ...@@ -3325,11 +3326,6 @@ static void try_enable_default_console(struct console *newcon)
newcon->flags |= CON_CONSDEV; newcon->flags |= CON_CONSDEV;
} }
#define con_printk(lvl, con, fmt, ...) \
printk(lvl pr_fmt("%sconsole [%s%d] " fmt), \
(con->flags & CON_BOOT) ? "boot" : "", \
con->name, con->index, ##__VA_ARGS__)
static void console_init_seq(struct console *newcon, bool bootcon_registered) static void console_init_seq(struct console *newcon, bool bootcon_registered)
{ {
struct console *con; struct console *con;
...@@ -3443,6 +3439,15 @@ void register_console(struct console *newcon) ...@@ -3443,6 +3439,15 @@ void register_console(struct console *newcon)
goto unlock; goto unlock;
} }
if (newcon->flags & CON_NBCON) {
/*
* Ensure the nbcon console buffers can be allocated
* before modifying any global data.
*/
if (!nbcon_alloc(newcon))
goto unlock;
}
/* /*
* See if we want to enable this console driver by default. * See if we want to enable this console driver by default.
* *
...@@ -3470,8 +3475,11 @@ void register_console(struct console *newcon) ...@@ -3470,8 +3475,11 @@ void register_console(struct console *newcon)
err = try_enable_preferred_console(newcon, false); err = try_enable_preferred_console(newcon, false);
/* printk() messages are not printed to the Braille console. */ /* printk() messages are not printed to the Braille console. */
if (err || newcon->flags & CON_BRL) if (err || newcon->flags & CON_BRL) {
if (newcon->flags & CON_NBCON)
nbcon_free(newcon);
goto unlock; goto unlock;
}
/* /*
* If we have a bootconsole, and are switching to a real console, * If we have a bootconsole, and are switching to a real console,
...@@ -3487,6 +3495,9 @@ void register_console(struct console *newcon) ...@@ -3487,6 +3495,9 @@ void register_console(struct console *newcon)
newcon->dropped = 0; newcon->dropped = 0;
console_init_seq(newcon, bootcon_registered); console_init_seq(newcon, bootcon_registered);
if (newcon->flags & CON_NBCON)
nbcon_init(newcon);
/* /*
* Put this console in the list - keep the * Put this console in the list - keep the
* preferred driver at the head of the list. * preferred driver at the head of the list.
...@@ -3578,6 +3589,9 @@ static int unregister_console_locked(struct console *console) ...@@ -3578,6 +3589,9 @@ static int unregister_console_locked(struct console *console)
*/ */
synchronize_srcu(&console_srcu); synchronize_srcu(&console_srcu);
if (console->flags & CON_NBCON)
nbcon_free(console);
console_sysfs_notify(); console_sysfs_notify();
if (console->exit) if (console->exit)
...@@ -3732,6 +3746,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre ...@@ -3732,6 +3746,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
struct console *c; struct console *c;
u64 last_diff = 0; u64 last_diff = 0;
u64 printk_seq; u64 printk_seq;
short flags;
int cookie; int cookie;
u64 diff; u64 diff;
u64 seq; u64 seq;
...@@ -3762,6 +3777,9 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre ...@@ -3762,6 +3777,9 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
for_each_console_srcu(c) { for_each_console_srcu(c) {
if (con && con != c) if (con && con != c)
continue; continue;
flags = console_srcu_read_flags(c);
/* /*
* If consoles are not usable, it cannot be expected * If consoles are not usable, it cannot be expected
* that they make forward progress, so only increment * that they make forward progress, so only increment
...@@ -3769,7 +3787,13 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre ...@@ -3769,7 +3787,13 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
*/ */
if (!console_is_usable(c)) if (!console_is_usable(c))
continue; continue;
printk_seq = c->seq;
if (flags & CON_NBCON) {
printk_seq = nbcon_seq_read(c);
} else {
printk_seq = c->seq;
}
if (printk_seq < seq) if (printk_seq < seq)
diff += seq - printk_seq; diff += seq - printk_seq;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment