]> Git Repo - J-linux.git/commitdiff
Merge branch 'rework/printk_safe-removal' into for-linus
authorPetr Mladek <[email protected]>
Thu, 18 Nov 2021 09:03:47 +0000 (10:03 +0100)
committerPetr Mladek <[email protected]>
Thu, 18 Nov 2021 09:03:47 +0000 (10:03 +0100)
1  2 
arch/powerpc/kernel/watchdog.c
include/linux/printk.h
kernel/printk/printk.c

index f9ea0e5357f9290a15c7c843a6b2ce45129b74bc,6b7a83d5e03edb7553e98e66960c4afd8dbc1961..3fa6d240bade21c0e51002f48956e12db9003263
@@@ -24,7 -24,6 +24,7 @@@
  #include <linux/kdebug.h>
  #include <linux/sched/debug.h>
  #include <linux/delay.h>
 +#include <linux/processor.h>
  #include <linux/smp.h>
  
  #include <asm/interrupt.h>
@@@ -187,6 -186,12 +187,12 @@@ static void watchdog_smp_panic(int cpu
        if (sysctl_hardlockup_all_cpu_backtrace)
                trigger_allbutself_cpu_backtrace();
  
+       /*
+        * Force flush any remote buffers that might be stuck in IRQ context
+        * and therefore could not run their irq_work.
+        */
+       printk_trigger_flush();
        if (hardlockup_panic)
                nmi_panic(NULL, "Hard LOCKUP");
  
diff --combined include/linux/printk.h
index 85b656f82d752ecf18d67a693e4de0201ddd9a2e,596ad6fa03366847302b75212754c85547f3df76..9497f6b983399ac0cf6a21d5e4b57f9e144e2d74
@@@ -2,13 -2,12 +2,13 @@@
  #ifndef __KERNEL_PRINTK__
  #define __KERNEL_PRINTK__
  
 -#include <stdarg.h>
 +#include <linux/stdarg.h>
  #include <linux/init.h>
  #include <linux/kern_levels.h>
  #include <linux/linkage.h>
  #include <linux/cache.h>
  #include <linux/ratelimit_types.h>
 +#include <linux/once_lite.h>
  
  extern const char linux_banner[];
  extern const char linux_proc_banner[];
@@@ -70,7 -69,16 +70,7 @@@ extern int console_printk[]
  #define minimum_console_loglevel (console_printk[2])
  #define default_console_loglevel (console_printk[3])
  
 -static inline void console_silent(void)
 -{
 -      console_loglevel = CONSOLE_LOGLEVEL_SILENT;
 -}
 -
 -static inline void console_verbose(void)
 -{
 -      if (console_loglevel)
 -              console_loglevel = CONSOLE_LOGLEVEL_MOTORMOUTH;
 -}
 +extern void console_verbose(void);
  
  /* strlen("ratelimit") + 1 */
  #define DEVKMSG_STR_MAX_SIZE 10
@@@ -153,12 -161,12 +153,12 @@@ asmlinkage __printf(1, 0
  int vprintk(const char *fmt, va_list args);
  
  asmlinkage __printf(1, 2) __cold
 -int printk(const char *fmt, ...);
 +int _printk(const char *fmt, ...);
  
  /*
   * Special printk facility for scheduler/timekeeping use only, _DO_NOT_USE_ !
   */
 -__printf(1, 2) __cold int printk_deferred(const char *fmt, ...);
 +__printf(1, 2) __cold int _printk_deferred(const char *fmt, ...);
  
  extern void __printk_safe_enter(void);
  extern void __printk_safe_exit(void);
@@@ -198,6 -206,7 +198,7 @@@ void dump_stack_print_info(const char *
  void show_regs_print_info(const char *log_lvl);
  extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold;
  extern asmlinkage void dump_stack(void) __cold;
+ void printk_trigger_flush(void);
  #else
  static inline __printf(1, 0)
  int vprintk(const char *s, va_list args)
        return 0;
  }
  static inline __printf(1, 2) __cold
 -int printk(const char *s, ...)
 +int _printk(const char *s, ...)
  {
        return 0;
  }
  static inline __printf(1, 2) __cold
 -int printk_deferred(const char *s, ...)
 +int _printk_deferred(const char *s, ...)
  {
        return 0;
  }
@@@ -274,6 -283,9 +275,9 @@@ static inline void dump_stack_lvl(cons
  static inline void dump_stack(void)
  {
  }
+ static inline void printk_trigger_flush(void)
+ {
+ }
  #endif
  
  #ifdef CONFIG_SMP
@@@ -336,117 -348,6 +340,117 @@@ extern int kptr_restrict
  #define pr_fmt(fmt) fmt
  #endif
  
 +struct module;
 +
 +#ifdef CONFIG_PRINTK_INDEX
 +struct pi_entry {
 +      const char *fmt;
 +      const char *func;
 +      const char *file;
 +      unsigned int line;
 +
 +      /*
 +       * While printk and pr_* have the level stored in the string at compile
 +       * time, some subsystems dynamically add it at runtime through the
 +       * format string. For these dynamic cases, we allow the subsystem to
 +       * tell us the level at compile time.
 +       *
 +       * NULL indicates that the level, if any, is stored in fmt.
 +       */
 +      const char *level;
 +
 +      /*
 +       * The format string used by various subsystem specific printk()
 +       * wrappers to prefix the message.
 +       *
 +       * Note that the static prefix defined by the pr_fmt() macro is stored
 +       * directly in the message format (@fmt), not here.
 +       */
 +      const char *subsys_fmt_prefix;
 +} __packed;
 +
 +#define __printk_index_emit(_fmt, _level, _subsys_fmt_prefix)         \
 +      do {                                                            \
 +              if (__builtin_constant_p(_fmt) && __builtin_constant_p(_level)) { \
 +                      /*
 +                       * We check __builtin_constant_p multiple times here
 +                       * for the same input because GCC will produce an error
 +                       * if we try to assign a static variable to fmt if it
 +                       * is not a constant, even with the outer if statement.
 +                       */                                             \
 +                      static const struct pi_entry _entry             \
 +                      __used = {                                      \
 +                              .fmt = __builtin_constant_p(_fmt) ? (_fmt) : NULL, \
 +                              .func = __func__,                       \
 +                              .file = __FILE__,                       \
 +                              .line = __LINE__,                       \
 +                              .level = __builtin_constant_p(_level) ? (_level) : NULL, \
 +                              .subsys_fmt_prefix = _subsys_fmt_prefix,\
 +                      };                                              \
 +                      static const struct pi_entry *_entry_ptr        \
 +                      __used __section(".printk_index") = &_entry;    \
 +              }                                                       \
 +      } while (0)
 +
 +#else /* !CONFIG_PRINTK_INDEX */
 +#define __printk_index_emit(...) do {} while (0)
 +#endif /* CONFIG_PRINTK_INDEX */
 +
 +/*
 + * Some subsystems have their own custom printk that applies a va_format to a
 + * generic format, for example, to include a device number or other metadata
 + * alongside the format supplied by the caller.
 + *
 + * In order to store these in the way they would be emitted by the printk
 + * infrastructure, the subsystem provides us with the start, fixed string, and
 + * any subsequent text in the format string.
 + *
 + * We take a variable argument list as pr_fmt/dev_fmt/etc are sometimes passed
 + * as multiple arguments (eg: `"%s: ", "blah"`), and we must only take the
 + * first one.
 + *
 + * subsys_fmt_prefix must be known at compile time, or compilation will fail
 + * (since this is a mistake). If fmt or level is not known at compile time, no
 + * index entry will be made (since this can legitimately happen).
 + */
 +#define printk_index_subsys_emit(subsys_fmt_prefix, level, fmt, ...) \
 +      __printk_index_emit(fmt, level, subsys_fmt_prefix)
 +
 +#define printk_index_wrap(_p_func, _fmt, ...)                         \
 +      ({                                                              \
 +              __printk_index_emit(_fmt, NULL, NULL);                  \
 +              _p_func(_fmt, ##__VA_ARGS__);                           \
 +      })
 +
 +
 +/**
 + * printk - print a kernel message
 + * @fmt: format string
 + *
 + * This is printk(). It can be called from any context. We want it to work.
 + *
 + * If printk indexing is enabled, _printk() is called from printk_index_wrap.
 + * Otherwise, printk is simply #defined to _printk.
 + *
 + * We try to grab the console_lock. If we succeed, it's easy - we log the
 + * output and call the console drivers.  If we fail to get the semaphore, we
 + * place the output into the log buffer and return. The current holder of
 + * the console_sem will notice the new output in console_unlock(); and will
 + * send it to the consoles before releasing the lock.
 + *
 + * One effect of this deferred printing is that code which calls printk() and
 + * then changes console_loglevel may break. This is because console_loglevel
 + * is inspected when the actual printing occurs.
 + *
 + * See also:
 + * printf(3)
 + *
 + * See the vsnprintf() documentation for format string extensions over C99.
 + */
 +#define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
 +#define printk_deferred(fmt, ...)                                     \
 +      printk_index_wrap(_printk_deferred, fmt, ##__VA_ARGS__)
 +
  /**
   * pr_emerg - Print an emergency-level message
   * @fmt: format string
  
  #ifdef CONFIG_PRINTK
  #define printk_once(fmt, ...)                                 \
 -({                                                            \
 -      static bool __section(".data.once") __print_once;       \
 -      bool __ret_print_once = !__print_once;                  \
 -                                                              \
 -      if (!__print_once) {                                    \
 -              __print_once = true;                            \
 -              printk(fmt, ##__VA_ARGS__);                     \
 -      }                                                       \
 -      unlikely(__ret_print_once);                             \
 -})
 +      DO_ONCE_LITE(printk, fmt, ##__VA_ARGS__)
  #define printk_deferred_once(fmt, ...)                                \
 -({                                                            \
 -      static bool __section(".data.once") __print_once;       \
 -      bool __ret_print_once = !__print_once;                  \
 -                                                              \
 -      if (!__print_once) {                                    \
 -              __print_once = true;                            \
 -              printk_deferred(fmt, ##__VA_ARGS__);            \
 -      }                                                       \
 -      unlikely(__ret_print_once);                             \
 -})
 +      DO_ONCE_LITE(printk_deferred, fmt, ##__VA_ARGS__)
  #else
  #define printk_once(fmt, ...)                                 \
        no_printk(fmt, ##__VA_ARGS__)
diff --combined kernel/printk/printk.c
index 9e5dfb1896a95d1cc7815a706ce652ca1ce070ef,eabe23b0a982f6e6f3a75164311aa4f77b871800..49e3c53ec5100f1efb4e8820d7b892d21b71bbdb
@@@ -350,6 -350,11 +350,6 @@@ static int console_msg_format = MSG_FOR
   * non-prinatable characters are escaped in the "\xff" notation.
   */
  
 -enum log_flags {
 -      LOG_NEWLINE     = 2,    /* text ended with a newline */
 -      LOG_CONT        = 8,    /* text is a fragment of a continuation line */
 -};
 -
  /* syslog_lock protects syslog_* variables and write access to clear_seq. */
  static DEFINE_MUTEX(syslog_lock);
  
@@@ -847,7 -852,7 +847,7 @@@ static int devkmsg_open(struct inode *i
                        return err;
        }
  
 -      user = kmalloc(sizeof(struct devkmsg_user), GFP_KERNEL);
 +      user = kvmalloc(sizeof(struct devkmsg_user), GFP_KERNEL);
        if (!user)
                return -ENOMEM;
  
@@@ -875,7 -880,7 +875,7 @@@ static int devkmsg_release(struct inod
        ratelimit_state_exit(&user->rs);
  
        mutex_destroy(&user->lock);
 -      kfree(user);
 +      kvfree(user);
        return 0;
  }
  
@@@ -1166,9 -1171,9 +1166,9 @@@ void __init setup_log_buf(int early
        return;
  
  err_free_descs:
 -      memblock_free(__pa(new_descs), new_descs_size);
 +      memblock_free_ptr(new_descs, new_descs_size);
  err_free_log_buf:
 -      memblock_free(__pa(new_log_buf), new_log_buf_len);
 +      memblock_free_ptr(new_log_buf, new_log_buf_len);
  }
  
  static bool __read_mostly ignore_loglevel;
@@@ -2022,24 -2027,23 +2022,24 @@@ static inline u32 printk_caller_id(void
  }
  
  /**
 - * parse_prefix - Parse level and control flags.
 + * printk_parse_prefix - Parse level and control flags.
   *
   * @text:     The terminated text message.
   * @level:    A pointer to the current level value, will be updated.
 - * @lflags:   A pointer to the current log flags, will be updated.
 + * @flags:    A pointer to the current printk_info flags, will be updated.
   *
   * @level may be NULL if the caller is not interested in the parsed value.
   * Otherwise the variable pointed to by @level must be set to
   * LOGLEVEL_DEFAULT in order to be updated with the parsed value.
   *
 - * @lflags may be NULL if the caller is not interested in the parsed value.
 - * Otherwise the variable pointed to by @lflags will be OR'd with the parsed
 + * @flags may be NULL if the caller is not interested in the parsed value.
 + * Otherwise the variable pointed to by @flags will be OR'd with the parsed
   * value.
   *
   * Return: The length of the parsed level and control flags.
   */
 -static u16 parse_prefix(char *text, int *level, enum log_flags *lflags)
 +u16 printk_parse_prefix(const char *text, int *level,
 +                      enum printk_info_flags *flags)
  {
        u16 prefix_len = 0;
        int kern_level;
                                *level = kern_level - '0';
                        break;
                case 'c':       /* KERN_CONT */
 -                      if (lflags)
 -                              *lflags |= LOG_CONT;
 +                      if (flags)
 +                              *flags |= LOG_CONT;
                }
  
                prefix_len += 2;
        return prefix_len;
  }
  
 -static u16 printk_sprint(char *text, u16 size, int facility, enum log_flags *lflags,
 -                       const char *fmt, va_list args)
 +__printf(5, 0)
 +static u16 printk_sprint(char *text, u16 size, int facility,
 +                       enum printk_info_flags *flags, const char *fmt,
 +                       va_list args)
  {
        u16 text_len;
  
        /* Mark and strip a trailing newline. */
        if (text_len && text[text_len - 1] == '\n') {
                text_len--;
 -              *lflags |= LOG_NEWLINE;
 +              *flags |= LOG_NEWLINE;
        }
  
        /* Strip log level and control flags. */
        if (facility == 0) {
                u16 prefix_len;
  
 -              prefix_len = parse_prefix(text, NULL, NULL);
 +              prefix_len = printk_parse_prefix(text, NULL, NULL);
                if (prefix_len) {
                        text_len -= prefix_len;
                        memmove(text, text + prefix_len, text_len);
@@@ -2102,7 -2104,7 +2102,7 @@@ int vprintk_store(int facility, int lev
  {
        const u32 caller_id = printk_caller_id();
        struct prb_reserved_entry e;
 -      enum log_flags lflags = 0;
 +      enum printk_info_flags flags = 0;
        struct printk_record r;
        unsigned long irqflags;
        u16 trunc_msg_len = 0;
  
        /* Extract log level or control flags. */
        if (facility == 0)
 -              parse_prefix(&prefix_buf[0], &level, &lflags);
 +              printk_parse_prefix(&prefix_buf[0], &level, &flags);
  
        if (level == LOGLEVEL_DEFAULT)
                level = default_message_loglevel;
  
        if (dev_info)
 -              lflags |= LOG_NEWLINE;
 +              flags |= LOG_NEWLINE;
  
 -      if (lflags & LOG_CONT) {
 +      if (flags & LOG_CONT) {
                prb_rec_init_wr(&r, reserve_size);
                if (prb_reserve_in_last(&e, prb, &r, caller_id, LOG_LINE_MAX)) {
                        text_len = printk_sprint(&r.text_buf[r.info->text_len], reserve_size,
 -                                               facility, &lflags, fmt, args);
 +                                               facility, &flags, fmt, args);
                        r.info->text_len += text_len;
  
 -                      if (lflags & LOG_NEWLINE) {
 +                      if (flags & LOG_NEWLINE) {
                                r.info->flags |= LOG_NEWLINE;
                                prb_final_commit(&e);
                        } else {
        }
  
        /* fill message */
 -      text_len = printk_sprint(&r.text_buf[0], reserve_size, facility, &lflags, fmt, args);
 +      text_len = printk_sprint(&r.text_buf[0], reserve_size, facility, &flags, fmt, args);
        if (trunc_msg_len)
                memcpy(&r.text_buf[text_len], trunc_msg, trunc_msg_len);
        r.info->text_len = text_len + trunc_msg_len;
        r.info->facility = facility;
        r.info->level = level & 7;
 -      r.info->flags = lflags & 0x1f;
 +      r.info->flags = flags & 0x1f;
        r.info->ts_nsec = ts_nsec;
        r.info->caller_id = caller_id;
        if (dev_info)
                memcpy(&r.info->dev_info, dev_info, sizeof(r.info->dev_info));
  
        /* A message without a trailing newline can be continued. */
 -      if (!(lflags & LOG_NEWLINE))
 +      if (!(flags & LOG_NEWLINE))
                prb_commit(&e);
        else
                prb_final_commit(&e);
@@@ -2257,7 -2259,28 +2257,7 @@@ int vprintk_default(const char *fmt, va
  }
  EXPORT_SYMBOL_GPL(vprintk_default);
  
 -/**
 - * printk - print a kernel message
 - * @fmt: format string
 - *
 - * This is printk(). It can be called from any context. We want it to work.
 - *
 - * We try to grab the console_lock. If we succeed, it's easy - we log the
 - * output and call the console drivers.  If we fail to get the semaphore, we
 - * place the output into the log buffer and return. The current holder of
 - * the console_sem will notice the new output in console_unlock(); and will
 - * send it to the consoles before releasing the lock.
 - *
 - * One effect of this deferred printing is that code which calls printk() and
 - * then changes console_loglevel may break. This is because console_loglevel
 - * is inspected when the actual printing occurs.
 - *
 - * See also:
 - * printf(3)
 - *
 - * See the vsnprintf() documentation for format string extensions over C99.
 - */
 -asmlinkage __visible int printk(const char *fmt, ...)
 +asmlinkage __visible int _printk(const char *fmt, ...)
  {
        va_list args;
        int r;
  
        return r;
  }
 -EXPORT_SYMBOL(printk);
 +EXPORT_SYMBOL(_printk);
  
  #else /* CONFIG_PRINTK */
  
@@@ -2454,18 -2477,6 +2454,18 @@@ module_param_named(console_suspend, con
  MODULE_PARM_DESC(console_suspend, "suspend console during suspend"
        " and hibernate operations");
  
 +static bool printk_console_no_auto_verbose;
 +
 +void console_verbose(void)
 +{
 +      if (console_loglevel && !printk_console_no_auto_verbose)
 +              console_loglevel = CONSOLE_LOGLEVEL_MOTORMOUTH;
 +}
 +EXPORT_SYMBOL_GPL(console_verbose);
 +
 +module_param_named(console_no_auto_verbose, printk_console_no_auto_verbose, bool, 0644);
 +MODULE_PARM_DESC(console_no_auto_verbose, "Disable console loglevel raise to highest on oops/panic/etc");
 +
  /**
   * suspend_console - suspend the console subsystem
   *
@@@ -2607,7 -2618,6 +2607,7 @@@ void console_unlock(void
        bool do_cond_resched, retry;
        struct printk_info info;
        struct printk_record r;
 +      u64 __maybe_unused next_seq;
  
        if (console_suspended) {
                up_console_sem();
@@@ -2720,10 -2730,8 +2720,10 @@@ skip
                        cond_resched();
        }
  
 -      console_locked = 0;
 +      /* Get consistent value of the next-to-be-used sequence number. */
 +      next_seq = console_seq;
  
 +      console_locked = 0;
        up_console_sem();
  
        /*
         * there's a new owner and the console_unlock() from them will do the
         * flush, no worries.
         */
 -      retry = prb_read_valid(prb, console_seq, NULL);
 +      retry = prb_read_valid(prb, next_seq, NULL);
        if (retry && console_trylock())
                goto again;
  }
@@@ -3253,6 -3261,11 +3253,11 @@@ void defer_console_output(void
        preempt_enable();
  }
  
+ void printk_trigger_flush(void)
+ {
+       defer_console_output();
+ }
  int vprintk_deferred(const char *fmt, va_list args)
  {
        int r;
        return r;
  }
  
 -int printk_deferred(const char *fmt, ...)
 +int _printk_deferred(const char *fmt, ...)
  {
        va_list args;
        int r;
This page took 0.095636 seconds and 4 git commands to generate.