Re: [PATCH 1/2] rcu: add rcu_access_pointer and rcu_dereference_protect

Previous thread: [PATCH 2/2] NFS: Fix RCU warnings in nfs_inode_return_delegation_noreclaim() by David Howells on Wednesday, April 7, 2010 - 6:57 am. (1 message)

Next thread: [GIT PULL] arch/microblaze fixes for 2.6.34-rc4 by Michal Simek on Wednesday, April 7, 2010 - 7:05 am. (1 message)
From: David Howells
Date: Wednesday, April 7, 2010 - 6:57 am

From: Paul E. McKenney <paulmck@linux.vnet.ibm.com>

This patch adds variants of rcu_dereference() that handle situations
where the RCU-protected data structure cannot change, perhaps due to
our holding the update-side lock, or where the RCU-protected pointer is
only to be fetched, not dereferenced.

The new rcu_access_pointer() primitive is for the case where the pointer
is be fetch and not dereferenced.  This primitive may be used without
protection, RCU or otherwise, due to the fact that it uses ACCESS_ONCE().

The new rcu_dereference_protect() primitive is for the case where updates
are prevented, for example, due to holding the update-side lock.  This
primitive does neither ACCESS_ONCE() nor smp_read_barrier_depends(), so
can only be used when updates are somehow prevented.

Suggested-by: David Howells <dhowells@redhat.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 include/linux/rcupdate.h |   34 ++++++++++++++++++++++++++++++++++
 1 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 872a98e..a1b14b6 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -209,9 +209,43 @@ static inline int rcu_read_lock_sched_held(void)
 		rcu_dereference_raw(p); \
 	})
 
+/**
+ * rcu_access_pointer - fetch RCU pointer with no dereferencing
+ *
+ * Return the value of the specified RCU-protected pointer, but omit the
+ * smp_read_barrier_depends() and keep the ACCESS_ONCE().  This is useful
+ * when the value of this pointer is accessed, but the pointer is not
+ * dereferenced, for example, when testing an RCU-protected pointer against
+ * NULL.  This may also be used in cases where update-side locks prevent
+ * the value of the pointer from changing, but rcu_dereference_protect()
+ * is a lighter-weight primitive for this use case.
+ */
+#define rcu_access_pointer(p) \
+	({ \
+		ACCESS_ONCE(p); \
+	})
+
+/**
+ * ...
From: Eric Dumazet
Date: Wednesday, April 7, 2010 - 7:56 am

This is not the version Paul posted. 

Removing checks just to shutup warnings ?

All the point is to get lockdep assistance, and you throw it away.

We want to explicit the condition, so that RCU users can explicitly
state what protects their data.



--

From: Paul E. McKenney
Date: Wednesday, April 7, 2010 - 8:59 am

What Eric said!!!  ;-)

							Thanx, Paul
--

From: David Howells
Date: Wednesday, April 7, 2010 - 8:40 am

You've missed the point.

For rcu_access_pointer(), _nothing_ protects the data, not only that, we don't
care: we're only checking the pointer.

For rcu_dereference_protect[ed](), I don't see that the check helps.  You
don't need to be holding the RCU lock to call it, but you do need to hold all
the requisite locks required to exclude others modifying it.  That's a
precondition for calling this function, so is there any point in testing it
again?

For instance, consider the following pseudocode:

	do_something(struct foo *p)
	{
		struct bar *b;
		spin_lock(&foo->lock);
		b = rcu_dereference_protected(
			foo->bar, lockdep_is_held(&foo->lock));
		do_something_to_bar(b);
		spin_unlock(&foo->lock);
	}

is there any need for the condition?  Does lockdep_is_held() have any side
effects beyond those listed in the Documentation directory or on its attached
banner comments?


Furthermore, I think the condition in rcu_dereference_check() may well be
misused.  For instance, Paul suggested:

	cred = rcu_dereference_check(delegation->cred,
				     delegation->inode == NULL);

but if 'c' is supposed to be the locks that protect the data, is this a valid
check?

David
--

From: Eric Dumazet
Date: Wednesday, April 7, 2010 - 9:00 am

How can you state this ?

Thats pretty simple, "always true" is a fine condition.


If you dont see how the check can help, why dont you unset

Yes, this is what is needed to help to catch when a condition is not
met.

Of course, on trivial code like this one, its pretty obvious condition
will be always true.

In many cases, smp_processor_id() checks are obvious too, yet we perform
them. It can help us sometimes, because many developers forget the

'c' is not a lock. Its a condition.

You as the author of this code, decide of the condition to check.

You therefore can answer yourself to this question.

Example of non trivial check :

static void __sk_free(struct sock *sk)
{
...
filter = rcu_dereference_check(sk->sk_filter,
			       atomic_read(&sk->sk_wmem_alloc) == 0);
...
}

In this check, there is no lock held.


commit a898def29e4119bc01ebe7ca97423181f4c0ea2d
Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Date:   Mon Feb 22 17:04:49 2010 -0800

    net: Add checking to rcu_dereference() primitives
    
    Update rcu_dereference() primitives to use new lockdep-based
    checking. The rcu_dereference() in __in6_dev_get() may be
    protected either by rcu_read_lock() or RTNL, per Eric Dumazet.
    The rcu_dereference() in __sk_free() is protected by the fact
    that it is never reached if an update could change it.  Check
    for this by using rcu_dereference_check() to verify that the
    struct sock's ->sk_wmem_alloc counter is zero.
    
    Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
    Acked-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
    Cc: laijs@cn.fujitsu.com
    Cc: dipankar@in.ibm.com
    Cc: mathieu.desnoyers@polymtl.ca
    Cc: josh@joshtriplett.org
    Cc: dvhltc@us.ibm.com
    Cc: niv@us.ibm.com
    Cc: peterz@infradead.org
    Cc: rostedt@goodmis.org
    Cc: Valdis.Kletnieks@vt.edu
    Cc: dhowells@redhat.com
    ...
From: David Howells
Date: Wednesday, April 7, 2010 - 9:19 am

If the condition for rcu_access_pointer() is always "always true", then it's
redundant, right?  rcu_access_pointer() is for checking the pointer only, not
checking the payload that pointer might point to.  So, what condition are you
supposed to be checking?

Sorry, I meant the state of the relevant locking context.


what is the value of sk->sk_wmem_alloc to the lock context of sk->sk_filter?
Why would lockdep be interested in sk_wmem_alloc?

Surely, the assertion that the value of sk->sk_filter is related to
sk_wmem_alloc being 0 is independent of the need to dereference sk_filter for
RCU purposes.  So why are these being combined?

Why not:

	ASSERT(atomic_read(&sk->sk_wmem_alloc) == 0);
	filter = rcu_dereference(sk->sk_filter);

This is much clearer, and you're not combining an unrelated assertion with the
RCU dereference.

David
--

From: Eric Dumazet
Date: Wednesday, April 7, 2010 - 9:29 am

1) Because we want the check being done only when CONFIG_PROVE_RCU is
set.

2) Because rcu_dereference() default condition is : 'Am I owning
rcu_read_lock() or equivalent'. 
In this context, I am _not_ owning rcu lock, so we will trigger a
warning.


So this is best done as is :)

I personally find this very clear and clean, this is why I acked Paul
patch :)

If we were 100% sure testing sk_wmem_alloc is not necessary, we would
have put :

filter = rcu_dereference_check(sk->sk_filter, 1);



--

From: Eric Dumazet
Date: Wednesday, April 7, 2010 - 9:35 am

Because when sk->sk_filter is eventually written by some thread, this
thread _must_ own a reference on the socket, that is sk_wmem_alloc > 0

So when reading sk->sk_filter, the general condition is : 
- We own the rcu lock 
- But on the particular case of __sk_free(),
  we owned the very last reference to sk (we are going to kfree it), so
nobody can possibly change sk->sk_filter under us.



--

Previous thread: [PATCH 2/2] NFS: Fix RCU warnings in nfs_inode_return_delegation_noreclaim() by David Howells on Wednesday, April 7, 2010 - 6:57 am. (1 message)

Next thread: [GIT PULL] arch/microblaze fixes for 2.6.34-rc4 by Michal Simek on Wednesday, April 7, 2010 - 7:05 am. (1 message)