rcu: Update docs for rcu_access_pointer and rcu_dereference_protected
Update examples and lists of APIs to include these new primitives. 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 Cc: eric.dumazet@gmail.com LKML-Reference: <1270852752-25278-3-git-send-email-paulmck@linux.vnet.ibm.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
c08c68dd76
commit
50aec0024e
4 changed files with 57 additions and 21 deletions
|
@ -34,7 +34,7 @@ NMI handler.
|
||||||
cpu = smp_processor_id();
|
cpu = smp_processor_id();
|
||||||
++nmi_count(cpu);
|
++nmi_count(cpu);
|
||||||
|
|
||||||
if (!rcu_dereference(nmi_callback)(regs, cpu))
|
if (!rcu_dereference_sched(nmi_callback)(regs, cpu))
|
||||||
default_do_nmi(regs);
|
default_do_nmi(regs);
|
||||||
|
|
||||||
nmi_exit();
|
nmi_exit();
|
||||||
|
@ -47,12 +47,13 @@ function pointer. If this handler returns zero, do_nmi() invokes the
|
||||||
default_do_nmi() function to handle a machine-specific NMI. Finally,
|
default_do_nmi() function to handle a machine-specific NMI. Finally,
|
||||||
preemption is restored.
|
preemption is restored.
|
||||||
|
|
||||||
Strictly speaking, rcu_dereference() is not needed, since this code runs
|
In theory, rcu_dereference_sched() is not needed, since this code runs
|
||||||
only on i386, which does not need rcu_dereference() anyway. However,
|
only on i386, which in theory does not need rcu_dereference_sched()
|
||||||
it is a good documentation aid, particularly for anyone attempting to
|
anyway. However, in practice it is a good documentation aid, particularly
|
||||||
do something similar on Alpha.
|
for anyone attempting to do something similar on Alpha or on systems
|
||||||
|
with aggressive optimizing compilers.
|
||||||
|
|
||||||
Quick Quiz: Why might the rcu_dereference() be necessary on Alpha,
|
Quick Quiz: Why might the rcu_dereference_sched() be necessary on Alpha,
|
||||||
given that the code referenced by the pointer is read-only?
|
given that the code referenced by the pointer is read-only?
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,17 +100,21 @@ invoke irq_enter() and irq_exit() on NMI entry and exit, respectively.
|
||||||
|
|
||||||
Answer to Quick Quiz
|
Answer to Quick Quiz
|
||||||
|
|
||||||
Why might the rcu_dereference() be necessary on Alpha, given
|
Why might the rcu_dereference_sched() be necessary on Alpha, given
|
||||||
that the code referenced by the pointer is read-only?
|
that the code referenced by the pointer is read-only?
|
||||||
|
|
||||||
Answer: The caller to set_nmi_callback() might well have
|
Answer: The caller to set_nmi_callback() might well have
|
||||||
initialized some data that is to be used by the
|
initialized some data that is to be used by the new NMI
|
||||||
new NMI handler. In this case, the rcu_dereference()
|
handler. In this case, the rcu_dereference_sched() would
|
||||||
would be needed, because otherwise a CPU that received
|
be needed, because otherwise a CPU that received an NMI
|
||||||
an NMI just after the new handler was set might see
|
just after the new handler was set might see the pointer
|
||||||
the pointer to the new NMI handler, but the old
|
to the new NMI handler, but the old pre-initialized
|
||||||
pre-initialized version of the handler's data.
|
version of the handler's data.
|
||||||
|
|
||||||
More important, the rcu_dereference() makes it clear
|
This same sad story can happen on other CPUs when using
|
||||||
to someone reading the code that the pointer is being
|
a compiler with aggressive pointer-value speculation
|
||||||
protected by RCU.
|
optimizations.
|
||||||
|
|
||||||
|
More important, the rcu_dereference_sched() makes it
|
||||||
|
clear to someone reading the code that the pointer is
|
||||||
|
being protected by RCU-sched.
|
||||||
|
|
|
@ -260,7 +260,8 @@ over a rather long period of time, but improvements are always welcome!
|
||||||
The reason that it is permissible to use RCU list-traversal
|
The reason that it is permissible to use RCU list-traversal
|
||||||
primitives when the update-side lock is held is that doing so
|
primitives when the update-side lock is held is that doing so
|
||||||
can be quite helpful in reducing code bloat when common code is
|
can be quite helpful in reducing code bloat when common code is
|
||||||
shared between readers and updaters.
|
shared between readers and updaters. Additional primitives
|
||||||
|
are provided for this case, as discussed in lockdep.txt.
|
||||||
|
|
||||||
10. Conversely, if you are in an RCU read-side critical section,
|
10. Conversely, if you are in an RCU read-side critical section,
|
||||||
and you don't hold the appropriate update-side lock, you -must-
|
and you don't hold the appropriate update-side lock, you -must-
|
||||||
|
@ -344,8 +345,8 @@ over a rather long period of time, but improvements are always welcome!
|
||||||
requiring SRCU's read-side deadlock immunity or low read-side
|
requiring SRCU's read-side deadlock immunity or low read-side
|
||||||
realtime latency.
|
realtime latency.
|
||||||
|
|
||||||
Note that, rcu_assign_pointer() and rcu_dereference() relate to
|
Note that, rcu_assign_pointer() relates to SRCU just as they do
|
||||||
SRCU just as they do to other forms of RCU.
|
to other forms of RCU.
|
||||||
|
|
||||||
15. The whole point of call_rcu(), synchronize_rcu(), and friends
|
15. The whole point of call_rcu(), synchronize_rcu(), and friends
|
||||||
is to wait until all pre-existing readers have finished before
|
is to wait until all pre-existing readers have finished before
|
||||||
|
|
|
@ -32,9 +32,20 @@ checking of rcu_dereference() primitives:
|
||||||
srcu_dereference(p, sp):
|
srcu_dereference(p, sp):
|
||||||
Check for SRCU read-side critical section.
|
Check for SRCU read-side critical section.
|
||||||
rcu_dereference_check(p, c):
|
rcu_dereference_check(p, c):
|
||||||
Use explicit check expression "c".
|
Use explicit check expression "c". This is useful in
|
||||||
|
code that is invoked by both readers and updaters.
|
||||||
rcu_dereference_raw(p)
|
rcu_dereference_raw(p)
|
||||||
Don't check. (Use sparingly, if at all.)
|
Don't check. (Use sparingly, if at all.)
|
||||||
|
rcu_dereference_protected(p, c):
|
||||||
|
Use explicit check expression "c", and omit all barriers
|
||||||
|
and compiler constraints. This is useful when the data
|
||||||
|
structure cannot change, for example, in code that is
|
||||||
|
invoked only by updaters.
|
||||||
|
rcu_access_pointer(p):
|
||||||
|
Return the value of the pointer and omit all barriers,
|
||||||
|
but retain the compiler constraints that prevent duplicating
|
||||||
|
or coalescsing. This is useful when when testing the
|
||||||
|
value of the pointer itself, for example, against NULL.
|
||||||
|
|
||||||
The rcu_dereference_check() check expression can be any boolean
|
The rcu_dereference_check() check expression can be any boolean
|
||||||
expression, but would normally include one of the rcu_read_lock_held()
|
expression, but would normally include one of the rcu_read_lock_held()
|
||||||
|
@ -59,7 +70,20 @@ In case (1), the pointer is picked up in an RCU-safe manner for vanilla
|
||||||
RCU read-side critical sections, in case (2) the ->file_lock prevents
|
RCU read-side critical sections, in case (2) the ->file_lock prevents
|
||||||
any change from taking place, and finally, in case (3) the current task
|
any change from taking place, and finally, in case (3) the current task
|
||||||
is the only task accessing the file_struct, again preventing any change
|
is the only task accessing the file_struct, again preventing any change
|
||||||
from taking place.
|
from taking place. If the above statement was invoked only from updater
|
||||||
|
code, it could instead be written as follows:
|
||||||
|
|
||||||
|
file = rcu_dereference_protected(fdt->fd[fd],
|
||||||
|
lockdep_is_held(&files->file_lock) ||
|
||||||
|
atomic_read(&files->count) == 1);
|
||||||
|
|
||||||
|
This would verify cases #2 and #3 above, and furthermore lockdep would
|
||||||
|
complain if this was used in an RCU read-side critical section unless one
|
||||||
|
of these two cases held. Because rcu_dereference_protected() omits all
|
||||||
|
barriers and compiler constraints, it generates better code than do the
|
||||||
|
other flavors of rcu_dereference(). On the other hand, it is illegal
|
||||||
|
to use rcu_dereference_protected() if either the RCU-protected pointer
|
||||||
|
or the RCU-protected data that it points to can change concurrently.
|
||||||
|
|
||||||
There are currently only "universal" versions of the rcu_assign_pointer()
|
There are currently only "universal" versions of the rcu_assign_pointer()
|
||||||
and RCU list-/tree-traversal primitives, which do not (yet) check for
|
and RCU list-/tree-traversal primitives, which do not (yet) check for
|
||||||
|
|
|
@ -840,6 +840,12 @@ SRCU: Initialization/cleanup
|
||||||
init_srcu_struct
|
init_srcu_struct
|
||||||
cleanup_srcu_struct
|
cleanup_srcu_struct
|
||||||
|
|
||||||
|
All: lockdep-checked RCU-protected pointer access
|
||||||
|
|
||||||
|
rcu_dereference_check
|
||||||
|
rcu_dereference_protected
|
||||||
|
rcu_access_pointer
|
||||||
|
|
||||||
See the comment headers in the source code (or the docbook generated
|
See the comment headers in the source code (or the docbook generated
|
||||||
from them) for more information.
|
from them) for more information.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue