All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] printk: Pass caller information to log_store().
@ 2019-02-16 10:59 Tetsuo Handa
  2019-02-20 12:18 ` Petr Mladek
  2019-02-21  2:22 ` Sergey Senozhatsky
  0 siblings, 2 replies; 6+ messages in thread
From: Tetsuo Handa @ 2019-02-16 10:59 UTC (permalink / raw)
  To: Dmitry Vyukov, Sergey Senozhatsky, Steven Rostedt,
	Sergey Senozhatsky, Petr Mladek
  Cc: linux-kernel, Tetsuo Handa

When thread1 called printk() which did not end with '\n', and then thread2
called printk() which ends with '\n' before thread1 calls pr_cont(), the
partial content saved into "struct cont" is flushed by thread2 despite the
partial content was generated by thread1. This leads to confusing output
as if the partial content was generated by thread2. Fix this problem by
passing correct caller information to log_store().

Before:

  [ T8533] abcdefghijklm
  [ T8533] ABCDEFGHIJKLMNOPQRSTUVWXYZ
  [ T8532] nopqrstuvwxyz
  [ T8532] abcdefghijklmnopqrstuvwxyz
  [ T8533] abcdefghijklm
  [ T8533] ABCDEFGHIJKLMNOPQRSTUVWXYZ
  [ T8532] nopqrstuvwxyz

After:

  [ T8507] abcdefghijklm
  [ T8508] ABCDEFGHIJKLMNOPQRSTUVWXYZ
  [ T8507] nopqrstuvwxyz
  [ T8507] abcdefghijklmnopqrstuvwxyz
  [ T8507] abcdefghijklm
  [ T8508] ABCDEFGHIJKLMNOPQRSTUVWXYZ
  [ T8507] nopqrstuvwxyz

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
 kernel/printk/printk.c | 39 ++++++++++++++++++++++++---------------
 1 file changed, 24 insertions(+), 15 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 33c0359..6547a88 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -585,7 +585,7 @@ static u32 truncate_msg(u16 *text_len, u16 *trunc_msg_len,
 }
 
 /* insert record into the buffer, discard old ones, update heads */
-static int log_store(int facility, int level,
+static int log_store(u32 caller_id, int facility, int level,
 		     enum log_flags flags, u64 ts_nsec,
 		     const char *dict, u16 dict_len,
 		     const char *text, u16 text_len)
@@ -634,10 +634,7 @@ static int log_store(int facility, int level,
 	else
 		msg->ts_nsec = local_clock();
 #ifdef CONFIG_PRINTK_CALLER
-	if (in_task())
-		msg->caller_id = task_pid_nr(current);
-	else
-		msg->caller_id = 0x80000000 + raw_smp_processor_id();
+	msg->caller_id = caller_id;
 #endif
 	memset(log_dict(msg) + dict_len, 0, pad_len);
 	msg->len = size;
@@ -1793,6 +1790,12 @@ static inline void printk_delay(void)
 	}
 }
 
+static inline u32 printk_caller_id(void)
+{
+	return in_task() ? task_pid_nr(current) :
+		0x80000000 + raw_smp_processor_id();
+}
+
 /*
  * Continuation lines are buffered, and not committed to the record buffer
  * until the line is complete, or a race forces it. The line fragments
@@ -1802,7 +1805,7 @@ static inline void printk_delay(void)
 static struct cont {
 	char buf[LOG_LINE_MAX];
 	size_t len;			/* length == 0 means unused buffer */
-	struct task_struct *owner;	/* task of first print*/
+	u32 caller_id;			/* printk_caller_id() of first print */
 	u64 ts_nsec;			/* time of first print */
 	u8 level;			/* log level of first message */
 	u8 facility;			/* log facility of first message */
@@ -1814,12 +1817,13 @@ static void cont_flush(void)
 	if (cont.len == 0)
 		return;
 
-	log_store(cont.facility, cont.level, cont.flags, cont.ts_nsec,
-		  NULL, 0, cont.buf, cont.len);
+	log_store(cont.caller_id, cont.facility, cont.level, cont.flags,
+		  cont.ts_nsec, NULL, 0, cont.buf, cont.len);
 	cont.len = 0;
 }
 
-static bool cont_add(int facility, int level, enum log_flags flags, const char *text, size_t len)
+static bool cont_add(u32 caller_id, int facility, int level,
+		     enum log_flags flags, const char *text, size_t len)
 {
 	/* If the line gets too long, split it up in separate records. */
 	if (cont.len + len > sizeof(cont.buf)) {
@@ -1830,7 +1834,7 @@ static bool cont_add(int facility, int level, enum log_flags flags, const char *
 	if (!cont.len) {
 		cont.facility = facility;
 		cont.level = level;
-		cont.owner = current;
+		cont.caller_id = caller_id;
 		cont.ts_nsec = local_clock();
 		cont.flags = flags;
 	}
@@ -1850,13 +1854,16 @@ static bool cont_add(int facility, int level, enum log_flags flags, const char *
 
 static size_t log_output(int facility, int level, enum log_flags lflags, const char *dict, size_t dictlen, char *text, size_t text_len)
 {
+	const u32 caller_id = printk_caller_id();
+
 	/*
 	 * If an earlier line was buffered, and we're a continuation
-	 * write from the same process, try to add it to the buffer.
+	 * write from the same context, try to add it to the buffer.
 	 */
 	if (cont.len) {
-		if (cont.owner == current && (lflags & LOG_CONT)) {
-			if (cont_add(facility, level, lflags, text, text_len))
+		if (cont.caller_id == caller_id && (lflags & LOG_CONT)) {
+			if (cont_add(caller_id, facility, level, lflags, text,
+				     text_len))
 				return text_len;
 		}
 		/* Otherwise, make sure it's flushed */
@@ -1869,12 +1876,14 @@ static size_t log_output(int facility, int level, enum log_flags lflags, const c
 
 	/* If it doesn't end in a newline, try to buffer the current line */
 	if (!(lflags & LOG_NEWLINE)) {
-		if (cont_add(facility, level, lflags, text, text_len))
+		if (cont_add(caller_id, facility, level, lflags, text,
+			     text_len))
 			return text_len;
 	}
 
 	/* Store it in the record log */
-	return log_store(facility, level, lflags, 0, dict, dictlen, text, text_len);
+	return log_store(caller_id, facility, level, lflags, 0, dict, dictlen,
+			 text, text_len);
 }
 
 /* Must be called under logbuf_lock. */
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] printk: Pass caller information to log_store().
  2019-02-16 10:59 [PATCH] printk: Pass caller information to log_store() Tetsuo Handa
@ 2019-02-20 12:18 ` Petr Mladek
  2019-02-21  2:23   ` Sergey Senozhatsky
  2019-02-21  2:22 ` Sergey Senozhatsky
  1 sibling, 1 reply; 6+ messages in thread
From: Petr Mladek @ 2019-02-20 12:18 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: Dmitry Vyukov, Sergey Senozhatsky, Steven Rostedt,
	Sergey Senozhatsky, linux-kernel

On Sat 2019-02-16 19:59:33, Tetsuo Handa wrote:
> When thread1 called printk() which did not end with '\n', and then thread2
> called printk() which ends with '\n' before thread1 calls pr_cont(), the
> partial content saved into "struct cont" is flushed by thread2 despite the
> partial content was generated by thread1. This leads to confusing output
> as if the partial content was generated by thread2. Fix this problem by
> passing correct caller information to log_store().
> 
> Before:
> 
>   [ T8533] abcdefghijklm
>   [ T8533] ABCDEFGHIJKLMNOPQRSTUVWXYZ
>   [ T8532] nopqrstuvwxyz
>   [ T8532] abcdefghijklmnopqrstuvwxyz
>   [ T8533] abcdefghijklm
>   [ T8533] ABCDEFGHIJKLMNOPQRSTUVWXYZ
>   [ T8532] nopqrstuvwxyz
> 
> After:
> 
>   [ T8507] abcdefghijklm
>   [ T8508] ABCDEFGHIJKLMNOPQRSTUVWXYZ
>   [ T8507] nopqrstuvwxyz
>   [ T8507] abcdefghijklmnopqrstuvwxyz
>   [ T8507] abcdefghijklm
>   [ T8508] ABCDEFGHIJKLMNOPQRSTUVWXYZ
>   [ T8507] nopqrstuvwxyz

Great catch!
 
> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>

The patch looks fine to me:

Reviewed-by: Petr Mladek <pmladek@suse.com>

There are just two cosmetic changes that I might do when pushing
the patch, see below.

> ---
>  kernel/printk/printk.c | 39 ++++++++++++++++++++++++---------------
>  1 file changed, 24 insertions(+), 15 deletions(-)
> 
> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index 33c0359..6547a88 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -1850,13 +1854,16 @@ static bool cont_add(int facility, int level, enum log_flags flags, const char *
>  
>  static size_t log_output(int facility, int level, enum log_flags lflags, const char *dict, size_t dictlen, char *text, size_t text_len)
>  {
> +	const u32 caller_id = printk_caller_id();
> +
>  	/*
>  	 * If an earlier line was buffered, and we're a continuation
> -	 * write from the same process, try to add it to the buffer.
> +	 * write from the same context, try to add it to the buffer.
>  	 */
>  	if (cont.len) {
> -		if (cont.owner == current && (lflags & LOG_CONT)) {
> -			if (cont_add(facility, level, lflags, text, text_len))
> +		if (cont.caller_id == caller_id && (lflags & LOG_CONT)) {
> +			if (cont_add(caller_id, facility, level, lflags, text,
> +				     text_len))

I think that this is the case when it is better to break the 80-character
per-line rule.

>  				return text_len;
>  		}
>  		/* Otherwise, make sure it's flushed */
> @@ -1869,12 +1876,14 @@ static size_t log_output(int facility, int level, enum log_flags lflags, const c
>  
>  	/* If it doesn't end in a newline, try to buffer the current line */
>  	if (!(lflags & LOG_NEWLINE)) {
> -		if (cont_add(facility, level, lflags, text, text_len))
> +		if (cont_add(caller_id, facility, level, lflags, text,
> +			     text_len))

Same here.

>  			return text_len;
>  	}
>  

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] printk: Pass caller information to log_store().
  2019-02-16 10:59 [PATCH] printk: Pass caller information to log_store() Tetsuo Handa
  2019-02-20 12:18 ` Petr Mladek
@ 2019-02-21  2:22 ` Sergey Senozhatsky
  2019-02-21  9:32   ` Petr Mladek
  1 sibling, 1 reply; 6+ messages in thread
From: Sergey Senozhatsky @ 2019-02-21  2:22 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: Dmitry Vyukov, Sergey Senozhatsky, Steven Rostedt,
	Sergey Senozhatsky, Petr Mladek, linux-kernel

On (02/16/19 19:59), Tetsuo Handa wrote:
>  /* insert record into the buffer, discard old ones, update heads */
> -static int log_store(int facility, int level,
> +static int log_store(u32 caller_id, int facility, int level,
>  		     enum log_flags flags, u64 ts_nsec,
>  		     const char *dict, u16 dict_len,
>  		     const char *text, u16 text_len)

I counted nine.

Dunno, we might want to just create a dummy struct and pass it
around, instead of doing

	vprintk_emit			(6 params)
	 vprintk_store			(6 params)
	  log_output			(7 params)
	   log_store			(9 params)

	-ss

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] printk: Pass caller information to log_store().
  2019-02-20 12:18 ` Petr Mladek
@ 2019-02-21  2:23   ` Sergey Senozhatsky
  2019-02-21 11:53     ` Petr Mladek
  0 siblings, 1 reply; 6+ messages in thread
From: Sergey Senozhatsky @ 2019-02-21  2:23 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Tetsuo Handa, Dmitry Vyukov, Sergey Senozhatsky, Steven Rostedt,
	Sergey Senozhatsky, linux-kernel

On (02/20/19 13:18), Petr Mladek wrote:
> > Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> 
> The patch looks fine to me:
> 
> Reviewed-by: Petr Mladek <pmladek@suse.com>

Reviewed-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>

	-ss

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] printk: Pass caller information to log_store().
  2019-02-21  2:22 ` Sergey Senozhatsky
@ 2019-02-21  9:32   ` Petr Mladek
  0 siblings, 0 replies; 6+ messages in thread
From: Petr Mladek @ 2019-02-21  9:32 UTC (permalink / raw)
  To: Sergey Senozhatsky
  Cc: Tetsuo Handa, Dmitry Vyukov, Steven Rostedt, Sergey Senozhatsky,
	linux-kernel

On Thu 2019-02-21 11:22:57, Sergey Senozhatsky wrote:
> On (02/16/19 19:59), Tetsuo Handa wrote:
> >  /* insert record into the buffer, discard old ones, update heads */
> > -static int log_store(int facility, int level,
> > +static int log_store(u32 caller_id, int facility, int level,
> >  		     enum log_flags flags, u64 ts_nsec,
> >  		     const char *dict, u16 dict_len,
> >  		     const char *text, u16 text_len)
> 
> I counted nine.
> 
> Dunno, we might want to just create a dummy struct and pass it
> around, instead of doing
> 
> 	vprintk_emit			(6 params)
> 	 vprintk_store			(6 params)
> 	  log_output			(7 params)
> 	   log_store			(9 params)

Yeah, it would make sense. I still dream about a bigger printk
code clean up. But let's see what comes from the realtime-related
patchset first.

Anyway, thanks for review.

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] printk: Pass caller information to log_store().
  2019-02-21  2:23   ` Sergey Senozhatsky
@ 2019-02-21 11:53     ` Petr Mladek
  0 siblings, 0 replies; 6+ messages in thread
From: Petr Mladek @ 2019-02-21 11:53 UTC (permalink / raw)
  To: Sergey Senozhatsky
  Cc: Tetsuo Handa, Dmitry Vyukov, Steven Rostedt, Sergey Senozhatsky,
	linux-kernel

On Thu 2019-02-21 11:23:41, Sergey Senozhatsky wrote:
> On (02/20/19 13:18), Petr Mladek wrote:
> > > Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> > 
> > The patch looks fine to me:
> > 
> > Reviewed-by: Petr Mladek <pmladek@suse.com>
> 
> Reviewed-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>

The patch has been pushed into printk.git, branch for-4.22
(aka for-5.1).

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-02-21 11:53 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-16 10:59 [PATCH] printk: Pass caller information to log_store() Tetsuo Handa
2019-02-20 12:18 ` Petr Mladek
2019-02-21  2:23   ` Sergey Senozhatsky
2019-02-21 11:53     ` Petr Mladek
2019-02-21  2:22 ` Sergey Senozhatsky
2019-02-21  9:32   ` Petr Mladek

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.