#include <linux/cpu.h>
#include <linux/notifier.h>
#include <linux/rculist.h>
+#include <linux/workqueue.h>
#include <asm/uaccess.h>
* The indices into log_buf are not constrained to log_buf_len - they
* must be masked before subscripting
*/
-static unsigned log_start; /* Index into log_buf: next char to be read by syslog() */
-static unsigned con_start; /* Index into log_buf: next char to be sent to consoles */
-static unsigned log_end; /* Index into log_buf: most-recently-written-char + 1 */
+
+/* Index into log_buf: next char to be read by syslog() */
+static unsigned __suspend_volatile_bss log_start;
+
+/* Index into log_buf: next char to be sent to consoles */
+static unsigned __suspend_volatile_bss con_start;
+
+/* Index into log_buf: most-recently-written-char + 1 */
+static unsigned __suspend_volatile_bss log_end;
+
/*
* If exclusive_console is non-NULL then only this console is to be printed to.
#ifdef CONFIG_PRINTK
-static char __log_buf[__LOG_BUF_LEN];
+static __suspend_volatile_bss char __log_buf[__LOG_BUF_LEN];
static char *log_buf = __log_buf;
static int log_buf_len = __LOG_BUF_LEN;
-static unsigned logged_chars; /* Number of chars produced since last read+clear operation */
+
+/* Number of chars produced since last read+clear operation */
+static __suspend_volatile_bss unsigned logged_chars;
static int saved_console_loglevel = -1;
#ifdef CONFIG_KEXEC
KERN_CRIT "BUG: recent printk recursion!\n";
static int recursion_bug;
static int new_text_line = 1;
-static char printk_buf[1024];
+static __suspend_volatile_bss char printk_buf[1024];
int printk_delay_msec __read_mostly;
this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
}
+static void console_unlock_work_fn(struct work_struct *work)
+{
+ if (console_trylock())
+ console_unlock();
+}
+
+static DECLARE_WORK(console_unlock_work, console_unlock_work_fn);
+
/**
* console_unlock - unlock the console system
*
{
unsigned long flags;
unsigned _con_start, _log_end;
- unsigned wake_klogd = 0, retry = 0;
+ unsigned wake_klogd = 0;
if (console_suspended) {
up(&console_sem);
console_may_schedule = 0;
-again:
- for ( ; ; ) {
- raw_spin_lock_irqsave(&logbuf_lock, flags);
- wake_klogd |= log_start - log_end;
- if (con_start == log_end)
- break; /* Nothing to print */
+ raw_spin_lock_irqsave(&logbuf_lock, flags);
+ wake_klogd |= log_start - log_end;
+ if (con_start != log_end) {
_con_start = con_start;
_log_end = log_end;
con_start = log_end; /* Flush */
stop_critical_timings(); /* don't trace print latency */
call_console_drivers(_con_start, _log_end);
start_critical_timings();
- local_irq_restore(flags);
+ } else {
+ raw_spin_unlock(&logbuf_lock);
}
+
console_locked = 0;
/* Release the exclusive_console once it is used */
if (unlikely(exclusive_console))
exclusive_console = NULL;
- raw_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.
+ * Someone could have filled up the buffer again, so re-check and
+ * schedule work if there's something to flush.
*/
raw_spin_lock(&logbuf_lock);
if (con_start != log_end)
- retry = 1;
+ if (!work_pending(&console_unlock_work))
+ schedule_work(&console_unlock_work);
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
- if (retry && console_trylock())
- goto again;
-
if (wake_klogd)
wake_up_klogd();
}