Merge branch 'for-5.8' into for-linus
[linux-block.git] / kernel / printk / printk.c
index 633f41a11d759c29adcabf3d9c4381a41c05d9ba..2bafd5ce405732a05b2bea748d7186ec9c8e1e84 100644 (file)
@@ -280,6 +280,7 @@ static struct console *exclusive_console;
 static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
 
 static int preferred_console = -1;
+static bool has_preferred_console;
 int console_set_on_cmdline;
 EXPORT_SYMBOL(console_set_on_cmdline);
 
@@ -460,6 +461,18 @@ static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
 static char *log_buf = __log_buf;
 static u32 log_buf_len = __LOG_BUF_LEN;
 
+/*
+ * We cannot access per-CPU data (e.g. per-CPU flush irq_work) before
+ * per_cpu_areas are initialised. This variable is set to true when
+ * it's safe to access per-CPU data.
+ */
+static bool __printk_percpu_data_ready __read_mostly;
+
+bool printk_percpu_data_ready(void)
+{
+       return __printk_percpu_data_ready;
+}
+
 /* Return log buffer address */
 char *log_buf_addr_get(void)
 {
@@ -962,6 +975,16 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
                user->idx = log_next_idx;
                user->seq = log_next_seq;
                break;
+       case SEEK_CUR:
+               /*
+                * It isn't supported due to the record nature of this
+                * interface: _SET _DATA and _END point to very specific
+                * record positions, while _CUR would be more useful in case
+                * of a byte-based log. Because of that, return the default
+                * errno value for invalid seek operation.
+                */
+               ret = -ESPIPE;
+               break;
        default:
                ret = -EINVAL;
        }
@@ -1146,12 +1169,28 @@ static void __init log_buf_add_cpu(void)
 static inline void log_buf_add_cpu(void) {}
 #endif /* CONFIG_SMP */
 
+static void __init set_percpu_data_ready(void)
+{
+       printk_safe_init();
+       /* Make sure we set this flag only after printk_safe() init is done */
+       barrier();
+       __printk_percpu_data_ready = true;
+}
+
 void __init setup_log_buf(int early)
 {
        unsigned long flags;
        char *new_log_buf;
        unsigned int free;
 
+       /*
+        * Some archs call setup_log_buf() multiple times - first is very
+        * early, e.g. from setup_arch(), and second - when percpu_areas
+        * are initialised.
+        */
+       if (!early)
+               set_percpu_data_ready();
+
        if (log_buf != __log_buf)
                return;
 
@@ -2112,7 +2151,7 @@ asmlinkage __visible void early_printk(const char *fmt, ...)
 #endif
 
 static int __add_preferred_console(char *name, int idx, char *options,
-                                  char *brl_options)
+                                  char *brl_options, bool user_specified)
 {
        struct console_cmdline *c;
        int i;
@@ -2127,6 +2166,8 @@ static int __add_preferred_console(char *name, int idx, char *options,
                if (strcmp(c->name, name) == 0 && c->index == idx) {
                        if (!brl_options)
                                preferred_console = i;
+                       if (user_specified)
+                               c->user_specified = true;
                        return 0;
                }
        }
@@ -2136,6 +2177,7 @@ static int __add_preferred_console(char *name, int idx, char *options,
                preferred_console = i;
        strlcpy(c->name, name, sizeof(c->name));
        c->options = options;
+       c->user_specified = user_specified;
        braille_set_options(c, brl_options);
 
        c->index = idx;
@@ -2162,6 +2204,9 @@ static int __init console_setup(char *str)
        char *s, *options, *brl_options = NULL;
        int idx;
 
+       if (str[0] == 0)
+               return 1;
+
        if (_braille_console_setup(&str, &brl_options))
                return 1;
 
@@ -2190,7 +2235,7 @@ static int __init console_setup(char *str)
        idx = simple_strtoul(s, NULL, 10);
        *s = 0;
 
-       __add_preferred_console(buf, idx, options, brl_options);
+       __add_preferred_console(buf, idx, options, brl_options, true);
        console_set_on_cmdline = 1;
        return 1;
 }
@@ -2211,7 +2256,7 @@ __setup("console=", console_setup);
  */
 int add_preferred_console(char *name, int idx, char *options)
 {
-       return __add_preferred_console(name, idx, options, NULL);
+       return __add_preferred_console(name, idx, options, NULL, false);
 }
 
 bool console_suspend_enabled = true;
@@ -2410,9 +2455,9 @@ again:
                printk_safe_enter_irqsave(flags);
                raw_spin_lock(&logbuf_lock);
                if (console_seq < log_first_seq) {
-                       len = sprintf(text,
-                                     "** %llu printk messages dropped **\n",
-                                     log_first_seq - console_seq);
+                       len = snprintf(text, sizeof(text),
+                                      "** %llu printk messages dropped **\n",
+                                      log_first_seq - console_seq);
 
                        /* messages are gone, move to first one */
                        console_seq = log_first_seq;
@@ -2623,6 +2668,63 @@ static int __init keep_bootcon_setup(char *str)
 
 early_param("keep_bootcon", keep_bootcon_setup);
 
+/*
+ * This is called by register_console() to try to match
+ * the newly registered console with any of the ones selected
+ * by either the command line or add_preferred_console() and
+ * setup/enable it.
+ *
+ * Care need to be taken with consoles that are statically
+ * enabled such as netconsole
+ */
+static int try_enable_new_console(struct console *newcon, bool user_specified)
+{
+       struct console_cmdline *c;
+       int i;
+
+       for (i = 0, c = console_cmdline;
+            i < MAX_CMDLINECONSOLES && c->name[0];
+            i++, c++) {
+               if (c->user_specified != user_specified)
+                       continue;
+               if (!newcon->match ||
+                   newcon->match(newcon, c->name, c->index, c->options) != 0) {
+                       /* default matching */
+                       BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name));
+                       if (strcmp(c->name, newcon->name) != 0)
+                               continue;
+                       if (newcon->index >= 0 &&
+                           newcon->index != c->index)
+                               continue;
+                       if (newcon->index < 0)
+                               newcon->index = c->index;
+
+                       if (_braille_register_console(newcon, c))
+                               return 0;
+
+                       if (newcon->setup &&
+                           newcon->setup(newcon, c->options) != 0)
+                               return -EIO;
+               }
+               newcon->flags |= CON_ENABLED;
+               if (i == preferred_console) {
+                       newcon->flags |= CON_CONSDEV;
+                       has_preferred_console = true;
+               }
+               return 0;
+       }
+
+       /*
+        * Some consoles, such as pstore and netconsole, can be enabled even
+        * without matching. Accept the pre-enabled consoles only when match()
+        * and setup() had a change to be called.
+        */
+       if (newcon->flags & CON_ENABLED && c->user_specified == user_specified)
+               return 0;
+
+       return -ENOENT;
+}
+
 /*
  * The console driver calls this routine during kernel initialization
  * to register the console printing procedure with printk() and to
@@ -2644,11 +2746,9 @@ early_param("keep_bootcon", keep_bootcon_setup);
  */
 void register_console(struct console *newcon)
 {
-       int i;
        unsigned long flags;
        struct console *bcon = NULL;
-       struct console_cmdline *c;
-       static bool has_preferred;
+       int err;
 
        for_each_console(bcon) {
                if (WARN(bcon == newcon, "console '%s%d' already registered\n",
@@ -2673,15 +2773,15 @@ void register_console(struct console *newcon)
        if (console_drivers && console_drivers->flags & CON_BOOT)
                bcon = console_drivers;
 
-       if (!has_preferred || bcon || !console_drivers)
-               has_preferred = preferred_console >= 0;
+       if (!has_preferred_console || bcon || !console_drivers)
+               has_preferred_console = preferred_console >= 0;
 
        /*
         *      See if we want to use this console driver. If we
         *      didn't select a console we take the first one
         *      that registers here.
         */
-       if (!has_preferred) {
+       if (!has_preferred_console) {
                if (newcon->index < 0)
                        newcon->index = 0;
                if (newcon->setup == NULL ||
@@ -2689,47 +2789,20 @@ void register_console(struct console *newcon)
                        newcon->flags |= CON_ENABLED;
                        if (newcon->device) {
                                newcon->flags |= CON_CONSDEV;
-                               has_preferred = true;
+                               has_preferred_console = true;
                        }
                }
        }
 
-       /*
-        *      See if this console matches one we selected on
-        *      the command line.
-        */
-       for (i = 0, c = console_cmdline;
-            i < MAX_CMDLINECONSOLES && c->name[0];
-            i++, c++) {
-               if (!newcon->match ||
-                   newcon->match(newcon, c->name, c->index, c->options) != 0) {
-                       /* default matching */
-                       BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name));
-                       if (strcmp(c->name, newcon->name) != 0)
-                               continue;
-                       if (newcon->index >= 0 &&
-                           newcon->index != c->index)
-                               continue;
-                       if (newcon->index < 0)
-                               newcon->index = c->index;
-
-                       if (_braille_register_console(newcon, c))
-                               return;
+       /* See if this console matches one we selected on the command line */
+       err = try_enable_new_console(newcon, true);
 
-                       if (newcon->setup &&
-                           newcon->setup(newcon, c->options) != 0)
-                               break;
-               }
+       /* If not, try to match against the platform default(s) */
+       if (err == -ENOENT)
+               err = try_enable_new_console(newcon, false);
 
-               newcon->flags |= CON_ENABLED;
-               if (i == preferred_console) {
-                       newcon->flags |= CON_CONSDEV;
-                       has_preferred = true;
-               }
-               break;
-       }
-
-       if (!(newcon->flags & CON_ENABLED))
+       /* printk() messages are not printed to the Braille console. */
+       if (err || newcon->flags & CON_BRL)
                return;
 
        /*
@@ -2751,6 +2824,8 @@ void register_console(struct console *newcon)
                console_drivers = newcon;
                if (newcon->next)
                        newcon->next->flags &= ~CON_CONSDEV;
+               /* Ensure this flag is always set for the head of the list */
+               newcon->flags |= CON_CONSDEV;
        } else {
                newcon->next = console_drivers->next;
                console_drivers->next = newcon;
@@ -2975,6 +3050,9 @@ static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = {
 
 void wake_up_klogd(void)
 {
+       if (!printk_percpu_data_ready())
+               return;
+
        preempt_disable();
        if (waitqueue_active(&log_wait)) {
                this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
@@ -2985,6 +3063,9 @@ void wake_up_klogd(void)
 
 void defer_console_output(void)
 {
+       if (!printk_percpu_data_ready())
+               return;
+
        preempt_disable();
        __this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT);
        irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
@@ -3326,7 +3407,7 @@ out:
 EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);
 
 /**
- * kmsg_dump_rewind_nolock - reset the interator (unlocked version)
+ * kmsg_dump_rewind_nolock - reset the iterator (unlocked version)
  * @dumper: registered kmsg dumper
  *
  * Reset the dumper's iterator so that kmsg_dump_get_line() and
@@ -3344,7 +3425,7 @@ void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper)
 }
 
 /**
- * kmsg_dump_rewind - reset the interator
+ * kmsg_dump_rewind - reset the iterator
  * @dumper: registered kmsg dumper
  *
  * Reset the dumper's iterator so that kmsg_dump_get_line() and