#include <linux/bootmem.h>
#include <linux/syscalls.h>
#include <linux/kexec.h>
-#include <linux/kdb.h>
#include <linux/ratelimit.h>
#include <linux/kmsg_dump.h>
#include <linux/syslog.h>
{
}
-#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
-
/* printk's without a loglevel use this.. */
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
*/
static int console_locked, console_suspended;
-/*
- * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars
- * It is also used in interesting ways to provide interlocking in
- * release_console_sem().
- */
-static DEFINE_SPINLOCK(logbuf_lock);
-
-#define LOG_BUF_MASK (log_buf_len-1)
-#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
+#define LOG_BUF_MASK(ns) ((ns)->buf_len-1)
+#define LOG_BUF(ns, idx) ((ns)->buf[(idx) & LOG_BUF_MASK(ns)])
/*
- * The indices into log_buf are not constrained to log_buf_len - they
- * must be masked before subscripting
+ * To access container syslog ring buffer
*/
-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 */
+#define sys_log_lock (syslog_ns->logbuf_lock)
+#define sys_log_start (syslog_ns->log_start)
+#define sys_log_end (syslog_ns->log_end)
+#define sys_log_con_start (syslog_ns->con_start)
+#define sys_log_buf_len (syslog_ns->buf_len)
+#define sys_log_logged_chars (syslog_ns->logged_chars)
+#define sys_log_buf (syslog_ns->buf)
/*
* Array of consoles built from command line options (console=)
#ifdef CONFIG_PRINTK
-static 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 */
static int saved_console_loglevel = -1;
#ifdef CONFIG_KEXEC
*/
void log_buf_kexec_setup(void)
{
- VMCOREINFO_SYMBOL(log_buf);
- VMCOREINFO_SYMBOL(log_end);
- VMCOREINFO_SYMBOL(log_buf_len);
- VMCOREINFO_SYMBOL(logged_chars);
+ struct syslog_ns *syslog_ns = current_syslog_ns();
+
+ VMCOREINFO_SYMBOL(sys_log_buf);
+ VMCOREINFO_SYMBOL(sys_log_end);
+ VMCOREINFO_SYMBOL(sys_log_buf_len);
+ VMCOREINFO_SYMBOL(sys_log_logged_chars);
}
#endif
static int __init log_buf_len_setup(char *str)
{
unsigned size = memparse(str, &str);
- unsigned long flags;
- if (size)
+ if (size) {
size = roundup_pow_of_two(size);
- if (size > log_buf_len) {
- unsigned start, dest_idx, offset;
- char *new_log_buf;
-
- new_log_buf = alloc_bootmem(size);
- if (!new_log_buf) {
- printk(KERN_WARNING "log_buf_len: allocation failed\n");
- goto out;
- }
-
- spin_lock_irqsave(&logbuf_lock, flags);
- log_buf_len = size;
- log_buf = new_log_buf;
-
- offset = start = min(con_start, log_start);
- dest_idx = 0;
- while (start != log_end) {
- log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)];
- start++;
- dest_idx++;
- }
- log_start -= offset;
- con_start -= offset;
- log_end -= offset;
- spin_unlock_irqrestore(&logbuf_lock, flags);
-
- printk(KERN_NOTICE "log_buf_len: %d\n", log_buf_len);
+ resize_syslog_ns(&init_syslog_ns, size);
}
-out:
return 1;
}
int do_clear = 0;
char c;
int error = 0;
+ struct syslog_ns *syslog_ns = current_syslog_ns();
error = security_syslog(type, from_file);
if (error)
goto out;
}
error = wait_event_interruptible(log_wait,
- (log_start - log_end));
+ (sys_log_start - sys_log_end));
if (error)
goto out;
i = 0;
- spin_lock_irq(&logbuf_lock);
- while (!error && (log_start != log_end) && i < len) {
- c = LOG_BUF(log_start);
- log_start++;
- spin_unlock_irq(&logbuf_lock);
+ spin_lock_irq(&sys_log_lock);
+ while (!error && (sys_log_start != sys_log_end) && i < len) {
+ c = LOG_BUF(syslog_ns, sys_log_start);
+ sys_log_start++;
+ spin_unlock_irq(&sys_log_lock);
error = __put_user(c,buf);
buf++;
i++;
cond_resched();
- spin_lock_irq(&logbuf_lock);
+ spin_lock_irq(&sys_log_lock);
}
- spin_unlock_irq(&logbuf_lock);
+ spin_unlock_irq(&sys_log_lock);
if (!error)
error = i;
break;
goto out;
}
count = len;
- if (count > log_buf_len)
- count = log_buf_len;
- spin_lock_irq(&logbuf_lock);
- if (count > logged_chars)
- count = logged_chars;
+ if (count > sys_log_buf_len)
+ count = sys_log_buf_len;
+ spin_lock_irq(&sys_log_lock);
+ if (count > sys_log_logged_chars)
+ count = sys_log_logged_chars;
if (do_clear)
- logged_chars = 0;
- limit = log_end;
+ sys_log_logged_chars = 0;
+ limit = sys_log_end;
/*
* __put_user() could sleep, and while we sleep
* printk() could overwrite the messages
*/
for (i = 0; i < count && !error; i++) {
j = limit-1-i;
- if (j + log_buf_len < log_end)
+ if (j + sys_log_buf_len < sys_log_end)
break;
- c = LOG_BUF(j);
- spin_unlock_irq(&logbuf_lock);
+ c = LOG_BUF(syslog_ns, j);
+ spin_unlock_irq(&sys_log_lock);
error = __put_user(c,&buf[count-1-i]);
cond_resched();
- spin_lock_irq(&logbuf_lock);
+ spin_lock_irq(&sys_log_lock);
}
- spin_unlock_irq(&logbuf_lock);
+ spin_unlock_irq(&sys_log_lock);
if (error)
break;
error = i;
break;
/* Clear ring buffer */
case SYSLOG_ACTION_CLEAR:
- logged_chars = 0;
+ sys_log_logged_chars = 0;
break;
/* Disable logging to console */
case SYSLOG_ACTION_CONSOLE_OFF:
break;
/* Number of chars in the log buffer */
case SYSLOG_ACTION_SIZE_UNREAD:
- error = log_end - log_start;
+ error = sys_log_end - sys_log_start;
break;
/* Size of the log buffer */
case SYSLOG_ACTION_SIZE_BUFFER:
- error = log_buf_len;
+ error = sys_log_buf_len;
break;
default:
error = -EINVAL;
return do_syslog(type, buf, len, SYSLOG_FROM_CALL);
}
-#ifdef CONFIG_KGDB_KDB
-/* kdb dmesg command needs access to the syslog buffer. do_syslog()
- * uses locks so it cannot be used during debugging. Just tell kdb
- * where the start and end of the physical and logical logs are. This
- * is equivalent to do_syslog(3).
- */
-void kdb_syslog_data(char *syslog_data[4])
-{
- syslog_data[0] = log_buf;
- syslog_data[1] = log_buf + log_buf_len;
- syslog_data[2] = log_buf + log_end -
- (logged_chars < log_buf_len ? logged_chars : log_buf_len);
- syslog_data[3] = log_buf + log_end;
-}
-#endif /* CONFIG_KGDB_KDB */
-
/*
* Call the console drivers on a range of log_buf
*/
-static void __call_console_drivers(unsigned start, unsigned end)
+static void __call_console_drivers(struct syslog_ns *syslog_ns,
+ unsigned start, unsigned end)
{
struct console *con;
if ((con->flags & CON_ENABLED) && con->write &&
(cpu_online(smp_processor_id()) ||
(con->flags & CON_ANYTIME)))
- con->write(con, &LOG_BUF(start), end - start);
+ con->write(con, &LOG_BUF(syslog_ns, start),
+ end - start);
}
}
/*
* Write out chars from start to end - 1 inclusive
*/
-static void _call_console_drivers(unsigned start,
- unsigned end, int msg_log_level)
+static void _call_console_drivers(struct syslog_ns *syslog_ns, unsigned start,
+ unsigned end, int msg_log_level)
{
if ((msg_log_level < console_loglevel || ignore_loglevel) &&
console_drivers && start != end) {
- if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
+ if ((start & LOG_BUF_MASK(syslog_ns)) >
+ (end & LOG_BUF_MASK(syslog_ns))) {
/* wrapped write */
- __call_console_drivers(start & LOG_BUF_MASK,
- log_buf_len);
- __call_console_drivers(0, end & LOG_BUF_MASK);
+ __call_console_drivers(syslog_ns,
+ start & LOG_BUF_MASK(syslog_ns),
+ sys_log_buf_len);
+ __call_console_drivers(syslog_ns, 0,
+ end & LOG_BUF_MASK(syslog_ns));
} else {
- __call_console_drivers(start, end);
+ __call_console_drivers(syslog_ns, start, end);
}
}
}
* log_buf[start] to log_buf[end - 1].
* The console_sem must be held.
*/
-static void call_console_drivers(unsigned start, unsigned end)
+static void call_console_drivers(struct syslog_ns *syslog_ns,
+ unsigned start, unsigned end)
{
unsigned cur_index, start_print;
static int msg_level = -1;
start_print = start;
while (cur_index != end) {
if (msg_level < 0 && ((end - cur_index) > 2) &&
- LOG_BUF(cur_index + 0) == '<' &&
- LOG_BUF(cur_index + 1) >= '0' &&
- LOG_BUF(cur_index + 1) <= '7' &&
- LOG_BUF(cur_index + 2) == '>') {
- msg_level = LOG_BUF(cur_index + 1) - '0';
+ LOG_BUF(syslog_ns, cur_index + 0) == '<' &&
+ LOG_BUF(syslog_ns, cur_index + 1) >= '0' &&
+ LOG_BUF(syslog_ns, cur_index + 1) <= '7' &&
+ LOG_BUF(syslog_ns, cur_index + 2) == '>') {
+ msg_level = LOG_BUF(syslog_ns, cur_index + 1) - '0';
cur_index += 3;
start_print = cur_index;
}
while (cur_index != end) {
- char c = LOG_BUF(cur_index);
+ char c = LOG_BUF(syslog_ns, cur_index);
cur_index++;
if (c == '\n') {
*/
msg_level = default_message_loglevel;
}
- _call_console_drivers(start_print, cur_index, msg_level);
+ _call_console_drivers(syslog_ns,
+ start_print, cur_index, msg_level);
msg_level = -1;
start_print = cur_index;
break;
}
}
}
- _call_console_drivers(start_print, end, msg_level);
+ _call_console_drivers(syslog_ns, start_print, end, msg_level);
}
-static void emit_log_char(char c)
+static void emit_log_char(struct syslog_ns *syslog_ns, char c)
{
- LOG_BUF(log_end) = c;
- log_end++;
- if (log_end - log_start > log_buf_len)
- log_start = log_end - log_buf_len;
- if (log_end - con_start > log_buf_len)
- con_start = log_end - log_buf_len;
- if (logged_chars < log_buf_len)
- logged_chars++;
+ LOG_BUF(syslog_ns, sys_log_end) = c;
+ sys_log_end++;
+ if (sys_log_end - sys_log_start > sys_log_buf_len)
+ sys_log_start = sys_log_end - sys_log_buf_len;
+ if (sys_log_end - sys_log_con_start > sys_log_buf_len)
+ sys_log_con_start = sys_log_end - sys_log_buf_len;
+ if (sys_log_logged_chars < sys_log_buf_len)
+ sys_log_logged_chars++;
}
/*
* every 10 seconds, to leave time for slow consoles to print a
* full oops.
*/
-static void zap_locks(void)
+static void zap_locks(struct syslog_ns *syslog_ns)
{
static unsigned long oops_timestamp;
oops_timestamp = jiffies;
/* If a crash is occurring, make sure we can't deadlock */
- spin_lock_init(&logbuf_lock);
+ spin_lock_init(&sys_log_lock);
/* And make sure that we print immediately */
init_MUTEX(&console_sem);
}
va_list args;
int r;
-#ifdef CONFIG_KGDB_KDB
- if (unlikely(kdb_trap_printk)) {
- va_start(args, fmt);
- r = vkdb_printf(fmt, args);
- va_end(args);
- return r;
- }
-#endif
va_start(args, fmt);
r = vprintk(fmt, args);
va_end(args);
* interrupts disabled. It should return with 'lockbuf_lock'
* released but interrupts still disabled.
*/
-static int acquire_console_semaphore_for_printk(unsigned int cpu)
+static int acquire_console_semaphore_for_printk(
+ struct syslog_ns *syslog_ns, unsigned int cpu)
{
int retval = 0;
}
}
printk_cpu = UINT_MAX;
- spin_unlock(&logbuf_lock);
+ spin_unlock(&sys_log_lock);
return retval;
}
static const char recursion_bug_msg [] =
{
int printed_len = 0;
int current_log_level = default_message_loglevel;
+ struct syslog_ns *syslog_ns = current_syslog_ns();
unsigned long flags;
int this_cpu;
char *p;
recursion_bug = 1;
goto out_restore_irqs;
}
- zap_locks();
+ zap_locks(syslog_ns);
}
lockdep_off();
- spin_lock(&logbuf_lock);
+ spin_lock(&sys_log_lock);
printk_cpu = this_cpu;
if (recursion_bug) {
/* Fallthrough - make sure we're on a new line */
case 'd': /* KERN_DEFAULT */
if (!new_text_line) {
- emit_log_char('\n');
+ emit_log_char(syslog_ns, '\n');
new_text_line = 1;
}
/* Fallthrough - skip the loglevel */
for ( ; *p; p++) {
if (new_text_line) {
/* Always output the token */
- emit_log_char('<');
- emit_log_char(current_log_level + '0');
- emit_log_char('>');
+ emit_log_char(syslog_ns, '<');
+ emit_log_char(syslog_ns, current_log_level + '0');
+ emit_log_char(syslog_ns, '>');
printed_len += 3;
new_text_line = 0;
t = cpu_clock(printk_cpu);
nanosec_rem = do_div(t, 1000000000);
- tlen = sprintf(tbuf, "[%5lu.%06lu] ",
+ tlen = sprintf(tbuf, "ns_id='%d' %5lu.%06lu] ",
+ syslog_ns->handle,
(unsigned long) t,
nanosec_rem / 1000);
for (tp = tbuf; tp < tbuf + tlen; tp++)
- emit_log_char(*tp);
+ emit_log_char(syslog_ns, *tp);
printed_len += tlen;
}
break;
}
- emit_log_char(*p);
+ emit_log_char(syslog_ns, *p);
if (*p == '\n')
new_text_line = 1;
}
* will release 'logbuf_lock' regardless of whether it
* actually gets the semaphore or not.
*/
- if (acquire_console_semaphore_for_printk(this_cpu))
+ if (acquire_console_semaphore_for_printk(syslog_ns, this_cpu))
release_console_sem();
lockdep_on();
EXPORT_SYMBOL(printk);
EXPORT_SYMBOL(vprintk);
-#else
-
-static void call_console_drivers(unsigned start, unsigned end)
-{
-}
-
#endif
static int __add_preferred_console(char *name, int idx, char *options,
*/
void release_console_sem(void)
{
- unsigned long flags;
- unsigned _con_start, _log_end;
- unsigned wake_klogd = 0;
-
if (console_suspended) {
up(&console_sem);
return;
}
console_may_schedule = 0;
-
- for ( ; ; ) {
- spin_lock_irqsave(&logbuf_lock, flags);
- wake_klogd |= log_start - log_end;
- if (con_start == log_end)
- break; /* Nothing to print */
- _con_start = con_start;
- _log_end = log_end;
- con_start = log_end; /* Flush */
- spin_unlock(&logbuf_lock);
- stop_critical_timings(); /* don't trace print latency */
- call_console_drivers(_con_start, _log_end);
- start_critical_timings();
- local_irq_restore(flags);
+#ifdef CONFIG_PRINTK
+ {
+ unsigned long flags;
+ unsigned _con_start, _log_end;
+ unsigned wake_klogd = 0;
+ struct syslog_ns *syslog_ns = current_syslog_ns();
+
+ for ( ; ; ) {
+ spin_lock_irqsave(&sys_log_lock, flags);
+ wake_klogd |= sys_log_start - sys_log_end;
+ if (sys_log_con_start == sys_log_end)
+ break; /* Nothing to print */
+ _con_start = sys_log_con_start;
+ _log_end = sys_log_end;
+ sys_log_con_start = sys_log_end; /* Flush */
+ spin_unlock(&sys_log_lock);
+ stop_critical_timings();/* don't trace print latency */
+ call_console_drivers(syslog_ns, _con_start, _log_end);
+ start_critical_timings();
+ local_irq_restore(flags);
+ }
+ spin_unlock_irqrestore(&sys_log_lock, flags);
+ if (wake_klogd)
+ wake_up_klogd();
}
+#endif
console_locked = 0;
up(&console_sem);
- spin_unlock_irqrestore(&logbuf_lock, flags);
- if (wake_klogd)
- wake_up_klogd();
}
EXPORT_SYMBOL(release_console_sem);
void register_console(struct console *newcon)
{
int i;
- unsigned long flags;
struct console *bcon = NULL;
/*
newcon->next = console_drivers->next;
console_drivers->next = newcon;
}
+#ifdef CONFIG_PRINTK
if (newcon->flags & CON_PRINTBUFFER) {
+ unsigned long flags;
/*
* release_console_sem() will print out the buffered messages
* for us.
*/
- spin_lock_irqsave(&logbuf_lock, flags);
- con_start = log_start;
- spin_unlock_irqrestore(&logbuf_lock, flags);
+
+ struct syslog_ns *syslog_ns = current_syslog_ns();
+
+ spin_lock_irqsave(&sys_log_lock, flags);
+ sys_log_con_start = sys_log_start;
+ spin_unlock_irqrestore(&sys_log_lock, flags);
}
+#endif
release_console_sem();
/*
const char *s1, *s2;
unsigned long l1, l2;
unsigned long flags;
+ struct syslog_ns *syslog_ns = current_syslog_ns();
/* Theoretically, the log could move on after we do this, but
there's not a lot we can do about that. The new messages
will overwrite the start of what we dump. */
- spin_lock_irqsave(&logbuf_lock, flags);
- end = log_end & LOG_BUF_MASK;
- chars = logged_chars;
- spin_unlock_irqrestore(&logbuf_lock, flags);
+ spin_lock_irqsave(&sys_log_lock, flags);
+ end = sys_log_end & LOG_BUF_MASK(syslog_ns);
+ chars = sys_log_logged_chars;
+ spin_unlock_irqrestore(&sys_log_lock, flags);
- if (logged_chars > end) {
- s1 = log_buf + log_buf_len - logged_chars + end;
- l1 = logged_chars - end;
+ if (sys_log_logged_chars > end) {
+ s1 = sys_log_buf + sys_log_buf_len - sys_log_logged_chars + end;
+ l1 = sys_log_logged_chars - end;
- s2 = log_buf;
+ s2 = sys_log_buf;
l2 = end;
} else {
s1 = "";
l1 = 0;
- s2 = log_buf + end - logged_chars;
- l2 = logged_chars;
+ s2 = sys_log_buf + end - sys_log_logged_chars;
+ l2 = sys_log_logged_chars;
}
if (!spin_trylock_irqsave(&dump_list_lock, flags)) {
spin_unlock_irqrestore(&dump_list_lock, flags);
}
#endif
+