printk: Fix console_sem vs logbuf_lock unlock race
[pandora-kernel.git] / kernel / printk.c
index 751e7b8..37dff34 100644 (file)
@@ -1244,7 +1244,7 @@ void console_unlock(void)
 {
        unsigned long flags;
        unsigned _con_start, _log_end;
-       unsigned wake_klogd = 0;
+       unsigned wake_klogd = 0, retry = 0;
 
        if (console_suspended) {
                up(&console_sem);
@@ -1253,6 +1253,7 @@ void console_unlock(void)
 
        console_may_schedule = 0;
 
+again:
        for ( ; ; ) {
                spin_lock_irqsave(&logbuf_lock, flags);
                wake_klogd |= log_start - log_end;
@@ -1273,8 +1274,23 @@ void console_unlock(void)
        if (unlikely(exclusive_console))
                exclusive_console = NULL;
 
-       spin_unlock_irqrestore(&logbuf_lock, flags);
+       spin_unlock(&logbuf_lock);
+
        up(&console_sem);
+
+       /*
+        * Someone could have filled up the buffer again, so re-check if there's
+        * something to flush. In case we cannot trylock the console_sem again,
+        * there's a new owner and the console_unlock() from them will do the
+        * flush, no worries.
+        */
+       spin_lock(&logbuf_lock);
+       if (con_start != log_end)
+               retry = 1;
+       spin_unlock_irqrestore(&logbuf_lock, flags);
+       if (retry && console_trylock())
+               goto again;
+
        if (wake_klogd)
                wake_up_klogd();
 }