linux-trace-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH] ring-buffer: use READ_ONCE() to read cpu_buffer->commit_page in concurrent environment
@ 2024-02-29 12:32 linke
  0 siblings, 0 replies; 10+ messages in thread
From: linke @ 2024-02-29 12:32 UTC (permalink / raw)
  To: rostedt
  Cc: lilinke99, linux-kernel, linux-trace-kernel, mathieu.desnoyers,
	mhiramat

Hi Steven, sorry for the late reply.

> 
> Now the reason for the above READ_ONCE() is because the variables *are*
> going to be used again. We do *not* want the compiler to play any games
> with that.
> 

I don't think it is because the variables are going to be used again. 
Compiler optimizations barely do bad things in single thread programs. It
is because cpu_buffer->commit_page may change concurrently and should be
accessed atomically.

	/* Make sure commit page didn't change */
	curr_commit_page = READ_ONCE(cpu_buffer->commit_page);
	curr_commit_ts = READ_ONCE(curr_commit_page->page->time_stamp);

	/* If the commit page changed, then there's more data */
	if (curr_commit_page != commit_page ||
	    curr_commit_ts != commit_ts)
		return 0;

This code read cpu_buffer->commit_page and time_stamp again to check
whether commit page changed. It shows that cpu_buffer->commit_page and 
time_stamp may be changed by other threads.

        commit_page = cpu_buffer->commit_page;
        commit_ts = commit_page->page->time_stamp;

So the commit_page and time_stamp above is read while other threads may
change it. I think it is a data race if it is not atomic. Thus it is 
necessary to use READ_ONCE() here.


^ permalink raw reply	[flat|nested] 10+ messages in thread
* Re: [PATCH] ring-buffer: use READ_ONCE() to read cpu_buffer->commit_page in concurrent environment
@ 2024-03-01  5:37 linke
  2024-03-01 15:49 ` Steven Rostedt
  0 siblings, 1 reply; 10+ messages in thread
From: linke @ 2024-03-01  5:37 UTC (permalink / raw)
  To: rostedt
  Cc: lilinke99, linux-kernel, linux-trace-kernel, mathieu.desnoyers,
	mhiramat

> So basically you are worried about read-tearing?
> 
> That wasn't mentioned in the change log.

Yes. Sorry for making this confused, I am not very familiar with this and
still learning.

> Funny part is, if the above timestamp read did a tear, then this would
> definitely not match, and would return the correct value. That is, the
> buffer is not empty because the only way for this to get corrupted is if
> something is in the process of writing to it.

I agree with you here.

	commit = rb_page_commit(commit_page);

But if commit_page above is the result of a torn read, the commit field
read by rb_page_commit() may not represent a valid value. 

In this case, READ_ONCE() is only needed for the commit_page.


^ permalink raw reply	[flat|nested] 10+ messages in thread
* Re: [PATCH] ring-buffer: use READ_ONCE() to read cpu_buffer->commit_page in concurrent environment
@ 2024-02-29 12:32 linke
  2024-02-29 15:21 ` Steven Rostedt
  0 siblings, 1 reply; 10+ messages in thread
From: linke @ 2024-02-29 12:32 UTC (permalink / raw)
  To: rostedt
  Cc: lilinke99, linux-kernel, linux-trace-kernel, mathieu.desnoyers,
	mhiramat

Hi Steven, sorry for the late reply.

> 
> Now the reason for the above READ_ONCE() is because the variables *are*
> going to be used again. We do *not* want the compiler to play any games
> with that.
> 

I don't think it is because the variables are going to be used again. 
Compiler optimizations barely do bad things in single thread programs. It
is because cpu_buffer->commit_page may change concurrently and should be
accessed atomically.

	/* Make sure commit page didn't change */
	curr_commit_page = READ_ONCE(cpu_buffer->commit_page);
	curr_commit_ts = READ_ONCE(curr_commit_page->page->time_stamp);

	/* If the commit page changed, then there's more data */
	if (curr_commit_page != commit_page ||
	    curr_commit_ts != commit_ts)
		return 0;

This code read cpu_buffer->commit_page and time_stamp again to check
whether commit page changed. It shows that cpu_buffer->commit_page and 
time_stamp may be changed by other threads.

        commit_page = cpu_buffer->commit_page;
        commit_ts = commit_page->page->time_stamp;

So the commit_page and time_stamp above is read while other threads may
change it. I think it is a data race if it is not atomic. Thus it is 
necessary to use READ_ONCE() here.


^ permalink raw reply	[flat|nested] 10+ messages in thread
* [PATCH] ring-buffer: use READ_ONCE() to read cpu_buffer->commit_page in concurrent environment
@ 2024-02-25  3:05 linke li
  2024-02-25 20:03 ` Steven Rostedt
  0 siblings, 1 reply; 10+ messages in thread
From: linke li @ 2024-02-25  3:05 UTC (permalink / raw)
  Cc: lilinke99, Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
	linux-kernel, linux-trace-kernel

In function ring_buffer_iter_empty(), cpu_buffer->commit_page and
curr_commit_page->page->time_stamp is read using READ_ONCE() in 
line 4354, 4355

4354    curr_commit_page = READ_ONCE(cpu_buffer->commit_page);
4355    curr_commit_ts = READ_ONCE(curr_commit_page->page->time_stamp);

while they are read directly in line 4340, 4341

4340    commit_page = cpu_buffer->commit_page;
4341    commit_ts = commit_page->page->time_stamp;

There is patch similar to this. commit c1c0ce31b242 ("r8169: fix the KCSAN reported data-race in rtl_tx() while reading tp->cur_tx")
This patch find two read of same variable while one is protected, another
is not. And READ_ONCE() is added to protect.

Signed-off-by: linke li <lilinke99@qq.com>
---
 kernel/trace/ring_buffer.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 0699027b4f4c..eb3fa629b837 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -4337,8 +4337,8 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter)
 	cpu_buffer = iter->cpu_buffer;
 	reader = cpu_buffer->reader_page;
 	head_page = cpu_buffer->head_page;
-	commit_page = cpu_buffer->commit_page;
-	commit_ts = commit_page->page->time_stamp;
+	commit_page = READ_ONCE(cpu_buffer->commit_page);
+	commit_ts = READ_ONCE(commit_page->page->time_stamp);
 
 	/*
 	 * When the writer goes across pages, it issues a cmpxchg which
-- 
2.39.3 (Apple Git-145)


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

end of thread, other threads:[~2024-03-01 17:09 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-02-29 12:32 [PATCH] ring-buffer: use READ_ONCE() to read cpu_buffer->commit_page in concurrent environment linke
  -- strict thread matches above, loose matches on Subject: below --
2024-03-01  5:37 linke
2024-03-01 15:49 ` Steven Rostedt
2024-03-01 16:37   ` Mathieu Desnoyers
2024-03-01 17:11     ` Steven Rostedt
2024-02-29 12:32 linke
2024-02-29 15:21 ` Steven Rostedt
2024-02-25  3:05 linke li
2024-02-25 20:03 ` Steven Rostedt
2024-02-26 18:53   ` Steven Rostedt

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).