linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: David Howells <dhowells@redhat.com>
To: linux-kernel@vger.kernel.org
Cc: jack@suse.cz, will.deacon@arm.com, rostedt@goodmis.org,
	dhowells@redhat.com, pmladek@suse.cz, dwmw2@infradead.org
Subject: [PATCH] printk: Don't discard earlier unprinted messages to make space
Date: Thu, 22 Oct 2015 11:16:50 +0100	[thread overview]
Message-ID: <20151022101650.25995.95155.stgit@warthog.procyon.org.uk> (raw)

printk() currently discards earlier messages to make space for new messages
arriving.  This has the distinct downside that if the kernel starts
churning out messages because of some initial incident, the report of the
initial incident is likely to be lost under a blizzard of:

	** NNN printk messages dropped **

messages from console_unlock().

The first message generated (typically an oops) is usually the most
important - the one you want to solve first - so we really want to see
that.

To this end, change log_store() to only write a message into the buffer if
there is sufficient space to hold that message.  The message may be
truncated if it will then fit.

This patch could be improved by noting that some messages got discarded
when next there is space to do so.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 kernel/printk/printk.c |   96 ++++++++++++++++++------------------------------
 1 file changed, 35 insertions(+), 61 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 8f0324ef72ab..c2099ede0bc8 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -46,6 +46,7 @@
 #include <linux/utsname.h>
 #include <linux/ctype.h>
 #include <linux/uio.h>
+#include <linux/circ_buf.h>
 
 #include <asm/uaccess.h>
 
@@ -336,48 +337,6 @@ static u32 log_next(u32 idx)
 	return idx + msg->len;
 }
 
-/*
- * Check whether there is enough free space for the given message.
- *
- * The same values of first_idx and next_idx mean that the buffer
- * is either empty or full.
- *
- * If the buffer is empty, we must respect the position of the indexes.
- * They cannot be reset to the beginning of the buffer.
- */
-static int logbuf_has_space(u32 msg_size, bool empty)
-{
-	u32 free;
-
-	if (log_next_idx > log_first_idx || empty)
-		free = max(log_buf_len - log_next_idx, log_first_idx);
-	else
-		free = log_first_idx - log_next_idx;
-
-	/*
-	 * We need space also for an empty header that signalizes wrapping
-	 * of the buffer.
-	 */
-	return free >= msg_size + sizeof(struct printk_log);
-}
-
-static int log_make_free_space(u32 msg_size)
-{
-	while (log_first_seq < log_next_seq) {
-		if (logbuf_has_space(msg_size, false))
-			return 0;
-		/* drop old messages until we have enough contiguous space */
-		log_first_idx = log_next(log_first_idx);
-		log_first_seq++;
-	}
-
-	/* sequence numbers are equal, so the log buffer is empty */
-	if (logbuf_has_space(msg_size, true))
-		return 0;
-
-	return -ENOMEM;
-}
-
 /* compute the message size including the padding bytes */
 static u32 msg_used_size(u16 text_len, u16 dict_len, u32 *pad_len)
 {
@@ -423,32 +382,47 @@ static int log_store(int facility, int level,
 		     const char *text, u16 text_len)
 {
 	struct printk_log *msg;
-	u32 size, pad_len;
+	u32 size, wsize, pad_len;
 	u16 trunc_msg_len = 0;
 
 	/* number of '\0' padding bytes to next message */
 	size = msg_used_size(text_len, dict_len, &pad_len);
 
-	if (log_make_free_space(size)) {
-		/* truncate the message if it is too long for empty buffer */
-		size = truncate_msg(&text_len, &trunc_msg_len,
-				    &dict_len, &pad_len);
-		/* survive when the log buffer is too small for trunc_msg */
-		if (log_make_free_space(size))
-			return 0;
-	}
+	/* See if we have sufficient space to insert a message.  Note we also
+	 * need to keep a gap right at the end of the buffer to insert a 'wrap
+	 * here' marker.
+	 */
+	wsize = size + sizeof(struct printk_log);
 
-	if (log_next_idx + size + sizeof(struct printk_log) > 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 printk_log));
-		log_next_idx = 0;
-	}
+	if (log_first_seq != log_next_seq && log_first_idx == log_next_idx)
+		return 0; /* Buffer is completely full */
+
+	if (CIRC_SPACE_TO_END(log_next_idx, log_first_idx, log_buf_len) >= wsize)
+		goto have_space_no_wrap;
+
+	if (CIRC_SPACE(log_next_idx, log_first_idx, log_buf_len) >= size)
+		goto have_space_wrap;
+
+	/* Try to truncate the message. */
+	size = truncate_msg(&text_len, &trunc_msg_len, &dict_len, &pad_len);
+	wsize = size + sizeof(struct printk_log);
+
+	if (CIRC_SPACE_TO_END(log_next_idx, log_first_idx, log_buf_len) >= wsize)
+		goto have_space_no_wrap;
+
+	if (CIRC_SPACE(log_next_idx, log_first_idx, log_buf_len) < size)
+		return 0;
+
+have_space_wrap:
+	/* This message plus an additional empty header does not fit at the end
+	 * of the buffer.  Insert an empty header with len == 0 as a wrap
+	 * around marker.
+	 */
+	memset(log_buf + log_next_idx, 0, sizeof(struct printk_log));
+	log_next_idx = 0;
 
-	/* fill message */
+have_space_no_wrap:
+	/* Write the message into the buffer */
 	msg = (struct printk_log *)(log_buf + log_next_idx);
 	memcpy(log_text(msg), text, text_len);
 	msg->text_len = text_len;


             reply	other threads:[~2015-10-22 10:16 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-10-22 10:16 David Howells [this message]
2015-10-22 10:28 ` [PATCH] printk: Don't discard earlier unprinted messages to make space David Woodhouse
2015-10-22 12:18   ` Jan Kara
2015-10-22 12:36     ` David Woodhouse
2015-10-22 12:30 ` Petr Mladek
2015-10-22 13:19   ` David Howells
2015-10-22 13:23     ` David Woodhouse
2015-10-23  8:49     ` Petr Mladek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20151022101650.25995.95155.stgit@warthog.procyon.org.uk \
    --to=dhowells@redhat.com \
    --cc=dwmw2@infradead.org \
    --cc=jack@suse.cz \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pmladek@suse.cz \
    --cc=rostedt@goodmis.org \
    --cc=will.deacon@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).