Patchwork [RFC,3/5] printk: modify printk interface for syslog_namespace

login
register
mail settings
Submitter Rui Xiang
Date Nov. 19, 2012, 8:16 a.m.
Message ID <50A9EAF0.4000902@gmail.com>
Download mbox | patch
Permalink /patch/199936/
State RFC
Delegated to: David Miller
Headers show

Comments

Rui Xiang - Nov. 19, 2012, 8:16 a.m.
From: Libo Chen <clbchenlibo.chen@huawei.com>

We re-implement printk by additional syslog_ns.

The function include printk, /dev/kmsg, do_syslog and kmsg_dump should be modifyed
for syslog_ns. Previous identifier *** such as log_first_seq should be replaced
by syslog_ns->***.

Signed-off-by: Libo Chen <clbchenlibo.chen@huawei.com>
Signed-off-by: Xiang Rui <rui.xiang@huawei.com>
---
 drivers/base/core.c    |    4 +-
 include/linux/printk.h |    4 +-
 kernel/printk.c        |  609 +++++++++++++++++++++++++++++-------------------
 3 files changed, 372 insertions(+), 245 deletions(-)
Serge E. Hallyn - Nov. 19, 2012, 2:29 p.m.
Quoting Rui Xiang (leo.ruixiang@gmail.com):
> From: Libo Chen <clbchenlibo.chen@huawei.com>
> 
> We re-implement printk by additional syslog_ns.
> 
> The function include printk, /dev/kmsg, do_syslog and kmsg_dump should be modifyed
> for syslog_ns. Previous identifier *** such as log_first_seq should be replaced
> by syslog_ns->***.
> 
> Signed-off-by: Libo Chen <clbchenlibo.chen@huawei.com>
> Signed-off-by: Xiang Rui <rui.xiang@huawei.com>
> ---
>  drivers/base/core.c    |    4 +-
>  include/linux/printk.h |    4 +-
>  kernel/printk.c        |  609 +++++++++++++++++++++++++++++-------------------
>  3 files changed, 372 insertions(+), 245 deletions(-)
> 
> diff --git a/drivers/base/core.c b/drivers/base/core.c
> index abea76c..665c2f7 100644
> --- a/drivers/base/core.c
> +++ b/drivers/base/core.c
> @@ -26,6 +26,7 @@
>  #include <linux/async.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/netdevice.h>
> +#include <linux/syslog_namespace.h>
> 
>  #include "base.h"
>  #include "power/power.h"
> @@ -1922,7 +1923,8 @@ int dev_vprintk_emit(int level, const struct device *dev,
> 
>  	hdrlen = create_syslog_header(dev, hdr, sizeof(hdr));
> 
> -	return vprintk_emit(0, level, hdrlen ? hdr : NULL, hdrlen, fmt, args);
> +	return vprintk_emit(0, level, hdrlen ? hdr : NULL, hdrlen,
> +				fmt, args, current_syslog_ns());
>  }
>  EXPORT_SYMBOL(dev_vprintk_emit);
> 
> diff --git a/include/linux/printk.h b/include/linux/printk.h
> index 9afc01e..e0c60d9 100644
> --- a/include/linux/printk.h
> +++ b/include/linux/printk.h
> @@ -7,6 +7,7 @@
>  extern const char linux_banner[];
>  extern const char linux_proc_banner[];
> 
> +struct syslog_namespace;
>  static inline int printk_get_level(const char *buffer)
>  {
>  	if (buffer[0] == KERN_SOH_ASCII && buffer[1]) {
> @@ -105,7 +106,8 @@ extern void printk_tick(void);
>  asmlinkage __printf(5, 0)
>  int vprintk_emit(int facility, int level,
>  		 const char *dict, size_t dictlen,
> -		 const char *fmt, va_list args);
> +		 const char *fmt, va_list args,
> +		 struct syslog_namespace *syslog_ns);
> 
>  asmlinkage __printf(1, 0)
>  int vprintk(const char *fmt, va_list args);
> diff --git a/kernel/printk.c b/kernel/printk.c
> index 2d607f4..2ef9c46 100644
> --- a/kernel/printk.c
> +++ b/kernel/printk.c
> @@ -42,6 +42,7 @@
>  #include <linux/notifier.h>
>  #include <linux/rculist.h>
>  #include <linux/poll.h>
> +#include <linux/syslog_namespace.h>
> 
>  #include <asm/uaccess.h>
> 
> @@ -214,46 +215,14 @@ struct log {
>   * The logbuf_lock protects kmsg buffer, indices, counters. It is also
>   * used in interesting ways to provide interlocking in console_unlock();
>   */
> -static DEFINE_RAW_SPINLOCK(logbuf_lock);
> 
>  #ifdef CONFIG_PRINTK
> -/* the next printk record to read by syslog(READ) or /proc/kmsg */
> -static u64 syslog_seq;
> -static u32 syslog_idx;
> -static enum log_flags syslog_prev;
> -static size_t syslog_partial;
> -
> -/* index and sequence number of the first record stored in the buffer */
> -static u64 log_first_seq;
> -static u32 log_first_idx;
> -
> -/* index and sequence number of the next record to store in the buffer */
> -static u64 log_next_seq;
> -static u32 log_next_idx;
> 
> -/* the next printk record to write to the console */
> -static u64 console_seq;
> -static u32 console_idx;
>  static enum log_flags console_prev;
> 
> -/* the next printk record to read after the last 'clear' command */
> -static u64 clear_seq;
> -static u32 clear_idx;
> -
>  #define PREFIX_MAX		32
>  #define LOG_LINE_MAX		1024 - PREFIX_MAX
> 
> -/* record buffer */
> -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
> -#define LOG_ALIGN 4
> -#else
> -#define LOG_ALIGN __alignof__(struct log)
> -#endif
> -#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
> -static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
> -static char *log_buf = __log_buf;
> -static u32 log_buf_len = __LOG_BUF_LEN;
> -
>  /* cpu currently holding logbuf_lock */
>  static volatile unsigned int logbuf_cpu = UINT_MAX;
> 
> @@ -270,23 +239,23 @@ static char *log_dict(const struct log *msg)
>  }
> 
>  /* get record by index; idx must point to valid msg */
> -static struct log *log_from_idx(u32 idx)
> +static struct log *log_from_idx(u32 idx, struct syslog_namespace *syslog_ns)
>  {
> -	struct log *msg = (struct log *)(log_buf + idx);
> +	struct log *msg = (struct log *)(syslog_ns->log_buf + idx);
> 
>  	/*
>  	 * A length == 0 record is the end of buffer marker. Wrap around and
>  	 * read the message at the start of the buffer.
>  	 */
>  	if (!msg->len)
> -		return (struct log *)log_buf;
> +		return (struct log *)syslog_ns->log_buf;
>  	return msg;
>  }
> 
>  /* get next record; idx must point to valid msg */
> -static u32 log_next(u32 idx)
> +static u32 log_next(u32 idx, struct syslog_namespace *syslog_ns)
>  {
> -	struct log *msg = (struct log *)(log_buf + idx);
> +	struct log *msg = (struct log *)(syslog_ns->log_buf + idx);
> 
>  	/* length == 0 indicates the end of the buffer; wrap */
>  	/*
> @@ -295,7 +264,7 @@ static u32 log_next(u32 idx)
>  	 * return the one after that.
>  	 */
>  	if (!msg->len) {
> -		msg = (struct log *)log_buf;
> +		msg = (struct log *)syslog_ns->log_buf;
>  		return msg->len;
>  	}
>  	return idx + msg->len;
> @@ -305,7 +274,8 @@ static u32 log_next(u32 idx)
>  static void log_store(int facility, int level,
>  		      enum log_flags flags, u64 ts_nsec,
>  		      const char *dict, u16 dict_len,
> -		      const char *text, u16 text_len)
> +		      const char *text, u16 text_len,
> +		      struct syslog_namespace *syslog_ns)
>  {
>  	struct log *msg;
>  	u32 size, pad_len;
> @@ -315,34 +285,40 @@ static void log_store(int facility, int level,
>  	pad_len = (-size) & (LOG_ALIGN - 1);
>  	size += pad_len;
> 
> -	while (log_first_seq < log_next_seq) {
> +	while (syslog_ns->log_first_seq < syslog_ns->log_next_seq) {
>  		u32 free;
> 
> -		if (log_next_idx > log_first_idx)
> -			free = max(log_buf_len - log_next_idx, log_first_idx);
> +		if (syslog_ns->log_next_idx > syslog_ns->log_first_idx)
> +			free = max(syslog_ns->log_buf_len -
> +				 syslog_ns->log_next_idx,
> +				 syslog_ns->log_first_idx);
>  		else
> -			free = log_first_idx - log_next_idx;
> +			free = syslog_ns->log_first_idx -
> +					 syslog_ns->log_next_idx;
> 
>  		if (free > size + sizeof(struct log))
>  			break;
> 
>  		/* drop old messages until we have enough contiuous space */
> -		log_first_idx = log_next(log_first_idx);
> -		log_first_seq++;
> +		syslog_ns->log_first_idx =
> +				log_next(syslog_ns->log_first_idx, syslog_ns);
> +		syslog_ns->log_first_seq++;
>  	}
> 
> -	if (log_next_idx + size + sizeof(struct log) >= log_buf_len) {
> +	if (syslog_ns->log_next_idx + size + sizeof(struct log) >=
> +						 syslog_ns->log_buf_len) {
>  		/*
>  		 * This message + an additional empty header does not fit
>  		 * at the end of the buffer. Add an empty header with len == 0
>  		 * to signify a wrap around.
>  		 */
> -		memset(log_buf + log_next_idx, 0, sizeof(struct log));
> -		log_next_idx = 0;
> +		memset(syslog_ns->log_buf + syslog_ns->log_next_idx,
> +						 0, sizeof(struct log));
> +		syslog_ns->log_next_idx = 0;
>  	}
> 
>  	/* fill message */
> -	msg = (struct log *)(log_buf + log_next_idx);
> +	msg = (struct log *)(syslog_ns->log_buf + syslog_ns->log_next_idx);
>  	memcpy(log_text(msg), text, text_len);
>  	msg->text_len = text_len;
>  	memcpy(log_dict(msg), dict, dict_len);
> @@ -358,8 +334,8 @@ static void log_store(int facility, int level,
>  	msg->len = sizeof(struct log) + text_len + dict_len + pad_len;
> 
>  	/* insert message */
> -	log_next_idx += msg->len;
> -	log_next_seq++;
> +	syslog_ns->log_next_idx += msg->len;
> +	syslog_ns->log_next_seq++;
>  }
> 
>  /* /dev/kmsg - userspace message inject/listen interface */
> @@ -368,6 +344,7 @@ struct devkmsg_user {
>  	u32 idx;
>  	enum log_flags prev;
>  	struct mutex lock;
> +	struct syslog_namespace *syslog_ns;
>  	char buf[8192];
>  };
> 
> @@ -431,6 +408,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
>  			    size_t count, loff_t *ppos)
>  {
>  	struct devkmsg_user *user = file->private_data;
> +	struct syslog_namespace *syslog_ns = user->syslog_ns;
>  	struct log *msg;
>  	u64 ts_usec;
>  	size_t i;
> @@ -444,32 +422,32 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
>  	ret = mutex_lock_interruptible(&user->lock);
>  	if (ret)
>  		return ret;
> -	raw_spin_lock_irq(&logbuf_lock);
> -	while (user->seq == log_next_seq) {
> +	raw_spin_lock_irq(&syslog_ns->logbuf_lock);
> +	while (user->seq == syslog_ns->log_next_seq) {
>  		if (file->f_flags & O_NONBLOCK) {
>  			ret = -EAGAIN;
> -			raw_spin_unlock_irq(&logbuf_lock);
> +			raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
>  			goto out;
>  		}
> 
> -		raw_spin_unlock_irq(&logbuf_lock);
> +		raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
>  		ret = wait_event_interruptible(log_wait,
> -					       user->seq != log_next_seq);
> +				user->seq != syslog_ns->log_next_seq);
>  		if (ret)
>  			goto out;
> -		raw_spin_lock_irq(&logbuf_lock);
> +		raw_spin_lock_irq(&syslog_ns->logbuf_lock);
>  	}
> 
> -	if (user->seq < log_first_seq) {
> +	if (user->seq < syslog_ns->log_first_seq) {
>  		/* our last seen message is gone, return error and reset */
> -		user->idx = log_first_idx;
> -		user->seq = log_first_seq;
> +		user->idx = syslog_ns->log_first_idx;
> +		user->seq = syslog_ns->log_first_seq;
>  		ret = -EPIPE;
> -		raw_spin_unlock_irq(&logbuf_lock);
> +		raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
>  		goto out;
>  	}
> 
> -	msg = log_from_idx(user->idx);
> +	msg = log_from_idx(user->idx, syslog_ns);
>  	ts_usec = msg->ts_nsec;
>  	do_div(ts_usec, 1000);
> 
> @@ -530,9 +508,9 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
>  		user->buf[len++] = '\n';
>  	}
> 
> -	user->idx = log_next(user->idx);
> +	user->idx = log_next(user->idx, syslog_ns);
>  	user->seq++;
> -	raw_spin_unlock_irq(&logbuf_lock);
> +	raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
> 
>  	if (len > count) {
>  		ret = -EINVAL;
> @@ -552,6 +530,7 @@ out:
>  static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
>  {
>  	struct devkmsg_user *user = file->private_data;
> +	struct syslog_namespace *syslog_ns = user->syslog_ns;
>  	loff_t ret = 0;
> 
>  	if (!user)
> @@ -559,12 +538,12 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
>  	if (offset)
>  		return -ESPIPE;
> 
> -	raw_spin_lock_irq(&logbuf_lock);
> +	raw_spin_lock_irq(&syslog_ns->logbuf_lock);
>  	switch (whence) {
>  	case SEEK_SET:
>  		/* the first record */
> -		user->idx = log_first_idx;
> -		user->seq = log_first_seq;
> +		user->idx = syslog_ns->log_first_idx;
> +		user->seq = syslog_ns->log_first_seq;
>  		break;
>  	case SEEK_DATA:
>  		/*
> @@ -572,24 +551,25 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
>  		 * like issued by 'dmesg -c'. Reading /dev/kmsg itself
>  		 * changes no global state, and does not clear anything.
>  		 */
> -		user->idx = clear_idx;
> -		user->seq = clear_seq;
> +		user->idx = syslog_ns->clear_idx;
> +		user->seq = syslog_ns->clear_seq;
>  		break;
>  	case SEEK_END:
>  		/* after the last record */
> -		user->idx = log_next_idx;
> -		user->seq = log_next_seq;
> +		user->idx = syslog_ns->log_next_idx;
> +		user->seq = syslog_ns->log_next_seq;
>  		break;
>  	default:
>  		ret = -EINVAL;
>  	}
> -	raw_spin_unlock_irq(&logbuf_lock);
> +	raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
>  	return ret;
>  }
> 
>  static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
>  {
>  	struct devkmsg_user *user = file->private_data;
> +	struct syslog_namespace *syslog_ns = user->syslog_ns;
>  	int ret = 0;
> 
>  	if (!user)
> @@ -597,20 +577,21 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
> 
>  	poll_wait(file, &log_wait, wait);
> 
> -	raw_spin_lock_irq(&logbuf_lock);
> -	if (user->seq < log_next_seq) {
> +	raw_spin_lock_irq(&syslog_ns->logbuf_lock);
> +	if (user->seq < syslog_ns->log_next_seq) {
>  		/* return error when data has vanished underneath us */
> -		if (user->seq < log_first_seq)
> +		if (user->seq < syslog_ns->log_first_seq)
>  			ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI;
>  		ret = POLLIN|POLLRDNORM;
>  	}
> -	raw_spin_unlock_irq(&logbuf_lock);
> +	raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
> 
>  	return ret;
>  }
> 
>  static int devkmsg_open(struct inode *inode, struct file *file)
>  {
> +	struct syslog_namespace *syslog_ns;
>  	struct devkmsg_user *user;
>  	int err;
> 
> @@ -628,10 +609,11 @@ static int devkmsg_open(struct inode *inode, struct file *file)
> 
>  	mutex_init(&user->lock);
> 
> -	raw_spin_lock_irq(&logbuf_lock);
> -	user->idx = log_first_idx;
> -	user->seq = log_first_seq;
> -	raw_spin_unlock_irq(&logbuf_lock);
> +	user->syslog_ns = current_syslog_ns();
> +	raw_spin_lock_irq(&syslog_ns->logbuf_lock);
> +	user->idx = syslog_ns->log_first_idx;
> +	user->seq = syslog_ns->log_first_seq;
> +	raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
> 
>  	file->private_data = user;
>  	return 0;
> @@ -669,10 +651,12 @@ const struct file_operations kmsg_fops = {
>   */
>  void log_buf_kexec_setup(void)
>  {
> -	VMCOREINFO_SYMBOL(log_buf);
> -	VMCOREINFO_SYMBOL(log_buf_len);
> -	VMCOREINFO_SYMBOL(log_first_idx);
> -	VMCOREINFO_SYMBOL(log_next_idx);
> +	struct syslog_namespace *syslog_ns = current_syslog_ns();
> +
> +	VMCOREINFO_SYMBOL(syslog_ns->log_buf);
> +	VMCOREINFO_SYMBOL(syslog_ns->log_buf_len);
> +	VMCOREINFO_SYMBOL(syslog_ns->log_first_idx);
> +	VMCOREINFO_SYMBOL(syslog_ns->log_next_idx);
>  	/*
>  	 * Export struct log size and field offsets. User space tools can
>  	 * parse it and detect any changes to structure down the line.
> @@ -692,10 +676,11 @@ static unsigned long __initdata new_log_buf_len;
>  static int __init log_buf_len_setup(char *str)
>  {
>  	unsigned size = memparse(str, &str);
> +	struct syslog_namespace *syslog_ns = &init_syslog_ns;
> 
>  	if (size)
>  		size = roundup_pow_of_two(size);
> -	if (size > log_buf_len)
> +	if (size > syslog_ns->log_buf_len)
>  		new_log_buf_len = size;
> 
>  	return 0;
> @@ -707,6 +692,7 @@ void __init setup_log_buf(int early)
>  	unsigned long flags;
>  	char *new_log_buf;
>  	int free;
> +	struct syslog_namespace *syslog_ns = &init_syslog_ns;
> 
>  	if (!new_log_buf_len)
>  		return;
> @@ -728,15 +714,15 @@ void __init setup_log_buf(int early)
>  		return;
>  	}
> 
> -	raw_spin_lock_irqsave(&logbuf_lock, flags);
> -	log_buf_len = new_log_buf_len;
> -	log_buf = new_log_buf;
> +	raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);
> +	memcpy(new_log_buf, syslog_ns->log_buf, __LOG_BUF_LEN);
> +	syslog_ns->log_buf_len = new_log_buf_len;
> +	syslog_ns->log_buf = new_log_buf;
>  	new_log_buf_len = 0;
> -	free = __LOG_BUF_LEN - log_next_idx;
> -	memcpy(log_buf, __log_buf, __LOG_BUF_LEN);
> -	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
> +	free = __LOG_BUF_LEN - syslog_ns->log_next_idx;
> +	raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
> 
> -	pr_info("log_buf_len: %d\n", log_buf_len);
> +	pr_info("log_buf_len: %d\n", syslog_ns->log_buf_len);
>  	pr_info("early log buf free: %d(%d%%)\n",
>  		free, (free * 100) / __LOG_BUF_LEN);
>  }
> @@ -937,7 +923,8 @@ static size_t msg_print_text(const struct log *msg, enum log_flags prev,
>  	return len;
>  }
> 
> -static int syslog_print(char __user *buf, int size)
> +static int syslog_print(char __user *buf, int size,
> +			 struct syslog_namespace *syslog_ns)
>  {
>  	char *text;
>  	struct log *msg;
> @@ -951,37 +938,38 @@ static int syslog_print(char __user *buf, int size)
>  		size_t n;
>  		size_t skip;
> 
> -		raw_spin_lock_irq(&logbuf_lock);
> -		if (syslog_seq < log_first_seq) {
> +		raw_spin_lock_irq(&syslog_ns->logbuf_lock);
> +		if (syslog_ns->syslog_seq < syslog_ns->log_first_seq) {
>  			/* messages are gone, move to first one */
> -			syslog_seq = log_first_seq;
> -			syslog_idx = log_first_idx;
> -			syslog_prev = 0;
> -			syslog_partial = 0;
> +			syslog_ns->syslog_seq = syslog_ns->log_first_seq;
> +			syslog_ns->syslog_idx = syslog_ns->log_first_idx;
> +			syslog_ns->syslog_prev = 0;
> +			syslog_ns->syslog_partial = 0;
>  		}
> -		if (syslog_seq == log_next_seq) {
> -			raw_spin_unlock_irq(&logbuf_lock);
> +		if (syslog_ns->syslog_seq == syslog_ns->log_next_seq) {
> +			raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
>  			break;
>  		}
> 
> -		skip = syslog_partial;
> -		msg = log_from_idx(syslog_idx);
> -		n = msg_print_text(msg, syslog_prev, true, text,
> +		skip = syslog_ns->syslog_partial;
> +		msg = log_from_idx(syslog_ns->syslog_idx, syslog_ns);
> +		n = msg_print_text(msg, syslog_ns->syslog_prev, true, text,
>  				   LOG_LINE_MAX + PREFIX_MAX);
> -		if (n - syslog_partial <= size) {
> +		if (n - syslog_ns->syslog_partial <= size) {
>  			/* message fits into buffer, move forward */
> -			syslog_idx = log_next(syslog_idx);
> -			syslog_seq++;
> -			syslog_prev = msg->flags;
> -			n -= syslog_partial;
> -			syslog_partial = 0;
> +			syslog_ns->syslog_idx =
> +				log_next(syslog_ns->syslog_idx, syslog_ns);
> +			syslog_ns->syslog_seq++;
> +			syslog_ns->syslog_prev = msg->flags;
> +			n -= syslog_ns->syslog_partial;
> +			syslog_ns->syslog_partial = 0;
>  		} else if (!len){
>  			/* partial read(), remember position */
>  			n = size;
> -			syslog_partial += n;
> +			syslog_ns->syslog_partial += n;
>  		} else
>  			n = 0;
> -		raw_spin_unlock_irq(&logbuf_lock);
> +		raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
> 
>  		if (!n)
>  			break;
> @@ -1001,7 +989,8 @@ static int syslog_print(char __user *buf, int size)
>  	return len;
>  }
> 
> -static int syslog_print_all(char __user *buf, int size, bool clear)
> +static int syslog_print_all(char __user *buf, int size, bool clear,
> +				struct syslog_namespace *syslog_ns)
>  {
>  	char *text;
>  	int len = 0;
> @@ -1010,55 +999,55 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
>  	if (!text)
>  		return -ENOMEM;
> 
> -	raw_spin_lock_irq(&logbuf_lock);
> +	raw_spin_lock_irq(&syslog_ns->logbuf_lock);
>  	if (buf) {
>  		u64 next_seq;
>  		u64 seq;
>  		u32 idx;
>  		enum log_flags prev;
> 
> -		if (clear_seq < log_first_seq) {
> +		if (syslog_ns->clear_seq < syslog_ns->log_first_seq) {
>  			/* messages are gone, move to first available one */
> -			clear_seq = log_first_seq;
> -			clear_idx = log_first_idx;
> +			syslog_ns->clear_seq = syslog_ns->log_first_seq;
> +			syslog_ns->clear_idx = syslog_ns->log_first_idx;
>  		}
> 
>  		/*
>  		 * Find first record that fits, including all following records,
>  		 * into the user-provided buffer for this dump.
>  		 */
> -		seq = clear_seq;
> -		idx = clear_idx;
> +		seq = syslog_ns->clear_seq;
> +		idx = syslog_ns->clear_idx;
>  		prev = 0;
> -		while (seq < log_next_seq) {
> -			struct log *msg = log_from_idx(idx);
> +		while (seq < syslog_ns->log_next_seq) {
> +			struct log *msg = log_from_idx(idx, syslog_ns);
> 
>  			len += msg_print_text(msg, prev, true, NULL, 0);
>  			prev = msg->flags;
> -			idx = log_next(idx);
> +			idx = log_next(idx, syslog_ns);
>  			seq++;
>  		}
> 
>  		/* move first record forward until length fits into the buffer */
> -		seq = clear_seq;
> -		idx = clear_idx;
> +		seq = syslog_ns->clear_seq;
> +		idx = syslog_ns->clear_idx;
>  		prev = 0;
> -		while (len > size && seq < log_next_seq) {
> -			struct log *msg = log_from_idx(idx);
> +		while (len > size && seq < syslog_ns->log_next_seq) {
> +			struct log *msg = log_from_idx(idx, syslog_ns);
> 
>  			len -= msg_print_text(msg, prev, true, NULL, 0);
>  			prev = msg->flags;
> -			idx = log_next(idx);
> +			idx = log_next(idx, syslog_ns);
>  			seq++;
>  		}
> 
>  		/* last message fitting into this dump */
> -		next_seq = log_next_seq;
> +		next_seq = syslog_ns->log_next_seq;
> 
>  		len = 0;
>  		prev = 0;
>  		while (len >= 0 && seq < next_seq) {
> -			struct log *msg = log_from_idx(idx);
> +			struct log *msg = log_from_idx(idx, syslog_ns);
>  			int textlen;
> 
>  			textlen = msg_print_text(msg, prev, true, text,
> @@ -1067,31 +1056,31 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
>  				len = textlen;
>  				break;
>  			}
> -			idx = log_next(idx);
> +			idx = log_next(idx, syslog_ns);
>  			seq++;
>  			prev = msg->flags;
> 
> -			raw_spin_unlock_irq(&logbuf_lock);
> +			raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
>  			if (copy_to_user(buf + len, text, textlen))
>  				len = -EFAULT;
>  			else
>  				len += textlen;
> -			raw_spin_lock_irq(&logbuf_lock);
> +			raw_spin_lock_irq(&syslog_ns->logbuf_lock);
> 
> -			if (seq < log_first_seq) {
> +			if (seq < syslog_ns->log_first_seq) {
>  				/* messages are gone, move to next one */
> -				seq = log_first_seq;
> -				idx = log_first_idx;
> +				seq = syslog_ns->log_first_seq;
> +				idx = syslog_ns->log_first_idx;
>  				prev = 0;
>  			}
>  		}
>  	}
> 
>  	if (clear) {
> -		clear_seq = log_next_seq;
> -		clear_idx = log_next_idx;
> +		syslog_ns->clear_seq = syslog_ns->log_next_seq;
> +		syslog_ns->clear_idx = syslog_ns->log_next_idx;
>  	}
> -	raw_spin_unlock_irq(&logbuf_lock);
> +	raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
> 
>  	kfree(text);
>  	return len;
> @@ -1102,6 +1091,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
>  	bool clear = false;
>  	static int saved_console_loglevel = -1;
>  	int error;
> +	struct syslog_namespace *syslog_ns = current_syslog_ns();
> 
>  	error = check_syslog_permissions(type, from_file);
>  	if (error)
> @@ -1128,10 +1118,10 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
>  			goto out;
>  		}
>  		error = wait_event_interruptible(log_wait,
> -						 syslog_seq != log_next_seq);
> +			syslog_ns->syslog_seq != syslog_ns->log_next_seq);
>  		if (error)
>  			goto out;
> -		error = syslog_print(buf, len);
> +		error = syslog_print(buf, len, syslog_ns);
>  		break;
>  	/* Read/clear last kernel messages */
>  	case SYSLOG_ACTION_READ_CLEAR:
> @@ -1149,11 +1139,11 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
>  			error = -EFAULT;
>  			goto out;
>  		}
> -		error = syslog_print_all(buf, len, clear);
> +		error = syslog_print_all(buf, len, clear, syslog_ns);
>  		break;
>  	/* Clear ring buffer */
>  	case SYSLOG_ACTION_CLEAR:
> -		syslog_print_all(NULL, 0, true);
> +		syslog_print_all(NULL, 0, true, syslog_ns);
>  		break;
>  	/* Disable logging to console */
>  	case SYSLOG_ACTION_CONSOLE_OFF:
> @@ -1182,13 +1172,13 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
>  		break;
>  	/* Number of chars in the log buffer */
>  	case SYSLOG_ACTION_SIZE_UNREAD:
> -		raw_spin_lock_irq(&logbuf_lock);
> -		if (syslog_seq < log_first_seq) {
> +		raw_spin_lock_irq(&syslog_ns->logbuf_lock);
> +		if (syslog_ns->syslog_seq < syslog_ns->log_first_seq) {
>  			/* messages are gone, move to first one */
> -			syslog_seq = log_first_seq;
> -			syslog_idx = log_first_idx;
> -			syslog_prev = 0;
> -			syslog_partial = 0;
> +			syslog_ns->syslog_seq = syslog_ns->log_first_seq;
> +			syslog_ns->syslog_idx = syslog_ns->log_first_idx;
> +			syslog_ns->syslog_prev = 0;
> +			syslog_ns->syslog_partial = 0;
>  		}
>  		if (from_file) {
>  			/*
> @@ -1196,28 +1186,28 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
>  			 * for pending data, not the size; return the count of
>  			 * records, not the length.
>  			 */
> -			error = log_next_idx - syslog_idx;
> +			error = syslog_ns->log_next_idx - syslog_ns->syslog_idx;
>  		} else {
> -			u64 seq = syslog_seq;
> -			u32 idx = syslog_idx;
> -			enum log_flags prev = syslog_prev;
> +			u64 seq = syslog_ns->syslog_seq;
> +			u32 idx = syslog_ns->syslog_idx;
> +			enum log_flags prev = syslog_ns->syslog_prev;
> 
>  			error = 0;
> -			while (seq < log_next_seq) {
> -				struct log *msg = log_from_idx(idx);
> +			while (seq < syslog_ns->log_next_seq) {
> +				struct log *msg = log_from_idx(idx, syslog_ns);
> 
>  				error += msg_print_text(msg, prev, true, NULL, 0);
> -				idx = log_next(idx);
> +				idx = log_next(idx, syslog_ns);
>  				seq++;
>  				prev = msg->flags;
>  			}
> -			error -= syslog_partial;
> +			error -= syslog_ns->syslog_partial;
>  		}
> -		raw_spin_unlock_irq(&logbuf_lock);
> +		raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
>  		break;
>  	/* Size of the log buffer */
>  	case SYSLOG_ACTION_SIZE_BUFFER:
> -		error = log_buf_len;
> +		error = syslog_ns->log_buf_len;
>  		break;
>  	default:
>  		error = -EINVAL;
> @@ -1282,7 +1272,7 @@ static void call_console_drivers(int level, const char *text, size_t len)
>   * 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_namespace *syslog_ns)
>  {
>  	static unsigned long oops_timestamp;
> 
> @@ -1294,7 +1284,7 @@ static void zap_locks(void)
> 
>  	debug_locks_off();
>  	/* If a crash is occurring, make sure we can't deadlock */
> -	raw_spin_lock_init(&logbuf_lock);
> +	raw_spin_lock_init(&syslog_ns->logbuf_lock);
>  	/* And make sure that we print immediately */
>  	sema_init(&console_sem, 1);
>  }
> @@ -1334,8 +1324,9 @@ static inline int can_use_console(unsigned int cpu)
>   * interrupts disabled. It should return with 'lockbuf_lock'
>   * released but interrupts still disabled.
>   */
> -static int console_trylock_for_printk(unsigned int cpu)
> -	__releases(&logbuf_lock)
> +static int console_trylock_for_printk(unsigned int cpu,
> +			 struct syslog_namespace *syslog_ns)
> +	__releases(&syslog_ns->logbuf_lock)
>  {
>  	int retval = 0, wake = 0;
> 
> @@ -1357,7 +1348,7 @@ static int console_trylock_for_printk(unsigned int cpu)
>  	logbuf_cpu = UINT_MAX;
>  	if (wake)
>  		up(&console_sem);
> -	raw_spin_unlock(&logbuf_lock);
> +	raw_spin_unlock(&syslog_ns->logbuf_lock);
>  	return retval;
>  }
> 
> @@ -1393,7 +1384,7 @@ static struct cont {
>  	bool flushed:1;			/* buffer sealed and committed */
>  } cont;
> 
> -static void cont_flush(enum log_flags flags)
> +static void cont_flush(enum log_flags flags, struct syslog_namespace *syslog_ns)
>  {
>  	if (cont.flushed)
>  		return;
> @@ -1407,7 +1398,7 @@ static void cont_flush(enum log_flags flags)
>  		 * line. LOG_NOCONS suppresses a duplicated output.
>  		 */
>  		log_store(cont.facility, cont.level, flags | LOG_NOCONS,
> -			  cont.ts_nsec, NULL, 0, cont.buf, cont.len);
> +			  cont.ts_nsec, NULL, 0, cont.buf, cont.len, syslog_ns);
>  		cont.flags = flags;
>  		cont.flushed = true;
>  	} else {
> @@ -1416,19 +1407,20 @@ static void cont_flush(enum log_flags flags)
>  		 * just submit it to the store and free the buffer.
>  		 */
>  		log_store(cont.facility, cont.level, flags, 0,
> -			  NULL, 0, cont.buf, cont.len);
> +			  NULL, 0, cont.buf, cont.len, syslog_ns);
>  		cont.len = 0;
>  	}
>  }
> 
> -static bool cont_add(int facility, int level, const char *text, size_t len)
> +static bool cont_add(int facility, int level, const char *text, size_t len,
> +					struct syslog_namespace *syslog_ns)
>  {
>  	if (cont.len && cont.flushed)
>  		return false;
> 
>  	if (cont.len + len > sizeof(cont.buf)) {
>  		/* the line gets too long, split it up in separate records */
> -		cont_flush(LOG_CONT);
> +		cont_flush(LOG_CONT, syslog_ns);
>  		return false;
>  	}
> 
> @@ -1446,7 +1438,7 @@ static bool cont_add(int facility, int level, const char *text, size_t len)
>  	cont.len += len;
> 
>  	if (cont.len > (sizeof(cont.buf) * 80) / 100)
> -		cont_flush(LOG_CONT);
> +		cont_flush(LOG_CONT, syslog_ns);
> 
>  	return true;
>  }
> @@ -1481,7 +1473,8 @@ static size_t cont_print_text(char *text, size_t size)
> 
>  asmlinkage int vprintk_emit(int facility, int level,
>  			    const char *dict, size_t dictlen,
> -			    const char *fmt, va_list args)
> +			    const char *fmt, va_list args,
> +			    struct syslog_namespace *syslog_ns)
>  {
>  	static int recursion_bug;
>  	static char textbuf[LOG_LINE_MAX];
> @@ -1514,11 +1507,11 @@ asmlinkage int vprintk_emit(int facility, int level,
>  			recursion_bug = 1;
>  			goto out_restore_irqs;
>  		}
> -		zap_locks();
> +		zap_locks(syslog_ns);
>  	}
> 
>  	lockdep_off();
> -	raw_spin_lock(&logbuf_lock);
> +	raw_spin_lock(&syslog_ns->logbuf_lock);
>  	logbuf_cpu = this_cpu;
> 
>  	if (recursion_bug) {
> @@ -1529,7 +1522,7 @@ asmlinkage int vprintk_emit(int facility, int level,
>  		printed_len += strlen(recursion_msg);
>  		/* emit KERN_CRIT message */
>  		log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
> -			  NULL, 0, recursion_msg, printed_len);
> +			  NULL, 0, recursion_msg, printed_len, syslog_ns);
>  	}
> 
>  	/*
> @@ -1576,12 +1569,12 @@ asmlinkage int vprintk_emit(int facility, int level,
>  		 * or another task also prints continuation lines.
>  		 */
>  		if (cont.len && (lflags & LOG_PREFIX || cont.owner != current))
> -			cont_flush(LOG_NEWLINE);
> +			cont_flush(LOG_NEWLINE, syslog_ns);
> 
>  		/* buffer line if possible, otherwise store it right away */
> -		if (!cont_add(facility, level, text, text_len))
> +		if (!cont_add(facility, level, text, text_len, syslog_ns))
>  			log_store(facility, level, lflags | LOG_CONT, 0,
> -				  dict, dictlen, text, text_len);
> +				  dict, dictlen, text, text_len, syslog_ns);
>  	} else {
>  		bool stored = false;
> 
> @@ -1593,13 +1586,14 @@ asmlinkage int vprintk_emit(int facility, int level,
>  		 */
>  		if (cont.len && cont.owner == current) {
>  			if (!(lflags & LOG_PREFIX))
> -				stored = cont_add(facility, level, text, text_len);
> -			cont_flush(LOG_NEWLINE);
> +				stored = cont_add(facility, level, text,
> +							 text_len, syslog_ns);
> +			cont_flush(LOG_NEWLINE, syslog_ns);
>  		}
> 
>  		if (!stored)
>  			log_store(facility, level, lflags, 0,
> -				  dict, dictlen, text, text_len);
> +				  dict, dictlen, text, text_len, syslog_ns);
>  	}
>  	printed_len += text_len;
> 
> @@ -1611,7 +1605,7 @@ asmlinkage int vprintk_emit(int facility, int level,
>  	 * The console_trylock_for_printk() function will release 'logbuf_lock'
>  	 * regardless of whether it actually gets the console semaphore or not.
>  	 */
> -	if (console_trylock_for_printk(this_cpu))
> +	if (console_trylock_for_printk(this_cpu, syslog_ns))
>  		console_unlock();
> 
>  	lockdep_on();
> @@ -1624,7 +1618,8 @@ EXPORT_SYMBOL(vprintk_emit);
> 
>  asmlinkage int vprintk(const char *fmt, va_list args)
>  {
> -	return vprintk_emit(0, -1, NULL, 0, fmt, args);
> +	return vprintk_emit(0, -1, NULL, 0, fmt, args,
> +				current_syslog_ns());
>  }
>  EXPORT_SYMBOL(vprintk);
> 
> @@ -1636,7 +1631,8 @@ asmlinkage int printk_emit(int facility, int level,
>  	int r;
> 
>  	va_start(args, fmt);
> -	r = vprintk_emit(facility, level, dict, dictlen, fmt, args);
> +	r = vprintk_emit(facility, level, dict, dictlen, fmt, args,
> +						current_syslog_ns());
>  	va_end(args);
> 
>  	return r;
> @@ -1678,7 +1674,7 @@ asmlinkage int printk(const char *fmt, ...)
>  	}
>  #endif
>  	va_start(args, fmt);
> -	r = vprintk_emit(0, -1, NULL, 0, fmt, args);
> +	r = vprintk_emit(0, -1, NULL, 0, fmt, args, current_syslog_ns());

Current is meaningless here.  The default should be using init_syslog_ns.

>  	va_end(args);
> 
>  	return r;
> @@ -1981,12 +1977,13 @@ void wake_up_klogd(void)
>  		this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
>  }
> 
> -static void console_cont_flush(char *text, size_t size)
> +static void console_cont_flush(char *text, size_t size,
> +			 struct syslog_namespace *syslog_ns)
>  {
>  	unsigned long flags;
>  	size_t len;
> 
> -	raw_spin_lock_irqsave(&logbuf_lock, flags);
> +	raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);
> 
>  	if (!cont.len)
>  		goto out;
> @@ -1996,18 +1993,131 @@ static void console_cont_flush(char *text, size_t size)
>  	 * busy. The earlier ones need to be printed before this one, we
>  	 * did not flush any fragment so far, so just let it queue up.
>  	 */
> -	if (console_seq < log_next_seq && !cont.cons)
> +	if (syslog_ns->console_seq < syslog_ns->log_next_seq && !cont.cons)
>  		goto out;
> 
>  	len = cont_print_text(text, size);
> -	raw_spin_unlock(&logbuf_lock);
> +	raw_spin_unlock(&syslog_ns->logbuf_lock);
>  	stop_critical_timings();
>  	call_console_drivers(cont.level, text, len);
>  	start_critical_timings();
>  	local_irq_restore(flags);
>  	return;
>  out:
> -	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
> +	raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
> +}
> +
> +/**
> + * syslog_console_unlock - unlock the console system for syslog_namespace
> + *
> + * Releases the console_lock which the caller holds on the console system
> + * and the console driver list.
> + *
> + * While the console_lock was held, console output may have been buffered
> + * by printk().  If this is the case, syslog_console_unlock(); emits
> + * the output prior to releasing the lock.
> + *
> + * If there is output waiting, we wake /dev/kmsg and syslog() users.
> + *
> + * syslog_console_unlock(); may be called from any context.
> + */
> +void syslog_console_unlock(struct syslog_namespace *syslog_ns)
> +{
> +	static char text[LOG_LINE_MAX + PREFIX_MAX];
> +	static u64 seen_seq;
> +	unsigned long flags;
> +	bool wake_klogd = false;
> +	bool retry;
> +
> +	if (console_suspended) {
> +		up(&console_sem);
> +		return;
> +	}
> +
> +	console_may_schedule = 0;
> +
> +	/* flush buffered message fragment immediately to console */
> +	console_cont_flush(text, sizeof(text), syslog_ns);
> +again:
> +	for (;;) {
> +		struct log *msg;
> +		size_t len;
> +		int level;
> +
> +		raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);
> +		if (seen_seq != syslog_ns->log_next_seq) {
> +			wake_klogd = true;
> +			seen_seq = syslog_ns->log_next_seq;
> +		}
> +
> +		if (syslog_ns->console_seq < syslog_ns->log_first_seq) {
> +			/* messages are gone, move to first one */
> +			syslog_ns->console_seq = syslog_ns->log_first_seq;
> +			syslog_ns->console_idx = syslog_ns->log_first_idx;
> +			console_prev = 0;
> +		}
> +skip:
> +		if (syslog_ns->console_seq == syslog_ns->log_next_seq)
> +			break;
> +
> +		msg = log_from_idx(syslog_ns->console_idx, syslog_ns);
> +		if (msg->flags & LOG_NOCONS) {
> +			/*
> +			 * Skip record we have buffered and already printed
> +			 * directly to the console when we received it.
> +			 */
> +			syslog_ns->console_idx =
> +				log_next(syslog_ns->console_idx, syslog_ns);
> +			syslog_ns->console_seq++;
> +			/*
> +			 * We will get here again when we register a new
> +			 * CON_PRINTBUFFER console. Clear the flag so we
> +			 * will properly dump everything later.
> +			 */
> +			msg->flags &= ~LOG_NOCONS;
> +			console_prev = msg->flags;
> +			goto skip;
> +		}
> +
> +		level = msg->level;
> +		len = msg_print_text(msg, console_prev, false,
> +				     text, sizeof(text));
> +		syslog_ns->console_idx =
> +			 log_next(syslog_ns->console_idx, syslog_ns);
> +		syslog_ns->console_seq++;
> +		console_prev = msg->flags;
> +		raw_spin_unlock(&syslog_ns->logbuf_lock);
> +
> +		stop_critical_timings();	/* don't trace print latency */
> +		call_console_drivers(level, text, len);
> +		start_critical_timings();
> +		local_irq_restore(flags);
> +	}
> +	console_locked = 0;
> +
> +	/* Release the exclusive_console once it is used */
> +	if (unlikely(exclusive_console))
> +		exclusive_console = NULL;
> +
> +	raw_spin_unlock(&syslog_ns->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.
> +	 */
> +	raw_spin_lock(&syslog_ns->logbuf_lock);
> +	retry = syslog_ns->console_seq != syslog_ns->log_next_seq;
> +	raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
> +
> +	if (retry && console_trylock())
> +		goto again;
> +
> +	if (wake_klogd)
> +		wake_up_klogd();
>  }
> 
>  /**
> @@ -2027,6 +2137,7 @@ out:
>  void console_unlock(void)
>  {
>  	static char text[LOG_LINE_MAX + PREFIX_MAX];
> +	struct syslog_namespace *syslog_ns = current_syslog_ns();
>  	static u64 seen_seq;
>  	unsigned long flags;
>  	bool wake_klogd = false;
> @@ -2040,37 +2151,38 @@ void console_unlock(void)
>  	console_may_schedule = 0;
> 
>  	/* flush buffered message fragment immediately to console */
> -	console_cont_flush(text, sizeof(text));
> +	console_cont_flush(text, sizeof(text), syslog_ns);
>  again:
>  	for (;;) {
>  		struct log *msg;
>  		size_t len;
>  		int level;
> 
> -		raw_spin_lock_irqsave(&logbuf_lock, flags);
> -		if (seen_seq != log_next_seq) {
> +		raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);
> +		if (seen_seq != syslog_ns->log_next_seq) {
>  			wake_klogd = true;
> -			seen_seq = log_next_seq;
> +			seen_seq = syslog_ns->log_next_seq;
>  		}
> 
> -		if (console_seq < log_first_seq) {
> +		if (syslog_ns->console_seq < syslog_ns->log_first_seq) {
>  			/* messages are gone, move to first one */
> -			console_seq = log_first_seq;
> -			console_idx = log_first_idx;
> +			syslog_ns->console_seq = syslog_ns->log_first_seq;
> +			syslog_ns->console_idx = syslog_ns->log_first_idx;
>  			console_prev = 0;
>  		}
>  skip:
> -		if (console_seq == log_next_seq)
> +		if (syslog_ns->console_seq == syslog_ns->log_next_seq)
>  			break;
> 
> -		msg = log_from_idx(console_idx);
> +		msg = log_from_idx(syslog_ns->console_idx, syslog_ns);
>  		if (msg->flags & LOG_NOCONS) {
>  			/*
>  			 * Skip record we have buffered and already printed
>  			 * directly to the console when we received it.
>  			 */
> -			console_idx = log_next(console_idx);
> -			console_seq++;
> +			syslog_ns->console_idx =
> +				 log_next(syslog_ns->console_idx, syslog_ns);
> +			syslog_ns->console_seq++;
>  			/*
>  			 * We will get here again when we register a new
>  			 * CON_PRINTBUFFER console. Clear the flag so we
> @@ -2084,10 +2196,11 @@ skip:
>  		level = msg->level;
>  		len = msg_print_text(msg, console_prev, false,
>  				     text, sizeof(text));
> -		console_idx = log_next(console_idx);
> -		console_seq++;
> +		syslog_ns->console_idx =
> +			 log_next(syslog_ns->console_idx, syslog_ns);
> +		syslog_ns->console_seq++;
>  		console_prev = msg->flags;
> -		raw_spin_unlock(&logbuf_lock);
> +		raw_spin_unlock(&syslog_ns->logbuf_lock);
> 
>  		stop_critical_timings();	/* don't trace print latency */
>  		call_console_drivers(level, text, len);
> @@ -2100,7 +2213,7 @@ skip:
>  	if (unlikely(exclusive_console))
>  		exclusive_console = NULL;
> 
> -	raw_spin_unlock(&logbuf_lock);
> +	raw_spin_unlock(&syslog_ns->logbuf_lock);
> 
>  	up(&console_sem);
> 
> @@ -2110,9 +2223,9 @@ skip:
>  	 * there's a new owner and the console_unlock() from them will do the
>  	 * flush, no worries.
>  	 */
> -	raw_spin_lock(&logbuf_lock);
> -	retry = console_seq != log_next_seq;
> -	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
> +	raw_spin_lock(&syslog_ns->logbuf_lock);
> +	retry = syslog_ns->console_seq != syslog_ns->log_next_seq;
> +	raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
> 
>  	if (retry && console_trylock())
>  		goto again;
> @@ -2237,6 +2350,7 @@ void register_console(struct console *newcon)
>  	int i;
>  	unsigned long flags;
>  	struct console *bcon = NULL;
> +	struct syslog_namespace *syslog_ns = &init_syslog_ns;
> 
>  	/*
>  	 * before we register a new CON_BOOT console, make sure we don't
> @@ -2346,11 +2460,11 @@ void register_console(struct console *newcon)
>  		 * console_unlock(); will print out the buffered messages
>  		 * for us.
>  		 */
> -		raw_spin_lock_irqsave(&logbuf_lock, flags);
> -		console_seq = syslog_seq;
> -		console_idx = syslog_idx;
> -		console_prev = syslog_prev;
> -		raw_spin_unlock_irqrestore(&logbuf_lock, flags);
> +		raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);
> +		syslog_ns->console_seq = syslog_ns->syslog_seq;
> +		syslog_ns->console_idx = syslog_ns->syslog_idx;
> +		console_prev = syslog_ns->syslog_prev;
> +		raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
>  		/*
>  		 * We're about to replay the log buffer.  Only do this to the
>  		 * just-registered console to avoid excessive message spam to
> @@ -2573,6 +2687,7 @@ void kmsg_dump(enum kmsg_dump_reason reason)
>  {
>  	struct kmsg_dumper *dumper;
>  	unsigned long flags;
> +	struct syslog_namespace *syslog_ns = &init_syslog_ns;
> 
>  	if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump)
>  		return;
> @@ -2585,12 +2700,12 @@ void kmsg_dump(enum kmsg_dump_reason reason)
>  		/* initialize iterator with data about the stored records */
>  		dumper->active = true;
> 
> -		raw_spin_lock_irqsave(&logbuf_lock, flags);
> -		dumper->cur_seq = clear_seq;
> -		dumper->cur_idx = clear_idx;
> -		dumper->next_seq = log_next_seq;
> -		dumper->next_idx = log_next_idx;
> -		raw_spin_unlock_irqrestore(&logbuf_lock, flags);
> +		raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);
> +		dumper->cur_seq = syslog_ns->clear_seq;
> +		dumper->cur_idx = syslog_ns->clear_idx;
> +		dumper->next_seq = syslog_ns->log_next_seq;
> +		dumper->next_idx = syslog_ns->log_next_idx;
> +		raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
> 
>  		/* invoke dumper which will iterate over records */
>  		dumper->dump(dumper, reason);
> @@ -2626,24 +2741,25 @@ bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog,
>  	struct log *msg;
>  	size_t l = 0;
>  	bool ret = false;
> +	struct syslog_namespace *syslog_ns = &init_syslog_ns;
> 
>  	if (!dumper->active)
>  		goto out;
> 
> -	if (dumper->cur_seq < log_first_seq) {
> +	if (dumper->cur_seq < syslog_ns->log_first_seq) {
>  		/* messages are gone, move to first available one */
> -		dumper->cur_seq = log_first_seq;
> -		dumper->cur_idx = log_first_idx;
> +		dumper->cur_seq = syslog_ns->log_first_seq;
> +		dumper->cur_idx = syslog_ns->log_first_idx;
>  	}
> 
>  	/* last entry */
> -	if (dumper->cur_seq >= log_next_seq)
> +	if (dumper->cur_seq >= syslog_ns->log_next_seq)
>  		goto out;
> 
> -	msg = log_from_idx(dumper->cur_idx);
> +	msg = log_from_idx(dumper->cur_idx, syslog_ns);
>  	l = msg_print_text(msg, 0, syslog, line, size);
> 
> -	dumper->cur_idx = log_next(dumper->cur_idx);
> +	dumper->cur_idx = log_next(dumper->cur_idx, syslog_ns);
>  	dumper->cur_seq++;
>  	ret = true;
>  out:
> @@ -2674,10 +2790,12 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
>  {
>  	unsigned long flags;
>  	bool ret;
> +	struct syslog_namespace *syslog_ns = &init_syslog_ns;
> +
> +	raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);
> 
> -	raw_spin_lock_irqsave(&logbuf_lock, flags);
>  	ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len);
> -	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
> +	raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
> 
>  	return ret;
>  }
> @@ -2713,20 +2831,21 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
>  	enum log_flags prev;
>  	size_t l = 0;
>  	bool ret = false;
> +	struct syslog_namespace *syslog_ns = &init_syslog_ns;
> 
>  	if (!dumper->active)
>  		goto out;
> 
> -	raw_spin_lock_irqsave(&logbuf_lock, flags);
> -	if (dumper->cur_seq < log_first_seq) {
> +	raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);
> +	if (dumper->cur_seq < syslog_ns->log_first_seq) {
>  		/* messages are gone, move to first available one */
> -		dumper->cur_seq = log_first_seq;
> -		dumper->cur_idx = log_first_idx;
> +		dumper->cur_seq = syslog_ns->log_first_seq;
> +		dumper->cur_idx = syslog_ns->log_first_idx;
>  	}
> 
>  	/* last entry */
>  	if (dumper->cur_seq >= dumper->next_seq) {
> -		raw_spin_unlock_irqrestore(&logbuf_lock, flags);
> +		raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
>  		goto out;
>  	}
> 
> @@ -2735,10 +2854,10 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
>  	idx = dumper->cur_idx;
>  	prev = 0;
>  	while (seq < dumper->next_seq) {
> -		struct log *msg = log_from_idx(idx);
> +		struct log *msg = log_from_idx(idx, syslog_ns);
> 
>  		l += msg_print_text(msg, prev, true, NULL, 0);
> -		idx = log_next(idx);
> +		idx = log_next(idx, syslog_ns);
>  		seq++;
>  		prev = msg->flags;
>  	}
> @@ -2748,10 +2867,10 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
>  	idx = dumper->cur_idx;
>  	prev = 0;
>  	while (l > size && seq < dumper->next_seq) {
> -		struct log *msg = log_from_idx(idx);
> +		struct log *msg = log_from_idx(idx, syslog_ns);
> 
>  		l -= msg_print_text(msg, prev, true, NULL, 0);
> -		idx = log_next(idx);
> +		idx = log_next(idx, syslog_ns);
>  		seq++;
>  		prev = msg->flags;
>  	}
> @@ -2763,10 +2882,10 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
>  	l = 0;
>  	prev = 0;
>  	while (seq < dumper->next_seq) {
> -		struct log *msg = log_from_idx(idx);
> +		struct log *msg = log_from_idx(idx, syslog_ns);
> 
>  		l += msg_print_text(msg, prev, syslog, buf + l, size - l);
> -		idx = log_next(idx);
> +		idx = log_next(idx, syslog_ns);
>  		seq++;
>  		prev = msg->flags;
>  	}
> @@ -2774,7 +2893,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
>  	dumper->next_seq = next_seq;
>  	dumper->next_idx = next_idx;
>  	ret = true;
> -	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
> +	raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
>  out:
>  	if (len)
>  		*len = l;
> @@ -2794,10 +2913,12 @@ EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);
>   */
>  void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper)
>  {
> -	dumper->cur_seq = clear_seq;
> -	dumper->cur_idx = clear_idx;
> -	dumper->next_seq = log_next_seq;
> -	dumper->next_idx = log_next_idx;
> +	struct syslog_namespace *syslog_ns = &init_syslog_ns;
> +
> +	dumper->cur_seq = syslog_ns->clear_seq;
> +	dumper->cur_idx = syslog_ns->clear_idx;
> +	dumper->next_seq = syslog_ns->log_next_seq;
> +	dumper->next_idx = syslog_ns->log_next_idx;
>  }
> 
>  /**
> @@ -2811,10 +2932,12 @@ void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper)
>  void kmsg_dump_rewind(struct kmsg_dumper *dumper)
>  {
>  	unsigned long flags;
> +	struct syslog_namespace *syslog_ns = &init_syslog_ns;
> +
> +	raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);
> 
> -	raw_spin_lock_irqsave(&logbuf_lock, flags);
>  	kmsg_dump_rewind_nolock(dumper);
> -	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
> +	raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
>  }
>  EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
>  #endif
> -- 
> 1.7.1
> 
> _______________________________________________
> Containers mailing list
> Containers@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/containers
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Joe Perches - Nov. 19, 2012, 2:53 p.m.
On Mon, 2012-11-19 at 14:29 +0000, Serge E. Hallyn wrote:
> > diff --git a/drivers/base/core.c b/drivers/base/core.c

48kb of quoted text...

> > @@ -1678,7 +1674,7 @@ asmlinkage int printk(const char *fmt, ...)
> >  	}
> >  #endif
> >  	va_start(args, fmt);
> > -	r = vprintk_emit(0, -1, NULL, 0, fmt, args);
> > +	r = vprintk_emit(0, -1, NULL, 0, fmt, args, current_syslog_ns());
> 
> Current is meaningless here.  The default should be using init_syslog_ns.

For a single sentence.  Please remember to trim your replies.

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rui Xiang - Nov. 21, 2012, 9:41 a.m.
From: Libo Chen <clbchenlibo.chen@huawei.com>

On 2012-11-19 22:29, Serge E. Hallyn wrote:> Quoting Rui Xiang (leo.ruixiang@gmail.com):
>> From: Libo Chen <clbchenlibo.chen@huawei.com>
>>
>> We re-implement printk by additional syslog_ns.
>>
>> The function include printk, /dev/kmsg, do_syslog and kmsg_dump should be modifyed
>> for syslog_ns. Previous identifier *** such as log_first_seq should be replaced
>> by syslog_ns->***.
>>
>> Signed-off-by: Libo Chen <clbchenlibo.chen@huawei.com>
>> Signed-off-by: Xiang Rui <rui.xiang@huawei.com>
>> ---

.......

>>  	lockdep_on();
>> @@ -1624,7 +1618,8 @@ EXPORT_SYMBOL(vprintk_emit);
>>
>>  asmlinkage int vprintk(const char *fmt, va_list args)
>>  {
>> -	return vprintk_emit(0, -1, NULL, 0, fmt, args);
>> +	return vprintk_emit(0, -1, NULL, 0, fmt, args,
>> +				current_syslog_ns());
>>  }
>>  EXPORT_SYMBOL(vprintk);
>>
>> @@ -1636,7 +1631,8 @@ asmlinkage int printk_emit(int facility, int level,
>>  	int r;
>>
>>  	va_start(args, fmt);
>> -	r = vprintk_emit(facility, level, dict, dictlen, fmt, args);
>> +	r = vprintk_emit(facility, level, dict, dictlen, fmt, args,
>> +						current_syslog_ns());
>>  	va_end(args);
>>
>>  	return r;
>> @@ -1678,7 +1674,7 @@ asmlinkage int printk(const char *fmt, ...)
>>  	}
>>  #endif
>>  	va_start(args, fmt);
>> -	r = vprintk_emit(0, -1, NULL, 0, fmt, args);
>> +	r = vprintk_emit(0, -1, NULL, 0, fmt, args, current_syslog_ns());
>
> Current is meaningless here.  The default should be using init_syslog_ns.

Thank for your attention.

I understand what you mean.
printk -> init_syslog_log
nsprintk(ns) -> container syslog

I think it makes sense.

thanks
Libo Chen
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Serge E. Hallyn - Nov. 21, 2012, 5:49 p.m.
I notice that you haven't made any changes to the struct cont.  I
suspect this means that to-be-continued msgs from one ns can be
erroneously mixed with another ns.

You said you don't mind putting the syslogns into the userns.  If
there's no reason not to do that, then we should do so as it will
remove a bunch of code (plus the use of a new CLONE flag) from your
patch, and the new syslog(NEW_NS) command from mine.

Now IMO the ideal place for syslog_ns would be in the devices ns,
but that does not yet exist, and may never.  The bonus to that would
be that the consoles sort of belong there.  I avoid this by not
having consoles in child syslog namespaces.  You put the console in
the ns.  I haven't looked closely enough to see if what you do is
ok (will do so soon).

WOuld you mind looking through my patch to see if it suffices for
your needs?  Where it does not, patches would be greatly appreciated
if simple enough.

Note I'm not at all wedded to my patchset.  I'm happy to go with
something else entirely.  My set was just a proof of concept.

thanks,
-serge
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/drivers/base/core.c b/drivers/base/core.c
index abea76c..665c2f7 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -26,6 +26,7 @@ 
 #include <linux/async.h>
 #include <linux/pm_runtime.h>
 #include <linux/netdevice.h>
+#include <linux/syslog_namespace.h>

 #include "base.h"
 #include "power/power.h"
@@ -1922,7 +1923,8 @@  int dev_vprintk_emit(int level, const struct device *dev,

 	hdrlen = create_syslog_header(dev, hdr, sizeof(hdr));

-	return vprintk_emit(0, level, hdrlen ? hdr : NULL, hdrlen, fmt, args);
+	return vprintk_emit(0, level, hdrlen ? hdr : NULL, hdrlen,
+				fmt, args, current_syslog_ns());
 }
 EXPORT_SYMBOL(dev_vprintk_emit);

diff --git a/include/linux/printk.h b/include/linux/printk.h
index 9afc01e..e0c60d9 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -7,6 +7,7 @@ 
 extern const char linux_banner[];
 extern const char linux_proc_banner[];

+struct syslog_namespace;
 static inline int printk_get_level(const char *buffer)
 {
 	if (buffer[0] == KERN_SOH_ASCII && buffer[1]) {
@@ -105,7 +106,8 @@  extern void printk_tick(void);
 asmlinkage __printf(5, 0)
 int vprintk_emit(int facility, int level,
 		 const char *dict, size_t dictlen,
-		 const char *fmt, va_list args);
+		 const char *fmt, va_list args,
+		 struct syslog_namespace *syslog_ns);

 asmlinkage __printf(1, 0)
 int vprintk(const char *fmt, va_list args);
diff --git a/kernel/printk.c b/kernel/printk.c
index 2d607f4..2ef9c46 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -42,6 +42,7 @@ 
 #include <linux/notifier.h>
 #include <linux/rculist.h>
 #include <linux/poll.h>
+#include <linux/syslog_namespace.h>

 #include <asm/uaccess.h>

@@ -214,46 +215,14 @@  struct log {
  * The logbuf_lock protects kmsg buffer, indices, counters. It is also
  * used in interesting ways to provide interlocking in console_unlock();
  */
-static DEFINE_RAW_SPINLOCK(logbuf_lock);

 #ifdef CONFIG_PRINTK
-/* the next printk record to read by syslog(READ) or /proc/kmsg */
-static u64 syslog_seq;
-static u32 syslog_idx;
-static enum log_flags syslog_prev;
-static size_t syslog_partial;
-
-/* index and sequence number of the first record stored in the buffer */
-static u64 log_first_seq;
-static u32 log_first_idx;
-
-/* index and sequence number of the next record to store in the buffer */
-static u64 log_next_seq;
-static u32 log_next_idx;

-/* the next printk record to write to the console */
-static u64 console_seq;
-static u32 console_idx;
 static enum log_flags console_prev;

-/* the next printk record to read after the last 'clear' command */
-static u64 clear_seq;
-static u32 clear_idx;
-
 #define PREFIX_MAX		32
 #define LOG_LINE_MAX		1024 - PREFIX_MAX

-/* record buffer */
-#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
-#define LOG_ALIGN 4
-#else
-#define LOG_ALIGN __alignof__(struct log)
-#endif
-#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
-static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
-static char *log_buf = __log_buf;
-static u32 log_buf_len = __LOG_BUF_LEN;
-
 /* cpu currently holding logbuf_lock */
 static volatile unsigned int logbuf_cpu = UINT_MAX;

@@ -270,23 +239,23 @@  static char *log_dict(const struct log *msg)
 }

 /* get record by index; idx must point to valid msg */
-static struct log *log_from_idx(u32 idx)
+static struct log *log_from_idx(u32 idx, struct syslog_namespace *syslog_ns)
 {
-	struct log *msg = (struct log *)(log_buf + idx);
+	struct log *msg = (struct log *)(syslog_ns->log_buf + idx);

 	/*
 	 * A length == 0 record is the end of buffer marker. Wrap around and
 	 * read the message at the start of the buffer.
 	 */
 	if (!msg->len)
-		return (struct log *)log_buf;
+		return (struct log *)syslog_ns->log_buf;
 	return msg;
 }

 /* get next record; idx must point to valid msg */
-static u32 log_next(u32 idx)
+static u32 log_next(u32 idx, struct syslog_namespace *syslog_ns)
 {
-	struct log *msg = (struct log *)(log_buf + idx);
+	struct log *msg = (struct log *)(syslog_ns->log_buf + idx);

 	/* length == 0 indicates the end of the buffer; wrap */
 	/*
@@ -295,7 +264,7 @@  static u32 log_next(u32 idx)
 	 * return the one after that.
 	 */
 	if (!msg->len) {
-		msg = (struct log *)log_buf;
+		msg = (struct log *)syslog_ns->log_buf;
 		return msg->len;
 	}
 	return idx + msg->len;
@@ -305,7 +274,8 @@  static u32 log_next(u32 idx)
 static void log_store(int facility, int level,
 		      enum log_flags flags, u64 ts_nsec,
 		      const char *dict, u16 dict_len,
-		      const char *text, u16 text_len)
+		      const char *text, u16 text_len,
+		      struct syslog_namespace *syslog_ns)
 {
 	struct log *msg;
 	u32 size, pad_len;
@@ -315,34 +285,40 @@  static void log_store(int facility, int level,
 	pad_len = (-size) & (LOG_ALIGN - 1);
 	size += pad_len;

-	while (log_first_seq < log_next_seq) {
+	while (syslog_ns->log_first_seq < syslog_ns->log_next_seq) {
 		u32 free;

-		if (log_next_idx > log_first_idx)
-			free = max(log_buf_len - log_next_idx, log_first_idx);
+		if (syslog_ns->log_next_idx > syslog_ns->log_first_idx)
+			free = max(syslog_ns->log_buf_len -
+				 syslog_ns->log_next_idx,
+				 syslog_ns->log_first_idx);
 		else
-			free = log_first_idx - log_next_idx;
+			free = syslog_ns->log_first_idx -
+					 syslog_ns->log_next_idx;

 		if (free > size + sizeof(struct log))
 			break;

 		/* drop old messages until we have enough contiuous space */
-		log_first_idx = log_next(log_first_idx);
-		log_first_seq++;
+		syslog_ns->log_first_idx =
+				log_next(syslog_ns->log_first_idx, syslog_ns);
+		syslog_ns->log_first_seq++;
 	}

-	if (log_next_idx + size + sizeof(struct log) >= log_buf_len) {
+	if (syslog_ns->log_next_idx + size + sizeof(struct log) >=
+						 syslog_ns->log_buf_len) {
 		/*
 		 * This message + an additional empty header does not fit
 		 * at the end of the buffer. Add an empty header with len == 0
 		 * to signify a wrap around.
 		 */
-		memset(log_buf + log_next_idx, 0, sizeof(struct log));
-		log_next_idx = 0;
+		memset(syslog_ns->log_buf + syslog_ns->log_next_idx,
+						 0, sizeof(struct log));
+		syslog_ns->log_next_idx = 0;
 	}

 	/* fill message */
-	msg = (struct log *)(log_buf + log_next_idx);
+	msg = (struct log *)(syslog_ns->log_buf + syslog_ns->log_next_idx);
 	memcpy(log_text(msg), text, text_len);
 	msg->text_len = text_len;
 	memcpy(log_dict(msg), dict, dict_len);
@@ -358,8 +334,8 @@  static void log_store(int facility, int level,
 	msg->len = sizeof(struct log) + text_len + dict_len + pad_len;

 	/* insert message */
-	log_next_idx += msg->len;
-	log_next_seq++;
+	syslog_ns->log_next_idx += msg->len;
+	syslog_ns->log_next_seq++;
 }

 /* /dev/kmsg - userspace message inject/listen interface */
@@ -368,6 +344,7 @@  struct devkmsg_user {
 	u32 idx;
 	enum log_flags prev;
 	struct mutex lock;
+	struct syslog_namespace *syslog_ns;
 	char buf[8192];
 };

@@ -431,6 +408,7 @@  static ssize_t devkmsg_read(struct file *file, char __user *buf,
 			    size_t count, loff_t *ppos)
 {
 	struct devkmsg_user *user = file->private_data;
+	struct syslog_namespace *syslog_ns = user->syslog_ns;
 	struct log *msg;
 	u64 ts_usec;
 	size_t i;
@@ -444,32 +422,32 @@  static ssize_t devkmsg_read(struct file *file, char __user *buf,
 	ret = mutex_lock_interruptible(&user->lock);
 	if (ret)
 		return ret;
-	raw_spin_lock_irq(&logbuf_lock);
-	while (user->seq == log_next_seq) {
+	raw_spin_lock_irq(&syslog_ns->logbuf_lock);
+	while (user->seq == syslog_ns->log_next_seq) {
 		if (file->f_flags & O_NONBLOCK) {
 			ret = -EAGAIN;
-			raw_spin_unlock_irq(&logbuf_lock);
+			raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
 			goto out;
 		}

-		raw_spin_unlock_irq(&logbuf_lock);
+		raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
 		ret = wait_event_interruptible(log_wait,
-					       user->seq != log_next_seq);
+				user->seq != syslog_ns->log_next_seq);
 		if (ret)
 			goto out;
-		raw_spin_lock_irq(&logbuf_lock);
+		raw_spin_lock_irq(&syslog_ns->logbuf_lock);
 	}

-	if (user->seq < log_first_seq) {
+	if (user->seq < syslog_ns->log_first_seq) {
 		/* our last seen message is gone, return error and reset */
-		user->idx = log_first_idx;
-		user->seq = log_first_seq;
+		user->idx = syslog_ns->log_first_idx;
+		user->seq = syslog_ns->log_first_seq;
 		ret = -EPIPE;
-		raw_spin_unlock_irq(&logbuf_lock);
+		raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
 		goto out;
 	}

-	msg = log_from_idx(user->idx);
+	msg = log_from_idx(user->idx, syslog_ns);
 	ts_usec = msg->ts_nsec;
 	do_div(ts_usec, 1000);

@@ -530,9 +508,9 @@  static ssize_t devkmsg_read(struct file *file, char __user *buf,
 		user->buf[len++] = '\n';
 	}

-	user->idx = log_next(user->idx);
+	user->idx = log_next(user->idx, syslog_ns);
 	user->seq++;
-	raw_spin_unlock_irq(&logbuf_lock);
+	raw_spin_unlock_irq(&syslog_ns->logbuf_lock);

 	if (len > count) {
 		ret = -EINVAL;
@@ -552,6 +530,7 @@  out:
 static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
 {
 	struct devkmsg_user *user = file->private_data;
+	struct syslog_namespace *syslog_ns = user->syslog_ns;
 	loff_t ret = 0;

 	if (!user)
@@ -559,12 +538,12 @@  static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
 	if (offset)
 		return -ESPIPE;

-	raw_spin_lock_irq(&logbuf_lock);
+	raw_spin_lock_irq(&syslog_ns->logbuf_lock);
 	switch (whence) {
 	case SEEK_SET:
 		/* the first record */
-		user->idx = log_first_idx;
-		user->seq = log_first_seq;
+		user->idx = syslog_ns->log_first_idx;
+		user->seq = syslog_ns->log_first_seq;
 		break;
 	case SEEK_DATA:
 		/*
@@ -572,24 +551,25 @@  static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
 		 * like issued by 'dmesg -c'. Reading /dev/kmsg itself
 		 * changes no global state, and does not clear anything.
 		 */
-		user->idx = clear_idx;
-		user->seq = clear_seq;
+		user->idx = syslog_ns->clear_idx;
+		user->seq = syslog_ns->clear_seq;
 		break;
 	case SEEK_END:
 		/* after the last record */
-		user->idx = log_next_idx;
-		user->seq = log_next_seq;
+		user->idx = syslog_ns->log_next_idx;
+		user->seq = syslog_ns->log_next_seq;
 		break;
 	default:
 		ret = -EINVAL;
 	}
-	raw_spin_unlock_irq(&logbuf_lock);
+	raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
 	return ret;
 }

 static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
 {
 	struct devkmsg_user *user = file->private_data;
+	struct syslog_namespace *syslog_ns = user->syslog_ns;
 	int ret = 0;

 	if (!user)
@@ -597,20 +577,21 @@  static unsigned int devkmsg_poll(struct file *file, poll_table *wait)

 	poll_wait(file, &log_wait, wait);

-	raw_spin_lock_irq(&logbuf_lock);
-	if (user->seq < log_next_seq) {
+	raw_spin_lock_irq(&syslog_ns->logbuf_lock);
+	if (user->seq < syslog_ns->log_next_seq) {
 		/* return error when data has vanished underneath us */
-		if (user->seq < log_first_seq)
+		if (user->seq < syslog_ns->log_first_seq)
 			ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI;
 		ret = POLLIN|POLLRDNORM;
 	}
-	raw_spin_unlock_irq(&logbuf_lock);
+	raw_spin_unlock_irq(&syslog_ns->logbuf_lock);

 	return ret;
 }

 static int devkmsg_open(struct inode *inode, struct file *file)
 {
+	struct syslog_namespace *syslog_ns;
 	struct devkmsg_user *user;
 	int err;

@@ -628,10 +609,11 @@  static int devkmsg_open(struct inode *inode, struct file *file)

 	mutex_init(&user->lock);

-	raw_spin_lock_irq(&logbuf_lock);
-	user->idx = log_first_idx;
-	user->seq = log_first_seq;
-	raw_spin_unlock_irq(&logbuf_lock);
+	user->syslog_ns = current_syslog_ns();
+	raw_spin_lock_irq(&syslog_ns->logbuf_lock);
+	user->idx = syslog_ns->log_first_idx;
+	user->seq = syslog_ns->log_first_seq;
+	raw_spin_unlock_irq(&syslog_ns->logbuf_lock);

 	file->private_data = user;
 	return 0;
@@ -669,10 +651,12 @@  const struct file_operations kmsg_fops = {
  */
 void log_buf_kexec_setup(void)
 {
-	VMCOREINFO_SYMBOL(log_buf);
-	VMCOREINFO_SYMBOL(log_buf_len);
-	VMCOREINFO_SYMBOL(log_first_idx);
-	VMCOREINFO_SYMBOL(log_next_idx);
+	struct syslog_namespace *syslog_ns = current_syslog_ns();
+
+	VMCOREINFO_SYMBOL(syslog_ns->log_buf);
+	VMCOREINFO_SYMBOL(syslog_ns->log_buf_len);
+	VMCOREINFO_SYMBOL(syslog_ns->log_first_idx);
+	VMCOREINFO_SYMBOL(syslog_ns->log_next_idx);
 	/*
 	 * Export struct log size and field offsets. User space tools can
 	 * parse it and detect any changes to structure down the line.
@@ -692,10 +676,11 @@  static unsigned long __initdata new_log_buf_len;
 static int __init log_buf_len_setup(char *str)
 {
 	unsigned size = memparse(str, &str);
+	struct syslog_namespace *syslog_ns = &init_syslog_ns;

 	if (size)
 		size = roundup_pow_of_two(size);
-	if (size > log_buf_len)
+	if (size > syslog_ns->log_buf_len)
 		new_log_buf_len = size;

 	return 0;
@@ -707,6 +692,7 @@  void __init setup_log_buf(int early)
 	unsigned long flags;
 	char *new_log_buf;
 	int free;
+	struct syslog_namespace *syslog_ns = &init_syslog_ns;

 	if (!new_log_buf_len)
 		return;
@@ -728,15 +714,15 @@  void __init setup_log_buf(int early)
 		return;
 	}

-	raw_spin_lock_irqsave(&logbuf_lock, flags);
-	log_buf_len = new_log_buf_len;
-	log_buf = new_log_buf;
+	raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);
+	memcpy(new_log_buf, syslog_ns->log_buf, __LOG_BUF_LEN);
+	syslog_ns->log_buf_len = new_log_buf_len;
+	syslog_ns->log_buf = new_log_buf;
 	new_log_buf_len = 0;
-	free = __LOG_BUF_LEN - log_next_idx;
-	memcpy(log_buf, __log_buf, __LOG_BUF_LEN);
-	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+	free = __LOG_BUF_LEN - syslog_ns->log_next_idx;
+	raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);

-	pr_info("log_buf_len: %d\n", log_buf_len);
+	pr_info("log_buf_len: %d\n", syslog_ns->log_buf_len);
 	pr_info("early log buf free: %d(%d%%)\n",
 		free, (free * 100) / __LOG_BUF_LEN);
 }
@@ -937,7 +923,8 @@  static size_t msg_print_text(const struct log *msg, enum log_flags prev,
 	return len;
 }

-static int syslog_print(char __user *buf, int size)
+static int syslog_print(char __user *buf, int size,
+			 struct syslog_namespace *syslog_ns)
 {
 	char *text;
 	struct log *msg;
@@ -951,37 +938,38 @@  static int syslog_print(char __user *buf, int size)
 		size_t n;
 		size_t skip;

-		raw_spin_lock_irq(&logbuf_lock);
-		if (syslog_seq < log_first_seq) {
+		raw_spin_lock_irq(&syslog_ns->logbuf_lock);
+		if (syslog_ns->syslog_seq < syslog_ns->log_first_seq) {
 			/* messages are gone, move to first one */
-			syslog_seq = log_first_seq;
-			syslog_idx = log_first_idx;
-			syslog_prev = 0;
-			syslog_partial = 0;
+			syslog_ns->syslog_seq = syslog_ns->log_first_seq;
+			syslog_ns->syslog_idx = syslog_ns->log_first_idx;
+			syslog_ns->syslog_prev = 0;
+			syslog_ns->syslog_partial = 0;
 		}
-		if (syslog_seq == log_next_seq) {
-			raw_spin_unlock_irq(&logbuf_lock);
+		if (syslog_ns->syslog_seq == syslog_ns->log_next_seq) {
+			raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
 			break;
 		}

-		skip = syslog_partial;
-		msg = log_from_idx(syslog_idx);
-		n = msg_print_text(msg, syslog_prev, true, text,
+		skip = syslog_ns->syslog_partial;
+		msg = log_from_idx(syslog_ns->syslog_idx, syslog_ns);
+		n = msg_print_text(msg, syslog_ns->syslog_prev, true, text,
 				   LOG_LINE_MAX + PREFIX_MAX);
-		if (n - syslog_partial <= size) {
+		if (n - syslog_ns->syslog_partial <= size) {
 			/* message fits into buffer, move forward */
-			syslog_idx = log_next(syslog_idx);
-			syslog_seq++;
-			syslog_prev = msg->flags;
-			n -= syslog_partial;
-			syslog_partial = 0;
+			syslog_ns->syslog_idx =
+				log_next(syslog_ns->syslog_idx, syslog_ns);
+			syslog_ns->syslog_seq++;
+			syslog_ns->syslog_prev = msg->flags;
+			n -= syslog_ns->syslog_partial;
+			syslog_ns->syslog_partial = 0;
 		} else if (!len){
 			/* partial read(), remember position */
 			n = size;
-			syslog_partial += n;
+			syslog_ns->syslog_partial += n;
 		} else
 			n = 0;
-		raw_spin_unlock_irq(&logbuf_lock);
+		raw_spin_unlock_irq(&syslog_ns->logbuf_lock);

 		if (!n)
 			break;
@@ -1001,7 +989,8 @@  static int syslog_print(char __user *buf, int size)
 	return len;
 }

-static int syslog_print_all(char __user *buf, int size, bool clear)
+static int syslog_print_all(char __user *buf, int size, bool clear,
+				struct syslog_namespace *syslog_ns)
 {
 	char *text;
 	int len = 0;
@@ -1010,55 +999,55 @@  static int syslog_print_all(char __user *buf, int size, bool clear)
 	if (!text)
 		return -ENOMEM;

-	raw_spin_lock_irq(&logbuf_lock);
+	raw_spin_lock_irq(&syslog_ns->logbuf_lock);
 	if (buf) {
 		u64 next_seq;
 		u64 seq;
 		u32 idx;
 		enum log_flags prev;

-		if (clear_seq < log_first_seq) {
+		if (syslog_ns->clear_seq < syslog_ns->log_first_seq) {
 			/* messages are gone, move to first available one */
-			clear_seq = log_first_seq;
-			clear_idx = log_first_idx;
+			syslog_ns->clear_seq = syslog_ns->log_first_seq;
+			syslog_ns->clear_idx = syslog_ns->log_first_idx;
 		}

 		/*
 		 * Find first record that fits, including all following records,
 		 * into the user-provided buffer for this dump.
 		 */
-		seq = clear_seq;
-		idx = clear_idx;
+		seq = syslog_ns->clear_seq;
+		idx = syslog_ns->clear_idx;
 		prev = 0;
-		while (seq < log_next_seq) {
-			struct log *msg = log_from_idx(idx);
+		while (seq < syslog_ns->log_next_seq) {
+			struct log *msg = log_from_idx(idx, syslog_ns);

 			len += msg_print_text(msg, prev, true, NULL, 0);
 			prev = msg->flags;
-			idx = log_next(idx);
+			idx = log_next(idx, syslog_ns);
 			seq++;
 		}

 		/* move first record forward until length fits into the buffer */
-		seq = clear_seq;
-		idx = clear_idx;
+		seq = syslog_ns->clear_seq;
+		idx = syslog_ns->clear_idx;
 		prev = 0;
-		while (len > size && seq < log_next_seq) {
-			struct log *msg = log_from_idx(idx);
+		while (len > size && seq < syslog_ns->log_next_seq) {
+			struct log *msg = log_from_idx(idx, syslog_ns);

 			len -= msg_print_text(msg, prev, true, NULL, 0);
 			prev = msg->flags;
-			idx = log_next(idx);
+			idx = log_next(idx, syslog_ns);
 			seq++;
 		}

 		/* last message fitting into this dump */
-		next_seq = log_next_seq;
+		next_seq = syslog_ns->log_next_seq;

 		len = 0;
 		prev = 0;
 		while (len >= 0 && seq < next_seq) {
-			struct log *msg = log_from_idx(idx);
+			struct log *msg = log_from_idx(idx, syslog_ns);
 			int textlen;

 			textlen = msg_print_text(msg, prev, true, text,
@@ -1067,31 +1056,31 @@  static int syslog_print_all(char __user *buf, int size, bool clear)
 				len = textlen;
 				break;
 			}
-			idx = log_next(idx);
+			idx = log_next(idx, syslog_ns);
 			seq++;
 			prev = msg->flags;

-			raw_spin_unlock_irq(&logbuf_lock);
+			raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
 			if (copy_to_user(buf + len, text, textlen))
 				len = -EFAULT;
 			else
 				len += textlen;
-			raw_spin_lock_irq(&logbuf_lock);
+			raw_spin_lock_irq(&syslog_ns->logbuf_lock);

-			if (seq < log_first_seq) {
+			if (seq < syslog_ns->log_first_seq) {
 				/* messages are gone, move to next one */
-				seq = log_first_seq;
-				idx = log_first_idx;
+				seq = syslog_ns->log_first_seq;
+				idx = syslog_ns->log_first_idx;
 				prev = 0;
 			}
 		}
 	}

 	if (clear) {
-		clear_seq = log_next_seq;
-		clear_idx = log_next_idx;
+		syslog_ns->clear_seq = syslog_ns->log_next_seq;
+		syslog_ns->clear_idx = syslog_ns->log_next_idx;
 	}
-	raw_spin_unlock_irq(&logbuf_lock);
+	raw_spin_unlock_irq(&syslog_ns->logbuf_lock);

 	kfree(text);
 	return len;
@@ -1102,6 +1091,7 @@  int do_syslog(int type, char __user *buf, int len, bool from_file)
 	bool clear = false;
 	static int saved_console_loglevel = -1;
 	int error;
+	struct syslog_namespace *syslog_ns = current_syslog_ns();

 	error = check_syslog_permissions(type, from_file);
 	if (error)
@@ -1128,10 +1118,10 @@  int do_syslog(int type, char __user *buf, int len, bool from_file)
 			goto out;
 		}
 		error = wait_event_interruptible(log_wait,
-						 syslog_seq != log_next_seq);
+			syslog_ns->syslog_seq != syslog_ns->log_next_seq);
 		if (error)
 			goto out;
-		error = syslog_print(buf, len);
+		error = syslog_print(buf, len, syslog_ns);
 		break;
 	/* Read/clear last kernel messages */
 	case SYSLOG_ACTION_READ_CLEAR:
@@ -1149,11 +1139,11 @@  int do_syslog(int type, char __user *buf, int len, bool from_file)
 			error = -EFAULT;
 			goto out;
 		}
-		error = syslog_print_all(buf, len, clear);
+		error = syslog_print_all(buf, len, clear, syslog_ns);
 		break;
 	/* Clear ring buffer */
 	case SYSLOG_ACTION_CLEAR:
-		syslog_print_all(NULL, 0, true);
+		syslog_print_all(NULL, 0, true, syslog_ns);
 		break;
 	/* Disable logging to console */
 	case SYSLOG_ACTION_CONSOLE_OFF:
@@ -1182,13 +1172,13 @@  int do_syslog(int type, char __user *buf, int len, bool from_file)
 		break;
 	/* Number of chars in the log buffer */
 	case SYSLOG_ACTION_SIZE_UNREAD:
-		raw_spin_lock_irq(&logbuf_lock);
-		if (syslog_seq < log_first_seq) {
+		raw_spin_lock_irq(&syslog_ns->logbuf_lock);
+		if (syslog_ns->syslog_seq < syslog_ns->log_first_seq) {
 			/* messages are gone, move to first one */
-			syslog_seq = log_first_seq;
-			syslog_idx = log_first_idx;
-			syslog_prev = 0;
-			syslog_partial = 0;
+			syslog_ns->syslog_seq = syslog_ns->log_first_seq;
+			syslog_ns->syslog_idx = syslog_ns->log_first_idx;
+			syslog_ns->syslog_prev = 0;
+			syslog_ns->syslog_partial = 0;
 		}
 		if (from_file) {
 			/*
@@ -1196,28 +1186,28 @@  int do_syslog(int type, char __user *buf, int len, bool from_file)
 			 * for pending data, not the size; return the count of
 			 * records, not the length.
 			 */
-			error = log_next_idx - syslog_idx;
+			error = syslog_ns->log_next_idx - syslog_ns->syslog_idx;
 		} else {
-			u64 seq = syslog_seq;
-			u32 idx = syslog_idx;
-			enum log_flags prev = syslog_prev;
+			u64 seq = syslog_ns->syslog_seq;
+			u32 idx = syslog_ns->syslog_idx;
+			enum log_flags prev = syslog_ns->syslog_prev;

 			error = 0;
-			while (seq < log_next_seq) {
-				struct log *msg = log_from_idx(idx);
+			while (seq < syslog_ns->log_next_seq) {
+				struct log *msg = log_from_idx(idx, syslog_ns);

 				error += msg_print_text(msg, prev, true, NULL, 0);
-				idx = log_next(idx);
+				idx = log_next(idx, syslog_ns);
 				seq++;
 				prev = msg->flags;
 			}
-			error -= syslog_partial;
+			error -= syslog_ns->syslog_partial;
 		}
-		raw_spin_unlock_irq(&logbuf_lock);
+		raw_spin_unlock_irq(&syslog_ns->logbuf_lock);
 		break;
 	/* Size of the log buffer */
 	case SYSLOG_ACTION_SIZE_BUFFER:
-		error = log_buf_len;
+		error = syslog_ns->log_buf_len;
 		break;
 	default:
 		error = -EINVAL;
@@ -1282,7 +1272,7 @@  static void call_console_drivers(int level, const char *text, size_t len)
  * 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_namespace *syslog_ns)
 {
 	static unsigned long oops_timestamp;

@@ -1294,7 +1284,7 @@  static void zap_locks(void)

 	debug_locks_off();
 	/* If a crash is occurring, make sure we can't deadlock */
-	raw_spin_lock_init(&logbuf_lock);
+	raw_spin_lock_init(&syslog_ns->logbuf_lock);
 	/* And make sure that we print immediately */
 	sema_init(&console_sem, 1);
 }
@@ -1334,8 +1324,9 @@  static inline int can_use_console(unsigned int cpu)
  * interrupts disabled. It should return with 'lockbuf_lock'
  * released but interrupts still disabled.
  */
-static int console_trylock_for_printk(unsigned int cpu)
-	__releases(&logbuf_lock)
+static int console_trylock_for_printk(unsigned int cpu,
+			 struct syslog_namespace *syslog_ns)
+	__releases(&syslog_ns->logbuf_lock)
 {
 	int retval = 0, wake = 0;

@@ -1357,7 +1348,7 @@  static int console_trylock_for_printk(unsigned int cpu)
 	logbuf_cpu = UINT_MAX;
 	if (wake)
 		up(&console_sem);
-	raw_spin_unlock(&logbuf_lock);
+	raw_spin_unlock(&syslog_ns->logbuf_lock);
 	return retval;
 }

@@ -1393,7 +1384,7 @@  static struct cont {
 	bool flushed:1;			/* buffer sealed and committed */
 } cont;

-static void cont_flush(enum log_flags flags)
+static void cont_flush(enum log_flags flags, struct syslog_namespace *syslog_ns)
 {
 	if (cont.flushed)
 		return;
@@ -1407,7 +1398,7 @@  static void cont_flush(enum log_flags flags)
 		 * line. LOG_NOCONS suppresses a duplicated output.
 		 */
 		log_store(cont.facility, cont.level, flags | LOG_NOCONS,
-			  cont.ts_nsec, NULL, 0, cont.buf, cont.len);
+			  cont.ts_nsec, NULL, 0, cont.buf, cont.len, syslog_ns);
 		cont.flags = flags;
 		cont.flushed = true;
 	} else {
@@ -1416,19 +1407,20 @@  static void cont_flush(enum log_flags flags)
 		 * just submit it to the store and free the buffer.
 		 */
 		log_store(cont.facility, cont.level, flags, 0,
-			  NULL, 0, cont.buf, cont.len);
+			  NULL, 0, cont.buf, cont.len, syslog_ns);
 		cont.len = 0;
 	}
 }

-static bool cont_add(int facility, int level, const char *text, size_t len)
+static bool cont_add(int facility, int level, const char *text, size_t len,
+					struct syslog_namespace *syslog_ns)
 {
 	if (cont.len && cont.flushed)
 		return false;

 	if (cont.len + len > sizeof(cont.buf)) {
 		/* the line gets too long, split it up in separate records */
-		cont_flush(LOG_CONT);
+		cont_flush(LOG_CONT, syslog_ns);
 		return false;
 	}

@@ -1446,7 +1438,7 @@  static bool cont_add(int facility, int level, const char *text, size_t len)
 	cont.len += len;

 	if (cont.len > (sizeof(cont.buf) * 80) / 100)
-		cont_flush(LOG_CONT);
+		cont_flush(LOG_CONT, syslog_ns);

 	return true;
 }
@@ -1481,7 +1473,8 @@  static size_t cont_print_text(char *text, size_t size)

 asmlinkage int vprintk_emit(int facility, int level,
 			    const char *dict, size_t dictlen,
-			    const char *fmt, va_list args)
+			    const char *fmt, va_list args,
+			    struct syslog_namespace *syslog_ns)
 {
 	static int recursion_bug;
 	static char textbuf[LOG_LINE_MAX];
@@ -1514,11 +1507,11 @@  asmlinkage int vprintk_emit(int facility, int level,
 			recursion_bug = 1;
 			goto out_restore_irqs;
 		}
-		zap_locks();
+		zap_locks(syslog_ns);
 	}

 	lockdep_off();
-	raw_spin_lock(&logbuf_lock);
+	raw_spin_lock(&syslog_ns->logbuf_lock);
 	logbuf_cpu = this_cpu;

 	if (recursion_bug) {
@@ -1529,7 +1522,7 @@  asmlinkage int vprintk_emit(int facility, int level,
 		printed_len += strlen(recursion_msg);
 		/* emit KERN_CRIT message */
 		log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
-			  NULL, 0, recursion_msg, printed_len);
+			  NULL, 0, recursion_msg, printed_len, syslog_ns);
 	}

 	/*
@@ -1576,12 +1569,12 @@  asmlinkage int vprintk_emit(int facility, int level,
 		 * or another task also prints continuation lines.
 		 */
 		if (cont.len && (lflags & LOG_PREFIX || cont.owner != current))
-			cont_flush(LOG_NEWLINE);
+			cont_flush(LOG_NEWLINE, syslog_ns);

 		/* buffer line if possible, otherwise store it right away */
-		if (!cont_add(facility, level, text, text_len))
+		if (!cont_add(facility, level, text, text_len, syslog_ns))
 			log_store(facility, level, lflags | LOG_CONT, 0,
-				  dict, dictlen, text, text_len);
+				  dict, dictlen, text, text_len, syslog_ns);
 	} else {
 		bool stored = false;

@@ -1593,13 +1586,14 @@  asmlinkage int vprintk_emit(int facility, int level,
 		 */
 		if (cont.len && cont.owner == current) {
 			if (!(lflags & LOG_PREFIX))
-				stored = cont_add(facility, level, text, text_len);
-			cont_flush(LOG_NEWLINE);
+				stored = cont_add(facility, level, text,
+							 text_len, syslog_ns);
+			cont_flush(LOG_NEWLINE, syslog_ns);
 		}

 		if (!stored)
 			log_store(facility, level, lflags, 0,
-				  dict, dictlen, text, text_len);
+				  dict, dictlen, text, text_len, syslog_ns);
 	}
 	printed_len += text_len;

@@ -1611,7 +1605,7 @@  asmlinkage int vprintk_emit(int facility, int level,
 	 * The console_trylock_for_printk() function will release 'logbuf_lock'
 	 * regardless of whether it actually gets the console semaphore or not.
 	 */
-	if (console_trylock_for_printk(this_cpu))
+	if (console_trylock_for_printk(this_cpu, syslog_ns))
 		console_unlock();

 	lockdep_on();
@@ -1624,7 +1618,8 @@  EXPORT_SYMBOL(vprintk_emit);

 asmlinkage int vprintk(const char *fmt, va_list args)
 {
-	return vprintk_emit(0, -1, NULL, 0, fmt, args);
+	return vprintk_emit(0, -1, NULL, 0, fmt, args,
+				current_syslog_ns());
 }
 EXPORT_SYMBOL(vprintk);

@@ -1636,7 +1631,8 @@  asmlinkage int printk_emit(int facility, int level,
 	int r;

 	va_start(args, fmt);
-	r = vprintk_emit(facility, level, dict, dictlen, fmt, args);
+	r = vprintk_emit(facility, level, dict, dictlen, fmt, args,
+						current_syslog_ns());
 	va_end(args);

 	return r;
@@ -1678,7 +1674,7 @@  asmlinkage int printk(const char *fmt, ...)
 	}
 #endif
 	va_start(args, fmt);
-	r = vprintk_emit(0, -1, NULL, 0, fmt, args);
+	r = vprintk_emit(0, -1, NULL, 0, fmt, args, current_syslog_ns());
 	va_end(args);

 	return r;
@@ -1981,12 +1977,13 @@  void wake_up_klogd(void)
 		this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
 }

-static void console_cont_flush(char *text, size_t size)
+static void console_cont_flush(char *text, size_t size,
+			 struct syslog_namespace *syslog_ns)
 {
 	unsigned long flags;
 	size_t len;

-	raw_spin_lock_irqsave(&logbuf_lock, flags);
+	raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);

 	if (!cont.len)
 		goto out;
@@ -1996,18 +1993,131 @@  static void console_cont_flush(char *text, size_t size)
 	 * busy. The earlier ones need to be printed before this one, we
 	 * did not flush any fragment so far, so just let it queue up.
 	 */
-	if (console_seq < log_next_seq && !cont.cons)
+	if (syslog_ns->console_seq < syslog_ns->log_next_seq && !cont.cons)
 		goto out;

 	len = cont_print_text(text, size);
-	raw_spin_unlock(&logbuf_lock);
+	raw_spin_unlock(&syslog_ns->logbuf_lock);
 	stop_critical_timings();
 	call_console_drivers(cont.level, text, len);
 	start_critical_timings();
 	local_irq_restore(flags);
 	return;
 out:
-	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+	raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
+}
+
+/**
+ * syslog_console_unlock - unlock the console system for syslog_namespace
+ *
+ * Releases the console_lock which the caller holds on the console system
+ * and the console driver list.
+ *
+ * While the console_lock was held, console output may have been buffered
+ * by printk().  If this is the case, syslog_console_unlock(); emits
+ * the output prior to releasing the lock.
+ *
+ * If there is output waiting, we wake /dev/kmsg and syslog() users.
+ *
+ * syslog_console_unlock(); may be called from any context.
+ */
+void syslog_console_unlock(struct syslog_namespace *syslog_ns)
+{
+	static char text[LOG_LINE_MAX + PREFIX_MAX];
+	static u64 seen_seq;
+	unsigned long flags;
+	bool wake_klogd = false;
+	bool retry;
+
+	if (console_suspended) {
+		up(&console_sem);
+		return;
+	}
+
+	console_may_schedule = 0;
+
+	/* flush buffered message fragment immediately to console */
+	console_cont_flush(text, sizeof(text), syslog_ns);
+again:
+	for (;;) {
+		struct log *msg;
+		size_t len;
+		int level;
+
+		raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);
+		if (seen_seq != syslog_ns->log_next_seq) {
+			wake_klogd = true;
+			seen_seq = syslog_ns->log_next_seq;
+		}
+
+		if (syslog_ns->console_seq < syslog_ns->log_first_seq) {
+			/* messages are gone, move to first one */
+			syslog_ns->console_seq = syslog_ns->log_first_seq;
+			syslog_ns->console_idx = syslog_ns->log_first_idx;
+			console_prev = 0;
+		}
+skip:
+		if (syslog_ns->console_seq == syslog_ns->log_next_seq)
+			break;
+
+		msg = log_from_idx(syslog_ns->console_idx, syslog_ns);
+		if (msg->flags & LOG_NOCONS) {
+			/*
+			 * Skip record we have buffered and already printed
+			 * directly to the console when we received it.
+			 */
+			syslog_ns->console_idx =
+				log_next(syslog_ns->console_idx, syslog_ns);
+			syslog_ns->console_seq++;
+			/*
+			 * We will get here again when we register a new
+			 * CON_PRINTBUFFER console. Clear the flag so we
+			 * will properly dump everything later.
+			 */
+			msg->flags &= ~LOG_NOCONS;
+			console_prev = msg->flags;
+			goto skip;
+		}
+
+		level = msg->level;
+		len = msg_print_text(msg, console_prev, false,
+				     text, sizeof(text));
+		syslog_ns->console_idx =
+			 log_next(syslog_ns->console_idx, syslog_ns);
+		syslog_ns->console_seq++;
+		console_prev = msg->flags;
+		raw_spin_unlock(&syslog_ns->logbuf_lock);
+
+		stop_critical_timings();	/* don't trace print latency */
+		call_console_drivers(level, text, len);
+		start_critical_timings();
+		local_irq_restore(flags);
+	}
+	console_locked = 0;
+
+	/* Release the exclusive_console once it is used */
+	if (unlikely(exclusive_console))
+		exclusive_console = NULL;
+
+	raw_spin_unlock(&syslog_ns->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.
+	 */
+	raw_spin_lock(&syslog_ns->logbuf_lock);
+	retry = syslog_ns->console_seq != syslog_ns->log_next_seq;
+	raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
+
+	if (retry && console_trylock())
+		goto again;
+
+	if (wake_klogd)
+		wake_up_klogd();
 }

 /**
@@ -2027,6 +2137,7 @@  out:
 void console_unlock(void)
 {
 	static char text[LOG_LINE_MAX + PREFIX_MAX];
+	struct syslog_namespace *syslog_ns = current_syslog_ns();
 	static u64 seen_seq;
 	unsigned long flags;
 	bool wake_klogd = false;
@@ -2040,37 +2151,38 @@  void console_unlock(void)
 	console_may_schedule = 0;

 	/* flush buffered message fragment immediately to console */
-	console_cont_flush(text, sizeof(text));
+	console_cont_flush(text, sizeof(text), syslog_ns);
 again:
 	for (;;) {
 		struct log *msg;
 		size_t len;
 		int level;

-		raw_spin_lock_irqsave(&logbuf_lock, flags);
-		if (seen_seq != log_next_seq) {
+		raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);
+		if (seen_seq != syslog_ns->log_next_seq) {
 			wake_klogd = true;
-			seen_seq = log_next_seq;
+			seen_seq = syslog_ns->log_next_seq;
 		}

-		if (console_seq < log_first_seq) {
+		if (syslog_ns->console_seq < syslog_ns->log_first_seq) {
 			/* messages are gone, move to first one */
-			console_seq = log_first_seq;
-			console_idx = log_first_idx;
+			syslog_ns->console_seq = syslog_ns->log_first_seq;
+			syslog_ns->console_idx = syslog_ns->log_first_idx;
 			console_prev = 0;
 		}
 skip:
-		if (console_seq == log_next_seq)
+		if (syslog_ns->console_seq == syslog_ns->log_next_seq)
 			break;

-		msg = log_from_idx(console_idx);
+		msg = log_from_idx(syslog_ns->console_idx, syslog_ns);
 		if (msg->flags & LOG_NOCONS) {
 			/*
 			 * Skip record we have buffered and already printed
 			 * directly to the console when we received it.
 			 */
-			console_idx = log_next(console_idx);
-			console_seq++;
+			syslog_ns->console_idx =
+				 log_next(syslog_ns->console_idx, syslog_ns);
+			syslog_ns->console_seq++;
 			/*
 			 * We will get here again when we register a new
 			 * CON_PRINTBUFFER console. Clear the flag so we
@@ -2084,10 +2196,11 @@  skip:
 		level = msg->level;
 		len = msg_print_text(msg, console_prev, false,
 				     text, sizeof(text));
-		console_idx = log_next(console_idx);
-		console_seq++;
+		syslog_ns->console_idx =
+			 log_next(syslog_ns->console_idx, syslog_ns);
+		syslog_ns->console_seq++;
 		console_prev = msg->flags;
-		raw_spin_unlock(&logbuf_lock);
+		raw_spin_unlock(&syslog_ns->logbuf_lock);

 		stop_critical_timings();	/* don't trace print latency */
 		call_console_drivers(level, text, len);
@@ -2100,7 +2213,7 @@  skip:
 	if (unlikely(exclusive_console))
 		exclusive_console = NULL;

-	raw_spin_unlock(&logbuf_lock);
+	raw_spin_unlock(&syslog_ns->logbuf_lock);

 	up(&console_sem);

@@ -2110,9 +2223,9 @@  skip:
 	 * there's a new owner and the console_unlock() from them will do the
 	 * flush, no worries.
 	 */
-	raw_spin_lock(&logbuf_lock);
-	retry = console_seq != log_next_seq;
-	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+	raw_spin_lock(&syslog_ns->logbuf_lock);
+	retry = syslog_ns->console_seq != syslog_ns->log_next_seq;
+	raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);

 	if (retry && console_trylock())
 		goto again;
@@ -2237,6 +2350,7 @@  void register_console(struct console *newcon)
 	int i;
 	unsigned long flags;
 	struct console *bcon = NULL;
+	struct syslog_namespace *syslog_ns = &init_syslog_ns;

 	/*
 	 * before we register a new CON_BOOT console, make sure we don't
@@ -2346,11 +2460,11 @@  void register_console(struct console *newcon)
 		 * console_unlock(); will print out the buffered messages
 		 * for us.
 		 */
-		raw_spin_lock_irqsave(&logbuf_lock, flags);
-		console_seq = syslog_seq;
-		console_idx = syslog_idx;
-		console_prev = syslog_prev;
-		raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+		raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);
+		syslog_ns->console_seq = syslog_ns->syslog_seq;
+		syslog_ns->console_idx = syslog_ns->syslog_idx;
+		console_prev = syslog_ns->syslog_prev;
+		raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
 		/*
 		 * We're about to replay the log buffer.  Only do this to the
 		 * just-registered console to avoid excessive message spam to
@@ -2573,6 +2687,7 @@  void kmsg_dump(enum kmsg_dump_reason reason)
 {
 	struct kmsg_dumper *dumper;
 	unsigned long flags;
+	struct syslog_namespace *syslog_ns = &init_syslog_ns;

 	if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump)
 		return;
@@ -2585,12 +2700,12 @@  void kmsg_dump(enum kmsg_dump_reason reason)
 		/* initialize iterator with data about the stored records */
 		dumper->active = true;

-		raw_spin_lock_irqsave(&logbuf_lock, flags);
-		dumper->cur_seq = clear_seq;
-		dumper->cur_idx = clear_idx;
-		dumper->next_seq = log_next_seq;
-		dumper->next_idx = log_next_idx;
-		raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+		raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);
+		dumper->cur_seq = syslog_ns->clear_seq;
+		dumper->cur_idx = syslog_ns->clear_idx;
+		dumper->next_seq = syslog_ns->log_next_seq;
+		dumper->next_idx = syslog_ns->log_next_idx;
+		raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);

 		/* invoke dumper which will iterate over records */
 		dumper->dump(dumper, reason);
@@ -2626,24 +2741,25 @@  bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog,
 	struct log *msg;
 	size_t l = 0;
 	bool ret = false;
+	struct syslog_namespace *syslog_ns = &init_syslog_ns;

 	if (!dumper->active)
 		goto out;

-	if (dumper->cur_seq < log_first_seq) {
+	if (dumper->cur_seq < syslog_ns->log_first_seq) {
 		/* messages are gone, move to first available one */
-		dumper->cur_seq = log_first_seq;
-		dumper->cur_idx = log_first_idx;
+		dumper->cur_seq = syslog_ns->log_first_seq;
+		dumper->cur_idx = syslog_ns->log_first_idx;
 	}

 	/* last entry */
-	if (dumper->cur_seq >= log_next_seq)
+	if (dumper->cur_seq >= syslog_ns->log_next_seq)
 		goto out;

-	msg = log_from_idx(dumper->cur_idx);
+	msg = log_from_idx(dumper->cur_idx, syslog_ns);
 	l = msg_print_text(msg, 0, syslog, line, size);

-	dumper->cur_idx = log_next(dumper->cur_idx);
+	dumper->cur_idx = log_next(dumper->cur_idx, syslog_ns);
 	dumper->cur_seq++;
 	ret = true;
 out:
@@ -2674,10 +2790,12 @@  bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
 {
 	unsigned long flags;
 	bool ret;
+	struct syslog_namespace *syslog_ns = &init_syslog_ns;
+
+	raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);

-	raw_spin_lock_irqsave(&logbuf_lock, flags);
 	ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len);
-	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+	raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);

 	return ret;
 }
@@ -2713,20 +2831,21 @@  bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
 	enum log_flags prev;
 	size_t l = 0;
 	bool ret = false;
+	struct syslog_namespace *syslog_ns = &init_syslog_ns;

 	if (!dumper->active)
 		goto out;

-	raw_spin_lock_irqsave(&logbuf_lock, flags);
-	if (dumper->cur_seq < log_first_seq) {
+	raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);
+	if (dumper->cur_seq < syslog_ns->log_first_seq) {
 		/* messages are gone, move to first available one */
-		dumper->cur_seq = log_first_seq;
-		dumper->cur_idx = log_first_idx;
+		dumper->cur_seq = syslog_ns->log_first_seq;
+		dumper->cur_idx = syslog_ns->log_first_idx;
 	}

 	/* last entry */
 	if (dumper->cur_seq >= dumper->next_seq) {
-		raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+		raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
 		goto out;
 	}

@@ -2735,10 +2854,10 @@  bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
 	idx = dumper->cur_idx;
 	prev = 0;
 	while (seq < dumper->next_seq) {
-		struct log *msg = log_from_idx(idx);
+		struct log *msg = log_from_idx(idx, syslog_ns);

 		l += msg_print_text(msg, prev, true, NULL, 0);
-		idx = log_next(idx);
+		idx = log_next(idx, syslog_ns);
 		seq++;
 		prev = msg->flags;
 	}
@@ -2748,10 +2867,10 @@  bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
 	idx = dumper->cur_idx;
 	prev = 0;
 	while (l > size && seq < dumper->next_seq) {
-		struct log *msg = log_from_idx(idx);
+		struct log *msg = log_from_idx(idx, syslog_ns);

 		l -= msg_print_text(msg, prev, true, NULL, 0);
-		idx = log_next(idx);
+		idx = log_next(idx, syslog_ns);
 		seq++;
 		prev = msg->flags;
 	}
@@ -2763,10 +2882,10 @@  bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
 	l = 0;
 	prev = 0;
 	while (seq < dumper->next_seq) {
-		struct log *msg = log_from_idx(idx);
+		struct log *msg = log_from_idx(idx, syslog_ns);

 		l += msg_print_text(msg, prev, syslog, buf + l, size - l);
-		idx = log_next(idx);
+		idx = log_next(idx, syslog_ns);
 		seq++;
 		prev = msg->flags;
 	}
@@ -2774,7 +2893,7 @@  bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
 	dumper->next_seq = next_seq;
 	dumper->next_idx = next_idx;
 	ret = true;
-	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+	raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
 out:
 	if (len)
 		*len = l;
@@ -2794,10 +2913,12 @@  EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);
  */
 void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper)
 {
-	dumper->cur_seq = clear_seq;
-	dumper->cur_idx = clear_idx;
-	dumper->next_seq = log_next_seq;
-	dumper->next_idx = log_next_idx;
+	struct syslog_namespace *syslog_ns = &init_syslog_ns;
+
+	dumper->cur_seq = syslog_ns->clear_seq;
+	dumper->cur_idx = syslog_ns->clear_idx;
+	dumper->next_seq = syslog_ns->log_next_seq;
+	dumper->next_idx = syslog_ns->log_next_idx;
 }

 /**
@@ -2811,10 +2932,12 @@  void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper)
 void kmsg_dump_rewind(struct kmsg_dumper *dumper)
 {
 	unsigned long flags;
+	struct syslog_namespace *syslog_ns = &init_syslog_ns;
+
+	raw_spin_lock_irqsave(&syslog_ns->logbuf_lock, flags);

-	raw_spin_lock_irqsave(&logbuf_lock, flags);
 	kmsg_dump_rewind_nolock(dumper);
-	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+	raw_spin_unlock_irqrestore(&syslog_ns->logbuf_lock, flags);
 }
 EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
 #endif