Allow printing when the kernel faults
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 5 Jun 2014 22:42:11 +0000 (15:42 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 5 Jun 2014 22:42:11 +0000 (15:42 -0700)
On occasion, printk faults due to other bugs.  It does so when holding
the output_lock, and then the fault handler deadlocks since it can't
print anything.

This just disables print locking when the kernel is in a trap context,
which almost always is a bug that we want to hear about.

kern/src/printf.c

index 43b6d01..a9d0c65 100644 (file)
@@ -11,6 +11,7 @@
 #include <atomic.h>
 #include <stdio.h>
 #include <stdarg.h>
+#include <smp.h>
 
 spinlock_t output_lock = SPINLOCK_INITIALIZER_IRQSAVE;
 
@@ -44,20 +45,31 @@ void buffered_putch(int ch, int **cnt)
 
 int vcprintf(const char *fmt, va_list ap)
 {
+       struct per_cpu_info *pcpui;
+       extern int booting;
        int cnt = 0;
        int *cntp = &cnt;
        volatile int i;
 
+       /* this ktrap depth stuff is in case the kernel faults in a printfmt call.
+        * we disable the locking if we're in a fault handler so that we don't
+        * deadlock. */
+       if (booting)
+               pcpui = &per_cpu_info[0];
+       else
+               pcpui = &per_cpu_info[core_id()];
        /* lock all output.  this will catch any printfs at line granularity.  when
         * tracing, we short-circuit the main lock call, so as not to clobber the
         * results as we print. */
-       #ifdef CONFIG_TRACE_LOCKS
-       int8_t irq_state = 0;
-       disable_irqsave(&irq_state);
-       __spin_lock(&output_lock);
-       #else
-       spin_lock_irqsave(&output_lock);
-       #endif
+       if (!ktrap_depth(pcpui)) {
+               #ifdef CONFIG_TRACE_LOCKS
+               int8_t irq_state = 0;
+               disable_irqsave(&irq_state);
+               __spin_lock(&output_lock);
+               #else
+               spin_lock_irqsave(&output_lock);
+               #endif
+       }
 
        // do the buffered printf
        #ifdef __DEPUTY__
@@ -69,12 +81,14 @@ int vcprintf(const char *fmt, va_list ap)
        // write out remaining chars in the buffer
        buffered_putch(-1,&cntp);
 
-       #ifdef CONFIG_TRACE_LOCKS
-       __spin_unlock(&output_lock);
-       enable_irqsave(&irq_state);
-       #else
-       spin_unlock_irqsave(&output_lock);
-       #endif
+       if (!ktrap_depth(pcpui)) {
+               #ifdef CONFIG_TRACE_LOCKS
+               __spin_unlock(&output_lock);
+               enable_irqsave(&irq_state);
+               #else
+               spin_unlock_irqsave(&output_lock);
+               #endif
+       }
 
        return cnt;
 }