]> git.ipfire.org Git - thirdparty/linux.git/blobdiff - kernel/printk/printk.c
Merge branch 'for-5.8' into for-linus
[thirdparty/linux.git] / kernel / printk / printk.c
index c59d9a1567ad36d9e52c73488c64d0407859919e..2bafd5ce405732a05b2bea748d7186ec9c8e1e84 100644 (file)
@@ -461,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)
 {
@@ -963,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;
        }
@@ -1147,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;
 
@@ -1773,9 +1811,6 @@ static void call_console_drivers(const char *ext_text, size_t ext_len,
 
        trace_console_rcuidle(text, len);
 
-       if (!console_drivers)
-               return;
-
        for_each_console(con) {
                if (exclusive_console && con != exclusive_console)
                        continue;
@@ -2169,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;
 
@@ -2712,19 +2750,17 @@ void register_console(struct console *newcon)
        struct console *bcon = NULL;
        int err;
 
-       if (console_drivers)
-               for_each_console(bcon)
-                       if (WARN(bcon == newcon,
-                                       "console '%s%d' already registered\n",
-                                       bcon->name, bcon->index))
-                               return;
+       for_each_console(bcon) {
+               if (WARN(bcon == newcon, "console '%s%d' already registered\n",
+                                        bcon->name, bcon->index))
+                       return;
+       }
 
        /*
         * before we register a new CON_BOOT console, make sure we don't
         * already have a valid console
         */
-       if (console_drivers && newcon->flags & CON_BOOT) {
-               /* find the last or real console */
+       if (newcon->flags & CON_BOOT) {
                for_each_console(bcon) {
                        if (!(bcon->flags & CON_BOOT)) {
                                pr_info("Too late to register bootconsole %s%d\n",
@@ -2847,7 +2883,7 @@ EXPORT_SYMBOL(register_console);
 
 int unregister_console(struct console *console)
 {
-        struct console *a, *b;
+       struct console *con;
        int res;
 
        pr_info("%sconsole [%s%d] disabled\n",
@@ -2855,26 +2891,30 @@ int unregister_console(struct console *console)
                console->name, console->index);
 
        res = _braille_unregister_console(console);
-       if (res)
+       if (res < 0)
                return res;
+       if (res > 0)
+               return 0;
 
-       res = 1;
+       res = -ENODEV;
        console_lock();
        if (console_drivers == console) {
                console_drivers=console->next;
                res = 0;
-       } else if (console_drivers) {
-               for (a=console_drivers->next, b=console_drivers ;
-                    a; b=a, a=b->next) {
-                       if (a == console) {
-                               b->next = a->next;
+       } else {
+               for_each_console(con) {
+                       if (con->next == console) {
+                               con->next = console->next;
                                res = 0;
                                break;
                        }
                }
        }
 
-       if (!res && (console->flags & CON_EXTENDED))
+       if (res)
+               goto out_disable_unlock;
+
+       if (console->flags & CON_EXTENDED)
                nr_ext_console_drivers--;
 
        /*
@@ -2887,6 +2927,16 @@ int unregister_console(struct console *console)
        console->flags &= ~CON_ENABLED;
        console_unlock();
        console_sysfs_notify();
+
+       if (console->exit)
+               res = console->exit(console);
+
+       return res;
+
+out_disable_unlock:
+       console->flags &= ~CON_ENABLED;
+       console_unlock();
+
        return res;
 }
 EXPORT_SYMBOL(unregister_console);
@@ -3000,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);
@@ -3010,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));
@@ -3351,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
@@ -3369,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