History

kdb: properly synchronize vkdb_printf() calls with other CPUs

kdb_printf_lock does not prevent other CPUs from entering the critical section because it is ignored when KDB_STATE_PRINTF_LOCK is set. The problematic situation might look like: CPU0 CPU1 vkdb_printf() if (!KDB_STATE(PRINTF_LOCK)) KDB_STATE_SET(PRINTF_LOCK); spin_lock_irqsave(&kdb_printf_lock, flags); vkdb_printf() if (!KDB_STATE(PRINTF_LOCK)) BANG: The PRINTF_LOCK state is set and CPU1 is entering the critical section without spinning on the lock. The problem is that the code tries to implement locking using two state variables that are not handled atomically. Well, we need a custom locking because we want to allow reentering the critical section on the very same CPU. Let's use solution from Petr Zijlstra that was proposed for a similar scenario, see https://lkml.kernel.org/r/20161018171513.734367391@infradead.org This patch uses the same trick with cmpxchg(). The only difference is that we want to handle only recursion from the same context and therefore we disable interrupts. In addition, KDB_STATE_PRINTF_LOCK is removed. In fact, we are not able to set it a non-racy way.

Petr Mladek committed 9 years ago

Commit d5d8d3d1 parent d1bd8ea2 files · +13 −18Browse files

Showing the changes to kernel/debug (2 of 2 files). Show all

Unified · Split

2 files
  1. kernel/debug/kdb/kdb_io.c +13 −17
  2. kernel/debug/kdb/kdb_private.h +0 −1
kernel/debug/kdb/kdb_io.c+13−17
@@ -555,16 +555,16 @@ int vkdb_printf(enum kdb_msgsrc src, const char *fmt, va_list ap) · 554 unmodified lines
555555 int colcount;
556556 int logging, saved_loglevel = 0;
557557 int saved_trap_printk;
558− int got_printf_lock = 0;
559558 int retlen = 0;
560559 int fnd, len;
560+ int this_cpu, old_cpu;
561+ static int kdb_printf_cpu = -1;
561562 char *cp, *cp2, *cphold = NULL, replaced_byte = ' ';
562563 char *moreprompt = "more> ";
563564 struct console *c = console_drivers;
564− static DEFINE_SPINLOCK(kdb_printf_lock);
565565 unsigned long uninitialized_var(flags);
566566
567− preempt_disable();
567+ local_irq_save(flags);
568568 saved_trap_printk = kdb_trap_printk;
569569 kdb_trap_printk = 0;
570570
@@ -572,12 +572,13 @@ int vkdb_printf(enum kdb_msgsrc src, const char *fmt, va_list ap) · 1 unmodified line
572572 * But if any cpu goes recursive in kdb, just print the output,
573573 * even if it is interleaved with any other text.
574574 */
575− if (!KDB_STATE(PRINTF_LOCK)) {
576− KDB_STATE_SET(PRINTF_LOCK);
577− spin_lock_irqsave(&kdb_printf_lock, flags);
578− got_printf_lock = 1;
579− } else {
580− __acquire(kdb_printf_lock);
575+ this_cpu = smp_processor_id();
576+ for (;;) {
577+ old_cpu = cmpxchg(&kdb_printf_cpu, -1, this_cpu);
578+ if (old_cpu == -1 || old_cpu == this_cpu)
579+ break;
580+
581+ cpu_relax();
581582 }
582583
583584 diag = kdbgetintenv("LINES", &linecount);
@@ -846,15 +847,10 @@ kdb_print_out: · 262 unmodified lines
846847 suspend_grep = 0; /* end of what may have been a recursive call */
847848 if (logging)
848849 console_loglevel = saved_loglevel;
849− if (KDB_STATE(PRINTF_LOCK) && got_printf_lock) {
850− got_printf_lock = 0;
851− spin_unlock_irqrestore(&kdb_printf_lock, flags);
852− KDB_STATE_CLEAR(PRINTF_LOCK);
853− } else {
854− __release(kdb_printf_lock);
855− }
850+ /* kdb_printf_cpu locked the code above. */
851+ smp_store_release(&kdb_printf_cpu, old_cpu);
856852 kdb_trap_printk = saved_trap_printk;
857− preempt_enable();
853+ local_irq_restore(flags);
858854 return retlen;
859855 }
860856
kernel/debug/kdb/kdb_private.h+0−1
@@ -132,7 +132,6 @@ extern int kdb_state; · 131 unmodified lines
132132 #define KDB_STATE_PAGER 0x00000400 /* pager is available */
133133 #define KDB_STATE_GO_SWITCH 0x00000800 /* go is switching
134134 * back to initial cpu */
135−#define KDB_STATE_PRINTF_LOCK 0x00001000 /* Holds kdb_printf lock */
136135 #define KDB_STATE_WAIT_IPI 0x00002000 /* Waiting for kdb_ipi() NMI */
137136 #define KDB_STATE_RECURSE 0x00004000 /* Recursive entry to kdb */
138137 #define KDB_STATE_IP_ADJUSTED 0x00008000 /* Restart IP has been