vserver 1.9.3
[linux-2.6.git] / kernel / printk.c
index 3b74688..11c6681 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/smp.h>
 #include <linux/security.h>
 #include <linux/bootmem.h>
+#include <linux/vs_base.h>
 
 #include <asm/uaccess.h>
 
@@ -192,6 +193,8 @@ static int __init log_buf_len_setup(char *str)
        unsigned long 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;
                char * new_log_buf;
@@ -247,7 +250,10 @@ int do_syslog(int type, char __user * buf, int len)
        unsigned long i, j, limit, count;
        int do_clear = 0;
        char c;
-       int error = 0;
+       int error = -EPERM;
+
+       if (!vx_check(0, VX_ADMIN|VX_WATCH))
+               return error;
 
        error = security_syslog(type);
        if (error)
@@ -471,6 +477,27 @@ static void emit_log_char(char c)
                logged_chars++;
 }
 
+/*
+ * Zap console related locks when oopsing. Only zap at most once
+ * every 10 seconds, to leave time for slow consoles to print a
+ * full oops.
+ */
+static void zap_locks(void)
+{
+       static unsigned long oops_timestamp;
+
+       if (time_after_eq(jiffies, oops_timestamp) &&
+                       !time_after(jiffies, oops_timestamp + 30*HZ))
+               return;
+
+       oops_timestamp = jiffies;
+
+       /* If a crash is occurring, make sure we can't deadlock */
+       spin_lock_init(&logbuf_lock);
+       /* And make sure that we print immediately */
+       init_MUTEX(&console_sem);
+}
+
 /*
  * This is printk.  It can be called from any context.  We want it to work.
  * 
@@ -487,26 +514,34 @@ static void emit_log_char(char c)
 asmlinkage int printk(const char *fmt, ...)
 {
        va_list args;
+       int r;
+
+       va_start(args, fmt);
+       r = vprintk(fmt, args);
+       va_end(args);
+
+       return r;
+}
+
+static volatile int printk_cpu = -1;
+
+asmlinkage int vprintk(const char *fmt, va_list args)
+{
        unsigned long flags;
        int printed_len;
        char *p;
        static char printk_buf[1024];
        static int log_level_unknown = 1;
 
-       if (oops_in_progress) {
-               /* If a crash is occurring, make sure we can't deadlock */
-               spin_lock_init(&logbuf_lock);
-               /* And make sure that we print immediately */
-               init_MUTEX(&console_sem);
-       }
+       if (unlikely(oops_in_progress && printk_cpu == smp_processor_id()))
+               zap_locks();
 
        /* This stops the holder of console_sem just where we want him */
        spin_lock_irqsave(&logbuf_lock, flags);
+       printk_cpu = smp_processor_id();
 
        /* Emit the output into the temporary buffer */
-       va_start(args, fmt);
        printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
-       va_end(args);
 
        /*
         * Copy the output into log_buf.  If the caller didn't provide
@@ -558,6 +593,7 @@ out:
        return printed_len;
 }
 EXPORT_SYMBOL(printk);
+EXPORT_SYMBOL(vprintk);
 
 /**
  * acquire_console_sem - lock the console system for exclusive use.
@@ -666,6 +702,47 @@ void console_unblank(void)
 }
 EXPORT_SYMBOL(console_unblank);
 
+/*
+ * Return the console tty driver structure and its associated index
+ */
+struct tty_driver *console_device(int *index)
+{
+       struct console *c;
+       struct tty_driver *driver = NULL;
+
+       acquire_console_sem();
+       for (c = console_drivers; c != NULL; c = c->next) {
+               if (!c->device)
+                       continue;
+               driver = c->device(c, index);
+               if (driver)
+                       break;
+       }
+       release_console_sem();
+       return driver;
+}
+
+/*
+ * Prevent further output on the passed console device so that (for example)
+ * serial drivers can disable console output before suspending a port, and can
+ * re-enable output afterwards.
+ */
+void console_stop(struct console *console)
+{
+       acquire_console_sem();
+       console->flags &= ~CON_ENABLED;
+       release_console_sem();
+}
+EXPORT_SYMBOL(console_stop);
+
+void console_start(struct console *console)
+{
+       acquire_console_sem();
+       console->flags |= CON_ENABLED;
+       release_console_sem();
+}
+EXPORT_SYMBOL(console_start);
+
 /*
  * The console driver calls this routine during kernel initialization
  * to register the console printing procedure with printk() and to