Merge tag 'fbdev-v4.19' of https://github.com/bzolnier/linux
[muen/linux.git] / kernel / printk / printk.c
index 7d32a86758cdd26d3e3c57787be9d65bd4ef132d..924e37fb1620b5440e3265b4cc3465dad50475c1 100644 (file)
@@ -352,7 +352,7 @@ static int console_msg_format = MSG_FORMAT_DEFAULT;
  */
 
 enum log_flags {
-       LOG_NOCONS      = 1,    /* already flushed, do not print to console */
+       LOG_NOCONS      = 1,    /* suppress print, do not print to console */
        LOG_NEWLINE     = 2,    /* text ended with a newline */
        LOG_PREFIX      = 4,    /* text started with a prefix */
        LOG_CONT        = 8,    /* text is a fragment of a continuation line */
@@ -1355,71 +1355,68 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
 {
        char *text;
        int len = 0;
+       u64 next_seq;
+       u64 seq;
+       u32 idx;
 
        text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL);
        if (!text)
                return -ENOMEM;
 
        logbuf_lock_irq();
-       if (buf) {
-               u64 next_seq;
-               u64 seq;
-               u32 idx;
+       /*
+        * Find first record that fits, including all following records,
+        * into the user-provided buffer for this dump.
+        */
+       seq = clear_seq;
+       idx = clear_idx;
+       while (seq < log_next_seq) {
+               struct printk_log *msg = log_from_idx(idx);
 
-               /*
-                * Find first record that fits, including all following records,
-                * into the user-provided buffer for this dump.
-                */
-               seq = clear_seq;
-               idx = clear_idx;
-               while (seq < log_next_seq) {
-                       struct printk_log *msg = log_from_idx(idx);
-
-                       len += msg_print_text(msg, true, NULL, 0);
-                       idx = log_next(idx);
-                       seq++;
-               }
+               len += msg_print_text(msg, true, NULL, 0);
+               idx = log_next(idx);
+               seq++;
+       }
 
-               /* move first record forward until length fits into the buffer */
-               seq = clear_seq;
-               idx = clear_idx;
-               while (len > size && seq < log_next_seq) {
-                       struct printk_log *msg = log_from_idx(idx);
+       /* move first record forward until length fits into the buffer */
+       seq = clear_seq;
+       idx = clear_idx;
+       while (len > size && seq < log_next_seq) {
+               struct printk_log *msg = log_from_idx(idx);
 
-                       len -= msg_print_text(msg, true, NULL, 0);
-                       idx = log_next(idx);
-                       seq++;
-               }
+               len -= msg_print_text(msg, true, NULL, 0);
+               idx = log_next(idx);
+               seq++;
+       }
 
-               /* last message fitting into this dump */
-               next_seq = log_next_seq;
+       /* last message fitting into this dump */
+       next_seq = log_next_seq;
 
-               len = 0;
-               while (len >= 0 && seq < next_seq) {
-                       struct printk_log *msg = log_from_idx(idx);
-                       int textlen;
+       len = 0;
+       while (len >= 0 && seq < next_seq) {
+               struct printk_log *msg = log_from_idx(idx);
+               int textlen;
 
-                       textlen = msg_print_text(msg, true, text,
-                                                LOG_LINE_MAX + PREFIX_MAX);
-                       if (textlen < 0) {
-                               len = textlen;
-                               break;
-                       }
-                       idx = log_next(idx);
-                       seq++;
+               textlen = msg_print_text(msg, true, text,
+                                        LOG_LINE_MAX + PREFIX_MAX);
+               if (textlen < 0) {
+                       len = textlen;
+                       break;
+               }
+               idx = log_next(idx);
+               seq++;
 
-                       logbuf_unlock_irq();
-                       if (copy_to_user(buf + len, text, textlen))
-                               len = -EFAULT;
-                       else
-                               len += textlen;
-                       logbuf_lock_irq();
-
-                       if (seq < log_first_seq) {
-                               /* messages are gone, move to next one */
-                               seq = log_first_seq;
-                               idx = log_first_idx;
-                       }
+               logbuf_unlock_irq();
+               if (copy_to_user(buf + len, text, textlen))
+                       len = -EFAULT;
+               else
+                       len += textlen;
+               logbuf_lock_irq();
+
+               if (seq < log_first_seq) {
+                       /* messages are gone, move to next one */
+                       seq = log_first_seq;
+                       idx = log_first_idx;
                }
        }
 
@@ -1433,6 +1430,14 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
        return len;
 }
 
+static void syslog_clear(void)
+{
+       logbuf_lock_irq();
+       clear_seq = log_next_seq;
+       clear_idx = log_next_idx;
+       logbuf_unlock_irq();
+}
+
 int do_syslog(int type, char __user *buf, int len, int source)
 {
        bool clear = false;
@@ -1477,7 +1482,7 @@ int do_syslog(int type, char __user *buf, int len, int source)
                break;
        /* Clear ring buffer */
        case SYSLOG_ACTION_CLEAR:
-               syslog_print_all(NULL, 0, true);
+               syslog_clear();
                break;
        /* Disable logging to console */
        case SYSLOG_ACTION_CONSOLE_OFF:
@@ -1827,28 +1832,16 @@ static size_t log_output(int facility, int level, enum log_flags lflags, const c
        return log_store(facility, level, lflags, 0, dict, dictlen, text, text_len);
 }
 
-asmlinkage int vprintk_emit(int facility, int level,
-                           const char *dict, size_t dictlen,
-                           const char *fmt, va_list args)
+/* Must be called under logbuf_lock. */
+int vprintk_store(int facility, int level,
+                 const char *dict, size_t dictlen,
+                 const char *fmt, va_list args)
 {
        static char textbuf[LOG_LINE_MAX];
        char *text = textbuf;
        size_t text_len;
        enum log_flags lflags = 0;
-       unsigned long flags;
-       int printed_len;
-       bool in_sched = false;
 
-       if (level == LOGLEVEL_SCHED) {
-               level = LOGLEVEL_DEFAULT;
-               in_sched = true;
-       }
-
-       boot_delay_msec(level);
-       printk_delay();
-
-       /* This stops the holder of console_sem just where we want him */
-       logbuf_lock_irqsave(flags);
        /*
         * The printf needs to come first; we need the syslog
         * prefix which might be passed-in as a parameter.
@@ -1889,8 +1882,32 @@ asmlinkage int vprintk_emit(int facility, int level,
        if (dict)
                lflags |= LOG_PREFIX|LOG_NEWLINE;
 
-       printed_len = log_output(facility, level, lflags, dict, dictlen, text, text_len);
+       if (suppress_message_printing(level))
+               lflags |= LOG_NOCONS;
+
+       return log_output(facility, level, lflags,
+                         dict, dictlen, text, text_len);
+}
+
+asmlinkage int vprintk_emit(int facility, int level,
+                           const char *dict, size_t dictlen,
+                           const char *fmt, va_list args)
+{
+       int printed_len;
+       bool in_sched = false;
+       unsigned long flags;
+
+       if (level == LOGLEVEL_SCHED) {
+               level = LOGLEVEL_DEFAULT;
+               in_sched = true;
+       }
 
+       boot_delay_msec(level);
+       printk_delay();
+
+       /* This stops the holder of console_sem just where we want him */
+       logbuf_lock_irqsave(flags);
+       printed_len = vprintk_store(facility, level, dict, dictlen, fmt, args);
        logbuf_unlock_irqrestore(flags);
 
        /* If called from the scheduler, we can not call up(). */
@@ -2016,7 +2033,6 @@ static void call_console_drivers(const char *ext_text, size_t ext_len,
                                 const char *text, size_t len) {}
 static size_t msg_print_text(const struct printk_log *msg,
                             bool syslog, char *buf, size_t size) { return 0; }
-static bool suppress_message_printing(int level) { return false; }
 
 #endif /* CONFIG_PRINTK */
 
@@ -2353,11 +2369,10 @@ skip:
                        break;
 
                msg = log_from_idx(console_idx);
-               if (suppress_message_printing(msg->level)) {
+               if (msg->flags & LOG_NOCONS) {
                        /*
-                        * Skip record we have buffered and already printed
-                        * directly to the console when we received it, and
-                        * record that has level above the console loglevel.
+                        * Skip record if !ignore_loglevel, and
+                        * record has level above the console loglevel.
                         */
                        console_idx = log_next(console_idx);
                        console_seq++;
@@ -2776,7 +2791,8 @@ EXPORT_SYMBOL(unregister_console);
 void __init console_init(void)
 {
        int ret;
-       initcall_t *call;
+       initcall_t call;
+       initcall_entry_t *ce;
 
        /* Setup the default TTY line discipline. */
        n_tty_init();
@@ -2785,13 +2801,14 @@ void __init console_init(void)
         * set up the console device so that later boot sequences can
         * inform about problems etc..
         */
-       call = __con_initcall_start;
+       ce = __con_initcall_start;
        trace_initcall_level("console");
-       while (call < __con_initcall_end) {
-               trace_initcall_start((*call));
-               ret = (*call)();
-               trace_initcall_finish((*call), ret);
-               call++;
+       while (ce < __con_initcall_end) {
+               call = initcall_from_entry(ce);
+               trace_initcall_start(call);
+               ret = call();
+               trace_initcall_finish(call, ret);
+               ce++;
        }
 }
 
@@ -2882,16 +2899,20 @@ void wake_up_klogd(void)
        preempt_enable();
 }
 
-int vprintk_deferred(const char *fmt, va_list args)
+void defer_console_output(void)
 {
-       int r;
-
-       r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args);
-
        preempt_disable();
        __this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT);
        irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
        preempt_enable();
+}
+
+int vprintk_deferred(const char *fmt, va_list args)
+{
+       int r;
+
+       r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args);
+       defer_console_output();
 
        return r;
 }