diff options
| author | David S. Miller <davem@davemloft.net> | 2012-07-19 11:17:30 -0700 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2012-07-19 11:17:30 -0700 | 
| commit | abaa72d7fd9a20a67b62e6afa0e746e27851dc33 (patch) | |
| tree | ebe4134fcc93a6e205e6004b3e652d7a62281651 /kernel/printk.c | |
| parent | 67da22d23fa6f3324e03bcd0580b914b2e4afbf3 (diff) | |
| parent | 3e4b9459fb0e149c6b74c9e89399a8fc39a92b44 (diff) | |
| download | olio-linux-3.10-abaa72d7fd9a20a67b62e6afa0e746e27851dc33.tar.xz olio-linux-3.10-abaa72d7fd9a20a67b62e6afa0e746e27851dc33.zip  | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Conflicts:
	drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
Diffstat (limited to 'kernel/printk.c')
| -rw-r--r-- | kernel/printk.c | 202 | 
1 files changed, 126 insertions, 76 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index dba18211685..177fa49357a 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -194,8 +194,10 @@ static int console_may_schedule;   */  enum log_flags { -	LOG_DEFAULT = 0, -	LOG_NOCONS = 1,		/* already flushed, do not print to console */ +	LOG_NOCONS	= 1,	/* already flushed, do not print to console */ +	LOG_NEWLINE	= 2,	/* text ended with a newline */ +	LOG_PREFIX	= 4,	/* text started with a prefix */ +	LOG_CONT	= 8,	/* text is a fragment of a continuation line */  };  struct log { @@ -217,6 +219,8 @@ static DEFINE_RAW_SPINLOCK(logbuf_lock);  /* 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; @@ -430,20 +434,20 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,  	ret = mutex_lock_interruptible(&user->lock);  	if (ret)  		return ret; -	raw_spin_lock(&logbuf_lock); +	raw_spin_lock_irq(&logbuf_lock);  	while (user->seq == log_next_seq) {  		if (file->f_flags & O_NONBLOCK) {  			ret = -EAGAIN; -			raw_spin_unlock(&logbuf_lock); +			raw_spin_unlock_irq(&logbuf_lock);  			goto out;  		} -		raw_spin_unlock(&logbuf_lock); +		raw_spin_unlock_irq(&logbuf_lock);  		ret = wait_event_interruptible(log_wait,  					       user->seq != log_next_seq);  		if (ret)  			goto out; -		raw_spin_lock(&logbuf_lock); +		raw_spin_lock_irq(&logbuf_lock);  	}  	if (user->seq < log_first_seq) { @@ -451,7 +455,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,  		user->idx = log_first_idx;  		user->seq = log_first_seq;  		ret = -EPIPE; -		raw_spin_unlock(&logbuf_lock); +		raw_spin_unlock_irq(&logbuf_lock);  		goto out;  	} @@ -465,7 +469,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,  	for (i = 0; i < msg->text_len; i++) {  		unsigned char c = log_text(msg)[i]; -		if (c < ' ' || c >= 128) +		if (c < ' ' || c >= 127 || c == '\\')  			len += sprintf(user->buf + len, "\\x%02x", c);  		else  			user->buf[len++] = c; @@ -489,7 +493,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,  				continue;  			} -			if (c < ' ' || c >= 128) { +			if (c < ' ' || c >= 127 || c == '\\') {  				len += sprintf(user->buf + len, "\\x%02x", c);  				continue;  			} @@ -501,7 +505,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,  	user->idx = log_next(user->idx);  	user->seq++; -	raw_spin_unlock(&logbuf_lock); +	raw_spin_unlock_irq(&logbuf_lock);  	if (len > count) {  		ret = -EINVAL; @@ -528,7 +532,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)  	if (offset)  		return -ESPIPE; -	raw_spin_lock(&logbuf_lock); +	raw_spin_lock_irq(&logbuf_lock);  	switch (whence) {  	case SEEK_SET:  		/* the first record */ @@ -552,7 +556,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)  	default:  		ret = -EINVAL;  	} -	raw_spin_unlock(&logbuf_lock); +	raw_spin_unlock_irq(&logbuf_lock);  	return ret;  } @@ -566,14 +570,14 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait)  	poll_wait(file, &log_wait, wait); -	raw_spin_lock(&logbuf_lock); +	raw_spin_lock_irq(&logbuf_lock);  	if (user->seq < log_next_seq) {  		/* return error when data has vanished underneath us */  		if (user->seq < log_first_seq)  			ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI;  		ret = POLLIN|POLLRDNORM;  	} -	raw_spin_unlock(&logbuf_lock); +	raw_spin_unlock_irq(&logbuf_lock);  	return ret;  } @@ -597,10 +601,10 @@ static int devkmsg_open(struct inode *inode, struct file *file)  	mutex_init(&user->lock); -	raw_spin_lock(&logbuf_lock); +	raw_spin_lock_irq(&logbuf_lock);  	user->idx = log_first_idx;  	user->seq = log_first_seq; -	raw_spin_unlock(&logbuf_lock); +	raw_spin_unlock_irq(&logbuf_lock);  	file->private_data = user;  	return 0; @@ -818,15 +822,18 @@ static size_t print_time(u64 ts, char *buf)  static size_t print_prefix(const struct log *msg, bool syslog, char *buf)  {  	size_t len = 0; +	unsigned int prefix = (msg->facility << 3) | msg->level;  	if (syslog) {  		if (buf) { -			len += sprintf(buf, "<%u>", msg->level); +			len += sprintf(buf, "<%u>", prefix);  		} else {  			len += 3; -			if (msg->level > 9) -				len++; -			if (msg->level > 99) +			if (prefix > 999) +				len += 3; +			else if (prefix > 99) +				len += 2; +			else if (prefix > 9)  				len++;  		}  	} @@ -835,13 +842,26 @@ static size_t print_prefix(const struct log *msg, bool syslog, char *buf)  	return len;  } -static size_t msg_print_text(const struct log *msg, bool syslog, -			     char *buf, size_t size) +static size_t msg_print_text(const struct log *msg, enum log_flags prev, +			     bool syslog, char *buf, size_t size)  {  	const char *text = log_text(msg);  	size_t text_size = msg->text_len; +	bool prefix = true; +	bool newline = true;  	size_t len = 0; +	if ((prev & LOG_CONT) && !(msg->flags & LOG_PREFIX)) +		prefix = false; + +	if (msg->flags & LOG_CONT) { +		if ((prev & LOG_CONT) && !(prev & LOG_NEWLINE)) +			prefix = false; + +		if (!(msg->flags & LOG_NEWLINE)) +			newline = false; +	} +  	do {  		const char *next = memchr(text, '\n', text_size);  		size_t text_len; @@ -859,16 +879,22 @@ static size_t msg_print_text(const struct log *msg, bool syslog,  			    text_len + 1>= size - len)  				break; -			len += print_prefix(msg, syslog, buf + len); +			if (prefix) +				len += print_prefix(msg, syslog, buf + len);  			memcpy(buf + len, text, text_len);  			len += text_len; -			buf[len++] = '\n'; +			if (next || newline) +				buf[len++] = '\n';  		} else {  			/* SYSLOG_ACTION_* buffer size only calculation */ -			len += print_prefix(msg, syslog, NULL); -			len += text_len + 1; +			if (prefix) +				len += print_prefix(msg, syslog, NULL); +			len += text_len; +			if (next || newline) +				len++;  		} +		prefix = true;  		text = next;  	} while (text); @@ -887,22 +913,35 @@ static int syslog_print(char __user *buf, int size)  	while (size > 0) {  		size_t n; +		size_t skip;  		raw_spin_lock_irq(&logbuf_lock);  		if (syslog_seq < 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;  		}  		if (syslog_seq == log_next_seq) {  			raw_spin_unlock_irq(&logbuf_lock);  			break;  		} + +		skip = syslog_partial;  		msg = log_from_idx(syslog_idx); -		n = msg_print_text(msg, true, text, LOG_LINE_MAX); -		if (n <= size) { +		n = msg_print_text(msg, syslog_prev, true, text, LOG_LINE_MAX); +		if (n - 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; +		} else if (!len){ +			/* partial read(), remember position */ +			n = size; +			syslog_partial += n;  		} else  			n = 0;  		raw_spin_unlock_irq(&logbuf_lock); @@ -910,17 +949,15 @@ static int syslog_print(char __user *buf, int size)  		if (!n)  			break; -		len += n; -		size -= n; -		buf += n; -		n = copy_to_user(buf - n, text, n); - -		if (n) { -			len -= n; +		if (copy_to_user(buf, text + skip, n)) {  			if (!len)  				len = -EFAULT;  			break;  		} + +		len += n; +		size -= n; +		buf += n;  	}  	kfree(text); @@ -941,6 +978,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)  		u64 next_seq;  		u64 seq;  		u32 idx; +		enum log_flags prev;  		if (clear_seq < log_first_seq) {  			/* messages are gone, move to first available one */ @@ -954,10 +992,11 @@ static int syslog_print_all(char __user *buf, int size, bool clear)  		 */  		seq = clear_seq;  		idx = clear_idx; +		prev = 0;  		while (seq < log_next_seq) {  			struct log *msg = log_from_idx(idx); -			len += msg_print_text(msg, true, NULL, 0); +			len += msg_print_text(msg, prev, true, NULL, 0);  			idx = log_next(idx);  			seq++;  		} @@ -965,10 +1004,11 @@ static int syslog_print_all(char __user *buf, int size, bool clear)  		/* move first record forward until length fits into the buffer */  		seq = clear_seq;  		idx = clear_idx; +		prev = 0;  		while (len > size && seq < log_next_seq) {  			struct log *msg = log_from_idx(idx); -			len -= msg_print_text(msg, true, NULL, 0); +			len -= msg_print_text(msg, prev, true, NULL, 0);  			idx = log_next(idx);  			seq++;  		} @@ -977,17 +1017,19 @@ static int syslog_print_all(char __user *buf, int size, bool clear)  		next_seq = log_next_seq;  		len = 0; +		prev = 0;  		while (len >= 0 && seq < next_seq) {  			struct log *msg = log_from_idx(idx);  			int textlen; -			textlen = msg_print_text(msg, true, text, LOG_LINE_MAX); +			textlen = msg_print_text(msg, prev, true, text, LOG_LINE_MAX);  			if (textlen < 0) {  				len = textlen;  				break;  			}  			idx = log_next(idx);  			seq++; +			prev = msg->flags;  			raw_spin_unlock_irq(&logbuf_lock);  			if (copy_to_user(buf + len, text, textlen)) @@ -1000,6 +1042,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)  				/* messages are gone, move to next one */  				seq = log_first_seq;  				idx = log_first_idx; +				prev = 0;  			}  		}  	} @@ -1018,7 +1061,6 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)  {  	bool clear = false;  	static int saved_console_loglevel = -1; -	static DEFINE_MUTEX(syslog_mutex);  	int error;  	error = check_syslog_permissions(type, from_file); @@ -1045,17 +1087,11 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)  			error = -EFAULT;  			goto out;  		} -		error = mutex_lock_interruptible(&syslog_mutex); -		if (error) -			goto out;  		error = wait_event_interruptible(log_wait,  						 syslog_seq != log_next_seq); -		if (error) { -			mutex_unlock(&syslog_mutex); +		if (error)  			goto out; -		}  		error = syslog_print(buf, len); -		mutex_unlock(&syslog_mutex);  		break;  	/* Read/clear last kernel messages */  	case SYSLOG_ACTION_READ_CLEAR: @@ -1111,6 +1147,8 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)  			/* messages are gone, move to first one */  			syslog_seq = log_first_seq;  			syslog_idx = log_first_idx; +			syslog_prev = 0; +			syslog_partial = 0;  		}  		if (from_file) {  			/* @@ -1120,19 +1158,20 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)  			 */  			error = log_next_idx - syslog_idx;  		} else { -			u64 seq; -			u32 idx; +			u64 seq = syslog_seq; +			u32 idx = syslog_idx; +			enum log_flags prev = syslog_prev;  			error = 0; -			seq = syslog_seq; -			idx = syslog_idx;  			while (seq < log_next_seq) {  				struct log *msg = log_from_idx(idx); -				error += msg_print_text(msg, true, NULL, 0); +				error += msg_print_text(msg, prev, true, NULL, 0);  				idx = log_next(idx);  				seq++; +				prev = msg->flags;  			} +			error -= syslog_partial;  		}  		raw_spin_unlock_irq(&logbuf_lock);  		break; @@ -1400,10 +1439,9 @@ asmlinkage int vprintk_emit(int facility, int level,  	static char textbuf[LOG_LINE_MAX];  	char *text = textbuf;  	size_t text_len; +	enum log_flags lflags = 0;  	unsigned long flags;  	int this_cpu; -	bool newline = false; -	bool prefix = false;  	int printed_len = 0;  	boot_delay_msec(); @@ -1442,7 +1480,7 @@ asmlinkage int vprintk_emit(int facility, int level,  		recursion_bug = 0;  		printed_len += strlen(recursion_msg);  		/* emit KERN_CRIT message */ -		log_store(0, 2, LOG_DEFAULT, 0, +		log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,  			  NULL, 0, recursion_msg, printed_len);  	} @@ -1455,7 +1493,7 @@ asmlinkage int vprintk_emit(int facility, int level,  	/* mark and strip a trailing newline */  	if (text_len && text[text_len-1] == '\n') {  		text_len--; -		newline = true; +		lflags |= LOG_NEWLINE;  	}  	/* strip syslog prefix and extract log level or control flags */ @@ -1465,7 +1503,7 @@ asmlinkage int vprintk_emit(int facility, int level,  			if (level == -1)  				level = text[1] - '0';  		case 'd':	/* KERN_DEFAULT */ -			prefix = true; +			lflags |= LOG_PREFIX;  		case 'c':	/* KERN_CONT */  			text += 3;  			text_len -= 3; @@ -1475,22 +1513,20 @@ asmlinkage int vprintk_emit(int facility, int level,  	if (level == -1)  		level = default_message_loglevel; -	if (dict) { -		prefix = true; -		newline = true; -	} +	if (dict) +		lflags |= LOG_PREFIX|LOG_NEWLINE; -	if (!newline) { +	if (!(lflags & LOG_NEWLINE)) {  		/*  		 * Flush the conflicting buffer. An earlier newline was missing,  		 * or another task also prints continuation lines.  		 */ -		if (cont.len && (prefix || cont.owner != current)) +		if (cont.len && (lflags & LOG_PREFIX || cont.owner != current))  			cont_flush();  		/* buffer line if possible, otherwise store it right away */  		if (!cont_add(facility, level, text, text_len)) -			log_store(facility, level, LOG_DEFAULT, 0, +			log_store(facility, level, lflags | LOG_CONT, 0,  				  dict, dictlen, text, text_len);  	} else {  		bool stored = false; @@ -1502,13 +1538,13 @@ asmlinkage int vprintk_emit(int facility, int level,  		 * flush it out and store this line separately.  		 */  		if (cont.len && cont.owner == current) { -			if (!prefix) +			if (!(lflags & LOG_PREFIX))  				stored = cont_add(facility, level, text, text_len);  			cont_flush();  		}  		if (!stored) -			log_store(facility, level, LOG_DEFAULT, 0, +			log_store(facility, level, lflags, 0,  				  dict, dictlen, text, text_len);  	}  	printed_len += text_len; @@ -1607,8 +1643,8 @@ static struct cont {  static struct log *log_from_idx(u32 idx) { return NULL; }  static u32 log_next(u32 idx) { return 0; }  static void call_console_drivers(int level, const char *text, size_t len) {} -static size_t msg_print_text(const struct log *msg, bool syslog, -			     char *buf, size_t size) { return 0; } +static size_t msg_print_text(const struct log *msg, enum log_flags prev, +			     bool syslog, char *buf, size_t size) { return 0; }  static size_t cont_print_text(char *text, size_t size) { return 0; }  #endif /* CONFIG_PRINTK */ @@ -1884,6 +1920,7 @@ void wake_up_klogd(void)  /* the next printk record to write to the console */  static u64 console_seq;  static u32 console_idx; +static enum log_flags console_prev;  /**   * console_unlock - unlock the console system @@ -1944,6 +1981,7 @@ again:  			/* messages are gone, move to first one */  			console_seq = log_first_seq;  			console_idx = log_first_idx; +			console_prev = 0;  		}  skip:  		if (console_seq == log_next_seq) @@ -1957,14 +1995,21 @@ skip:  			 */  			console_idx = log_next(console_idx);  			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;  			goto skip;  		}  		level = msg->level; -		len = msg_print_text(msg, false, text, sizeof(text)); - +		len = msg_print_text(msg, console_prev, false, +				     text, sizeof(text));  		console_idx = log_next(console_idx);  		console_seq++; +		console_prev = msg->flags;  		raw_spin_unlock(&logbuf_lock);  		stop_critical_timings();	/* don't trace print latency */ @@ -2227,6 +2272,7 @@ void register_console(struct console *newcon)  		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);  		/*  		 * We're about to replay the log buffer.  Only do this to the @@ -2520,8 +2566,7 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,  	}  	msg = log_from_idx(dumper->cur_idx); -	l = msg_print_text(msg, syslog, -			      line, size); +	l = msg_print_text(msg, 0, syslog, line, size);  	dumper->cur_idx = log_next(dumper->cur_idx);  	dumper->cur_seq++; @@ -2561,6 +2606,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,  	u32 idx;  	u64 next_seq;  	u32 next_idx; +	enum log_flags prev;  	size_t l = 0;  	bool ret = false; @@ -2583,23 +2629,27 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,  	/* calculate length of entire buffer */  	seq = dumper->cur_seq;  	idx = dumper->cur_idx; +	prev = 0;  	while (seq < dumper->next_seq) {  		struct log *msg = log_from_idx(idx); -		l += msg_print_text(msg, true, NULL, 0); +		l += msg_print_text(msg, prev, true, NULL, 0);  		idx = log_next(idx);  		seq++; +		prev = msg->flags;  	}  	/* move first record forward until length fits into the buffer */  	seq = dumper->cur_seq;  	idx = dumper->cur_idx; +	prev = 0;  	while (l > size && seq < dumper->next_seq) {  		struct log *msg = log_from_idx(idx); -		l -= msg_print_text(msg, true, NULL, 0); +		l -= msg_print_text(msg, prev, true, NULL, 0);  		idx = log_next(idx);  		seq++; +		prev = msg->flags;  	}  	/* last message in next interation */ @@ -2607,14 +2657,14 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,  	next_idx = idx;  	l = 0; +	prev = 0;  	while (seq < dumper->next_seq) {  		struct log *msg = log_from_idx(idx); -		l += msg_print_text(msg, syslog, -				    buf + l, size - l); - +		l += msg_print_text(msg, prev, syslog, buf + l, size - l);  		idx = log_next(idx);  		seq++; +		prev = msg->flags;  	}  	dumper->next_seq = next_seq;  |