Merge branch 'for-4.19-nmi' into for-linus
authorPetr Mladek <pmladek@suse.com>
Tue, 14 Aug 2018 11:36:15 +0000 (13:36 +0200)
committerPetr Mladek <pmladek@suse.com>
Tue, 14 Aug 2018 11:36:15 +0000 (13:36 +0200)
1  2 
include/linux/printk.h
kernel/printk/printk.c

diff --combined include/linux/printk.h
@@@ -50,15 -50,15 +50,15 @@@ static inline const char *printk_skip_h
  /* We show everything that is MORE important than this.. */
  #define CONSOLE_LOGLEVEL_SILENT  0 /* Mum's the word */
  #define CONSOLE_LOGLEVEL_MIN   1 /* Minimum loglevel we let people use */
 -#define CONSOLE_LOGLEVEL_QUIET         4 /* Shhh ..., when booted with "quiet" */
  #define CONSOLE_LOGLEVEL_DEBUG        10 /* issue debug messages */
  #define CONSOLE_LOGLEVEL_MOTORMOUTH 15        /* You can't shut this one up */
  
  /*
 - * Default used to be hard-coded at 7, we're now allowing it to be set from
 - * kernel config.
 + * Default used to be hard-coded at 7, quiet used to be hardcoded at 4,
 + * we're now allowing both to be set from kernel config.
   */
  #define CONSOLE_LOGLEVEL_DEFAULT CONFIG_CONSOLE_LOGLEVEL_DEFAULT
 +#define CONSOLE_LOGLEVEL_QUIET         CONFIG_CONSOLE_LOGLEVEL_QUIET
  
  extern int console_printk[];
  
@@@ -148,9 -148,13 +148,13 @@@ void early_printk(const char *s, ...) 
  #ifdef CONFIG_PRINTK_NMI
  extern void printk_nmi_enter(void);
  extern void printk_nmi_exit(void);
+ extern void printk_nmi_direct_enter(void);
+ extern void printk_nmi_direct_exit(void);
  #else
  static inline void printk_nmi_enter(void) { }
  static inline void printk_nmi_exit(void) { }
+ static inline void printk_nmi_direct_enter(void) { }
+ static inline void printk_nmi_direct_exit(void) { }
  #endif /* PRINTK_NMI */
  
  #ifdef CONFIG_PRINTK
diff --combined kernel/printk/printk.c
@@@ -349,7 -349,7 +349,7 @@@ static int console_msg_format = MSG_FOR
   */
  
  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 */
@@@ -1352,68 -1352,71 +1352,68 @@@ static int syslog_print_all(char __use
  {
        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);
 +
 +              len += msg_print_text(msg, true, NULL, 0);
 +              idx = log_next(idx);
 +              seq++;
 +      }
  
 -              /*
 -               * 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++;
 -              }
 +      /* 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();
  
 -                      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;
 -                      }
 +              if (seq < log_first_seq) {
 +                      /* messages are gone, move to next one */
 +                      seq = log_first_seq;
 +                      idx = log_first_idx;
                }
        }
  
        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;
                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:
@@@ -1829,28 -1824,16 +1829,16 @@@ static size_t log_output(int facility, 
        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.
        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(). */
@@@ -2021,6 -2022,7 +2030,6 @@@ static void call_console_drivers(const 
                                 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 */
  
@@@ -2356,10 -2358,11 +2365,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++;
@@@ -2884,16 -2887,20 +2893,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;
  }