All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paolo Abeni <pabeni@redhat.com>
To: paulmck@linux.vnet.ibm.com
Cc: linux-kernel@vger.kernel.org,
	Josh Triplett <josh@joshtriplett.org>,
	Steven Rostedt <rostedt@goodmis.org>,
	"David S. Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	Hannes Frederic Sowa <hannes@stressinduktion.org>,
	netdev@vger.kernel.org
Subject: Re: [PATCH 0/4] RCU: introduce noref debug
Date: Mon, 09 Oct 2017 18:53:12 +0200	[thread overview]
Message-ID: <1507567992.21825.9.camel@redhat.com> (raw)
In-Reply-To: <20171006163414.GC3521@linux.vnet.ibm.com>

On Fri, 2017-10-06 at 09:34 -0700, Paul E. McKenney wrote:
> On Fri, Oct 06, 2017 at 05:10:09PM +0200, Paolo Abeni wrote:
> > Hi,
> > 
> > On Fri, 2017-10-06 at 06:34 -0700, Paul E. McKenney wrote:
> > > On Fri, Oct 06, 2017 at 02:57:45PM +0200, Paolo Abeni wrote:
> > > > The networking subsystem is currently using some kind of long-lived
> > > > RCU-protected, references to avoid the overhead of full book-keeping.
> > > > 
> > > > Such references - skb_dst() noref - are stored inside the skbs and can be
> > > > moved across relevant slices of the network stack, with the users
> > > > being in charge of properly clearing the relevant skb - or properly refcount
> > > > the related dst references - before the skb escapes the RCU section.
> > > > 
> > > > We currently don't have any deterministic debug infrastructure to check
> > > > the dst noref usages - and the introduction of others noref artifact is
> > > > currently under discussion.
> > > > 
> > > > This series tries to tackle the above introducing an RCU debug infrastructure
> > > > aimed at spotting incorrect noref pointer usage, in patch one. The
> > > > infrastructure is small and must be explicitly enabled via a newly introduced
> > > > build option.
> > > > 
> > > > Patch two uses such infrastructure to track dst noref usage in the networking
> > > > stack.
> > > > 
> > > > Patch 3 and 4 are bugfixes for small buglet found running this infrastructure
> > > > on basic scenarios.
> > 
> > Thank you for the prompt reply!
> > > 
> > > This patchset does not look like it handles rcu_read_lock() nesting.
> > > For example, given code like this:
> > > 
> > > 	void foo(void)
> > > 	{
> > > 		rcu_read_lock();
> > > 		rcu_track_noref(&key2, &noref2, true);
> > > 		do_something();
> > > 		rcu_track_noref(&key2, &noref2, false);
> > > 		rcu_read_unlock();
> > > 	}
> > > 
> > > 	void bar(void)
> > > 	{
> > > 		rcu_read_lock();
> > > 		rcu_track_noref(&key1, &noref1, true);
> > > 		do_something_more();
> > > 		foo();
> > > 		do_something_else();
> > > 		rcu_track_noref(&key1, &noref1, false);
> > > 		rcu_read_unlock();
> > > 	}
> > > 
> > > 	void grill(void)
> > > 	{
> > > 		foo();
> > > 	}
> > > 
> > > It looks like foo()'s rcu_read_unlock() will complain about key1.
> > > You could remove foo()'s rcu_read_lock() and rcu_read_unlock(), but
> > > that will break the call from grill().
> > 
> > Actually the code should cope correctly with your example; when foo()'s
> > rcu_read_unlock() is called, 'cache' contains:
> > 
> > { { &key1, &noref1, 1},  // ...
> > 
> > and when the related __rcu_check_noref() is invoked preempt_count() is
> > 2 - because the check is called before decreasing the preempt counter.
> > 
> > In the main loop inside __rcu_check_noref() we will hit always the
> > 'continue' statement because 'cache->store[i].nesting != nesting', so
> > no warn will be triggered.
> 
> You are right, it was too early, and my example wasn't correct.  How
> about this one?
> 
> 	void foo(void (*f)(struct s *sp), struct s **spp)
> 	{
> 		rcu_read_lock();
> 		rcu_track_noref(&key2, &noref2, true);
> 		f(spp);
> 		rcu_track_noref(&key2, &noref2, false);
> 		rcu_read_unlock();
> 	}
> 
> 	void barcb(struct s **spp)
> 	{
> 		*spp = &noref3;
> 		rcu_track_noref(&key3, *spp, true);
> 	}
> 
> 	void bar(void)
> 	{
> 		struct s *sp;
> 
> 		rcu_read_lock();
> 		rcu_track_noref(&key1, &noref1, true);
> 		do_something_more();
> 		foo(barcb, &sp);
> 		do_something_else(sp);
> 		rcu_track_noref(&key3, sp, false);
> 		rcu_track_noref(&key1, &noref1, false);
> 		rcu_read_unlock();
> 	}
> 
> 	void grillcb(struct s **spp)
> 	{
> 		*spp
> 	}
> 
> 	void grill(void)
> 	{
> 		foo();
> 	}

You are right: this will generate a splat, even if the code it safe.
The false positive can be avoided looking for leaked references only in
the outermost rcu unlook. I did a previous implementation performing
such check, but it emitted very generic splat so I tried to be more
strict. The latter choice allowed to find/do 3/4.

What about using save_stack_trace() in rcu_track_noref(, true) and
reporting such stack trace when the check in the outer most rcu fails?

the current strict/false-postive-prone check could be enabled under an
additional build flag.

> How does the user select the key argument?  It looks like someone
> can choose to just pass in NULL -- is that the intent, or am I confused
> about this as well?

The 'key' argument is intented to discriminate the scope of the same
noref dst attached to different skbs, which happens e.g. as a result of
as skb_dst_copy().

In a generic use case, it can be NULL, too.

> I am also concerned about false negatives when the user invokes
> rcu_track_noref(..., false) but then leaks the pointer anyway.  Or is
> there something you are doing that catches this that I am missing?

If the rcu_track_noref(..., false) is misplaced or missing, yes we can
have false negative. 

In the noref rcu use-case the rcu_track_noref(, false) call is/must be
placed side-by-side with the code clearing the the noref pointer, so
is/should be quite easy avoiding such mistakes.

Cheers,

Paolo

  reply	other threads:[~2017-10-09 16:53 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-10-06 12:57 [PATCH 0/4] RCU: introduce noref debug Paolo Abeni
2017-10-06 12:57 ` [PATCH 1/4] rcu: " Paolo Abeni
2017-10-06 14:13   ` Steven Rostedt
2017-10-06 12:57 ` [PATCH 2/4] net: use RCU noref infrastructure to track dst noref Paolo Abeni
2017-10-06 12:57 ` [PATCH 3/4] ipv4: drop unneeded and misleading RCU lock in ip_route_input_noref() Paolo Abeni
2017-10-06 12:57 ` [PATCH 4/4] tcp: avoid noref dst leak on input path Paolo Abeni
2017-10-06 14:37   ` Eric Dumazet
2017-10-06 15:21     ` Paolo Abeni
2017-10-06 15:32       ` Eric Dumazet
2017-10-06 13:34 ` [PATCH 0/4] RCU: introduce noref debug Paul E. McKenney
2017-10-06 15:10   ` Paolo Abeni
2017-10-06 16:34     ` Paul E. McKenney
2017-10-09 16:53       ` Paolo Abeni [this message]
2017-10-11  4:02         ` Paul E. McKenney
2017-10-11 14:50           ` Paolo Abeni
2017-10-11 15:45             ` Paul E. McKenney

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=1507567992.21825.9.camel@redhat.com \
    --to=pabeni@redhat.com \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=hannes@stressinduktion.org \
    --cc=josh@joshtriplett.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=paulmck@linux.vnet.ibm.com \
    --cc=rostedt@goodmis.org \
    /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.