doc: Remove obsolete RCU update functions from RCU documentation
Now that synchronize_rcu_bh, synchronize_rcu_bh_expedited, call_rcu_bh, rcu_barrier_bh, synchronize_sched, synchronize_sched_expedited, call_rcu_sched, rcu_barrier_sched, get_state_synchronize_sched, and cond_synchronize_sched are obsolete, let's remove them from the documentation aside from a small historical section. Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
This commit is contained in:
parent
9e98c678c2
commit
4fea6ef0b2
|
@ -155,8 +155,7 @@ keeping lock contention under control at all tree levels regardless
|
||||||
of the level of loading on the system.
|
of the level of loading on the system.
|
||||||
|
|
||||||
</p><p>RCU updaters wait for normal grace periods by registering
|
</p><p>RCU updaters wait for normal grace periods by registering
|
||||||
RCU callbacks, either directly via <tt>call_rcu()</tt> and
|
RCU callbacks, either directly via <tt>call_rcu()</tt>
|
||||||
friends (namely <tt>call_rcu_bh()</tt> and <tt>call_rcu_sched()</tt>),
|
|
||||||
or indirectly via <tt>synchronize_rcu()</tt> and friends.
|
or indirectly via <tt>synchronize_rcu()</tt> and friends.
|
||||||
RCU callbacks are represented by <tt>rcu_head</tt> structures,
|
RCU callbacks are represented by <tt>rcu_head</tt> structures,
|
||||||
which are queued on <tt>rcu_data</tt> structures while they are
|
which are queued on <tt>rcu_data</tt> structures while they are
|
||||||
|
|
|
@ -56,6 +56,7 @@ sections.
|
||||||
RCU-preempt Expedited Grace Periods</a></h2>
|
RCU-preempt Expedited Grace Periods</a></h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
<tt>CONFIG_PREEMPT=y</tt> kernels implement RCU-preempt.
|
||||||
The overall flow of the handling of a given CPU by an RCU-preempt
|
The overall flow of the handling of a given CPU by an RCU-preempt
|
||||||
expedited grace period is shown in the following diagram:
|
expedited grace period is shown in the following diagram:
|
||||||
|
|
||||||
|
@ -139,6 +140,7 @@ or offline, among other things.
|
||||||
RCU-sched Expedited Grace Periods</a></h2>
|
RCU-sched Expedited Grace Periods</a></h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
<tt>CONFIG_PREEMPT=n</tt> kernels implement RCU-sched.
|
||||||
The overall flow of the handling of a given CPU by an RCU-sched
|
The overall flow of the handling of a given CPU by an RCU-sched
|
||||||
expedited grace period is shown in the following diagram:
|
expedited grace period is shown in the following diagram:
|
||||||
|
|
||||||
|
@ -146,7 +148,7 @@ expedited grace period is shown in the following diagram:
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
As with RCU-preempt, RCU-sched's
|
As with RCU-preempt, RCU-sched's
|
||||||
<tt>synchronize_sched_expedited()</tt> ignores offline and
|
<tt>synchronize_rcu_expedited()</tt> ignores offline and
|
||||||
idle CPUs, again because they are in remotely detectable
|
idle CPUs, again because they are in remotely detectable
|
||||||
quiescent states.
|
quiescent states.
|
||||||
However, because the
|
However, because the
|
||||||
|
|
|
@ -34,12 +34,11 @@ Similarly, any code that happens before the beginning of a given RCU grace
|
||||||
period is guaranteed to see the effects of all accesses following the end
|
period is guaranteed to see the effects of all accesses following the end
|
||||||
of that grace period that are within RCU read-side critical sections.
|
of that grace period that are within RCU read-side critical sections.
|
||||||
|
|
||||||
<p>This guarantee is particularly pervasive for <tt>synchronize_sched()</tt>,
|
<p>Note well that RCU-sched read-side critical sections include any region
|
||||||
for which RCU-sched read-side critical sections include any region
|
|
||||||
of code for which preemption is disabled.
|
of code for which preemption is disabled.
|
||||||
Given that each individual machine instruction can be thought of as
|
Given that each individual machine instruction can be thought of as
|
||||||
an extremely small region of preemption-disabled code, one can think of
|
an extremely small region of preemption-disabled code, one can think of
|
||||||
<tt>synchronize_sched()</tt> as <tt>smp_mb()</tt> on steroids.
|
<tt>synchronize_rcu()</tt> as <tt>smp_mb()</tt> on steroids.
|
||||||
|
|
||||||
<p>RCU updaters use this guarantee by splitting their updates into
|
<p>RCU updaters use this guarantee by splitting their updates into
|
||||||
two phases, one of which is executed before the grace period and
|
two phases, one of which is executed before the grace period and
|
||||||
|
|
|
@ -81,18 +81,19 @@ currently executing on some other CPU. We therefore cannot free
|
||||||
up any data structures used by the old NMI handler until execution
|
up any data structures used by the old NMI handler until execution
|
||||||
of it completes on all other CPUs.
|
of it completes on all other CPUs.
|
||||||
|
|
||||||
One way to accomplish this is via synchronize_sched(), perhaps as
|
One way to accomplish this is via synchronize_rcu(), perhaps as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
unset_nmi_callback();
|
unset_nmi_callback();
|
||||||
synchronize_sched();
|
synchronize_rcu();
|
||||||
kfree(my_nmi_data);
|
kfree(my_nmi_data);
|
||||||
|
|
||||||
This works because synchronize_sched() blocks until all CPUs complete
|
This works because (as of v4.20) synchronize_rcu() blocks until all
|
||||||
any preemption-disabled segments of code that they were executing.
|
CPUs complete any preemption-disabled segments of code that they were
|
||||||
Since NMI handlers disable preemption, synchronize_sched() is guaranteed
|
executing.
|
||||||
|
Since NMI handlers disable preemption, synchronize_rcu() is guaranteed
|
||||||
not to return until all ongoing NMI handlers exit. It is therefore safe
|
not to return until all ongoing NMI handlers exit. It is therefore safe
|
||||||
to free up the handler's data as soon as synchronize_sched() returns.
|
to free up the handler's data as soon as synchronize_rcu() returns.
|
||||||
|
|
||||||
Important note: for this to work, the architecture in question must
|
Important note: for this to work, the architecture in question must
|
||||||
invoke nmi_enter() and nmi_exit() on NMI entry and exit, respectively.
|
invoke nmi_enter() and nmi_exit() on NMI entry and exit, respectively.
|
||||||
|
|
|
@ -86,10 +86,8 @@ even on a UP system. So do not do it! Even on a UP system, the RCU
|
||||||
infrastructure -must- respect grace periods, and -must- invoke callbacks
|
infrastructure -must- respect grace periods, and -must- invoke callbacks
|
||||||
from a known environment in which no locks are held.
|
from a known environment in which no locks are held.
|
||||||
|
|
||||||
It -is- safe for synchronize_sched() and synchronize_rcu_bh() to return
|
Note that it -is- safe for synchronize_rcu() to return immediately on
|
||||||
immediately on an UP system. It is also safe for synchronize_rcu()
|
UP systems, including !PREEMPT SMP builds running on UP systems.
|
||||||
to return immediately on UP systems, except when running preemptable
|
|
||||||
RCU.
|
|
||||||
|
|
||||||
Quick Quiz #3: Why can't synchronize_rcu() return immediately on
|
Quick Quiz #3: Why can't synchronize_rcu() return immediately on
|
||||||
UP systems running preemptable RCU?
|
UP systems running preemptable RCU?
|
||||||
|
|
|
@ -182,16 +182,13 @@ over a rather long period of time, but improvements are always welcome!
|
||||||
when publicizing a pointer to a structure that can
|
when publicizing a pointer to a structure that can
|
||||||
be traversed by an RCU read-side critical section.
|
be traversed by an RCU read-side critical section.
|
||||||
|
|
||||||
5. If call_rcu(), or a related primitive such as call_rcu_bh(),
|
5. If call_rcu() or call_srcu() is used, the callback function will
|
||||||
call_rcu_sched(), or call_srcu() is used, the callback function
|
be called from softirq context. In particular, it cannot block.
|
||||||
will be called from softirq context. In particular, it cannot
|
|
||||||
block.
|
|
||||||
|
|
||||||
6. Since synchronize_rcu() can block, it cannot be called from
|
6. Since synchronize_rcu() can block, it cannot be called
|
||||||
any sort of irq context. The same rule applies for
|
from any sort of irq context. The same rule applies
|
||||||
synchronize_rcu_bh(), synchronize_sched(), synchronize_srcu(),
|
for synchronize_srcu(), synchronize_rcu_expedited(), and
|
||||||
synchronize_rcu_expedited(), synchronize_rcu_bh_expedited(),
|
synchronize_srcu_expedited().
|
||||||
synchronize_sched_expedite(), and synchronize_srcu_expedited().
|
|
||||||
|
|
||||||
The expedited forms of these primitives have the same semantics
|
The expedited forms of these primitives have the same semantics
|
||||||
as the non-expedited forms, but expediting is both expensive and
|
as the non-expedited forms, but expediting is both expensive and
|
||||||
|
@ -212,20 +209,20 @@ over a rather long period of time, but improvements are always welcome!
|
||||||
of the system, especially to real-time workloads running on
|
of the system, especially to real-time workloads running on
|
||||||
the rest of the system.
|
the rest of the system.
|
||||||
|
|
||||||
7. If the updater uses call_rcu() or synchronize_rcu(), then the
|
7. As of v4.20, a given kernel implements only one RCU flavor,
|
||||||
corresponding readers must use rcu_read_lock() and
|
which is RCU-sched for PREEMPT=n and RCU-preempt for PREEMPT=y.
|
||||||
rcu_read_unlock(). If the updater uses call_rcu_bh() or
|
If the updater uses call_rcu() or synchronize_rcu(),
|
||||||
synchronize_rcu_bh(), then the corresponding readers must
|
then the corresponding readers my use rcu_read_lock() and
|
||||||
use rcu_read_lock_bh() and rcu_read_unlock_bh(). If the
|
rcu_read_unlock(), rcu_read_lock_bh() and rcu_read_unlock_bh(),
|
||||||
updater uses call_rcu_sched() or synchronize_sched(), then
|
or any pair of primitives that disables and re-enables preemption,
|
||||||
the corresponding readers must disable preemption, possibly
|
for example, rcu_read_lock_sched() and rcu_read_unlock_sched().
|
||||||
by calling rcu_read_lock_sched() and rcu_read_unlock_sched().
|
If the updater uses synchronize_srcu() or call_srcu(),
|
||||||
If the updater uses synchronize_srcu() or call_srcu(), then
|
then the corresponding readers must use srcu_read_lock() and
|
||||||
the corresponding readers must use srcu_read_lock() and
|
|
||||||
srcu_read_unlock(), and with the same srcu_struct. The rules for
|
srcu_read_unlock(), and with the same srcu_struct. The rules for
|
||||||
the expedited primitives are the same as for their non-expedited
|
the expedited primitives are the same as for their non-expedited
|
||||||
counterparts. Mixing things up will result in confusion and
|
counterparts. Mixing things up will result in confusion and
|
||||||
broken kernels.
|
broken kernels, and has even resulted in an exploitable security
|
||||||
|
issue.
|
||||||
|
|
||||||
One exception to this rule: rcu_read_lock() and rcu_read_unlock()
|
One exception to this rule: rcu_read_lock() and rcu_read_unlock()
|
||||||
may be substituted for rcu_read_lock_bh() and rcu_read_unlock_bh()
|
may be substituted for rcu_read_lock_bh() and rcu_read_unlock_bh()
|
||||||
|
@ -288,8 +285,7 @@ over a rather long period of time, but improvements are always welcome!
|
||||||
d. Periodically invoke synchronize_rcu(), permitting a limited
|
d. Periodically invoke synchronize_rcu(), permitting a limited
|
||||||
number of updates per grace period.
|
number of updates per grace period.
|
||||||
|
|
||||||
The same cautions apply to call_rcu_bh(), call_rcu_sched(),
|
The same cautions apply to call_srcu() and kfree_rcu().
|
||||||
call_srcu(), and kfree_rcu().
|
|
||||||
|
|
||||||
Note that although these primitives do take action to avoid memory
|
Note that although these primitives do take action to avoid memory
|
||||||
exhaustion when any given CPU has too many callbacks, a determined
|
exhaustion when any given CPU has too many callbacks, a determined
|
||||||
|
@ -336,12 +332,12 @@ over a rather long period of time, but improvements are always welcome!
|
||||||
to safely access and/or modify that data structure.
|
to safely access and/or modify that data structure.
|
||||||
|
|
||||||
RCU callbacks are -usually- executed on the same CPU that executed
|
RCU callbacks are -usually- executed on the same CPU that executed
|
||||||
the corresponding call_rcu(), call_rcu_bh(), or call_rcu_sched(),
|
the corresponding call_rcu() or call_srcu(). but are by -no-
|
||||||
but are by -no- means guaranteed to be. For example, if a given
|
means guaranteed to be. For example, if a given CPU goes offline
|
||||||
CPU goes offline while having an RCU callback pending, then that
|
while having an RCU callback pending, then that RCU callback
|
||||||
RCU callback will execute on some surviving CPU. (If this was
|
will execute on some surviving CPU. (If this was not the case,
|
||||||
not the case, a self-spawning RCU callback would prevent the
|
a self-spawning RCU callback would prevent the victim CPU from
|
||||||
victim CPU from ever going offline.)
|
ever going offline.)
|
||||||
|
|
||||||
13. Unlike other forms of RCU, it -is- permissible to block in an
|
13. Unlike other forms of RCU, it -is- permissible to block in an
|
||||||
SRCU read-side critical section (demarked by srcu_read_lock()
|
SRCU read-side critical section (demarked by srcu_read_lock()
|
||||||
|
@ -381,8 +377,7 @@ over a rather long period of time, but improvements are always welcome!
|
||||||
|
|
||||||
SRCU's expedited primitive (synchronize_srcu_expedited())
|
SRCU's expedited primitive (synchronize_srcu_expedited())
|
||||||
never sends IPIs to other CPUs, so it is easier on
|
never sends IPIs to other CPUs, so it is easier on
|
||||||
real-time workloads than is synchronize_rcu_expedited(),
|
real-time workloads than is synchronize_rcu_expedited().
|
||||||
synchronize_rcu_bh_expedited() or synchronize_sched_expedited().
|
|
||||||
|
|
||||||
Note that rcu_dereference() and rcu_assign_pointer() relate to
|
Note that rcu_dereference() and rcu_assign_pointer() relate to
|
||||||
SRCU just as they do to other forms of RCU.
|
SRCU just as they do to other forms of RCU.
|
||||||
|
@ -428,22 +423,19 @@ over a rather long period of time, but improvements are always welcome!
|
||||||
These debugging aids can help you find problems that are
|
These debugging aids can help you find problems that are
|
||||||
otherwise extremely difficult to spot.
|
otherwise extremely difficult to spot.
|
||||||
|
|
||||||
17. If you register a callback using call_rcu(), call_rcu_bh(),
|
17. If you register a callback using call_rcu() or call_srcu(),
|
||||||
call_rcu_sched(), or call_srcu(), and pass in a function defined
|
and pass in a function defined within a loadable module,
|
||||||
within a loadable module, then it in necessary to wait for
|
then it in necessary to wait for all pending callbacks to
|
||||||
all pending callbacks to be invoked after the last invocation
|
be invoked after the last invocation and before unloading
|
||||||
and before unloading that module. Note that it is absolutely
|
that module. Note that it is absolutely -not- sufficient to
|
||||||
-not- sufficient to wait for a grace period! The current (say)
|
wait for a grace period! The current (say) synchronize_rcu()
|
||||||
synchronize_rcu() implementation waits only for all previous
|
implementation waits only for all previous callbacks registered
|
||||||
callbacks registered on the CPU that synchronize_rcu() is running
|
on the CPU that synchronize_rcu() is running on, but it is -not-
|
||||||
on, but it is -not- guaranteed to wait for callbacks registered
|
guaranteed to wait for callbacks registered on other CPUs.
|
||||||
on other CPUs.
|
|
||||||
|
|
||||||
You instead need to use one of the barrier functions:
|
You instead need to use one of the barrier functions:
|
||||||
|
|
||||||
o call_rcu() -> rcu_barrier()
|
o call_rcu() -> rcu_barrier()
|
||||||
o call_rcu_bh() -> rcu_barrier()
|
|
||||||
o call_rcu_sched() -> rcu_barrier()
|
|
||||||
o call_srcu() -> srcu_barrier()
|
o call_srcu() -> srcu_barrier()
|
||||||
|
|
||||||
However, these barrier functions are absolutely -not- guaranteed
|
However, these barrier functions are absolutely -not- guaranteed
|
||||||
|
|
|
@ -52,10 +52,10 @@ o If I am running on a uniprocessor kernel, which can only do one
|
||||||
o How can I see where RCU is currently used in the Linux kernel?
|
o How can I see where RCU is currently used in the Linux kernel?
|
||||||
|
|
||||||
Search for "rcu_read_lock", "rcu_read_unlock", "call_rcu",
|
Search for "rcu_read_lock", "rcu_read_unlock", "call_rcu",
|
||||||
"rcu_read_lock_bh", "rcu_read_unlock_bh", "call_rcu_bh",
|
"rcu_read_lock_bh", "rcu_read_unlock_bh", "srcu_read_lock",
|
||||||
"srcu_read_lock", "srcu_read_unlock", "synchronize_rcu",
|
"srcu_read_unlock", "synchronize_rcu", "synchronize_net",
|
||||||
"synchronize_net", "synchronize_srcu", and the other RCU
|
"synchronize_srcu", and the other RCU primitives. Or grab one
|
||||||
primitives. Or grab one of the cscope databases from:
|
of the cscope databases from:
|
||||||
|
|
||||||
http://www.rdrop.com/users/paulmck/RCU/linuxusage/rculocktab.html
|
http://www.rdrop.com/users/paulmck/RCU/linuxusage/rculocktab.html
|
||||||
|
|
||||||
|
|
|
@ -83,16 +83,15 @@ Pseudo-code using rcu_barrier() is as follows:
|
||||||
2. Execute rcu_barrier().
|
2. Execute rcu_barrier().
|
||||||
3. Allow the module to be unloaded.
|
3. Allow the module to be unloaded.
|
||||||
|
|
||||||
There are also rcu_barrier_bh(), rcu_barrier_sched(), and srcu_barrier()
|
There is also an srcu_barrier() function for SRCU, and you of course
|
||||||
functions for the other flavors of RCU, and you of course must match
|
must match the flavor of rcu_barrier() with that of call_rcu(). If your
|
||||||
the flavor of rcu_barrier() with that of call_rcu(). If your module
|
module uses multiple flavors of call_rcu(), then it must also use multiple
|
||||||
uses multiple flavors of call_rcu(), then it must also use multiple
|
|
||||||
flavors of rcu_barrier() when unloading that module. For example, if
|
flavors of rcu_barrier() when unloading that module. For example, if
|
||||||
it uses call_rcu_bh(), call_srcu() on srcu_struct_1, and call_srcu() on
|
it uses call_rcu(), call_srcu() on srcu_struct_1, and call_srcu() on
|
||||||
srcu_struct_2(), then the following three lines of code will be required
|
srcu_struct_2(), then the following three lines of code will be required
|
||||||
when unloading:
|
when unloading:
|
||||||
|
|
||||||
1 rcu_barrier_bh();
|
1 rcu_barrier();
|
||||||
2 srcu_barrier(&srcu_struct_1);
|
2 srcu_barrier(&srcu_struct_1);
|
||||||
3 srcu_barrier(&srcu_struct_2);
|
3 srcu_barrier(&srcu_struct_2);
|
||||||
|
|
||||||
|
@ -185,12 +184,12 @@ module invokes call_rcu() from timers, you will need to first cancel all
|
||||||
the timers, and only then invoke rcu_barrier() to wait for any remaining
|
the timers, and only then invoke rcu_barrier() to wait for any remaining
|
||||||
RCU callbacks to complete.
|
RCU callbacks to complete.
|
||||||
|
|
||||||
Of course, if you module uses call_rcu_bh(), you will need to invoke
|
Of course, if you module uses call_rcu(), you will need to invoke
|
||||||
rcu_barrier_bh() before unloading. Similarly, if your module uses
|
rcu_barrier() before unloading. Similarly, if your module uses
|
||||||
call_rcu_sched(), you will need to invoke rcu_barrier_sched() before
|
call_srcu(), you will need to invoke srcu_barrier() before unloading,
|
||||||
unloading. If your module uses call_rcu(), call_rcu_bh(), -and-
|
and on the same srcu_struct structure. If your module uses call_rcu()
|
||||||
call_rcu_sched(), then you will need to invoke each of rcu_barrier(),
|
-and- call_srcu(), then you will need to invoke rcu_barrier() -and-
|
||||||
rcu_barrier_bh(), and rcu_barrier_sched().
|
srcu_barrier().
|
||||||
|
|
||||||
|
|
||||||
Implementing rcu_barrier()
|
Implementing rcu_barrier()
|
||||||
|
@ -223,8 +222,8 @@ shown below. Note that the final "1" in on_each_cpu()'s argument list
|
||||||
ensures that all the calls to rcu_barrier_func() will have completed
|
ensures that all the calls to rcu_barrier_func() will have completed
|
||||||
before on_each_cpu() returns. Line 9 then waits for the completion.
|
before on_each_cpu() returns. Line 9 then waits for the completion.
|
||||||
|
|
||||||
This code was rewritten in 2008 to support rcu_barrier_bh() and
|
This code was rewritten in 2008 and several times thereafter, but this
|
||||||
rcu_barrier_sched() in addition to the original rcu_barrier().
|
still gives the general idea.
|
||||||
|
|
||||||
The rcu_barrier_func() runs on each CPU, where it invokes call_rcu()
|
The rcu_barrier_func() runs on each CPU, where it invokes call_rcu()
|
||||||
to post an RCU callback, as follows:
|
to post an RCU callback, as follows:
|
||||||
|
|
Loading…
Reference in New Issue