]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - kernel/printk/printk.c
Merge remote-tracking branch 'bcon/master'
[karo-tx-linux.git] / kernel / printk / printk.c
similarity index 90%
rename from kernel/printk.c
rename to kernel/printk/printk.c
index 5221c591ccbe0efecce759bb954a083500009211..49739db37b92435f159d0add6e3ec427e9c51611 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/security.h>
 #include <linux/bootmem.h>
 #include <linux/memblock.h>
+#include <linux/aio.h>
 #include <linux/syscalls.h>
 #include <linux/kexec.h>
 #include <linux/kdb.h>
 #include <linux/notifier.h>
 #include <linux/rculist.h>
 #include <linux/poll.h>
+#include <linux/irq_work.h>
+#include <linux/utsname.h>
 
 #include <asm/uaccess.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/printk.h>
 
-/*
- * Architectures can override it:
- */
-void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
-{
-}
+#include "console_cmdline.h"
+#include "braille.h"
 
 /* printk's without a loglevel use this.. */
 #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
@@ -62,8 +61,6 @@ void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
 #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
 #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */
 
-DECLARE_WAIT_QUEUE_HEAD(log_wait);
-
 int console_printk[4] = {
        DEFAULT_CONSOLE_LOGLEVEL,       /* console_loglevel */
        DEFAULT_MESSAGE_LOGLEVEL,       /* default_message_loglevel */
@@ -87,6 +84,12 @@ static DEFINE_SEMAPHORE(console_sem);
 struct console *console_drivers;
 EXPORT_SYMBOL_GPL(console_drivers);
 
+#ifdef CONFIG_LOCKDEP
+static struct lockdep_map console_lock_dep_map = {
+       .name = "console_lock"
+};
+#endif
+
 /*
  * This is used for debugging the mess that is the VT code by
  * keeping track if we have the console semaphore held. It's
@@ -105,19 +108,11 @@ static struct console *exclusive_console;
 /*
  *     Array of consoles built from command line options (console=)
  */
-struct console_cmdline
-{
-       char    name[8];                        /* Name of the driver       */
-       int     index;                          /* Minor dev. to use        */
-       char    *options;                       /* Options for the driver   */
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       char    *brl_options;                   /* Options for braille driver */
-#endif
-};
 
 #define MAX_CMDLINECONSOLES 8
 
 static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
+
 static int selected_console = -1;
 static int preferred_console = -1;
 int console_set_on_cmdline;
@@ -178,7 +173,7 @@ static int console_may_schedule;
  *         67                           "g"
  *   0032     00 00 00                  padding to next message header
  *
- * The 'struct log' buffer header must never be directly exported to
+ * The 'struct printk_log' buffer header must never be directly exported to
  * userspace, it is a kernel-private implementation detail that might
  * need to be changed in the future, when the requirements change.
  *
@@ -200,7 +195,7 @@ enum log_flags {
        LOG_CONT        = 8,    /* text is a fragment of a continuation line */
 };
 
-struct log {
+struct printk_log {
        u64 ts_nsec;            /* timestamp in nanoseconds */
        u16 len;                /* length of entire record */
        u16 text_len;           /* length of text buffer */
@@ -217,6 +212,7 @@ struct log {
 static DEFINE_RAW_SPINLOCK(logbuf_lock);
 
 #ifdef CONFIG_PRINTK
+DECLARE_WAIT_QUEUE_HEAD(log_wait);
 /* the next printk record to read by syslog(READ) or /proc/kmsg */
 static u64 syslog_seq;
 static u32 syslog_idx;
@@ -247,7 +243,7 @@ static u32 clear_idx;
 #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
 #define LOG_ALIGN 4
 #else
-#define LOG_ALIGN __alignof__(struct log)
+#define LOG_ALIGN __alignof__(struct printk_log)
 #endif
 #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
 static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
@@ -258,35 +254,35 @@ static u32 log_buf_len = __LOG_BUF_LEN;
 static volatile unsigned int logbuf_cpu = UINT_MAX;
 
 /* human readable text of the record */
-static char *log_text(const struct log *msg)
+static char *log_text(const struct printk_log *msg)
 {
-       return (char *)msg + sizeof(struct log);
+       return (char *)msg + sizeof(struct printk_log);
 }
 
 /* optional key/value pair dictionary attached to the record */
-static char *log_dict(const struct log *msg)
+static char *log_dict(const struct printk_log *msg)
 {
-       return (char *)msg + sizeof(struct log) + msg->text_len;
+       return (char *)msg + sizeof(struct printk_log) + msg->text_len;
 }
 
 /* get record by index; idx must point to valid msg */
-static struct log *log_from_idx(u32 idx)
+static struct printk_log *log_from_idx(u32 idx)
 {
-       struct log *msg = (struct log *)(log_buf + idx);
+       struct printk_log *msg = (struct printk_log *)(log_buf + idx);
 
        /*
         * A length == 0 record is the end of buffer marker. Wrap around and
         * read the message at the start of the buffer.
         */
        if (!msg->len)
-               return (struct log *)log_buf;
+               return (struct printk_log *)log_buf;
        return msg;
 }
 
 /* get next record; idx must point to valid msg */
 static u32 log_next(u32 idx)
 {
-       struct log *msg = (struct log *)(log_buf + idx);
+       struct printk_log *msg = (struct printk_log *)(log_buf + idx);
 
        /* length == 0 indicates the end of the buffer; wrap */
        /*
@@ -295,7 +291,7 @@ static u32 log_next(u32 idx)
         * return the one after that.
         */
        if (!msg->len) {
-               msg = (struct log *)log_buf;
+               msg = (struct printk_log *)log_buf;
                return msg->len;
        }
        return idx + msg->len;
@@ -307,11 +303,11 @@ static void log_store(int facility, int level,
                      const char *dict, u16 dict_len,
                      const char *text, u16 text_len)
 {
-       struct log *msg;
+       struct printk_log *msg;
        u32 size, pad_len;
 
        /* number of '\0' padding bytes to next message */
-       size = sizeof(struct log) + text_len + dict_len;
+       size = sizeof(struct printk_log) + text_len + dict_len;
        pad_len = (-size) & (LOG_ALIGN - 1);
        size += pad_len;
 
@@ -323,7 +319,7 @@ static void log_store(int facility, int level,
                else
                        free = log_first_idx - log_next_idx;
 
-               if (free > size + sizeof(struct log))
+               if (free > size + sizeof(struct printk_log))
                        break;
 
                /* drop old messages until we have enough contiuous space */
@@ -331,18 +327,18 @@ static void log_store(int facility, int level,
                log_first_seq++;
        }
 
-       if (log_next_idx + size + sizeof(struct log) >= log_buf_len) {
+       if (log_next_idx + size + sizeof(struct printk_log) >= log_buf_len) {
                /*
                 * This message + an additional empty header does not fit
                 * at the end of the buffer. Add an empty header with len == 0
                 * to signify a wrap around.
                 */
-               memset(log_buf + log_next_idx, 0, sizeof(struct log));
+               memset(log_buf + log_next_idx, 0, sizeof(struct printk_log));
                log_next_idx = 0;
        }
 
        /* fill message */
-       msg = (struct log *)(log_buf + log_next_idx);
+       msg = (struct printk_log *)(log_buf + log_next_idx);
        memcpy(log_text(msg), text, text_len);
        msg->text_len = text_len;
        memcpy(log_dict(msg), dict, dict_len);
@@ -355,13 +351,60 @@ static void log_store(int facility, int level,
        else
                msg->ts_nsec = local_clock();
        memset(log_dict(msg) + dict_len, 0, pad_len);
-       msg->len = sizeof(struct log) + text_len + dict_len + pad_len;
+       msg->len = sizeof(struct printk_log) + text_len + dict_len + pad_len;
 
        /* insert message */
        log_next_idx += msg->len;
        log_next_seq++;
 }
 
+#ifdef CONFIG_SECURITY_DMESG_RESTRICT
+int dmesg_restrict = 1;
+#else
+int dmesg_restrict;
+#endif
+
+static int syslog_action_restricted(int type)
+{
+       if (dmesg_restrict)
+               return 1;
+       /*
+        * Unless restricted, we allow "read all" and "get buffer size"
+        * for everybody.
+        */
+       return type != SYSLOG_ACTION_READ_ALL &&
+              type != SYSLOG_ACTION_SIZE_BUFFER;
+}
+
+static int check_syslog_permissions(int type, bool from_file)
+{
+       /*
+        * If this is from /proc/kmsg and we've already opened it, then we've
+        * already done the capabilities checks at open time.
+        */
+       if (from_file && type != SYSLOG_ACTION_OPEN)
+               return 0;
+
+       if (syslog_action_restricted(type)) {
+               if (capable(CAP_SYSLOG))
+                       return 0;
+               /*
+                * For historical reasons, accept CAP_SYS_ADMIN too, with
+                * a warning.
+                */
+               if (capable(CAP_SYS_ADMIN)) {
+                       pr_warn_once("%s (%d): Attempt to access syslog with "
+                                    "CAP_SYS_ADMIN but no CAP_SYSLOG "
+                                    "(deprecated).\n",
+                                current->comm, task_pid_nr(current));
+                       return 0;
+               }
+               return -EPERM;
+       }
+       return security_syslog(type);
+}
+
+
 /* /dev/kmsg - userspace message inject/listen interface */
 struct devkmsg_user {
        u64 seq;
@@ -431,7 +474,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
                            size_t count, loff_t *ppos)
 {
        struct devkmsg_user *user = file->private_data;
-       struct log *msg;
+       struct printk_log *msg;
        u64 ts_usec;
        size_t i;
        char cont = '-';
@@ -602,7 +645,8 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
                /* return error when data has vanished underneath us */
                if (user->seq < log_first_seq)
                        ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI;
-               ret = POLLIN|POLLRDNORM;
+               else
+                       ret = POLLIN|POLLRDNORM;
        }
        raw_spin_unlock_irq(&logbuf_lock);
 
@@ -618,7 +662,8 @@ static int devkmsg_open(struct inode *inode, struct file *file)
        if ((file->f_flags & O_ACCMODE) == O_WRONLY)
                return 0;
 
-       err = security_syslog(SYSLOG_ACTION_READ_ALL);
+       err = check_syslog_permissions(SYSLOG_ACTION_READ_ALL,
+                                      SYSLOG_FROM_READER);
        if (err)
                return err;
 
@@ -674,14 +719,14 @@ void log_buf_kexec_setup(void)
        VMCOREINFO_SYMBOL(log_first_idx);
        VMCOREINFO_SYMBOL(log_next_idx);
        /*
-        * Export struct log size and field offsets. User space tools can
+        * Export struct printk_log size and field offsets. User space tools can
         * parse it and detect any changes to structure down the line.
         */
-       VMCOREINFO_STRUCT_SIZE(log);
-       VMCOREINFO_OFFSET(log, ts_nsec);
-       VMCOREINFO_OFFSET(log, len);
-       VMCOREINFO_OFFSET(log, text_len);
-       VMCOREINFO_OFFSET(log, dict_len);
+       VMCOREINFO_STRUCT_SIZE(printk_log);
+       VMCOREINFO_OFFSET(printk_log, ts_nsec);
+       VMCOREINFO_OFFSET(printk_log, len);
+       VMCOREINFO_OFFSET(printk_log, text_len);
+       VMCOREINFO_OFFSET(printk_log, dict_len);
 }
 #endif
 
@@ -811,45 +856,6 @@ static inline void boot_delay_msec(int level)
 }
 #endif
 
-#ifdef CONFIG_SECURITY_DMESG_RESTRICT
-int dmesg_restrict = 1;
-#else
-int dmesg_restrict;
-#endif
-
-static int syslog_action_restricted(int type)
-{
-       if (dmesg_restrict)
-               return 1;
-       /* Unless restricted, we allow "read all" and "get buffer size" for everybody */
-       return type != SYSLOG_ACTION_READ_ALL && type != SYSLOG_ACTION_SIZE_BUFFER;
-}
-
-static int check_syslog_permissions(int type, bool from_file)
-{
-       /*
-        * If this is from /proc/kmsg and we've already opened it, then we've
-        * already done the capabilities checks at open time.
-        */
-       if (from_file && type != SYSLOG_ACTION_OPEN)
-               return 0;
-
-       if (syslog_action_restricted(type)) {
-               if (capable(CAP_SYSLOG))
-                       return 0;
-               /* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */
-               if (capable(CAP_SYS_ADMIN)) {
-                       printk_once(KERN_WARNING "%s (%d): "
-                                "Attempt to access syslog with CAP_SYS_ADMIN "
-                                "but no CAP_SYSLOG (deprecated).\n",
-                                current->comm, task_pid_nr(current));
-                       return 0;
-               }
-               return -EPERM;
-       }
-       return 0;
-}
-
 #if defined(CONFIG_PRINTK_TIME)
 static bool printk_time = 1;
 #else
@@ -873,7 +879,7 @@ static size_t print_time(u64 ts, char *buf)
                       (unsigned long)ts, rem_nsec / 1000);
 }
 
-static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
+static size_t print_prefix(const struct printk_log *msg, bool syslog, char *buf)
 {
        size_t len = 0;
        unsigned int prefix = (msg->facility << 3) | msg->level;
@@ -896,7 +902,7 @@ static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
        return len;
 }
 
-static size_t msg_print_text(const struct log *msg, enum log_flags prev,
+static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
                             bool syslog, char *buf, size_t size)
 {
        const char *text = log_text(msg);
@@ -958,7 +964,7 @@ static size_t msg_print_text(const struct log *msg, enum log_flags prev,
 static int syslog_print(char __user *buf, int size)
 {
        char *text;
-       struct log *msg;
+       struct printk_log *msg;
        int len = 0;
 
        text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL);
@@ -1049,7 +1055,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                idx = clear_idx;
                prev = 0;
                while (seq < log_next_seq) {
-                       struct log *msg = log_from_idx(idx);
+                       struct printk_log *msg = log_from_idx(idx);
 
                        len += msg_print_text(msg, prev, true, NULL, 0);
                        prev = msg->flags;
@@ -1062,7 +1068,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                idx = clear_idx;
                prev = 0;
                while (len > size && seq < log_next_seq) {
-                       struct log *msg = log_from_idx(idx);
+                       struct printk_log *msg = log_from_idx(idx);
 
                        len -= msg_print_text(msg, prev, true, NULL, 0);
                        prev = msg->flags;
@@ -1076,7 +1082,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                len = 0;
                prev = 0;
                while (len >= 0 && seq < next_seq) {
-                       struct log *msg = log_from_idx(idx);
+                       struct printk_log *msg = log_from_idx(idx);
                        int textlen;
 
                        textlen = msg_print_text(msg, prev, true, text,
@@ -1222,7 +1228,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
 
                        error = 0;
                        while (seq < log_next_seq) {
-                               struct log *msg = log_from_idx(idx);
+                               struct printk_log *msg = log_from_idx(idx);
 
                                error += msg_print_text(msg, prev, true, NULL, 0);
                                idx = log_next(idx);
@@ -1247,7 +1253,7 @@ out:
 
 SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
 {
-       return do_syslog(type, buf, len, SYSLOG_FROM_CALL);
+       return do_syslog(type, buf, len, SYSLOG_FROM_READER);
 }
 
 /*
@@ -1259,7 +1265,7 @@ static void call_console_drivers(int level, const char *text, size_t len)
 {
        struct console *con;
 
-       trace_console(text, 0, len, len);
+       trace_console(text, len);
 
        if (!console_drivers)
                return;
@@ -1359,9 +1365,9 @@ static int console_trylock_for_printk(unsigned int cpu)
                }
        }
        logbuf_cpu = UINT_MAX;
+       raw_spin_unlock(&logbuf_lock);
        if (wake)
                up(&console_sem);
-       raw_spin_unlock(&logbuf_lock);
        return retval;
 }
 
@@ -1709,15 +1715,38 @@ static struct cont {
        u8 level;
        bool flushed:1;
 } cont;
-static struct log *log_from_idx(u32 idx) { return NULL; }
+static struct printk_log *log_from_idx(u32 idx) { return NULL; }
 static u32 log_next(u32 idx) { return 0; }
 static void call_console_drivers(int level, const char *text, size_t len) {}
-static size_t msg_print_text(const struct log *msg, enum log_flags prev,
+static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
                             bool syslog, char *buf, size_t size) { return 0; }
 static size_t cont_print_text(char *text, size_t size) { return 0; }
 
 #endif /* CONFIG_PRINTK */
 
+#ifdef CONFIG_EARLY_PRINTK
+struct console *early_console;
+
+void early_vprintk(const char *fmt, va_list ap)
+{
+       if (early_console) {
+               char buf[512];
+               int n = vscnprintf(buf, sizeof(buf), fmt, ap);
+
+               early_console->write(early_console, buf, n);
+       }
+}
+
+asmlinkage void early_printk(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       early_vprintk(fmt, ap);
+       va_end(ap);
+}
+#endif
+
 static int __add_preferred_console(char *name, int idx, char *options,
                                   char *brl_options)
 {
@@ -1728,23 +1757,23 @@ static int __add_preferred_console(char *name, int idx, char *options,
         *      See if this tty is not yet registered, and
         *      if we have a slot free.
         */
-       for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
-               if (strcmp(console_cmdline[i].name, name) == 0 &&
-                         console_cmdline[i].index == idx) {
-                               if (!brl_options)
-                                       selected_console = i;
-                               return 0;
+       for (i = 0, c = console_cmdline;
+            i < MAX_CMDLINECONSOLES && c->name[0];
+            i++, c++) {
+               if (strcmp(c->name, name) == 0 && c->index == idx) {
+                       if (!brl_options)
+                               selected_console = i;
+                       return 0;
                }
+       }
        if (i == MAX_CMDLINECONSOLES)
                return -E2BIG;
        if (!brl_options)
                selected_console = i;
-       c = &console_cmdline[i];
        strlcpy(c->name, name, sizeof(c->name));
        c->options = options;
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       c->brl_options = brl_options;
-#endif
+       braille_set_options(c, brl_options);
+
        c->index = idx;
        return 0;
 }
@@ -1757,20 +1786,8 @@ static int __init console_setup(char *str)
        char *s, *options, *brl_options = NULL;
        int idx;
 
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       if (!memcmp(str, "brl,", 4)) {
-               brl_options = "";
-               str += 4;
-       } else if (!memcmp(str, "brl=", 4)) {
-               brl_options = str + 4;
-               str = strchr(brl_options, ',');
-               if (!str) {
-                       printk(KERN_ERR "need port name after brl=\n");
-                       return 1;
-               }
-               *(str++) = 0;
-       }
-#endif
+       if (_braille_console_setup(&str, &brl_options))
+               return 1;
 
        /*
         * Decode str into name, index, options.
@@ -1825,15 +1842,15 @@ int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, cha
        struct console_cmdline *c;
        int i;
 
-       for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
-               if (strcmp(console_cmdline[i].name, name) == 0 &&
-                         console_cmdline[i].index == idx) {
-                               c = &console_cmdline[i];
-                               strlcpy(c->name, name_new, sizeof(c->name));
-                               c->name[sizeof(c->name) - 1] = 0;
-                               c->options = options;
-                               c->index = idx_new;
-                               return i;
+       for (i = 0, c = console_cmdline;
+            i < MAX_CMDLINECONSOLES && c->name[0];
+            i++, c++)
+               if (strcmp(c->name, name) == 0 && c->index == idx) {
+                       strlcpy(c->name, name_new, sizeof(c->name));
+                       c->name[sizeof(c->name) - 1] = 0;
+                       c->options = options;
+                       c->index = idx_new;
+                       return i;
                }
        /* not found */
        return -1;
@@ -1888,7 +1905,7 @@ void resume_console(void)
  * called when a new CPU comes online (or fails to come up), and ensures
  * that any such output gets printed.
  */
-static int __cpuinit console_cpu_notify(struct notifier_block *self,
+static int console_cpu_notify(struct notifier_block *self,
        unsigned long action, void *hcpu)
 {
        switch (action) {
@@ -1919,6 +1936,7 @@ void console_lock(void)
                return;
        console_locked = 1;
        console_may_schedule = 1;
+       mutex_acquire(&console_lock_dep_map, 0, 0, _RET_IP_);
 }
 EXPORT_SYMBOL(console_lock);
 
@@ -1940,6 +1958,7 @@ int console_trylock(void)
        }
        console_locked = 1;
        console_may_schedule = 0;
+       mutex_acquire(&console_lock_dep_map, 0, 1, _RET_IP_);
        return 1;
 }
 EXPORT_SYMBOL(console_trylock);
@@ -1949,43 +1968,6 @@ int is_console_locked(void)
        return console_locked;
 }
 
-/*
- * Delayed printk version, for scheduler-internal messages:
- */
-#define PRINTK_BUF_SIZE                512
-
-#define PRINTK_PENDING_WAKEUP  0x01
-#define PRINTK_PENDING_SCHED   0x02
-
-static DEFINE_PER_CPU(int, printk_pending);
-static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf);
-
-void printk_tick(void)
-{
-       if (__this_cpu_read(printk_pending)) {
-               int pending = __this_cpu_xchg(printk_pending, 0);
-               if (pending & PRINTK_PENDING_SCHED) {
-                       char *buf = __get_cpu_var(printk_sched_buf);
-                       printk(KERN_WARNING "[sched_delayed] %s", buf);
-               }
-               if (pending & PRINTK_PENDING_WAKEUP)
-                       wake_up_interruptible(&log_wait);
-       }
-}
-
-int printk_needs_cpu(int cpu)
-{
-       if (cpu_is_offline(cpu))
-               printk_tick();
-       return __this_cpu_read(printk_pending);
-}
-
-void wake_up_klogd(void)
-{
-       if (waitqueue_active(&log_wait))
-               this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
-}
-
 static void console_cont_flush(char *text, size_t size)
 {
        unsigned long flags;
@@ -2048,7 +2030,7 @@ void console_unlock(void)
        console_cont_flush(text, sizeof(text));
 again:
        for (;;) {
-               struct log *msg;
+               struct printk_log *msg;
                size_t len;
                int level;
 
@@ -2100,6 +2082,7 @@ skip:
                local_irq_restore(flags);
        }
        console_locked = 0;
+       mutex_release(&console_lock_dep_map, 1, _RET_IP_);
 
        /* Release the exclusive_console once it is used */
        if (unlikely(exclusive_console))
@@ -2242,6 +2225,7 @@ void register_console(struct console *newcon)
        int i;
        unsigned long flags;
        struct console *bcon = NULL;
+       struct console_cmdline *c;
 
        /*
         * before we register a new CON_BOOT console, make sure we don't
@@ -2289,30 +2273,25 @@ void register_console(struct console *newcon)
         *      See if this console matches one we selected on
         *      the command line.
         */
-       for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
-                       i++) {
-               if (strcmp(console_cmdline[i].name, newcon->name) != 0)
+       for (i = 0, c = console_cmdline;
+            i < MAX_CMDLINECONSOLES && c->name[0];
+            i++, c++) {
+               if (strcmp(c->name, newcon->name) != 0)
                        continue;
                if (newcon->index >= 0 &&
-                   newcon->index != console_cmdline[i].index)
+                   newcon->index != c->index)
                        continue;
                if (newcon->index < 0)
-                       newcon->index = console_cmdline[i].index;
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-               if (console_cmdline[i].brl_options) {
-                       newcon->flags |= CON_BRL;
-                       braille_register_console(newcon,
-                                       console_cmdline[i].index,
-                                       console_cmdline[i].options,
-                                       console_cmdline[i].brl_options);
+                       newcon->index = c->index;
+
+               if (_braille_register_console(newcon, c))
                        return;
-               }
-#endif
+
                if (newcon->setup &&
                    newcon->setup(newcon, console_cmdline[i].options) != 0)
                        break;
                newcon->flags |= CON_ENABLED;
-               newcon->index = console_cmdline[i].index;
+               newcon->index = c->index;
                if (i == selected_console) {
                        newcon->flags |= CON_CONSDEV;
                        preferred_console = selected_console;
@@ -2395,13 +2374,13 @@ EXPORT_SYMBOL(register_console);
 int unregister_console(struct console *console)
 {
         struct console *a, *b;
-       int res = 1;
+       int res;
 
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       if (console->flags & CON_BRL)
-               return braille_unregister_console(console);
-#endif
+       res = _braille_unregister_console(console);
+       if (res)
+               return res;
 
+       res = 1;
        console_lock();
        if (console_drivers == console) {
                console_drivers=console->next;
@@ -2447,6 +2426,44 @@ static int __init printk_late_init(void)
 late_initcall(printk_late_init);
 
 #if defined CONFIG_PRINTK
+/*
+ * Delayed printk version, for scheduler-internal messages:
+ */
+#define PRINTK_BUF_SIZE                512
+
+#define PRINTK_PENDING_WAKEUP  0x01
+#define PRINTK_PENDING_SCHED   0x02
+
+static DEFINE_PER_CPU(int, printk_pending);
+static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf);
+
+static void wake_up_klogd_work_func(struct irq_work *irq_work)
+{
+       int pending = __this_cpu_xchg(printk_pending, 0);
+
+       if (pending & PRINTK_PENDING_SCHED) {
+               char *buf = __get_cpu_var(printk_sched_buf);
+               printk(KERN_WARNING "[sched_delayed] %s", buf);
+       }
+
+       if (pending & PRINTK_PENDING_WAKEUP)
+               wake_up_interruptible(&log_wait);
+}
+
+static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = {
+       .func = wake_up_klogd_work_func,
+       .flags = IRQ_WORK_LAZY,
+};
+
+void wake_up_klogd(void)
+{
+       preempt_disable();
+       if (waitqueue_active(&log_wait)) {
+               this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
+               irq_work_queue(&__get_cpu_var(wake_up_klogd_work));
+       }
+       preempt_enable();
+}
 
 int printk_sched(const char *fmt, ...)
 {
@@ -2463,6 +2480,7 @@ int printk_sched(const char *fmt, ...)
        va_end(args);
 
        __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED);
+       irq_work_queue(&__get_cpu_var(wake_up_klogd_work));
        local_irq_restore(flags);
 
        return r;
@@ -2628,7 +2646,7 @@ void kmsg_dump(enum kmsg_dump_reason reason)
 bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog,
                               char *line, size_t size, size_t *len)
 {
-       struct log *msg;
+       struct printk_log *msg;
        size_t l = 0;
        bool ret = false;
 
@@ -2740,7 +2758,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        idx = dumper->cur_idx;
        prev = 0;
        while (seq < dumper->next_seq) {
-               struct log *msg = log_from_idx(idx);
+               struct printk_log *msg = log_from_idx(idx);
 
                l += msg_print_text(msg, prev, true, NULL, 0);
                idx = log_next(idx);
@@ -2753,7 +2771,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        idx = dumper->cur_idx;
        prev = 0;
        while (l > size && seq < dumper->next_seq) {
-               struct log *msg = log_from_idx(idx);
+               struct printk_log *msg = log_from_idx(idx);
 
                l -= msg_print_text(msg, prev, true, NULL, 0);
                idx = log_next(idx);
@@ -2768,7 +2786,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        l = 0;
        prev = 0;
        while (seq < dumper->next_seq) {
-               struct log *msg = log_from_idx(idx);
+               struct printk_log *msg = log_from_idx(idx);
 
                l += msg_print_text(msg, prev, syslog, buf + l, size - l);
                idx = log_next(idx);
@@ -2822,4 +2840,65 @@ void kmsg_dump_rewind(struct kmsg_dumper *dumper)
        raw_spin_unlock_irqrestore(&logbuf_lock, flags);
 }
 EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
+
+static char dump_stack_arch_desc_str[128];
+
+/**
+ * dump_stack_set_arch_desc - set arch-specific str to show with task dumps
+ * @fmt: printf-style format string
+ * @...: arguments for the format string
+ *
+ * The configured string will be printed right after utsname during task
+ * dumps.  Usually used to add arch-specific system identifiers.  If an
+ * arch wants to make use of such an ID string, it should initialize this
+ * as soon as possible during boot.
+ */
+void __init dump_stack_set_arch_desc(const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       vsnprintf(dump_stack_arch_desc_str, sizeof(dump_stack_arch_desc_str),
+                 fmt, args);
+       va_end(args);
+}
+
+/**
+ * dump_stack_print_info - print generic debug info for dump_stack()
+ * @log_lvl: log level
+ *
+ * Arch-specific dump_stack() implementations can use this function to
+ * print out the same debug information as the generic dump_stack().
+ */
+void dump_stack_print_info(const char *log_lvl)
+{
+       printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s\n",
+              log_lvl, raw_smp_processor_id(), current->pid, current->comm,
+              print_tainted(), init_utsname()->release,
+              (int)strcspn(init_utsname()->version, " "),
+              init_utsname()->version);
+
+       if (dump_stack_arch_desc_str[0] != '\0')
+               printk("%sHardware name: %s\n",
+                      log_lvl, dump_stack_arch_desc_str);
+
+       print_worker_info(log_lvl, current);
+}
+
+/**
+ * show_regs_print_info - print generic debug info for show_regs()
+ * @log_lvl: log level
+ *
+ * show_regs() implementations can use this function to print out generic
+ * debug information.
+ */
+void show_regs_print_info(const char *log_lvl)
+{
+       dump_stack_print_info(log_lvl);
+
+       printk("%stask: %p ti: %p task.ti: %p\n",
+              log_lvl, current, current_thread_info(),
+              task_thread_info(current));
+}
+
 #endif