Merge branch 'mm-pkeys-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[deliverable/linux.git] / kernel / printk / printk.c
index c963ba534a784f456a5a2f1375025eaf1f27ccdd..bfbf284e421864377f72d4d2cb22a9dde264f327 100644 (file)
@@ -367,16 +367,20 @@ static int logbuf_has_space(u32 msg_size, bool empty)
 
 static int log_make_free_space(u32 msg_size)
 {
-       while (log_first_seq < log_next_seq) {
-               if (logbuf_has_space(msg_size, false))
-                       return 0;
+       while (log_first_seq < log_next_seq &&
+              !logbuf_has_space(msg_size, false)) {
                /* drop old messages until we have enough contiguous space */
                log_first_idx = log_next(log_first_idx);
                log_first_seq++;
        }
 
+       if (clear_seq < log_first_seq) {
+               clear_seq = log_first_seq;
+               clear_idx = log_first_idx;
+       }
+
        /* sequence numbers are equal, so the log buffer is empty */
-       if (logbuf_has_space(msg_size, true))
+       if (logbuf_has_space(msg_size, log_first_seq == log_next_seq))
                return 0;
 
        return -ENOMEM;
@@ -854,6 +858,7 @@ void log_buf_kexec_setup(void)
        VMCOREINFO_SYMBOL(log_buf);
        VMCOREINFO_SYMBOL(log_buf_len);
        VMCOREINFO_SYMBOL(log_first_idx);
+       VMCOREINFO_SYMBOL(clear_idx);
        VMCOREINFO_SYMBOL(log_next_idx);
        /*
         * Export struct printk_log size and field offsets. User space tools can
@@ -1216,12 +1221,6 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                u32 idx;
                enum log_flags prev;
 
-               if (clear_seq < log_first_seq) {
-                       /* messages are gone, move to first available one */
-                       clear_seq = log_first_seq;
-                       clear_idx = log_first_idx;
-               }
-
                /*
                 * Find first record that fits, including all following records,
                 * into the user-provided buffer for this dump.
@@ -1483,58 +1482,6 @@ static void zap_locks(void)
        sema_init(&console_sem, 1);
 }
 
-/*
- * Check if we have any console that is capable of printing while cpu is
- * booting or shutting down. Requires console_sem.
- */
-static int have_callable_console(void)
-{
-       struct console *con;
-
-       for_each_console(con)
-               if (con->flags & CON_ANYTIME)
-                       return 1;
-
-       return 0;
-}
-
-/*
- * Can we actually use the console at this time on this cpu?
- *
- * Console drivers may assume that per-cpu resources have been allocated. So
- * unless they're explicitly marked as being able to cope (CON_ANYTIME) don't
- * call them until this CPU is officially up.
- */
-static inline int can_use_console(unsigned int cpu)
-{
-       return cpu_online(cpu) || have_callable_console();
-}
-
-/*
- * Try to get console ownership to actually show the kernel
- * messages from a 'printk'. Return true (and with the
- * console_lock held, and 'console_locked' set) if it
- * is successful, false otherwise.
- */
-static int console_trylock_for_printk(void)
-{
-       unsigned int cpu = smp_processor_id();
-
-       if (!console_trylock())
-               return 0;
-       /*
-        * If we can't use the console, we need to release the console
-        * semaphore by hand to avoid flushing the buffer. We need to hold the
-        * console semaphore in order to do this test safely.
-        */
-       if (!can_use_console(cpu)) {
-               console_locked = 0;
-               up_console_sem();
-               return 0;
-       }
-       return 1;
-}
-
 int printk_delay_msec __read_mostly;
 
 static inline void printk_delay(void)
@@ -1681,7 +1628,6 @@ asmlinkage int vprintk_emit(int facility, int level,
        boot_delay_msec(level);
        printk_delay();
 
-       /* This stops the holder of console_sem just where we want him */
        local_irq_save(flags);
        this_cpu = smp_processor_id();
 
@@ -1705,6 +1651,7 @@ asmlinkage int vprintk_emit(int facility, int level,
        }
 
        lockdep_off();
+       /* This stops the holder of console_sem just where we want him */
        raw_spin_lock(&logbuf_lock);
        logbuf_cpu = this_cpu;
 
@@ -1809,21 +1756,13 @@ asmlinkage int vprintk_emit(int facility, int level,
        /* If called from the scheduler, we can not call up(). */
        if (!in_sched) {
                lockdep_off();
-               /*
-                * Disable preemption to avoid being preempted while holding
-                * console_sem which would prevent anyone from printing to
-                * console
-                */
-               preempt_disable();
-
                /*
                 * Try to acquire and then immediately release the console
                 * semaphore.  The release will print out buffers and wake up
                 * /dev/kmsg and syslog() users.
                 */
-               if (console_trylock_for_printk())
+               if (console_trylock())
                        console_unlock();
-               preempt_enable();
                lockdep_on();
        }
 
@@ -2174,7 +2113,20 @@ int console_trylock(void)
                return 0;
        }
        console_locked = 1;
-       console_may_schedule = 0;
+       /*
+        * When PREEMPT_COUNT disabled we can't reliably detect if it's
+        * safe to schedule (e.g. calling printk while holding a spin_lock),
+        * because preempt_disable()/preempt_enable() are just barriers there
+        * and preempt_count() is always 0.
+        *
+        * RCU read sections have a separate preemption counter when
+        * PREEMPT_RCU enabled thus we must take extra care and check
+        * rcu_preempt_depth(), otherwise RCU read sections modify
+        * preempt_count().
+        */
+       console_may_schedule = !oops_in_progress &&
+                       preemptible() &&
+                       !rcu_preempt_depth();
        return 1;
 }
 EXPORT_SYMBOL(console_trylock);
@@ -2184,6 +2136,34 @@ int is_console_locked(void)
        return console_locked;
 }
 
+/*
+ * Check if we have any console that is capable of printing while cpu is
+ * booting or shutting down. Requires console_sem.
+ */
+static int have_callable_console(void)
+{
+       struct console *con;
+
+       for_each_console(con)
+               if ((con->flags & CON_ENABLED) &&
+                               (con->flags & CON_ANYTIME))
+                       return 1;
+
+       return 0;
+}
+
+/*
+ * Can we actually use the console at this time on this cpu?
+ *
+ * Console drivers may assume that per-cpu resources have been allocated. So
+ * unless they're explicitly marked as being able to cope (CON_ANYTIME) don't
+ * call them until this CPU is officially up.
+ */
+static inline int can_use_console(void)
+{
+       return cpu_online(raw_smp_processor_id()) || have_callable_console();
+}
+
 static void console_cont_flush(char *text, size_t size)
 {
        unsigned long flags;
@@ -2254,9 +2234,21 @@ void console_unlock(void)
        do_cond_resched = console_may_schedule;
        console_may_schedule = 0;
 
+again:
+       /*
+        * We released the console_sem lock, so we need to recheck if
+        * cpu is online and (if not) is there at least one CON_ANYTIME
+        * console.
+        */
+       if (!can_use_console()) {
+               console_locked = 0;
+               up_console_sem();
+               return;
+       }
+
        /* flush buffered message fragment immediately to console */
        console_cont_flush(text, sizeof(text));
-again:
+
        for (;;) {
                struct printk_log *msg;
                size_t ext_len = 0;
This page took 0.043989 seconds and 5 git commands to generate.