]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'core-printk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Jul 2013 01:14:24 +0000 (18:14 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Jul 2013 01:14:24 +0000 (18:14 -0700)
Pull printk locking fix from Thomas Gleixner:
 "A single lock ordering fix in the printk code"

* 'core-printk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  printk: Fix rq->lock vs logbuf_lock unlock lock inversion

1  2 
kernel/printk.c

diff --combined kernel/printk.c
index 8212c1aef125f2d4290cbe0e55564d7e9a5a57de,e698e80d842821a926169467820051ffa866a0d3..d37d45c90ae6fc863a257f75751976a4bfe2f9ef
@@@ -32,7 -32,6 +32,7 @@@
  #include <linux/security.h>
  #include <linux/bootmem.h>
  #include <linux/memblock.h>
 +#include <linux/aio.h>
  #include <linux/syscalls.h>
  #include <linux/kexec.h>
  #include <linux/kdb.h>
  #include <linux/notifier.h>
  #include <linux/rculist.h>
  #include <linux/poll.h>
 +#include <linux/irq_work.h>
 +#include <linux/utsname.h>
  
  #include <asm/uaccess.h>
  
  #define CREATE_TRACE_POINTS
  #include <trace/events/printk.h>
  
 -/*
 - * Architectures can override it:
 - */
 -void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
 -{
 -}
 -
  /* printk's without a loglevel use this.. */
  #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
  
@@@ -58,6 -62,8 +58,6 @@@
  #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
  #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */
  
 -DECLARE_WAIT_QUEUE_HEAD(log_wait);
 -
  int console_printk[4] = {
        DEFAULT_CONSOLE_LOGLEVEL,       /* console_loglevel */
        DEFAULT_MESSAGE_LOGLEVEL,       /* default_message_loglevel */
@@@ -81,12 -87,6 +81,12 @@@ static DEFINE_SEMAPHORE(console_sem)
  struct console *console_drivers;
  EXPORT_SYMBOL_GPL(console_drivers);
  
 +#ifdef CONFIG_LOCKDEP
 +static struct lockdep_map console_lock_dep_map = {
 +      .name = "console_lock"
 +};
 +#endif
 +
  /*
   * This is used for debugging the mess that is the VT code by
   * keeping track if we have the console semaphore held. It's
@@@ -217,7 -217,6 +217,7 @@@ struct log 
  static DEFINE_RAW_SPINLOCK(logbuf_lock);
  
  #ifdef CONFIG_PRINTK
 +DECLARE_WAIT_QUEUE_HEAD(log_wait);
  /* the next printk record to read by syslog(READ) or /proc/kmsg */
  static u64 syslog_seq;
  static u32 syslog_idx;
@@@ -363,53 -362,6 +363,53 @@@ static void log_store(int facility, in
        log_next_seq++;
  }
  
 +#ifdef CONFIG_SECURITY_DMESG_RESTRICT
 +int dmesg_restrict = 1;
 +#else
 +int dmesg_restrict;
 +#endif
 +
 +static int syslog_action_restricted(int type)
 +{
 +      if (dmesg_restrict)
 +              return 1;
 +      /*
 +       * Unless restricted, we allow "read all" and "get buffer size"
 +       * for everybody.
 +       */
 +      return type != SYSLOG_ACTION_READ_ALL &&
 +             type != SYSLOG_ACTION_SIZE_BUFFER;
 +}
 +
 +static int check_syslog_permissions(int type, bool from_file)
 +{
 +      /*
 +       * If this is from /proc/kmsg and we've already opened it, then we've
 +       * already done the capabilities checks at open time.
 +       */
 +      if (from_file && type != SYSLOG_ACTION_OPEN)
 +              return 0;
 +
 +      if (syslog_action_restricted(type)) {
 +              if (capable(CAP_SYSLOG))
 +                      return 0;
 +              /*
 +               * For historical reasons, accept CAP_SYS_ADMIN too, with
 +               * a warning.
 +               */
 +              if (capable(CAP_SYS_ADMIN)) {
 +                      pr_warn_once("%s (%d): Attempt to access syslog with "
 +                                   "CAP_SYS_ADMIN but no CAP_SYSLOG "
 +                                   "(deprecated).\n",
 +                               current->comm, task_pid_nr(current));
 +                      return 0;
 +              }
 +              return -EPERM;
 +      }
 +      return security_syslog(type);
 +}
 +
 +
  /* /dev/kmsg - userspace message inject/listen interface */
  struct devkmsg_user {
        u64 seq;
@@@ -650,8 -602,7 +650,8 @@@ static unsigned int devkmsg_poll(struc
                /* return error when data has vanished underneath us */
                if (user->seq < log_first_seq)
                        ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI;
 -              ret = POLLIN|POLLRDNORM;
 +              else
 +                      ret = POLLIN|POLLRDNORM;
        }
        raw_spin_unlock_irq(&logbuf_lock);
  
@@@ -667,8 -618,7 +667,8 @@@ static int devkmsg_open(struct inode *i
        if ((file->f_flags & O_ACCMODE) == O_WRONLY)
                return 0;
  
 -      err = security_syslog(SYSLOG_ACTION_READ_ALL);
 +      err = check_syslog_permissions(SYSLOG_ACTION_READ_ALL,
 +                                     SYSLOG_FROM_READER);
        if (err)
                return err;
  
@@@ -861,6 -811,45 +861,6 @@@ static inline void boot_delay_msec(int 
  }
  #endif
  
 -#ifdef CONFIG_SECURITY_DMESG_RESTRICT
 -int dmesg_restrict = 1;
 -#else
 -int dmesg_restrict;
 -#endif
 -
 -static int syslog_action_restricted(int type)
 -{
 -      if (dmesg_restrict)
 -              return 1;
 -      /* Unless restricted, we allow "read all" and "get buffer size" for everybody */
 -      return type != SYSLOG_ACTION_READ_ALL && type != SYSLOG_ACTION_SIZE_BUFFER;
 -}
 -
 -static int check_syslog_permissions(int type, bool from_file)
 -{
 -      /*
 -       * If this is from /proc/kmsg and we've already opened it, then we've
 -       * already done the capabilities checks at open time.
 -       */
 -      if (from_file && type != SYSLOG_ACTION_OPEN)
 -              return 0;
 -
 -      if (syslog_action_restricted(type)) {
 -              if (capable(CAP_SYSLOG))
 -                      return 0;
 -              /* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */
 -              if (capable(CAP_SYS_ADMIN)) {
 -                      printk_once(KERN_WARNING "%s (%d): "
 -                               "Attempt to access syslog with CAP_SYS_ADMIN "
 -                               "but no CAP_SYSLOG (deprecated).\n",
 -                               current->comm, task_pid_nr(current));
 -                      return 0;
 -              }
 -              return -EPERM;
 -      }
 -      return 0;
 -}
 -
  #if defined(CONFIG_PRINTK_TIME)
  static bool printk_time = 1;
  #else
@@@ -1258,7 -1247,7 +1258,7 @@@ out
  
  SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
  {
 -      return do_syslog(type, buf, len, SYSLOG_FROM_CALL);
 +      return do_syslog(type, buf, len, SYSLOG_FROM_READER);
  }
  
  /*
@@@ -1270,7 -1259,7 +1270,7 @@@ static void call_console_drivers(int le
  {
        struct console *con;
  
 -      trace_console(text, 0, len, len);
 +      trace_console(text, len);
  
        if (level >= console_loglevel && !ignore_loglevel)
                return;
@@@ -1369,9 -1358,9 +1369,9 @@@ static int console_trylock_for_printk(u
                }
        }
        logbuf_cpu = UINT_MAX;
+       raw_spin_unlock(&logbuf_lock);
        if (wake)
                up(&console_sem);
-       raw_spin_unlock(&logbuf_lock);
        return retval;
  }
  
@@@ -1728,29 -1717,6 +1728,29 @@@ static size_t cont_print_text(char *tex
  
  #endif /* CONFIG_PRINTK */
  
 +#ifdef CONFIG_EARLY_PRINTK
 +struct console *early_console;
 +
 +void early_vprintk(const char *fmt, va_list ap)
 +{
 +      if (early_console) {
 +              char buf[512];
 +              int n = vscnprintf(buf, sizeof(buf), fmt, ap);
 +
 +              early_console->write(early_console, buf, n);
 +      }
 +}
 +
 +asmlinkage void early_printk(const char *fmt, ...)
 +{
 +      va_list ap;
 +
 +      va_start(ap, fmt);
 +      early_vprintk(fmt, ap);
 +      va_end(ap);
 +}
 +#endif
 +
  static int __add_preferred_console(char *name, int idx, char *options,
                                   char *brl_options)
  {
@@@ -1952,7 -1918,6 +1952,7 @@@ void console_lock(void
                return;
        console_locked = 1;
        console_may_schedule = 1;
 +      mutex_acquire(&console_lock_dep_map, 0, 0, _RET_IP_);
  }
  EXPORT_SYMBOL(console_lock);
  
@@@ -1974,7 -1939,6 +1974,7 @@@ int console_trylock(void
        }
        console_locked = 1;
        console_may_schedule = 0;
 +      mutex_acquire(&console_lock_dep_map, 0, 1, _RET_IP_);
        return 1;
  }
  EXPORT_SYMBOL(console_trylock);
@@@ -1984,6 -1948,43 +1984,6 @@@ int is_console_locked(void
        return console_locked;
  }
  
 -/*
 - * Delayed printk version, for scheduler-internal messages:
 - */
 -#define PRINTK_BUF_SIZE               512
 -
 -#define PRINTK_PENDING_WAKEUP 0x01
 -#define PRINTK_PENDING_SCHED  0x02
 -
 -static DEFINE_PER_CPU(int, printk_pending);
 -static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf);
 -
 -void printk_tick(void)
 -{
 -      if (__this_cpu_read(printk_pending)) {
 -              int pending = __this_cpu_xchg(printk_pending, 0);
 -              if (pending & PRINTK_PENDING_SCHED) {
 -                      char *buf = __get_cpu_var(printk_sched_buf);
 -                      printk(KERN_WARNING "[sched_delayed] %s", buf);
 -              }
 -              if (pending & PRINTK_PENDING_WAKEUP)
 -                      wake_up_interruptible(&log_wait);
 -      }
 -}
 -
 -int printk_needs_cpu(int cpu)
 -{
 -      if (cpu_is_offline(cpu))
 -              printk_tick();
 -      return __this_cpu_read(printk_pending);
 -}
 -
 -void wake_up_klogd(void)
 -{
 -      if (waitqueue_active(&log_wait))
 -              this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
 -}
 -
  static void console_cont_flush(char *text, size_t size)
  {
        unsigned long flags;
@@@ -2098,7 -2099,6 +2098,7 @@@ skip
                local_irq_restore(flags);
        }
        console_locked = 0;
 +      mutex_release(&console_lock_dep_map, 1, _RET_IP_);
  
        /* Release the exclusive_console once it is used */
        if (unlikely(exclusive_console))
@@@ -2446,44 -2446,6 +2446,44 @@@ static int __init printk_late_init(void
  late_initcall(printk_late_init);
  
  #if defined CONFIG_PRINTK
 +/*
 + * Delayed printk version, for scheduler-internal messages:
 + */
 +#define PRINTK_BUF_SIZE               512
 +
 +#define PRINTK_PENDING_WAKEUP 0x01
 +#define PRINTK_PENDING_SCHED  0x02
 +
 +static DEFINE_PER_CPU(int, printk_pending);
 +static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf);
 +
 +static void wake_up_klogd_work_func(struct irq_work *irq_work)
 +{
 +      int pending = __this_cpu_xchg(printk_pending, 0);
 +
 +      if (pending & PRINTK_PENDING_SCHED) {
 +              char *buf = __get_cpu_var(printk_sched_buf);
 +              printk(KERN_WARNING "[sched_delayed] %s", buf);
 +      }
 +
 +      if (pending & PRINTK_PENDING_WAKEUP)
 +              wake_up_interruptible(&log_wait);
 +}
 +
 +static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = {
 +      .func = wake_up_klogd_work_func,
 +      .flags = IRQ_WORK_LAZY,
 +};
 +
 +void wake_up_klogd(void)
 +{
 +      preempt_disable();
 +      if (waitqueue_active(&log_wait)) {
 +              this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
 +              irq_work_queue(&__get_cpu_var(wake_up_klogd_work));
 +      }
 +      preempt_enable();
 +}
  
  int printk_sched(const char *fmt, ...)
  {
        va_end(args);
  
        __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED);
 +      irq_work_queue(&__get_cpu_var(wake_up_klogd_work));
        local_irq_restore(flags);
  
        return r;
@@@ -2860,65 -2821,4 +2860,65 @@@ void kmsg_dump_rewind(struct kmsg_dumpe
        raw_spin_unlock_irqrestore(&logbuf_lock, flags);
  }
  EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
 +
 +static char dump_stack_arch_desc_str[128];
 +
 +/**
 + * dump_stack_set_arch_desc - set arch-specific str to show with task dumps
 + * @fmt: printf-style format string
 + * @...: arguments for the format string
 + *
 + * The configured string will be printed right after utsname during task
 + * dumps.  Usually used to add arch-specific system identifiers.  If an
 + * arch wants to make use of such an ID string, it should initialize this
 + * as soon as possible during boot.
 + */
 +void __init dump_stack_set_arch_desc(const char *fmt, ...)
 +{
 +      va_list args;
 +
 +      va_start(args, fmt);
 +      vsnprintf(dump_stack_arch_desc_str, sizeof(dump_stack_arch_desc_str),
 +                fmt, args);
 +      va_end(args);
 +}
 +
 +/**
 + * dump_stack_print_info - print generic debug info for dump_stack()
 + * @log_lvl: log level
 + *
 + * Arch-specific dump_stack() implementations can use this function to
 + * print out the same debug information as the generic dump_stack().
 + */
 +void dump_stack_print_info(const char *log_lvl)
 +{
 +      printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s\n",
 +             log_lvl, raw_smp_processor_id(), current->pid, current->comm,
 +             print_tainted(), init_utsname()->release,
 +             (int)strcspn(init_utsname()->version, " "),
 +             init_utsname()->version);
 +
 +      if (dump_stack_arch_desc_str[0] != '\0')
 +              printk("%sHardware name: %s\n",
 +                     log_lvl, dump_stack_arch_desc_str);
 +
 +      print_worker_info(log_lvl, current);
 +}
 +
 +/**
 + * show_regs_print_info - print generic debug info for show_regs()
 + * @log_lvl: log level
 + *
 + * show_regs() implementations can use this function to print out generic
 + * debug information.
 + */
 +void show_regs_print_info(const char *log_lvl)
 +{
 +      dump_stack_print_info(log_lvl);
 +
 +      printk("%stask: %p ti: %p task.ti: %p\n",
 +             log_lvl, current, current_thread_info(),
 +             task_thread_info(current));
 +}
 +
  #endif