rcu: Improve rcu_assign_pointer() and RCU_INIT_POINTER() documentation
The differences between rcu_assign_pointer() and RCU_INIT_POINTER() are subtle, and it is easy to use the the cheaper RCU_INIT_POINTER() when the more-expensive rcu_assign_pointer() should have been used instead. The consequences of this mistake are quite severe. This commit therefore carefully lays out the situations in which it it permissible to use RCU_INIT_POINTER(). Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
This commit is contained in:
parent
d322f45cee
commit
6846c0c540
@ -754,11 +754,18 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
|
|||||||
* any prior initialization. Returns the value assigned.
|
* any prior initialization. Returns the value assigned.
|
||||||
*
|
*
|
||||||
* Inserts memory barriers on architectures that require them
|
* Inserts memory barriers on architectures that require them
|
||||||
* (pretty much all of them other than x86), and also prevents
|
* (which is most of them), and also prevents the compiler from
|
||||||
* the compiler from reordering the code that initializes the
|
* reordering the code that initializes the structure after the pointer
|
||||||
* structure after the pointer assignment. More importantly, this
|
* assignment. More importantly, this call documents which pointers
|
||||||
* call documents which pointers will be dereferenced by RCU read-side
|
* will be dereferenced by RCU read-side code.
|
||||||
* code.
|
*
|
||||||
|
* In some special cases, you may use RCU_INIT_POINTER() instead
|
||||||
|
* of rcu_assign_pointer(). RCU_INIT_POINTER() is a bit faster due
|
||||||
|
* to the fact that it does not constrain either the CPU or the compiler.
|
||||||
|
* That said, using RCU_INIT_POINTER() when you should have used
|
||||||
|
* rcu_assign_pointer() is a very bad thing that results in
|
||||||
|
* impossible-to-diagnose memory corruption. So please be careful.
|
||||||
|
* See the RCU_INIT_POINTER() comment header for details.
|
||||||
*/
|
*/
|
||||||
#define rcu_assign_pointer(p, v) \
|
#define rcu_assign_pointer(p, v) \
|
||||||
__rcu_assign_pointer((p), (v), __rcu)
|
__rcu_assign_pointer((p), (v), __rcu)
|
||||||
@ -766,8 +773,34 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
|
|||||||
/**
|
/**
|
||||||
* RCU_INIT_POINTER() - initialize an RCU protected pointer
|
* RCU_INIT_POINTER() - initialize an RCU protected pointer
|
||||||
*
|
*
|
||||||
* Initialize an RCU-protected pointer in such a way to avoid RCU-lockdep
|
* Initialize an RCU-protected pointer in special cases where readers
|
||||||
* splats.
|
* do not need ordering constraints on the CPU or the compiler. These
|
||||||
|
* special cases are:
|
||||||
|
*
|
||||||
|
* 1. This use of RCU_INIT_POINTER() is NULLing out the pointer -or-
|
||||||
|
* 2. The caller has taken whatever steps are required to prevent
|
||||||
|
* RCU readers from concurrently accessing this pointer -or-
|
||||||
|
* 3. The referenced data structure has already been exposed to
|
||||||
|
* readers either at compile time or via rcu_assign_pointer() -and-
|
||||||
|
* a. You have not made -any- reader-visible changes to
|
||||||
|
* this structure since then -or-
|
||||||
|
* b. It is OK for readers accessing this structure from its
|
||||||
|
* new location to see the old state of the structure. (For
|
||||||
|
* example, the changes were to statistical counters or to
|
||||||
|
* other state where exact synchronization is not required.)
|
||||||
|
*
|
||||||
|
* Failure to follow these rules governing use of RCU_INIT_POINTER() will
|
||||||
|
* result in impossible-to-diagnose memory corruption. As in the structures
|
||||||
|
* will look OK in crash dumps, but any concurrent RCU readers might
|
||||||
|
* see pre-initialized values of the referenced data structure. So
|
||||||
|
* please be very careful how you use RCU_INIT_POINTER()!!!
|
||||||
|
*
|
||||||
|
* If you are creating an RCU-protected linked structure that is accessed
|
||||||
|
* by a single external-to-structure RCU-protected pointer, then you may
|
||||||
|
* use RCU_INIT_POINTER() to initialize the internal RCU-protected
|
||||||
|
* pointers, but you must use rcu_assign_pointer() to initialize the
|
||||||
|
* external-to-structure pointer -after- you have completely initialized
|
||||||
|
* the reader-accessible portions of the linked structure.
|
||||||
*/
|
*/
|
||||||
#define RCU_INIT_POINTER(p, v) \
|
#define RCU_INIT_POINTER(p, v) \
|
||||||
p = (typeof(*v) __force __rcu *)(v)
|
p = (typeof(*v) __force __rcu *)(v)
|
||||||
|
Loading…
Reference in New Issue
Block a user