[PATCH] rcu: Mention rcu_bh in description of rcutorture's torture_type parameter
[linux-2.6.git] / kernel / printk.c
index 2251be8..771f5e8 100644 (file)
@@ -11,7 +11,7 @@
  * Ted Ts'o, 2/11/93.
  * Modified for sysctl support, 1/8/97, Chris Horn.
  * Fixed SMP synchronization, 08/08/99, Manfred Spraul
- *     manfreds@colorfullife.com
+ *     manfred@colorfullife.com
  * Rewrote bits to get rid of console_lock
  *     01Mar01 Andrew Morton <andrewm@uow.edu.au>
  */
@@ -24,8 +24,8 @@
 #include <linux/console.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/interrupt.h>                   /* For in_interrupt() */
-#include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/smp.h>
 #include <linux/security.h>
@@ -52,7 +52,7 @@ int console_printk[4] = {
        DEFAULT_CONSOLE_LOGLEVEL,       /* default_console_loglevel */
 };
 
-EXPORT_SYMBOL(console_printk);
+EXPORT_UNUSED_SYMBOL(console_printk);  /*  June 2006  */
 
 /*
  * Low lever drivers may need that to know if they can schedule in
@@ -67,6 +67,7 @@ EXPORT_SYMBOL(oops_in_progress);
  * driver system.
  */
 static DECLARE_MUTEX(console_sem);
+static DECLARE_MUTEX(secondary_console_sem);
 struct console *console_drivers;
 /*
  * This is used for debugging the mess that is the VT code by
@@ -76,7 +77,7 @@ struct console *console_drivers;
  * path in the console code where we end up in places I want
  * locked without the console sempahore held
  */
-static int console_locked;
+static int console_locked, console_suspended;
 
 /*
  * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars
@@ -122,44 +123,6 @@ static char *log_buf = __log_buf;
 static int log_buf_len = __LOG_BUF_LEN;
 static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */
 
-/*
- *     Setup a list of consoles. Called from init/main.c
- */
-static int __init console_setup(char *str)
-{
-       char name[sizeof(console_cmdline[0].name)];
-       char *s, *options;
-       int idx;
-
-       /*
-        *      Decode str into name, index, options.
-        */
-       if (str[0] >= '0' && str[0] <= '9') {
-               strcpy(name, "ttyS");
-               strncpy(name + 4, str, sizeof(name) - 5);
-       } else
-               strncpy(name, str, sizeof(name) - 1);
-       name[sizeof(name) - 1] = 0;
-       if ((options = strchr(str, ',')) != NULL)
-               *(options++) = 0;
-#ifdef __sparc__
-       if (!strcmp(str, "ttya"))
-               strcpy(name, "ttyS0");
-       if (!strcmp(str, "ttyb"))
-               strcpy(name, "ttyS1");
-#endif
-       for (s = name; *s; s++)
-               if ((*s >= '0' && *s <= '9') || *s == ',')
-                       break;
-       idx = simple_strtoul(s, NULL, 10);
-       *s = 0;
-
-       add_preferred_console(name, idx, options);
-       return 1;
-}
-
-__setup("console=", console_setup);
-
 static int __init log_buf_len_setup(char *str)
 {
        unsigned long size = memparse(str, &str);
@@ -364,7 +327,9 @@ static void __call_console_drivers(unsigned long start, unsigned long end)
        struct console *con;
 
        for (con = console_drivers; con; con = con->next) {
-               if ((con->flags & CON_ENABLED) && con->write)
+               if ((con->flags & CON_ENABLED) && con->write &&
+                               (cpu_online(smp_processor_id()) ||
+                               (con->flags & CON_ANYTIME)))
                        con->write(con, &LOG_BUF(start), end - start);
        }
 }
@@ -398,8 +363,7 @@ static void call_console_drivers(unsigned long start, unsigned long end)
        unsigned long cur_index, start_print;
        static int msg_level = -1;
 
-       if (((long)(start - end)) > 0)
-               BUG();
+       BUG_ON(((long)(start - end)) > 0);
 
        cur_index = start;
        start_print = start;
@@ -475,6 +439,7 @@ static int printk_time = 1;
 #else
 static int printk_time = 0;
 #endif
+module_param(printk_time, int, S_IRUGO | S_IWUSR);
 
 static int __init printk_time_setup(char *str)
 {
@@ -491,6 +456,18 @@ __attribute__((weak)) unsigned long long printk_clock(void)
        return sched_clock();
 }
 
+/* Check if we have any console registered that can be called early in boot. */
+static int have_callable_console(void)
+{
+       struct console *con;
+
+       for (con = console_drivers; con; con = con->next)
+               if (con->flags & CON_ANYTIME)
+                       return 1;
+
+       return 0;
+}
+
 /**
  * printk - print a kernel message
  * @fmt: format string
@@ -541,7 +518,9 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                zap_locks();
 
        /* This stops the holder of console_sem just where we want him */
-       spin_lock_irqsave(&logbuf_lock, flags);
+       local_irq_save(flags);
+       lockdep_off();
+       spin_lock(&logbuf_lock);
        printk_cpu = smp_processor_id();
 
        /* Emit the output into the temporary buffer */
@@ -604,27 +583,31 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                        log_level_unknown = 1;
        }
 
-       if (!cpu_online(smp_processor_id())) {
+       if (!down_trylock(&console_sem)) {
                /*
-                * Some console drivers may assume that per-cpu resources have
-                * been allocated.  So don't allow them to be called by this
-                * CPU until it is officially up.  We shouldn't be calling into
-                * random console drivers on a CPU which doesn't exist yet..
+                * We own the drivers.  We can drop the spinlock and
+                * let release_console_sem() print the text, maybe ...
                 */
-               printk_cpu = UINT_MAX;
-               spin_unlock_irqrestore(&logbuf_lock, flags);
-               goto out;
-       }
-       if (!down_trylock(&console_sem)) {
                console_locked = 1;
+               printk_cpu = UINT_MAX;
+               spin_unlock(&logbuf_lock);
+
                /*
-                * We own the drivers.  We can drop the spinlock and let
-                * release_console_sem() print the text
+                * 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.
                 */
-               printk_cpu = UINT_MAX;
-               spin_unlock_irqrestore(&logbuf_lock, flags);
-               console_may_schedule = 0;
-               release_console_sem();
+               if (cpu_online(smp_processor_id()) || have_callable_console()) {
+                       console_may_schedule = 0;
+                       release_console_sem();
+               } else {
+                       /* Release by hand to avoid flushing the buffer. */
+                       console_locked = 0;
+                       up(&console_sem);
+               }
+               lockdep_on();
+               local_irq_restore(flags);
        } else {
                /*
                 * Someone else owns the drivers.  We drop the spinlock, which
@@ -632,9 +615,11 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                 * console drivers with the output which we just produced.
                 */
                printk_cpu = UINT_MAX;
-               spin_unlock_irqrestore(&logbuf_lock, flags);
+               spin_unlock(&logbuf_lock);
+               lockdep_on();
+               local_irq_restore(flags);
        }
-out:
+
        preempt_enable();
        return printed_len;
 }
@@ -659,6 +644,44 @@ static void call_console_drivers(unsigned long start, unsigned long end)
 
 #endif
 
+/*
+ * Set up a list of consoles.  Called from init/main.c
+ */
+static int __init console_setup(char *str)
+{
+       char name[sizeof(console_cmdline[0].name)];
+       char *s, *options;
+       int idx;
+
+       /*
+        * Decode str into name, index, options.
+        */
+       if (str[0] >= '0' && str[0] <= '9') {
+               strcpy(name, "ttyS");
+               strncpy(name + 4, str, sizeof(name) - 5);
+       } else {
+               strncpy(name, str, sizeof(name) - 1);
+       }
+       name[sizeof(name) - 1] = 0;
+       if ((options = strchr(str, ',')) != NULL)
+               *(options++) = 0;
+#ifdef __sparc__
+       if (!strcmp(str, "ttya"))
+               strcpy(name, "ttyS0");
+       if (!strcmp(str, "ttyb"))
+               strcpy(name, "ttyS1");
+#endif
+       for (s = name; *s; s++)
+               if ((*s >= '0' && *s <= '9') || *s == ',')
+                       break;
+       idx = simple_strtoul(s, NULL, 10);
+       *s = 0;
+
+       add_preferred_console(name, idx, options);
+       return 1;
+}
+__setup("console=", console_setup);
+
 /**
  * add_preferred_console - add a device to the list of preferred consoles.
  * @name: device name
@@ -698,6 +721,26 @@ int __init add_preferred_console(char *name, int idx, char *options)
        return 0;
 }
 
+#ifndef CONFIG_DISABLE_CONSOLE_SUSPEND
+/**
+ * suspend_console - suspend the console subsystem
+ *
+ * This disables printk() while we go into suspend states
+ */
+void suspend_console(void)
+{
+       printk("Suspending console(s)\n");
+       acquire_console_sem();
+       console_suspended = 1;
+}
+
+void resume_console(void)
+{
+       console_suspended = 0;
+       release_console_sem();
+}
+#endif /* CONFIG_DISABLE_CONSOLE_SUSPEND */
+
 /**
  * acquire_console_sem - lock the console system for exclusive use.
  *
@@ -708,8 +751,11 @@ int __init add_preferred_console(char *name, int idx, char *options)
  */
 void acquire_console_sem(void)
 {
-       if (in_interrupt())
-               BUG();
+       BUG_ON(in_interrupt());
+       if (console_suspended) {
+               down(&secondary_console_sem);
+               return;
+       }
        down(&console_sem);
        console_locked = 1;
        console_may_schedule = 1;
@@ -730,7 +776,7 @@ int is_console_locked(void)
 {
        return console_locked;
 }
-EXPORT_SYMBOL(is_console_locked);
+EXPORT_UNUSED_SYMBOL(is_console_locked);  /*  June 2006  */
 
 /**
  * release_console_sem - unlock the console system
@@ -752,6 +798,13 @@ void release_console_sem(void)
        unsigned long _con_start, _log_end;
        unsigned long wake_klogd = 0;
 
+       if (console_suspended) {
+               up(&secondary_console_sem);
+               return;
+       }
+
+       console_may_schedule = 0;
+
        for ( ; ; ) {
                spin_lock_irqsave(&logbuf_lock, flags);
                wake_klogd |= log_start - log_end;
@@ -765,11 +818,17 @@ void release_console_sem(void)
                local_irq_restore(flags);
        }
        console_locked = 0;
-       console_may_schedule = 0;
        up(&console_sem);
        spin_unlock_irqrestore(&logbuf_lock, flags);
-       if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait))
-               wake_up_interruptible(&log_wait);
+       if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait)) {
+               /*
+                * If we printk from within the lock dependency code,
+                * from within the scheduler code, then do not lock
+                * up due to self-recursion:
+                */
+               if (!lockdep_internal())
+                       wake_up_interruptible(&log_wait);
+       }
 }
 EXPORT_SYMBOL(release_console_sem);