All of lore.kernel.org
 help / color / mirror / Atom feed
From: Frederic Weisbecker <frederic@kernel.org>
To: joel@joelfernandes.org
Cc: linux-kernel@vger.kernel.org, Ingo Molnar <mingo@redhat.com>,
	Josh Triplett <josh@joshtriplett.org>,
	Lai Jiangshan <jiangshanlai@gmail.com>,
	Marco Elver <elver@google.com>,
	Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
	"Paul E. McKenney" <paulmck@kernel.org>,
	rcu@vger.kernel.org, Steven Rostedt <rostedt@goodmis.org>,
	"Uladzislau Rezki (Sony)" <urezki@gmail.com>,
	fweisbec@gmail.com, neeraj.iitr10@gmail.com,
	stern@rowland.harvard.edu
Subject: Re: [PATCH v7 6/6] rcu/segcblist: Add additional comments to explain smp_mb()
Date: Sat, 17 Oct 2020 15:29:54 +0200	[thread overview]
Message-ID: <20201017132954.GA15657@lothringen> (raw)
In-Reply-To: <20201017031941.GD4015033@google.com>

On Fri, Oct 16, 2020 at 11:19:41PM -0400, joel@joelfernandes.org wrote:
> On Fri, Oct 16, 2020 at 09:27:53PM -0400, joel@joelfernandes.org wrote:
> [..]
> > > > + *
> > > > + * Memory barrier is needed after adding to length for the case
> > > > + * where length transitions from 0 -> 1. This is because rcu_barrier()
> > > > + * should never miss an update to the length. So the update to length
> > > > + * has to be seen *before* any modifications to the segmented list. Otherwise a
> > > > + * race can happen.
> > > > + * P0 (what P1 sees)	P1
> > > > + * queue to list
> > > > + *                      rcu_barrier sees len as 0
> > > > + * set len = 1.
> > > > + *                      rcu_barrier does nothing.
> > > 
> > > So that would be:
> > > 
> > >       call_rcu()                    rcu_barrier()
> > >       --                            --
> > >       WRITE(len, len + 1)           l = READ(len)
> > >       smp_mb()                      if (!l)
> > >       queue                            check next CPU...
> > > 
> > > 
> > > But I still don't see against what it pairs in rcu_barrier.
> > 
> > Actually, for the second case maybe a similar reasoning can be applied
> > (control dependency) but I'm unable to come up with a litmus test.
> > In fact, now I'm wondering how is it possible that call_rcu() races with
> > rcu_barrier(). The module should ensure that no more call_rcu() should happen
> > before rcu_barrier() is called.
> > 
> > confused
> 
> So I made a litmus test to show that smp_mb() is needed also after the update
> to length. Basically, otherwise it is possible the callback will see garbage
> that the module cleanup/unload did.
> 
> C rcubarrier+ctrldep
> 
> (*
>  * Result: Never
>  *
>  * This litmus test shows that rcu_barrier (P1) prematurely
>  * returning by reading len 0 can cause issues if P0 does
>  * NOT have a smb_mb() after WRITE_ONCE(len, 1).
>  * mod_data == 2 means module was unloaded (so data is garbage).
>  *)
> 
> { int len = 0; int enq = 0; }
> 
> P0(int *len, int *mod_data, int *enq)
> {
> 	int r0;
> 
> 	WRITE_ONCE(*len, 1);
> 	smp_mb();		/* Needed! */
> 	WRITE_ONCE(*enq, 1);
> 
> 	r0 = READ_ONCE(*mod_data);
> }
> 
> P1(int *len, int *mod_data, int *enq)
> {
> 	int r0;
> 	int r1;
> 
> 	r1 = READ_ONCE(*enq);
> 
> 	// barrier Just for test purpose ("exists" clause) to force the..
> 	// ..rcu_barrier() to see enq before len
> 	smp_mb();		
> 	r0 = READ_ONCE(*len);
> 
> 	// implicit memory barrier due to conditional */
> 	if (r0 == 0)
> 		WRITE_ONCE(*mod_data, 2);
> }

I'm not sure what scenario P1 refers to in practice, and to what module?

> 
> // Did P0 read garbage?
> exists (0:r0=2 /\ 1:r0=0 /\ 1:r1=1)
> 


What also scares me is that in rcu_barrier():

	for_each_possible_cpu(cpu) {
		rdp = per_cpu_ptr(&rcu_data, cpu);
		if (cpu_is_offline(cpu) &&
		    !rcu_segcblist_is_offloaded(&rdp->cblist))
			continue;
		if (rcu_segcblist_n_cbs(&rdp->cblist) && cpu_online(cpu)) {
			rcu_barrier_trace(TPS("OnlineQ"), cpu,
					  rcu_state.barrier_sequence);
			smp_call_function_single(cpu, rcu_barrier_func, (void *)cpu, 1);
		} else if (rcu_segcblist_n_cbs(&rdp->cblist) &&
			   cpu_is_offline(cpu)) {
			rcu_barrier_trace(TPS("OfflineNoCBQ"), cpu,
					  rcu_state.barrier_sequence);
			local_irq_disable();
			rcu_barrier_func((void *)cpu);
			local_irq_enable();
		} else if (cpu_is_offline(cpu)) {
			rcu_barrier_trace(TPS("OfflineNoCBNoQ"), cpu,
					  rcu_state.barrier_sequence);
		} else {
			rcu_barrier_trace(TPS("OnlineNQ"), cpu,
					  rcu_state.barrier_sequence);
		}
	}

I can't find something that makes sure this isn't racy while reading
rcu_segcblist_n_cbs(&rdp->cblist).

I mean what I see sums up to this:

      CPU 0                                CPU 1
      rcu_barrier()                        call_rcu()/rcu_segcblist_enqueue()
      ------------                         --------

                                           smp_mb();
                                           inc_len();
					   smp_mb();
					   queue callback;
      for_each_possible_cpu(cpu)
          if (!rcu_segcblist_n_cbs(&rdp->cblist))
	      continue;

It looks possible for rcu_barrier() to believe there is no callback enqueued
and see rcu_segcblist_n_cbs(&rdp->cblist) == 0 here.

I'm very likely missing something obvious somewhere.

  reply	other threads:[~2020-10-17 13:29 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-15  0:22 [PATCH v7 0/6] Add support for length of each segment in the segcblist Joel Fernandes (Google)
2020-10-15  0:22 ` [PATCH v7 1/6] rcu/tree: Make rcu_do_batch count how many callbacks were executed Joel Fernandes (Google)
2020-10-15  0:22 ` [PATCH v7 2/6] rcu/segcblist: Add counters to segcblist datastructure Joel Fernandes (Google)
2020-10-15 12:21   ` Frederic Weisbecker
2020-10-17  1:31     ` joel
2020-10-21 15:33     ` joel
2020-10-21 21:53       ` Frederic Weisbecker
2020-10-21 22:31         ` Joel Fernandes
2020-10-18  8:23   ` [rcu/segcblist] e08055898f: WARNING:at_kernel/rcu/srcutree.c:#cleanup_srcu_struct kernel test robot
2020-10-21 14:40     ` joel
2020-10-15  0:22 ` [PATCH v7 3/6] rcu/trace: Add tracing for how segcb list changes Joel Fernandes (Google)
2020-10-15  0:22 ` [PATCH v7 4/6] rcu/segcblist: Remove useless rcupdate.h include Joel Fernandes (Google)
2020-10-15  0:23 ` [PATCH v7 5/6] rcu/tree: Remove redundant smp_mb() in rcu_do_batch Joel Fernandes (Google)
2020-10-15  0:23 ` [PATCH v7 6/6] rcu/segcblist: Add additional comments to explain smp_mb() Joel Fernandes (Google)
2020-10-15 13:35   ` Frederic Weisbecker
2020-10-17  1:27     ` joel
2020-10-17  3:19       ` joel
2020-10-17 13:29         ` Frederic Weisbecker [this message]
2020-10-18  0:35           ` joel
2020-10-19 12:37             ` Frederic Weisbecker
2020-10-21 18:57               ` Joel Fernandes
2020-10-21 21:16                 ` Frederic Weisbecker
2020-10-17 20:24         ` Alan Stern
2020-10-18 20:45           ` Joel Fernandes
2020-10-18 21:15             ` Alan Stern
2020-10-17 14:31       ` Alan Stern
2020-10-18 20:16         ` Joel Fernandes

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=20201017132954.GA15657@lothringen \
    --to=frederic@kernel.org \
    --cc=elver@google.com \
    --cc=fweisbec@gmail.com \
    --cc=jiangshanlai@gmail.com \
    --cc=joel@joelfernandes.org \
    --cc=josh@joshtriplett.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=mingo@redhat.com \
    --cc=neeraj.iitr10@gmail.com \
    --cc=paulmck@kernel.org \
    --cc=rcu@vger.kernel.org \
    --cc=rostedt@goodmis.org \
    --cc=stern@rowland.harvard.edu \
    --cc=urezki@gmail.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 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.