Skip to content

Commit 2d786a5

Browse files
committed
Merge branch 'rework/nbcon-in-kdb' into for-linus
2 parents 475bb52 + 466348a commit 2d786a5

8 files changed

Lines changed: 176 additions & 73 deletions

File tree

arch/um/kernel/kmsg_dump.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ static void kmsg_dumper_stdout(struct kmsg_dumper *dumper,
3131
* expected to output the crash information.
3232
*/
3333
if (strcmp(con->name, "ttynull") != 0 &&
34-
(console_srcu_read_flags(con) & CON_ENABLED)) {
34+
console_is_usable(con, console_srcu_read_flags(con), true)) {
3535
break;
3636
}
3737
}

drivers/tty/serial/kgdboc.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,6 @@ static int __init kgdboc_earlycon_init(char *opt)
577577
console_list_lock();
578578
for_each_console(con) {
579579
if (con->write && con->read &&
580-
(con->flags & (CON_BOOT | CON_ENABLED)) &&
581580
(!opt || !opt[0] || strcmp(con->name, opt) == 0))
582581
break;
583582
}

include/linux/console.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/irq_work.h>
2020
#include <linux/rculist.h>
2121
#include <linux/rcuwait.h>
22+
#include <linux/smp.h>
2223
#include <linux/types.h>
2324
#include <linux/vesa.h>
2425

@@ -602,16 +603,70 @@ static inline bool console_is_registered(const struct console *con)
602603
extern void nbcon_cpu_emergency_enter(void);
603604
extern void nbcon_cpu_emergency_exit(void);
604605
extern bool nbcon_can_proceed(struct nbcon_write_context *wctxt);
606+
extern void nbcon_write_context_set_buf(struct nbcon_write_context *wctxt,
607+
char *buf, unsigned int len);
605608
extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt);
606609
extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt);
607610
extern void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt);
611+
extern bool nbcon_kdb_try_acquire(struct console *con,
612+
struct nbcon_write_context *wctxt);
613+
extern void nbcon_kdb_release(struct nbcon_write_context *wctxt);
614+
615+
/*
616+
* Check if the given console is currently capable and allowed to print
617+
* records. Note that this function does not consider the current context,
618+
* which can also play a role in deciding if @con can be used to print
619+
* records.
620+
*/
621+
static inline bool console_is_usable(struct console *con, short flags, bool use_atomic)
622+
{
623+
if (!(flags & CON_ENABLED))
624+
return false;
625+
626+
if ((flags & CON_SUSPENDED))
627+
return false;
628+
629+
if (flags & CON_NBCON) {
630+
/* The write_atomic() callback is optional. */
631+
if (use_atomic && !con->write_atomic)
632+
return false;
633+
634+
/*
635+
* For the !use_atomic case, @printk_kthreads_running is not
636+
* checked because the write_thread() callback is also used
637+
* via the legacy loop when the printer threads are not
638+
* available.
639+
*/
640+
} else {
641+
if (!con->write)
642+
return false;
643+
}
644+
645+
/*
646+
* Console drivers may assume that per-cpu resources have been
647+
* allocated. So unless they're explicitly marked as being able to
648+
* cope (CON_ANYTIME) don't call them until this CPU is officially up.
649+
*/
650+
if (!cpu_online(raw_smp_processor_id()) && !(flags & CON_ANYTIME))
651+
return false;
652+
653+
return true;
654+
}
655+
608656
#else
609657
static inline void nbcon_cpu_emergency_enter(void) { }
610658
static inline void nbcon_cpu_emergency_exit(void) { }
611659
static inline bool nbcon_can_proceed(struct nbcon_write_context *wctxt) { return false; }
660+
static inline void nbcon_write_context_set_buf(struct nbcon_write_context *wctxt,
661+
char *buf, unsigned int len) { }
612662
static inline bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) { return false; }
613663
static inline bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) { return false; }
614664
static inline void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt) { }
665+
static inline bool nbcon_kdb_try_acquire(struct console *con,
666+
struct nbcon_write_context *wctxt) { return false; }
667+
static inline void nbcon_kdb_release(struct nbcon_write_context *wctxt) { }
668+
static inline bool console_is_usable(struct console *con, short flags,
669+
bool use_atomic) { return false; }
615670
#endif
616671

617672
extern int console_set_on_cmdline;

include/linux/kdb.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515

1616
#include <linux/list.h>
17+
#include <linux/smp.h>
1718

1819
/* Shifted versions of the command enable bits are be used if the command
1920
* 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)
207208
/* Dynamic kdb shell command registration */
208209
extern int kdb_register(kdbtab_t *cmd);
209210
extern void kdb_unregister(kdbtab_t *cmd);
211+
212+
/* Return true when KDB as locked for printing a message on this CPU. */
213+
static inline
214+
bool kdb_printf_on_this_cpu(void)
215+
{
216+
/*
217+
* We can use raw_smp_processor_id() here because the task could
218+
* not get migrated when KDB has locked for printing on this CPU.
219+
*/
220+
return unlikely(READ_ONCE(kdb_printf_cpu) == raw_smp_processor_id());
221+
}
222+
210223
#else /* ! CONFIG_KGDB_KDB */
211224
static inline __printf(1, 2) int kdb_printf(const char *fmt, ...) { return 0; }
212225
static inline void kdb_init(int level) {}
213226
static inline int kdb_register(kdbtab_t *cmd) { return 0; }
214227
static inline void kdb_unregister(kdbtab_t *cmd) {}
228+
229+
static inline bool kdb_printf_on_this_cpu(void) { return false; }
230+
215231
#endif /* CONFIG_KGDB_KDB */
216232
enum {
217233
KDB_NOT_INITIALIZED,

kernel/debug/kdb/kdb_io.c

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -589,24 +589,41 @@ static void kdb_msg_write(const char *msg, int msg_len)
589589
*/
590590
cookie = console_srcu_read_lock();
591591
for_each_console_srcu(c) {
592-
if (!(console_srcu_read_flags(c) & CON_ENABLED))
592+
short flags = console_srcu_read_flags(c);
593+
594+
if (!console_is_usable(c, flags, true))
593595
continue;
594596
if (c == dbg_io_ops->cons)
595597
continue;
596-
if (!c->write)
597-
continue;
598-
/*
599-
* Set oops_in_progress to encourage the console drivers to
600-
* disregard their internal spin locks: in the current calling
601-
* context the risk of deadlock is a bigger problem than risks
602-
* due to re-entering the console driver. We operate directly on
603-
* oops_in_progress rather than using bust_spinlocks() because
604-
* the calls bust_spinlocks() makes on exit are not appropriate
605-
* for this calling context.
606-
*/
607-
++oops_in_progress;
608-
c->write(c, msg, msg_len);
609-
--oops_in_progress;
598+
599+
if (flags & CON_NBCON) {
600+
struct nbcon_write_context wctxt = { };
601+
602+
/*
603+
* Do not continue if the console is NBCON and the context
604+
* can't be acquired.
605+
*/
606+
if (!nbcon_kdb_try_acquire(c, &wctxt))
607+
continue;
608+
609+
nbcon_write_context_set_buf(&wctxt, (char *)msg, msg_len);
610+
611+
c->write_atomic(c, &wctxt);
612+
nbcon_kdb_release(&wctxt);
613+
} else {
614+
/*
615+
* Set oops_in_progress to encourage the console drivers to
616+
* disregard their internal spin locks: in the current calling
617+
* context the risk of deadlock is a bigger problem than risks
618+
* due to re-entering the console driver. We operate directly on
619+
* oops_in_progress rather than using bust_spinlocks() because
620+
* the calls bust_spinlocks() makes on exit are not appropriate
621+
* for this calling context.
622+
*/
623+
++oops_in_progress;
624+
c->write(c, msg, msg_len);
625+
--oops_in_progress;
626+
}
610627
touch_nmi_watchdog();
611628
}
612629
console_srcu_read_unlock(cookie);

kernel/printk/internal.h

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* internal.h - printk internal definitions
44
*/
55
#include <linux/console.h>
6-
#include <linux/percpu.h>
76
#include <linux/types.h>
87

98
#if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL)
@@ -112,47 +111,6 @@ bool nbcon_kthread_create(struct console *con);
112111
void nbcon_kthread_stop(struct console *con);
113112
void nbcon_kthreads_wake(void);
114113

115-
/*
116-
* Check if the given console is currently capable and allowed to print
117-
* records. Note that this function does not consider the current context,
118-
* which can also play a role in deciding if @con can be used to print
119-
* records.
120-
*/
121-
static inline bool console_is_usable(struct console *con, short flags, bool use_atomic)
122-
{
123-
if (!(flags & CON_ENABLED))
124-
return false;
125-
126-
if ((flags & CON_SUSPENDED))
127-
return false;
128-
129-
if (flags & CON_NBCON) {
130-
/* The write_atomic() callback is optional. */
131-
if (use_atomic && !con->write_atomic)
132-
return false;
133-
134-
/*
135-
* For the !use_atomic case, @printk_kthreads_running is not
136-
* checked because the write_thread() callback is also used
137-
* via the legacy loop when the printer threads are not
138-
* available.
139-
*/
140-
} else {
141-
if (!con->write)
142-
return false;
143-
}
144-
145-
/*
146-
* Console drivers may assume that per-cpu resources have been
147-
* allocated. So unless they're explicitly marked as being able to
148-
* cope (CON_ANYTIME) don't call them until this CPU is officially up.
149-
*/
150-
if (!cpu_online(raw_smp_processor_id()) && !(flags & CON_ANYTIME))
151-
return false;
152-
153-
return true;
154-
}
155-
156114
/**
157115
* nbcon_kthread_wake - Wake up a console printing thread
158116
* @con: Console to operate on
@@ -204,9 +162,6 @@ static inline bool nbcon_legacy_emit_next_record(struct console *con, bool *hand
204162
static inline void nbcon_kthread_wake(struct console *con) { }
205163
static inline void nbcon_kthreads_wake(void) { }
206164

207-
static inline bool console_is_usable(struct console *con, short flags,
208-
bool use_atomic) { return false; }
209-
210165
#endif /* CONFIG_PRINTK */
211166

212167
extern bool have_boot_console;

kernel/printk/nbcon.c

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/export.h>
1111
#include <linux/init.h>
1212
#include <linux/irqflags.h>
13+
#include <linux/kdb.h>
1314
#include <linux/kthread.h>
1415
#include <linux/minmax.h>
1516
#include <linux/panic.h>
@@ -252,13 +253,16 @@ static int nbcon_context_try_acquire_direct(struct nbcon_context *ctxt,
252253
* since all non-panic CPUs are stopped during panic(), it
253254
* is safer to have them avoid gaining console ownership.
254255
*
255-
* If this acquire is a reacquire (and an unsafe takeover
256+
* One exception is when kdb has locked for printing on this CPU.
257+
*
258+
* Second exception is a reacquire (and an unsafe takeover
256259
* has not previously occurred) then it is allowed to attempt
257260
* a direct acquire in panic. This gives console drivers an
258261
* opportunity to perform any necessary cleanup if they were
259262
* interrupted by the panic CPU while printing.
260263
*/
261264
if (panic_on_other_cpu() &&
265+
!kdb_printf_on_this_cpu() &&
262266
(!is_reacquire || cur->unsafe_takeover)) {
263267
return -EPERM;
264268
}
@@ -853,8 +857,8 @@ static bool __nbcon_context_update_unsafe(struct nbcon_context *ctxt, bool unsaf
853857
return nbcon_context_can_proceed(ctxt, &cur);
854858
}
855859

856-
static void nbcon_write_context_set_buf(struct nbcon_write_context *wctxt,
857-
char *buf, unsigned int len)
860+
void nbcon_write_context_set_buf(struct nbcon_write_context *wctxt,
861+
char *buf, unsigned int len)
858862
{
859863
struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
860864
struct console *con = ctxt->console;
@@ -1894,3 +1898,64 @@ void nbcon_device_release(struct console *con)
18941898
console_srcu_read_unlock(cookie);
18951899
}
18961900
EXPORT_SYMBOL_GPL(nbcon_device_release);
1901+
1902+
/**
1903+
* nbcon_kdb_try_acquire - Try to acquire nbcon console and enter unsafe
1904+
* section
1905+
* @con: The nbcon console to acquire
1906+
* @wctxt: The nbcon write context to be used on success
1907+
*
1908+
* Context: Under console_srcu_read_lock() for emitting a single kdb message
1909+
* using the given con->write_atomic() callback. Can be called
1910+
* only when the console is usable at the moment.
1911+
*
1912+
* Return: True if the console was acquired. False otherwise.
1913+
*
1914+
* kdb emits messages on consoles registered for printk() without
1915+
* storing them into the ring buffer. It has to acquire the console
1916+
* ownerhip so that it could call con->write_atomic() callback a safe way.
1917+
*
1918+
* This function acquires the nbcon console using priority NBCON_PRIO_EMERGENCY
1919+
* and marks it unsafe for handover/takeover.
1920+
*/
1921+
bool nbcon_kdb_try_acquire(struct console *con,
1922+
struct nbcon_write_context *wctxt)
1923+
{
1924+
struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
1925+
1926+
memset(ctxt, 0, sizeof(*ctxt));
1927+
ctxt->console = con;
1928+
ctxt->prio = NBCON_PRIO_EMERGENCY;
1929+
1930+
if (!nbcon_context_try_acquire(ctxt, false))
1931+
return false;
1932+
1933+
if (!nbcon_context_enter_unsafe(ctxt))
1934+
return false;
1935+
1936+
return true;
1937+
}
1938+
1939+
/**
1940+
* nbcon_kdb_release - Exit unsafe section and release the nbcon console
1941+
*
1942+
* @wctxt: The nbcon write context initialized by a successful
1943+
* nbcon_kdb_try_acquire()
1944+
*/
1945+
void nbcon_kdb_release(struct nbcon_write_context *wctxt)
1946+
{
1947+
struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
1948+
1949+
if (!nbcon_context_exit_unsafe(ctxt))
1950+
return;
1951+
1952+
nbcon_context_release(ctxt);
1953+
1954+
/*
1955+
* Flush any new printk() messages added when the console was blocked.
1956+
* Only the console used by the given write context was blocked.
1957+
* The console was locked only when the write_atomic() callback
1958+
* was usable.
1959+
*/
1960+
__nbcon_atomic_flush_pending_con(ctxt->console, prb_next_reserve_seq(prb), false);
1961+
}

kernel/printk/printk.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3331,12 +3331,10 @@ void console_unblank(void)
33313331
*/
33323332
cookie = console_srcu_read_lock();
33333333
for_each_console_srcu(c) {
3334-
short flags = console_srcu_read_flags(c);
3335-
3336-
if (flags & CON_SUSPENDED)
3334+
if (!console_is_usable(c, console_srcu_read_flags(c), true))
33373335
continue;
33383336

3339-
if ((flags & CON_ENABLED) && c->unblank) {
3337+
if (c->unblank) {
33403338
found_unblank = true;
33413339
break;
33423340
}
@@ -3373,12 +3371,10 @@ void console_unblank(void)
33733371

33743372
cookie = console_srcu_read_lock();
33753373
for_each_console_srcu(c) {
3376-
short flags = console_srcu_read_flags(c);
3377-
3378-
if (flags & CON_SUSPENDED)
3374+
if (!console_is_usable(c, console_srcu_read_flags(c), true))
33793375
continue;
33803376

3381-
if ((flags & CON_ENABLED) && c->unblank)
3377+
if (c->unblank)
33823378
c->unblank();
33833379
}
33843380
console_srcu_read_unlock(cookie);

0 commit comments

Comments
 (0)