Commit 2d786a5b authored by Petr Mladek's avatar Petr Mladek
Browse files

Merge branch 'rework/nbcon-in-kdb' into for-linus

parents 475bb520 466348ab
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ static void kmsg_dumper_stdout(struct kmsg_dumper *dumper,
		 * expected to output the crash information.
		 */
		if (strcmp(con->name, "ttynull") != 0 &&
		    (console_srcu_read_flags(con) & CON_ENABLED)) {
		    console_is_usable(con, console_srcu_read_flags(con), true)) {
			break;
		}
	}
+0 −1
Original line number Diff line number Diff line
@@ -577,7 +577,6 @@ static int __init kgdboc_earlycon_init(char *opt)
	console_list_lock();
	for_each_console(con) {
		if (con->write && con->read &&
		    (con->flags & (CON_BOOT | CON_ENABLED)) &&
		    (!opt || !opt[0] || strcmp(con->name, opt) == 0))
			break;
	}
+55 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/irq_work.h>
#include <linux/rculist.h>
#include <linux/rcuwait.h>
#include <linux/smp.h>
#include <linux/types.h>
#include <linux/vesa.h>

@@ -602,16 +603,70 @@ static inline bool console_is_registered(const struct console *con)
extern void nbcon_cpu_emergency_enter(void);
extern void nbcon_cpu_emergency_exit(void);
extern bool nbcon_can_proceed(struct nbcon_write_context *wctxt);
extern void nbcon_write_context_set_buf(struct nbcon_write_context *wctxt,
					char *buf, unsigned int len);
extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt);
extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt);
extern void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt);
extern bool nbcon_kdb_try_acquire(struct console *con,
				  struct nbcon_write_context *wctxt);
extern void nbcon_kdb_release(struct nbcon_write_context *wctxt);

/*
 * Check if the given console is currently capable and allowed to print
 * records. Note that this function does not consider the current context,
 * which can also play a role in deciding if @con can be used to print
 * records.
 */
static inline bool console_is_usable(struct console *con, short flags, bool use_atomic)
{
	if (!(flags & CON_ENABLED))
		return false;

	if ((flags & CON_SUSPENDED))
		return false;

	if (flags & CON_NBCON) {
		/* The write_atomic() callback is optional. */
		if (use_atomic && !con->write_atomic)
			return false;

		/*
		 * For the !use_atomic case, @printk_kthreads_running is not
		 * checked because the write_thread() callback is also used
		 * via the legacy loop when the printer threads are not
		 * available.
		 */
	} else {
		if (!con->write)
			return false;
	}

	/*
	 * Console drivers may assume that per-cpu resources have been
	 * allocated. So unless they're explicitly marked as being able to
	 * cope (CON_ANYTIME) don't call them until this CPU is officially up.
	 */
	if (!cpu_online(raw_smp_processor_id()) && !(flags & CON_ANYTIME))
		return false;

	return true;
}

#else
static inline void nbcon_cpu_emergency_enter(void) { }
static inline void nbcon_cpu_emergency_exit(void) { }
static inline bool nbcon_can_proceed(struct nbcon_write_context *wctxt) { return false; }
static inline void nbcon_write_context_set_buf(struct nbcon_write_context *wctxt,
					       char *buf, unsigned int len) { }
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; }
static inline void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt) { }
static inline bool nbcon_kdb_try_acquire(struct console *con,
					 struct nbcon_write_context *wctxt) { return false; }
static inline void nbcon_kdb_release(struct nbcon_write_context *wctxt) { }
static inline bool console_is_usable(struct console *con, short flags,
				     bool use_atomic) { return false; }
#endif

extern int console_set_on_cmdline;
+16 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
 */

#include <linux/list.h>
#include <linux/smp.h>

/* Shifted versions of the command enable bits are be used if the command
 * has no arguments (see kdb_check_flags). This allows commands, such as
@@ -207,11 +208,26 @@ static inline const char *kdb_walk_kallsyms(loff_t *pos)
/* Dynamic kdb shell command registration */
extern int kdb_register(kdbtab_t *cmd);
extern void kdb_unregister(kdbtab_t *cmd);

/* Return true when KDB as locked for printing a message on this CPU. */
static inline
bool kdb_printf_on_this_cpu(void)
{
	/*
	 * We can use raw_smp_processor_id() here because the task could
	 * not get migrated when KDB has locked for printing on this CPU.
	 */
	return unlikely(READ_ONCE(kdb_printf_cpu) == raw_smp_processor_id());
}

#else /* ! CONFIG_KGDB_KDB */
static inline __printf(1, 2) int kdb_printf(const char *fmt, ...) { return 0; }
static inline void kdb_init(int level) {}
static inline int kdb_register(kdbtab_t *cmd) { return 0; }
static inline void kdb_unregister(kdbtab_t *cmd) {}

static inline bool kdb_printf_on_this_cpu(void) { return false; }

#endif	/* CONFIG_KGDB_KDB */
enum {
	KDB_NOT_INITIALIZED,
+32 −15
Original line number Diff line number Diff line
@@ -589,12 +589,28 @@ static void kdb_msg_write(const char *msg, int msg_len)
	 */
	cookie = console_srcu_read_lock();
	for_each_console_srcu(c) {
		if (!(console_srcu_read_flags(c) & CON_ENABLED))
		short flags = console_srcu_read_flags(c);

		if (!console_is_usable(c, flags, true))
			continue;
		if (c == dbg_io_ops->cons)
			continue;
		if (!c->write)

		if (flags & CON_NBCON) {
			struct nbcon_write_context wctxt = { };

			/*
			 * Do not continue if the console is NBCON and the context
			 * can't be acquired.
			 */
			if (!nbcon_kdb_try_acquire(c, &wctxt))
				continue;

			nbcon_write_context_set_buf(&wctxt, (char *)msg, msg_len);

			c->write_atomic(c, &wctxt);
			nbcon_kdb_release(&wctxt);
		} else {
			/*
			 * Set oops_in_progress to encourage the console drivers to
			 * disregard their internal spin locks: in the current calling
@@ -607,6 +623,7 @@ static void kdb_msg_write(const char *msg, int msg_len)
			++oops_in_progress;
			c->write(c, msg, msg_len);
			--oops_in_progress;
		}
		touch_nmi_watchdog();
	}
	console_srcu_read_unlock(cookie);
Loading