Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Kernel v2.6.25-rc7 /kernel/printk.c

Filename:/kernel/printk.c
Lines Added:116
Lines Deleted:85
Also changed in: (Previous) 2.6.25-rc6-git8  2.6.25-rc6  2.6.25-rc5  2.6.25-rc4  2.6.25-rc3-git6  2.6.25-rc3-git5 
(Following) 2.6.25-rc8  2.6.25-rc9  2.6.25-rc9-git3  2.6.25  2.6.25-git14  2.6.25-git15 

Location
[  2.6.25-rc7
  [  kernel
     o  printk.c

Patch

diff --git a/kernel/printk.c b/kernel/printk.c
index 89011bf..c46a20a 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -32,10 +32,16 @@
 #include <linux/security.h>
 #include <linux/bootmem.h>
 #include <linux/syscalls.h>
-#include <linux/jiffies.h>
 
 #include <asm/uaccess.h>
 
+/*
+ * Architectures can override it:
+ */
+void __attribute__((weak)) early_printk(const char *fmt, ...)
+{
+}
+
 #define __LOG_BUF_LEN   (1 << CONFIG_LOG_BUF_SHIFT)
 
 /* printk's without a loglevel use this.. */
@@ -86,16 +92,16 @@ static int console_locked, console_suspended;
  */
 static DEFINE_SPINLOCK(logbuf_lock);
 
-#define LOG_BUF_MASK   (log_buf_len-1)
+#define LOG_BUF_MASK (log_buf_len-1)
 #define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
 
 /*
  * The indices into log_buf are not constrained to log_buf_len - they
  * must be masked before subscripting
  */
-static unsigned long log_start;   /* Index into log_buf: next char to be read by syslog() */
-static unsigned long con_start;   /* Index into log_buf: next char to be sent to consoles */
-static unsigned long log_end;   /* Index into log_buf: most-recently-written-char + 1 */
+static unsigned log_start;   /* Index into log_buf: next char to be read by syslog() */
+static unsigned con_start;   /* Index into log_buf: next char to be sent to consoles */
+static unsigned log_end;   /* Index into log_buf: most-recently-written-char + 1 */
 
 /*
  *   Array of consoles built from command line options (console=)
@@ -121,17 +127,17 @@ static int console_may_schedule;
 static char __log_buf[__LOG_BUF_LEN];
 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 */
+static unsigned logged_chars; /* Number of chars produced since last read+clear operation */
 
 static int __init log_buf_len_setup(char *str)
 {
-   unsigned long size = memparse(str, &str);
+   unsigned size = memparse(str, &str);
    unsigned long flags;
 
    if (size)
       size = roundup_pow_of_two(size);
    if (size > log_buf_len) {
-      unsigned long start, dest_idx, offset;
+      unsigned start, dest_idx, offset;
       char *new_log_buf;
 
       new_log_buf = alloc_bootmem(size);
@@ -288,7 +294,7 @@ int log_buf_read(int idx)
  */
 int do_syslog(int type, char __user *buf, int len)
 {
-   unsigned long i, j, limit, count;
+   unsigned i, j, limit, count;
    int do_clear = 0;
    char c;
    int error = 0;
@@ -429,7 +435,7 @@ asmlinkage long sys_syslog(int type, char __user *buf, int len)
 /*
  * Call the console drivers on a range of log_buf
  */
-static void __call_console_drivers(unsigned long start, unsigned long end)
+static void __call_console_drivers(unsigned start, unsigned end)
 {
    struct console *con;
 
@@ -448,16 +454,16 @@ static int __init ignore_loglevel_setup(char *str)
    ignore_loglevel = 1;
    printk(KERN_INFO "debug: ignoring loglevel setting.\n");
 
-   return 1;
+   return 0;
 }
 
-__setup("ignore_loglevel", ignore_loglevel_setup);
+early_param("ignore_loglevel", ignore_loglevel_setup);
 
 /*
  * Write out chars from start to end - 1 inclusive
  */
-static void _call_console_drivers(unsigned long start,
-            unsigned long end, int msg_log_level)
+static void _call_console_drivers(unsigned start,
+            unsigned end, int msg_log_level)
 {
    if ((msg_log_level < console_loglevel || ignore_loglevel) &&
          console_drivers && start != end) {
@@ -477,12 +483,12 @@ static void _call_console_drivers(unsigned long start,
  * log_buf[start] to log_buf[end - 1].
  * The console_sem must be held.
  */
-static void call_console_drivers(unsigned long start, unsigned long end)
+static void call_console_drivers(unsigned start, unsigned end)
 {
-   unsigned long cur_index, start_print;
+   unsigned cur_index, start_print;
    static int msg_level = -1;
 
-   BUG_ON(((long)(start - end)) > 0);
+   BUG_ON(((int)(start - end)) > 0);
 
    cur_index = start;
    start_print = start;
@@ -560,24 +566,6 @@ static int printk_time = 0;
 #endif
 module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
 
-static int __init printk_time_setup(char *str)
-{
-   if (*str)
-      return 0;
-   printk_time = 1;
-   printk(KERN_NOTICE "The 'time' option is deprecated and "
-      "is scheduled for removal in early 2008\n");
-   printk(KERN_NOTICE "Use 'printk.time=<value>' instead\n");
-   return 1;
-}
-
-__setup("time", printk_time_setup);
-
-__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)
 {
@@ -628,30 +616,91 @@ asmlinkage int printk(const char *fmt, ...)
 /* cpu currently holding logbuf_lock */
 static volatile unsigned int printk_cpu = UINT_MAX;
 
+/*
+ * Can we actually use the console at this time on this cpu?
+ *
+ * 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.
+ */
+static inline int can_use_console(unsigned int cpu)
+{
+   return cpu_online(cpu) || have_callable_console();
+}
+
+/*
+ * Try to get console ownership to actually show the kernel
+ * messages from a 'printk'. Return true (and with the
+ * console_semaphore held, and 'console_locked' set) if it
+ * is successful, false otherwise.
+ *
+ * This gets called with the 'logbuf_lock' spinlock held and
+ * interrupts disabled. It should return with 'lockbuf_lock'
+ * released but interrupts still disabled.
+ */
+static int acquire_console_semaphore_for_printk(unsigned int cpu)
+{
+   int retval = 0;
+
+   if (can_use_console(cpu))
+      retval = !try_acquire_console_sem();
+   printk_cpu = UINT_MAX;
+   spin_unlock(&logbuf_lock);
+   return retval;
+}
+
+const char printk_recursion_bug_msg [] =
+         KERN_CRIT "BUG: recent printk recursion!\n";
+static int printk_recursion_bug;
+
 asmlinkage int vprintk(const char *fmt, va_list args)
 {
+   static int log_level_unknown = 1;
+   static char printk_buf[1024];
+
    unsigned long flags;
-   int printed_len;
+   int printed_len = 0;
+   int this_cpu;
    char *p;
-   static char printk_buf[1024];
-   static int log_level_unknown = 1;
 
    boot_delay_msec();
 
    preempt_disable();
-   if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id())
-      /* If a crash is occurring during printk() on this CPU,
-       * make sure we can't deadlock */
-      zap_locks();
-
    /* This stops the holder of console_sem just where we want him */
    raw_local_irq_save(flags);
+   this_cpu = smp_processor_id();
+
+   /*
+    * Ouch, printk recursed into itself!
+    */
+   if (unlikely(printk_cpu == this_cpu)) {
+      /*
+       * If a crash is occurring during printk() on this CPU,
+       * then try to get the crash message out but make sure
+       * we can't deadlock. Otherwise just return to avoid the
+       * recursion and return - but flag the recursion so that
+       * it can be printed at the next appropriate moment:
+       */
+      if (!oops_in_progress) {
+         printk_recursion_bug = 1;
+         goto out_restore_irqs;
+      }
+      zap_locks();
+   }
+
    lockdep_off();
    spin_lock(&logbuf_lock);
-   printk_cpu = smp_processor_id();
+   printk_cpu = this_cpu;
 
+   if (printk_recursion_bug) {
+      printk_recursion_bug = 0;
+      strcpy(printk_buf, printk_recursion_bug_msg);
+      printed_len = sizeof(printk_recursion_bug_msg);
+   }
    /* Emit the output into the temporary buffer */
-   printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
+   printed_len += vscnprintf(printk_buf + printed_len,
+              sizeof(printk_buf) - printed_len, fmt, args);
 
    /*
     * Copy the output into log_buf.  If the caller didn't provide
@@ -680,7 +729,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                loglev_char = default_message_loglevel
                   + '0';
             }
-            t = printk_clock();
+            t = cpu_clock(printk_cpu);
             nanosec_rem = do_div(t, 1000000000);
             tlen = sprintf(tbuf,
                   "<%c>[%5lu.%06lu] ",
@@ -710,42 +759,22 @@ asmlinkage int vprintk(const char *fmt, va_list args)
          log_level_unknown = 1;
    }
 
-   if (!down_trylock(&console_sem)) {
-      /*
-       * We own the drivers.  We can drop the spinlock and
-       * let release_console_sem() print the text, maybe ...
-       */
-      console_locked = 1;
-      printk_cpu = UINT_MAX;
-      spin_unlock(&logbuf_lock);
+   /*
+    * Try to acquire and then immediately release the
+    * console semaphore. The release will do all the
+    * actual magic (print out buffers, wake up klogd,
+    * etc). 
+    *
+    * The acquire_console_semaphore_for_printk() function
+    * will release 'logbuf_lock' regardless of whether it
+    * actually gets the semaphore or not.
+    */
+   if (acquire_console_semaphore_for_printk(this_cpu))
+      release_console_sem();
 
-      /*
-       * 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(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();
-      raw_local_irq_restore(flags);
-   } else {
-      /*
-       * Someone else owns the drivers.  We drop the spinlock, which
-       * allows the semaphore holder to proceed and to call the
-       * console drivers with the output which we just produced.
-       */
-      printk_cpu = UINT_MAX;
-      spin_unlock(&logbuf_lock);
-      lockdep_on();
-      raw_local_irq_restore(flags);
-   }
+   lockdep_on();
+out_restore_irqs:
+   raw_local_irq_restore(flags);
 
    preempt_enable();
    return printed_len;
@@ -760,7 +789,7 @@ asmlinkage long sys_syslog(int type, char __user *buf, int len)
    return -ENOSYS;
 }
 
-static void call_console_drivers(unsigned long start, unsigned long end)
+static void call_console_drivers(unsigned start, unsigned end)
 {
 }
 
@@ -953,8 +982,8 @@ void wake_up_klogd(void)
 void release_console_sem(void)
 {
    unsigned long flags;
-   unsigned long _con_start, _log_end;
-   unsigned long wake_klogd = 0;
+   unsigned _con_start, _log_end;
+   unsigned wake_klogd = 0;
 
    if (console_suspended) {
       up(&secondary_console_sem);
@@ -1235,6 +1264,7 @@ void tty_write_message(struct tty_struct *tty, char *msg)
    return;
 }
 
+#if defined CONFIG_PRINTK
 /*
  * printk rate limiting, lifted from the networking subsystem.
  *
@@ -1245,7 +1275,7 @@ void tty_write_message(struct tty_struct *tty, char *msg)
 int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
 {
    static DEFINE_SPINLOCK(ratelimit_lock);
-   static unsigned long toks = 10 * 5 * HZ;
+   static unsigned toks = 10 * 5 * HZ;
    static unsigned long last_msg;
    static int missed;
    unsigned long flags;
@@ -1304,3 +1334,4 @@ bool printk_timed_ratelimit(unsigned long *caller_jiffies,
    return false;
 }
 EXPORT_SYMBOL(printk_timed_ratelimit);
+#endif


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.