forked from Minki/linux
docs: rcu: convert some articles from html to ReST
There are 4 RCU articles that are written on html format. The way they are, they can't be part of the Linux Kernel documentation body nor share the styles and pdf output. So, convert them to ReST format. This way, make htmldocs and make pdfdocs will produce a documentation output that will be like the original ones, but will be part of the Linux Kernel documentation body. Part of the conversion was done with the help of pandoc, but the result had some broken things that had to be manually fixed. Following are manual changes Mauro made when doing the automatic conversion: Quoting from: https://lore.kernel.org/rcu/20190726154550.5eeae294@coco.lan/ > > At least the pandoc's version I used here has a bug: its conversion > > from html to ReST on those files only start after a <body> tag - or > > when the first quiz table starts. I only discovered that adding a > > <body> at the beginning of the file solve this book at the last > > conversions. > > > > So, for most html->ReST conversions, I manually converted the first > > part of the document, basically stripping html paragraph tags and > > by replacing highlights by the ReST syntax. > > > > Also, all the quiz tables seem to assume some javascript macro or > > css style that would be hiding the answer part until the mouse moves > > to it. Such macro/css was not there at the kernel tree. So, the quiz > > answers have the same color as the background, making them invisible. > > Even if we had such macro/css, this is not portable for pdf/LaTeX output > > (and I'm not sure if this would work with ePub). > > > > So, I ended by manually doing the table conversion. > > > > Finally, I double-checked if the conversions ended ok, addressing any > > issues that might have heppened. > > > > So, after both automatic conversion and manual fixes, I opened both the > > html files produced by Sphinx and the original ones and compared them > > line per line (except for the indexes, as Sphinx produces them > > automatically), in order to see if all information from the original > > files will be there on a format close to what we have on other ReST > > files, fixing any pending issues if any. Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
This commit is contained in:
parent
c07e6f36bc
commit
ccc9971e21
File diff suppressed because it is too large
Load Diff
1163
Documentation/RCU/Design/Data-Structures/Data-Structures.rst
Normal file
1163
Documentation/RCU/Design/Data-Structures/Data-Structures.rst
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,668 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head><title>A Tour Through TREE_RCU's Expedited Grace Periods</title>
|
||||
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
This document describes RCU's expedited grace periods.
|
||||
Unlike RCU's normal grace periods, which accept long latencies to attain
|
||||
high efficiency and minimal disturbance, expedited grace periods accept
|
||||
lower efficiency and significant disturbance to attain shorter latencies.
|
||||
|
||||
<p>
|
||||
There are two flavors of RCU (RCU-preempt and RCU-sched), with an earlier
|
||||
third RCU-bh flavor having been implemented in terms of the other two.
|
||||
Each of the two implementations is covered in its own section.
|
||||
|
||||
<ol>
|
||||
<li> <a href="#Expedited Grace Period Design">
|
||||
Expedited Grace Period Design</a>
|
||||
<li> <a href="#RCU-preempt Expedited Grace Periods">
|
||||
RCU-preempt Expedited Grace Periods</a>
|
||||
<li> <a href="#RCU-sched Expedited Grace Periods">
|
||||
RCU-sched Expedited Grace Periods</a>
|
||||
<li> <a href="#Expedited Grace Period and CPU Hotplug">
|
||||
Expedited Grace Period and CPU Hotplug</a>
|
||||
<li> <a href="#Expedited Grace Period Refinements">
|
||||
Expedited Grace Period Refinements</a>
|
||||
</ol>
|
||||
|
||||
<h2><a name="Expedited Grace Period Design">
|
||||
Expedited Grace Period Design</a></h2>
|
||||
|
||||
<p>
|
||||
The expedited RCU grace periods cannot be accused of being subtle,
|
||||
given that they for all intents and purposes hammer every CPU that
|
||||
has not yet provided a quiescent state for the current expedited
|
||||
grace period.
|
||||
The one saving grace is that the hammer has grown a bit smaller
|
||||
over time: The old call to <tt>try_stop_cpus()</tt> has been
|
||||
replaced with a set of calls to <tt>smp_call_function_single()</tt>,
|
||||
each of which results in an IPI to the target CPU.
|
||||
The corresponding handler function checks the CPU's state, motivating
|
||||
a faster quiescent state where possible, and triggering a report
|
||||
of that quiescent state.
|
||||
As always for RCU, once everything has spent some time in a quiescent
|
||||
state, the expedited grace period has completed.
|
||||
|
||||
<p>
|
||||
The details of the <tt>smp_call_function_single()</tt> handler's
|
||||
operation depend on the RCU flavor, as described in the following
|
||||
sections.
|
||||
|
||||
<h2><a name="RCU-preempt Expedited Grace Periods">
|
||||
RCU-preempt Expedited Grace Periods</a></h2>
|
||||
|
||||
<p>
|
||||
<tt>CONFIG_PREEMPT=y</tt> kernels implement 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:
|
||||
|
||||
<p><img src="ExpRCUFlow.svg" alt="ExpRCUFlow.svg" width="55%">
|
||||
|
||||
<p>
|
||||
The solid arrows denote direct action, for example, a function call.
|
||||
The dotted arrows denote indirect action, for example, an IPI
|
||||
or a state that is reached after some time.
|
||||
|
||||
<p>
|
||||
If a given CPU is offline or idle, <tt>synchronize_rcu_expedited()</tt>
|
||||
will ignore it because idle and offline CPUs are already residing
|
||||
in quiescent states.
|
||||
Otherwise, the expedited grace period will use
|
||||
<tt>smp_call_function_single()</tt> to send the CPU an IPI, which
|
||||
is handled by <tt>rcu_exp_handler()</tt>.
|
||||
|
||||
<p>
|
||||
However, because this is preemptible RCU, <tt>rcu_exp_handler()</tt>
|
||||
can check to see if the CPU is currently running in an RCU read-side
|
||||
critical section.
|
||||
If not, the handler can immediately report a quiescent state.
|
||||
Otherwise, it sets flags so that the outermost <tt>rcu_read_unlock()</tt>
|
||||
invocation will provide the needed quiescent-state report.
|
||||
This flag-setting avoids the previous forced preemption of all
|
||||
CPUs that might have RCU read-side critical sections.
|
||||
In addition, this flag-setting is done so as to avoid increasing
|
||||
the overhead of the common-case fastpath through the scheduler.
|
||||
|
||||
<p>
|
||||
Again because this is preemptible RCU, an RCU read-side critical section
|
||||
can be preempted.
|
||||
When that happens, RCU will enqueue the task, which will the continue to
|
||||
block the current expedited grace period until it resumes and finds its
|
||||
outermost <tt>rcu_read_unlock()</tt>.
|
||||
The CPU will report a quiescent state just after enqueuing the task because
|
||||
the CPU is no longer blocking the grace period.
|
||||
It is instead the preempted task doing the blocking.
|
||||
The list of blocked tasks is managed by <tt>rcu_preempt_ctxt_queue()</tt>,
|
||||
which is called from <tt>rcu_preempt_note_context_switch()</tt>, which
|
||||
in turn is called from <tt>rcu_note_context_switch()</tt>, which in
|
||||
turn is called from the scheduler.
|
||||
|
||||
<table>
|
||||
<tr><th> </th></tr>
|
||||
<tr><th align="left">Quick Quiz:</th></tr>
|
||||
<tr><td>
|
||||
Why not just have the expedited grace period check the
|
||||
state of all the CPUs?
|
||||
After all, that would avoid all those real-time-unfriendly IPIs.
|
||||
</td></tr>
|
||||
<tr><th align="left">Answer:</th></tr>
|
||||
<tr><td bgcolor="#ffffff"><font color="ffffff">
|
||||
Because we want the RCU read-side critical sections to run fast,
|
||||
which means no memory barriers.
|
||||
Therefore, it is not possible to safely check the state from some
|
||||
other CPU.
|
||||
And even if it was possible to safely check the state, it would
|
||||
still be necessary to IPI the CPU to safely interact with the
|
||||
upcoming <tt>rcu_read_unlock()</tt> invocation, which means that
|
||||
the remote state testing would not help the worst-case
|
||||
latency that real-time applications care about.
|
||||
|
||||
<p><font color="ffffff">One way to prevent your real-time
|
||||
application from getting hit with these IPIs is to
|
||||
build your kernel with <tt>CONFIG_NO_HZ_FULL=y</tt>.
|
||||
RCU would then perceive the CPU running your application
|
||||
as being idle, and it would be able to safely detect that
|
||||
state without needing to IPI the CPU.
|
||||
</font></td></tr>
|
||||
<tr><td> </td></tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
Please note that this is just the overall flow:
|
||||
Additional complications can arise due to races with CPUs going idle
|
||||
or offline, among other things.
|
||||
|
||||
<h2><a name="RCU-sched Expedited Grace Periods">
|
||||
RCU-sched Expedited Grace Periods</a></h2>
|
||||
|
||||
<p>
|
||||
<tt>CONFIG_PREEMPT=n</tt> kernels implement 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:
|
||||
|
||||
<p><img src="ExpSchedFlow.svg" alt="ExpSchedFlow.svg" width="55%">
|
||||
|
||||
<p>
|
||||
As with RCU-preempt, RCU-sched's
|
||||
<tt>synchronize_rcu_expedited()</tt> ignores offline and
|
||||
idle CPUs, again because they are in remotely detectable
|
||||
quiescent states.
|
||||
However, because the
|
||||
<tt>rcu_read_lock_sched()</tt> and <tt>rcu_read_unlock_sched()</tt>
|
||||
leave no trace of their invocation, in general it is not possible to tell
|
||||
whether or not the current CPU is in an RCU read-side critical section.
|
||||
The best that RCU-sched's <tt>rcu_exp_handler()</tt> can do is to check
|
||||
for idle, on the off-chance that the CPU went idle while the IPI
|
||||
was in flight.
|
||||
If the CPU is idle, then <tt>rcu_exp_handler()</tt> reports
|
||||
the quiescent state.
|
||||
|
||||
<p> Otherwise, the handler forces a future context switch by setting the
|
||||
NEED_RESCHED flag of the current task's thread flag and the CPU preempt
|
||||
counter.
|
||||
At the time of the context switch, the CPU reports the quiescent state.
|
||||
Should the CPU go offline first, it will report the quiescent state
|
||||
at that time.
|
||||
|
||||
<h2><a name="Expedited Grace Period and CPU Hotplug">
|
||||
Expedited Grace Period and CPU Hotplug</a></h2>
|
||||
|
||||
<p>
|
||||
The expedited nature of expedited grace periods require a much tighter
|
||||
interaction with CPU hotplug operations than is required for normal
|
||||
grace periods.
|
||||
In addition, attempting to IPI offline CPUs will result in splats, but
|
||||
failing to IPI online CPUs can result in too-short grace periods.
|
||||
Neither option is acceptable in production kernels.
|
||||
|
||||
<p>
|
||||
The interaction between expedited grace periods and CPU hotplug operations
|
||||
is carried out at several levels:
|
||||
|
||||
<ol>
|
||||
<li> The number of CPUs that have ever been online is tracked
|
||||
by the <tt>rcu_state</tt> structure's <tt>->ncpus</tt>
|
||||
field.
|
||||
The <tt>rcu_state</tt> structure's <tt>->ncpus_snap</tt>
|
||||
field tracks the number of CPUs that have ever been online
|
||||
at the beginning of an RCU expedited grace period.
|
||||
Note that this number never decreases, at least in the absence
|
||||
of a time machine.
|
||||
<li> The identities of the CPUs that have ever been online is
|
||||
tracked by the <tt>rcu_node</tt> structure's
|
||||
<tt>->expmaskinitnext</tt> field.
|
||||
The <tt>rcu_node</tt> structure's <tt>->expmaskinit</tt>
|
||||
field tracks the identities of the CPUs that were online
|
||||
at least once at the beginning of the most recent RCU
|
||||
expedited grace period.
|
||||
The <tt>rcu_state</tt> structure's <tt>->ncpus</tt> and
|
||||
<tt>->ncpus_snap</tt> fields are used to detect when
|
||||
new CPUs have come online for the first time, that is,
|
||||
when the <tt>rcu_node</tt> structure's <tt>->expmaskinitnext</tt>
|
||||
field has changed since the beginning of the last RCU
|
||||
expedited grace period, which triggers an update of each
|
||||
<tt>rcu_node</tt> structure's <tt>->expmaskinit</tt>
|
||||
field from its <tt>->expmaskinitnext</tt> field.
|
||||
<li> Each <tt>rcu_node</tt> structure's <tt>->expmaskinit</tt>
|
||||
field is used to initialize that structure's
|
||||
<tt>->expmask</tt> at the beginning of each RCU
|
||||
expedited grace period.
|
||||
This means that only those CPUs that have been online at least
|
||||
once will be considered for a given grace period.
|
||||
<li> Any CPU that goes offline will clear its bit in its leaf
|
||||
<tt>rcu_node</tt> structure's <tt>->qsmaskinitnext</tt>
|
||||
field, so any CPU with that bit clear can safely be ignored.
|
||||
However, it is possible for a CPU coming online or going offline
|
||||
to have this bit set for some time while <tt>cpu_online</tt>
|
||||
returns <tt>false</tt>.
|
||||
<li> For each non-idle CPU that RCU believes is currently online, the grace
|
||||
period invokes <tt>smp_call_function_single()</tt>.
|
||||
If this succeeds, the CPU was fully online.
|
||||
Failure indicates that the CPU is in the process of coming online
|
||||
or going offline, in which case it is necessary to wait for a
|
||||
short time period and try again.
|
||||
The purpose of this wait (or series of waits, as the case may be)
|
||||
is to permit a concurrent CPU-hotplug operation to complete.
|
||||
<li> In the case of RCU-sched, one of the last acts of an outgoing CPU
|
||||
is to invoke <tt>rcu_report_dead()</tt>, which
|
||||
reports a quiescent state for that CPU.
|
||||
However, this is likely paranoia-induced redundancy. <!-- @@@ -->
|
||||
</ol>
|
||||
|
||||
<table>
|
||||
<tr><th> </th></tr>
|
||||
<tr><th align="left">Quick Quiz:</th></tr>
|
||||
<tr><td>
|
||||
Why all the dancing around with multiple counters and masks
|
||||
tracking CPUs that were once online?
|
||||
Why not just have a single set of masks tracking the currently
|
||||
online CPUs and be done with it?
|
||||
</td></tr>
|
||||
<tr><th align="left">Answer:</th></tr>
|
||||
<tr><td bgcolor="#ffffff"><font color="ffffff">
|
||||
Maintaining single set of masks tracking the online CPUs <i>sounds</i>
|
||||
easier, at least until you try working out all the race conditions
|
||||
between grace-period initialization and CPU-hotplug operations.
|
||||
For example, suppose initialization is progressing down the
|
||||
tree while a CPU-offline operation is progressing up the tree.
|
||||
This situation can result in bits set at the top of the tree
|
||||
that have no counterparts at the bottom of the tree.
|
||||
Those bits will never be cleared, which will result in
|
||||
grace-period hangs.
|
||||
In short, that way lies madness, to say nothing of a great many
|
||||
bugs, hangs, and deadlocks.
|
||||
|
||||
<p><font color="ffffff">
|
||||
In contrast, the current multi-mask multi-counter scheme ensures
|
||||
that grace-period initialization will always see consistent masks
|
||||
up and down the tree, which brings significant simplifications
|
||||
over the single-mask method.
|
||||
|
||||
<p><font color="ffffff">
|
||||
This is an instance of
|
||||
<a href="http://www.cs.columbia.edu/~library/TR-repository/reports/reports-1992/cucs-039-92.ps.gz"><font color="ffffff">
|
||||
deferring work in order to avoid synchronization</a>.
|
||||
Lazily recording CPU-hotplug events at the beginning of the next
|
||||
grace period greatly simplifies maintenance of the CPU-tracking
|
||||
bitmasks in the <tt>rcu_node</tt> tree.
|
||||
</font></td></tr>
|
||||
<tr><td> </td></tr>
|
||||
</table>
|
||||
|
||||
<h2><a name="Expedited Grace Period Refinements">
|
||||
Expedited Grace Period Refinements</a></h2>
|
||||
|
||||
<ol>
|
||||
<li> <a href="#Idle-CPU Checks">Idle-CPU checks</a>.
|
||||
<li> <a href="#Batching via Sequence Counter">
|
||||
Batching via sequence counter</a>.
|
||||
<li> <a href="#Funnel Locking and Wait/Wakeup">
|
||||
Funnel locking and wait/wakeup</a>.
|
||||
<li> <a href="#Use of Workqueues">Use of Workqueues</a>.
|
||||
<li> <a href="#Stall Warnings">Stall warnings</a>.
|
||||
<li> <a href="#Mid-Boot Operation">Mid-boot operation</a>.
|
||||
</ol>
|
||||
|
||||
<h3><a name="Idle-CPU Checks">Idle-CPU Checks</a></h3>
|
||||
|
||||
<p>
|
||||
Each expedited grace period checks for idle CPUs when initially forming
|
||||
the mask of CPUs to be IPIed and again just before IPIing a CPU
|
||||
(both checks are carried out by <tt>sync_rcu_exp_select_cpus()</tt>).
|
||||
If the CPU is idle at any time between those two times, the CPU will
|
||||
not be IPIed.
|
||||
Instead, the task pushing the grace period forward will include the
|
||||
idle CPUs in the mask passed to <tt>rcu_report_exp_cpu_mult()</tt>.
|
||||
|
||||
<p>
|
||||
For RCU-sched, there is an additional check:
|
||||
If the IPI has interrupted the idle loop, then
|
||||
<tt>rcu_exp_handler()</tt> invokes <tt>rcu_report_exp_rdp()</tt>
|
||||
to report the corresponding quiescent state.
|
||||
|
||||
<p>
|
||||
For RCU-preempt, there is no specific check for idle in the
|
||||
IPI handler (<tt>rcu_exp_handler()</tt>), but because
|
||||
RCU read-side critical sections are not permitted within the
|
||||
idle loop, if <tt>rcu_exp_handler()</tt> sees that the CPU is within
|
||||
RCU read-side critical section, the CPU cannot possibly be idle.
|
||||
Otherwise, <tt>rcu_exp_handler()</tt> invokes
|
||||
<tt>rcu_report_exp_rdp()</tt> to report the corresponding quiescent
|
||||
state, regardless of whether or not that quiescent state was due to
|
||||
the CPU being idle.
|
||||
|
||||
<p>
|
||||
In summary, RCU expedited grace periods check for idle when building
|
||||
the bitmask of CPUs that must be IPIed, just before sending each IPI,
|
||||
and (either explicitly or implicitly) within the IPI handler.
|
||||
|
||||
<h3><a name="Batching via Sequence Counter">
|
||||
Batching via Sequence Counter</a></h3>
|
||||
|
||||
<p>
|
||||
If each grace-period request was carried out separately, expedited
|
||||
grace periods would have abysmal scalability and
|
||||
problematic high-load characteristics.
|
||||
Because each grace-period operation can serve an unlimited number of
|
||||
updates, it is important to <i>batch</i> requests, so that a single
|
||||
expedited grace-period operation will cover all requests in the
|
||||
corresponding batch.
|
||||
|
||||
<p>
|
||||
This batching is controlled by a sequence counter named
|
||||
<tt>->expedited_sequence</tt> in the <tt>rcu_state</tt> structure.
|
||||
This counter has an odd value when there is an expedited grace period
|
||||
in progress and an even value otherwise, so that dividing the counter
|
||||
value by two gives the number of completed grace periods.
|
||||
During any given update request, the counter must transition from
|
||||
even to odd and then back to even, thus indicating that a grace
|
||||
period has elapsed.
|
||||
Therefore, if the initial value of the counter is <tt>s</tt>,
|
||||
the updater must wait until the counter reaches at least the
|
||||
value <tt>(s+3)&~0x1</tt>.
|
||||
This counter is managed by the following access functions:
|
||||
|
||||
<ol>
|
||||
<li> <tt>rcu_exp_gp_seq_start()</tt>, which marks the start of
|
||||
an expedited grace period.
|
||||
<li> <tt>rcu_exp_gp_seq_end()</tt>, which marks the end of an
|
||||
expedited grace period.
|
||||
<li> <tt>rcu_exp_gp_seq_snap()</tt>, which obtains a snapshot of
|
||||
the counter.
|
||||
<li> <tt>rcu_exp_gp_seq_done()</tt>, which returns <tt>true</tt>
|
||||
if a full expedited grace period has elapsed since the
|
||||
corresponding call to <tt>rcu_exp_gp_seq_snap()</tt>.
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
Again, only one request in a given batch need actually carry out
|
||||
a grace-period operation, which means there must be an efficient
|
||||
way to identify which of many concurrent reqeusts will initiate
|
||||
the grace period, and that there be an efficient way for the
|
||||
remaining requests to wait for that grace period to complete.
|
||||
However, that is the topic of the next section.
|
||||
|
||||
<h3><a name="Funnel Locking and Wait/Wakeup">
|
||||
Funnel Locking and Wait/Wakeup</a></h3>
|
||||
|
||||
<p>
|
||||
The natural way to sort out which of a batch of updaters will initiate
|
||||
the expedited grace period is to use the <tt>rcu_node</tt> combining
|
||||
tree, as implemented by the <tt>exp_funnel_lock()</tt> function.
|
||||
The first updater corresponding to a given grace period arriving
|
||||
at a given <tt>rcu_node</tt> structure records its desired grace-period
|
||||
sequence number in the <tt>->exp_seq_rq</tt> field and moves up
|
||||
to the next level in the tree.
|
||||
Otherwise, if the <tt>->exp_seq_rq</tt> field already contains
|
||||
the sequence number for the desired grace period or some later one,
|
||||
the updater blocks on one of four wait queues in the
|
||||
<tt>->exp_wq[]</tt> array, using the second-from-bottom
|
||||
and third-from bottom bits as an index.
|
||||
An <tt>->exp_lock</tt> field in the <tt>rcu_node</tt> structure
|
||||
synchronizes access to these fields.
|
||||
|
||||
<p>
|
||||
An empty <tt>rcu_node</tt> tree is shown in the following diagram,
|
||||
with the white cells representing the <tt>->exp_seq_rq</tt> field
|
||||
and the red cells representing the elements of the
|
||||
<tt>->exp_wq[]</tt> array.
|
||||
|
||||
<p><img src="Funnel0.svg" alt="Funnel0.svg" width="75%">
|
||||
|
||||
<p>
|
||||
The next diagram shows the situation after the arrival of Task A
|
||||
and Task B at the leftmost and rightmost leaf <tt>rcu_node</tt>
|
||||
structures, respectively.
|
||||
The current value of the <tt>rcu_state</tt> structure's
|
||||
<tt>->expedited_sequence</tt> field is zero, so adding three and
|
||||
clearing the bottom bit results in the value two, which both tasks
|
||||
record in the <tt>->exp_seq_rq</tt> field of their respective
|
||||
<tt>rcu_node</tt> structures:
|
||||
|
||||
<p><img src="Funnel1.svg" alt="Funnel1.svg" width="75%">
|
||||
|
||||
<p>
|
||||
Each of Tasks A and B will move up to the root
|
||||
<tt>rcu_node</tt> structure.
|
||||
Suppose that Task A wins, recording its desired grace-period sequence
|
||||
number and resulting in the state shown below:
|
||||
|
||||
<p><img src="Funnel2.svg" alt="Funnel2.svg" width="75%">
|
||||
|
||||
<p>
|
||||
Task A now advances to initiate a new grace period, while Task B
|
||||
moves up to the root <tt>rcu_node</tt> structure, and, seeing that
|
||||
its desired sequence number is already recorded, blocks on
|
||||
<tt>->exp_wq[1]</tt>.
|
||||
|
||||
<table>
|
||||
<tr><th> </th></tr>
|
||||
<tr><th align="left">Quick Quiz:</th></tr>
|
||||
<tr><td>
|
||||
Why <tt>->exp_wq[1]</tt>?
|
||||
Given that the value of these tasks' desired sequence number is
|
||||
two, so shouldn't they instead block on <tt>->exp_wq[2]</tt>?
|
||||
</td></tr>
|
||||
<tr><th align="left">Answer:</th></tr>
|
||||
<tr><td bgcolor="#ffffff"><font color="ffffff">
|
||||
No.
|
||||
|
||||
<p><font color="ffffff">
|
||||
Recall that the bottom bit of the desired sequence number indicates
|
||||
whether or not a grace period is currently in progress.
|
||||
It is therefore necessary to shift the sequence number right one
|
||||
bit position to obtain the number of the grace period.
|
||||
This results in <tt>->exp_wq[1]</tt>.
|
||||
</font></td></tr>
|
||||
<tr><td> </td></tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
If Tasks C and D also arrive at this point, they will compute the
|
||||
same desired grace-period sequence number, and see that both leaf
|
||||
<tt>rcu_node</tt> structures already have that value recorded.
|
||||
They will therefore block on their respective <tt>rcu_node</tt>
|
||||
structures' <tt>->exp_wq[1]</tt> fields, as shown below:
|
||||
|
||||
<p><img src="Funnel3.svg" alt="Funnel3.svg" width="75%">
|
||||
|
||||
<p>
|
||||
Task A now acquires the <tt>rcu_state</tt> structure's
|
||||
<tt>->exp_mutex</tt> and initiates the grace period, which
|
||||
increments <tt>->expedited_sequence</tt>.
|
||||
Therefore, if Tasks E and F arrive, they will compute
|
||||
a desired sequence number of 4 and will record this value as
|
||||
shown below:
|
||||
|
||||
<p><img src="Funnel4.svg" alt="Funnel4.svg" width="75%">
|
||||
|
||||
<p>
|
||||
Tasks E and F will propagate up the <tt>rcu_node</tt>
|
||||
combining tree, with Task F blocking on the root <tt>rcu_node</tt>
|
||||
structure and Task E wait for Task A to finish so that
|
||||
it can start the next grace period.
|
||||
The resulting state is as shown below:
|
||||
|
||||
<p><img src="Funnel5.svg" alt="Funnel5.svg" width="75%">
|
||||
|
||||
<p>
|
||||
Once the grace period completes, Task A
|
||||
starts waking up the tasks waiting for this grace period to complete,
|
||||
increments the <tt>->expedited_sequence</tt>,
|
||||
acquires the <tt>->exp_wake_mutex</tt> and then releases the
|
||||
<tt>->exp_mutex</tt>.
|
||||
This results in the following state:
|
||||
|
||||
<p><img src="Funnel6.svg" alt="Funnel6.svg" width="75%">
|
||||
|
||||
<p>
|
||||
Task E can then acquire <tt>->exp_mutex</tt> and increment
|
||||
<tt>->expedited_sequence</tt> to the value three.
|
||||
If new tasks G and H arrive and moves up the combining tree at the
|
||||
same time, the state will be as follows:
|
||||
|
||||
<p><img src="Funnel7.svg" alt="Funnel7.svg" width="75%">
|
||||
|
||||
<p>
|
||||
Note that three of the root <tt>rcu_node</tt> structure's
|
||||
waitqueues are now occupied.
|
||||
However, at some point, Task A will wake up the
|
||||
tasks blocked on the <tt>->exp_wq</tt> waitqueues, resulting
|
||||
in the following state:
|
||||
|
||||
<p><img src="Funnel8.svg" alt="Funnel8.svg" width="75%">
|
||||
|
||||
<p>
|
||||
Execution will continue with Tasks E and H completing
|
||||
their grace periods and carrying out their wakeups.
|
||||
|
||||
<table>
|
||||
<tr><th> </th></tr>
|
||||
<tr><th align="left">Quick Quiz:</th></tr>
|
||||
<tr><td>
|
||||
What happens if Task A takes so long to do its wakeups
|
||||
that Task E's grace period completes?
|
||||
</td></tr>
|
||||
<tr><th align="left">Answer:</th></tr>
|
||||
<tr><td bgcolor="#ffffff"><font color="ffffff">
|
||||
Then Task E will block on the <tt>->exp_wake_mutex</tt>,
|
||||
which will also prevent it from releasing <tt>->exp_mutex</tt>,
|
||||
which in turn will prevent the next grace period from starting.
|
||||
This last is important in preventing overflow of the
|
||||
<tt>->exp_wq[]</tt> array.
|
||||
</font></td></tr>
|
||||
<tr><td> </td></tr>
|
||||
</table>
|
||||
|
||||
<h3><a name="Use of Workqueues">Use of Workqueues</a></h3>
|
||||
|
||||
<p>
|
||||
In earlier implementations, the task requesting the expedited
|
||||
grace period also drove it to completion.
|
||||
This straightforward approach had the disadvantage of needing to
|
||||
account for POSIX signals sent to user tasks,
|
||||
so more recent implemementations use the Linux kernel's
|
||||
<a href="https://www.kernel.org/doc/Documentation/core-api/workqueue.rst">workqueues</a>.
|
||||
|
||||
<p>
|
||||
The requesting task still does counter snapshotting and funnel-lock
|
||||
processing, but the task reaching the top of the funnel lock
|
||||
does a <tt>schedule_work()</tt> (from <tt>_synchronize_rcu_expedited()</tt>
|
||||
so that a workqueue kthread does the actual grace-period processing.
|
||||
Because workqueue kthreads do not accept POSIX signals, grace-period-wait
|
||||
processing need not allow for POSIX signals.
|
||||
|
||||
In addition, this approach allows wakeups for the previous expedited
|
||||
grace period to be overlapped with processing for the next expedited
|
||||
grace period.
|
||||
Because there are only four sets of waitqueues, it is necessary to
|
||||
ensure that the previous grace period's wakeups complete before the
|
||||
next grace period's wakeups start.
|
||||
This is handled by having the <tt>->exp_mutex</tt>
|
||||
guard expedited grace-period processing and the
|
||||
<tt>->exp_wake_mutex</tt> guard wakeups.
|
||||
The key point is that the <tt>->exp_mutex</tt> is not released
|
||||
until the first wakeup is complete, which means that the
|
||||
<tt>->exp_wake_mutex</tt> has already been acquired at that point.
|
||||
This approach ensures that the previous grace period's wakeups can
|
||||
be carried out while the current grace period is in process, but
|
||||
that these wakeups will complete before the next grace period starts.
|
||||
This means that only three waitqueues are required, guaranteeing that
|
||||
the four that are provided are sufficient.
|
||||
|
||||
<h3><a name="Stall Warnings">Stall Warnings</a></h3>
|
||||
|
||||
<p>
|
||||
Expediting grace periods does nothing to speed things up when RCU
|
||||
readers take too long, and therefore expedited grace periods check
|
||||
for stalls just as normal grace periods do.
|
||||
|
||||
<table>
|
||||
<tr><th> </th></tr>
|
||||
<tr><th align="left">Quick Quiz:</th></tr>
|
||||
<tr><td>
|
||||
But why not just let the normal grace-period machinery
|
||||
detect the stalls, given that a given reader must block
|
||||
both normal and expedited grace periods?
|
||||
</td></tr>
|
||||
<tr><th align="left">Answer:</th></tr>
|
||||
<tr><td bgcolor="#ffffff"><font color="ffffff">
|
||||
Because it is quite possible that at a given time there
|
||||
is no normal grace period in progress, in which case the
|
||||
normal grace period cannot emit a stall warning.
|
||||
</font></td></tr>
|
||||
<tr><td> </td></tr>
|
||||
</table>
|
||||
|
||||
The <tt>synchronize_sched_expedited_wait()</tt> function loops waiting
|
||||
for the expedited grace period to end, but with a timeout set to the
|
||||
current RCU CPU stall-warning time.
|
||||
If this time is exceeded, any CPUs or <tt>rcu_node</tt> structures
|
||||
blocking the current grace period are printed.
|
||||
Each stall warning results in another pass through the loop, but the
|
||||
second and subsequent passes use longer stall times.
|
||||
|
||||
<h3><a name="Mid-Boot Operation">Mid-boot operation</a></h3>
|
||||
|
||||
<p>
|
||||
The use of workqueues has the advantage that the expedited
|
||||
grace-period code need not worry about POSIX signals.
|
||||
Unfortunately, it has the
|
||||
corresponding disadvantage that workqueues cannot be used until
|
||||
they are initialized, which does not happen until some time after
|
||||
the scheduler spawns the first task.
|
||||
Given that there are parts of the kernel that really do want to
|
||||
execute grace periods during this mid-boot “dead zone”,
|
||||
expedited grace periods must do something else during thie time.
|
||||
|
||||
<p>
|
||||
What they do is to fall back to the old practice of requiring that the
|
||||
requesting task drive the expedited grace period, as was the case
|
||||
before the use of workqueues.
|
||||
However, the requesting task is only required to drive the grace period
|
||||
during the mid-boot dead zone.
|
||||
Before mid-boot, a synchronous grace period is a no-op.
|
||||
Some time after mid-boot, workqueues are used.
|
||||
|
||||
<p>
|
||||
Non-expedited non-SRCU synchronous grace periods must also operate
|
||||
normally during mid-boot.
|
||||
This is handled by causing non-expedited grace periods to take the
|
||||
expedited code path during mid-boot.
|
||||
|
||||
<p>
|
||||
The current code assumes that there are no POSIX signals during
|
||||
the mid-boot dead zone.
|
||||
However, if an overwhelming need for POSIX signals somehow arises,
|
||||
appropriate adjustments can be made to the expedited stall-warning code.
|
||||
One such adjustment would reinstate the pre-workqueue stall-warning
|
||||
checks, but only during the mid-boot dead zone.
|
||||
|
||||
<p>
|
||||
With this refinement, synchronous grace periods can now be used from
|
||||
task context pretty much any time during the life of the kernel.
|
||||
That is, aside from some points in the suspend, hibernate, or shutdown
|
||||
code path.
|
||||
|
||||
<h3><a name="Summary">
|
||||
Summary</a></h3>
|
||||
|
||||
<p>
|
||||
Expedited grace periods use a sequence-number approach to promote
|
||||
batching, so that a single grace-period operation can serve numerous
|
||||
requests.
|
||||
A funnel lock is used to efficiently identify the one task out of
|
||||
a concurrent group that will request the grace period.
|
||||
All members of the group will block on waitqueues provided in
|
||||
the <tt>rcu_node</tt> structure.
|
||||
The actual grace-period processing is carried out by a workqueue.
|
||||
|
||||
<p>
|
||||
CPU-hotplug operations are noted lazily in order to prevent the need
|
||||
for tight synchronization between expedited grace periods and
|
||||
CPU-hotplug operations.
|
||||
The dyntick-idle counters are used to avoid sending IPIs to idle CPUs,
|
||||
at least in the common case.
|
||||
RCU-preempt and RCU-sched use different IPI handlers and different
|
||||
code to respond to the state changes carried out by those handlers,
|
||||
but otherwise use common code.
|
||||
|
||||
<p>
|
||||
Quiescent states are tracked using the <tt>rcu_node</tt> tree,
|
||||
and once all necessary quiescent states have been reported,
|
||||
all tasks waiting on this expedited grace period are awakened.
|
||||
A pair of mutexes are used to allow one grace period's wakeups
|
||||
to proceed concurrently with the next grace period's processing.
|
||||
|
||||
<p>
|
||||
This combination of mechanisms allows expedited grace periods to
|
||||
run reasonably efficiently.
|
||||
However, for non-time-critical tasks, normal grace periods should be
|
||||
used instead because their longer duration permits much higher
|
||||
degrees of batching, and thus much lower per-request overheads.
|
||||
|
||||
</body></html>
|
@ -0,0 +1,521 @@
|
||||
=================================================
|
||||
A Tour Through TREE_RCU's Expedited Grace Periods
|
||||
=================================================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This document describes RCU's expedited grace periods.
|
||||
Unlike RCU's normal grace periods, which accept long latencies to attain
|
||||
high efficiency and minimal disturbance, expedited grace periods accept
|
||||
lower efficiency and significant disturbance to attain shorter latencies.
|
||||
|
||||
There are two flavors of RCU (RCU-preempt and RCU-sched), with an earlier
|
||||
third RCU-bh flavor having been implemented in terms of the other two.
|
||||
Each of the two implementations is covered in its own section.
|
||||
|
||||
Expedited Grace Period Design
|
||||
=============================
|
||||
|
||||
The expedited RCU grace periods cannot be accused of being subtle,
|
||||
given that they for all intents and purposes hammer every CPU that
|
||||
has not yet provided a quiescent state for the current expedited
|
||||
grace period.
|
||||
The one saving grace is that the hammer has grown a bit smaller
|
||||
over time: The old call to ``try_stop_cpus()`` has been
|
||||
replaced with a set of calls to ``smp_call_function_single()``,
|
||||
each of which results in an IPI to the target CPU.
|
||||
The corresponding handler function checks the CPU's state, motivating
|
||||
a faster quiescent state where possible, and triggering a report
|
||||
of that quiescent state.
|
||||
As always for RCU, once everything has spent some time in a quiescent
|
||||
state, the expedited grace period has completed.
|
||||
|
||||
The details of the ``smp_call_function_single()`` handler's
|
||||
operation depend on the RCU flavor, as described in the following
|
||||
sections.
|
||||
|
||||
RCU-preempt Expedited Grace Periods
|
||||
===================================
|
||||
|
||||
``CONFIG_PREEMPT=y`` kernels implement 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:
|
||||
|
||||
.. kernel-figure:: ExpRCUFlow.svg
|
||||
|
||||
The solid arrows denote direct action, for example, a function call.
|
||||
The dotted arrows denote indirect action, for example, an IPI
|
||||
or a state that is reached after some time.
|
||||
|
||||
If a given CPU is offline or idle, ``synchronize_rcu_expedited()``
|
||||
will ignore it because idle and offline CPUs are already residing
|
||||
in quiescent states.
|
||||
Otherwise, the expedited grace period will use
|
||||
``smp_call_function_single()`` to send the CPU an IPI, which
|
||||
is handled by ``rcu_exp_handler()``.
|
||||
|
||||
However, because this is preemptible RCU, ``rcu_exp_handler()``
|
||||
can check to see if the CPU is currently running in an RCU read-side
|
||||
critical section.
|
||||
If not, the handler can immediately report a quiescent state.
|
||||
Otherwise, it sets flags so that the outermost ``rcu_read_unlock()``
|
||||
invocation will provide the needed quiescent-state report.
|
||||
This flag-setting avoids the previous forced preemption of all
|
||||
CPUs that might have RCU read-side critical sections.
|
||||
In addition, this flag-setting is done so as to avoid increasing
|
||||
the overhead of the common-case fastpath through the scheduler.
|
||||
|
||||
Again because this is preemptible RCU, an RCU read-side critical section
|
||||
can be preempted.
|
||||
When that happens, RCU will enqueue the task, which will the continue to
|
||||
block the current expedited grace period until it resumes and finds its
|
||||
outermost ``rcu_read_unlock()``.
|
||||
The CPU will report a quiescent state just after enqueuing the task because
|
||||
the CPU is no longer blocking the grace period.
|
||||
It is instead the preempted task doing the blocking.
|
||||
The list of blocked tasks is managed by ``rcu_preempt_ctxt_queue()``,
|
||||
which is called from ``rcu_preempt_note_context_switch()``, which
|
||||
in turn is called from ``rcu_note_context_switch()``, which in
|
||||
turn is called from the scheduler.
|
||||
|
||||
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Quick Quiz**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Why not just have the expedited grace period check the state of all |
|
||||
| the CPUs? After all, that would avoid all those real-time-unfriendly |
|
||||
| IPIs. |
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Answer**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Because we want the RCU read-side critical sections to run fast, |
|
||||
| which means no memory barriers. Therefore, it is not possible to |
|
||||
| safely check the state from some other CPU. And even if it was |
|
||||
| possible to safely check the state, it would still be necessary to |
|
||||
| IPI the CPU to safely interact with the upcoming |
|
||||
| ``rcu_read_unlock()`` invocation, which means that the remote state |
|
||||
| testing would not help the worst-case latency that real-time |
|
||||
| applications care about. |
|
||||
| |
|
||||
| One way to prevent your real-time application from getting hit with |
|
||||
| these IPIs is to build your kernel with ``CONFIG_NO_HZ_FULL=y``. RCU |
|
||||
| would then perceive the CPU running your application as being idle, |
|
||||
| and it would be able to safely detect that state without needing to |
|
||||
| IPI the CPU. |
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
Please note that this is just the overall flow: Additional complications
|
||||
can arise due to races with CPUs going idle or offline, among other
|
||||
things.
|
||||
|
||||
RCU-sched Expedited Grace Periods
|
||||
---------------------------------
|
||||
|
||||
``CONFIG_PREEMPT=n`` kernels implement 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:
|
||||
|
||||
.. kernel-figure:: ExpSchedFlow.svg
|
||||
|
||||
As with RCU-preempt, RCU-sched's ``synchronize_rcu_expedited()`` ignores
|
||||
offline and idle CPUs, again because they are in remotely detectable
|
||||
quiescent states. However, because the ``rcu_read_lock_sched()`` and
|
||||
``rcu_read_unlock_sched()`` leave no trace of their invocation, in
|
||||
general it is not possible to tell whether or not the current CPU is in
|
||||
an RCU read-side critical section. The best that RCU-sched's
|
||||
``rcu_exp_handler()`` can do is to check for idle, on the off-chance
|
||||
that the CPU went idle while the IPI was in flight. If the CPU is idle,
|
||||
then ``rcu_exp_handler()`` reports the quiescent state.
|
||||
|
||||
Otherwise, the handler forces a future context switch by setting the
|
||||
NEED_RESCHED flag of the current task's thread flag and the CPU preempt
|
||||
counter. At the time of the context switch, the CPU reports the
|
||||
quiescent state. Should the CPU go offline first, it will report the
|
||||
quiescent state at that time.
|
||||
|
||||
Expedited Grace Period and CPU Hotplug
|
||||
--------------------------------------
|
||||
|
||||
The expedited nature of expedited grace periods require a much tighter
|
||||
interaction with CPU hotplug operations than is required for normal
|
||||
grace periods. In addition, attempting to IPI offline CPUs will result
|
||||
in splats, but failing to IPI online CPUs can result in too-short grace
|
||||
periods. Neither option is acceptable in production kernels.
|
||||
|
||||
The interaction between expedited grace periods and CPU hotplug
|
||||
operations is carried out at several levels:
|
||||
|
||||
#. The number of CPUs that have ever been online is tracked by the
|
||||
``rcu_state`` structure's ``->ncpus`` field. The ``rcu_state``
|
||||
structure's ``->ncpus_snap`` field tracks the number of CPUs that
|
||||
have ever been online at the beginning of an RCU expedited grace
|
||||
period. Note that this number never decreases, at least in the
|
||||
absence of a time machine.
|
||||
#. The identities of the CPUs that have ever been online is tracked by
|
||||
the ``rcu_node`` structure's ``->expmaskinitnext`` field. The
|
||||
``rcu_node`` structure's ``->expmaskinit`` field tracks the
|
||||
identities of the CPUs that were online at least once at the
|
||||
beginning of the most recent RCU expedited grace period. The
|
||||
``rcu_state`` structure's ``->ncpus`` and ``->ncpus_snap`` fields are
|
||||
used to detect when new CPUs have come online for the first time,
|
||||
that is, when the ``rcu_node`` structure's ``->expmaskinitnext``
|
||||
field has changed since the beginning of the last RCU expedited grace
|
||||
period, which triggers an update of each ``rcu_node`` structure's
|
||||
``->expmaskinit`` field from its ``->expmaskinitnext`` field.
|
||||
#. Each ``rcu_node`` structure's ``->expmaskinit`` field is used to
|
||||
initialize that structure's ``->expmask`` at the beginning of each
|
||||
RCU expedited grace period. This means that only those CPUs that have
|
||||
been online at least once will be considered for a given grace
|
||||
period.
|
||||
#. Any CPU that goes offline will clear its bit in its leaf ``rcu_node``
|
||||
structure's ``->qsmaskinitnext`` field, so any CPU with that bit
|
||||
clear can safely be ignored. However, it is possible for a CPU coming
|
||||
online or going offline to have this bit set for some time while
|
||||
``cpu_online`` returns ``false``.
|
||||
#. For each non-idle CPU that RCU believes is currently online, the
|
||||
grace period invokes ``smp_call_function_single()``. If this
|
||||
succeeds, the CPU was fully online. Failure indicates that the CPU is
|
||||
in the process of coming online or going offline, in which case it is
|
||||
necessary to wait for a short time period and try again. The purpose
|
||||
of this wait (or series of waits, as the case may be) is to permit a
|
||||
concurrent CPU-hotplug operation to complete.
|
||||
#. In the case of RCU-sched, one of the last acts of an outgoing CPU is
|
||||
to invoke ``rcu_report_dead()``, which reports a quiescent state for
|
||||
that CPU. However, this is likely paranoia-induced redundancy.
|
||||
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Quick Quiz**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Why all the dancing around with multiple counters and masks tracking |
|
||||
| CPUs that were once online? Why not just have a single set of masks |
|
||||
| tracking the currently online CPUs and be done with it? |
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Answer**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Maintaining single set of masks tracking the online CPUs *sounds* |
|
||||
| easier, at least until you try working out all the race conditions |
|
||||
| between grace-period initialization and CPU-hotplug operations. For |
|
||||
| example, suppose initialization is progressing down the tree while a |
|
||||
| CPU-offline operation is progressing up the tree. This situation can |
|
||||
| result in bits set at the top of the tree that have no counterparts |
|
||||
| at the bottom of the tree. Those bits will never be cleared, which |
|
||||
| will result in grace-period hangs. In short, that way lies madness, |
|
||||
| to say nothing of a great many bugs, hangs, and deadlocks. |
|
||||
| In contrast, the current multi-mask multi-counter scheme ensures that |
|
||||
| grace-period initialization will always see consistent masks up and |
|
||||
| down the tree, which brings significant simplifications over the |
|
||||
| single-mask method. |
|
||||
| |
|
||||
| This is an instance of `deferring work in order to avoid |
|
||||
| synchronization <http://www.cs.columbia.edu/~library/TR-repository/re |
|
||||
| ports/reports-1992/cucs-039-92.ps.gz>`__. |
|
||||
| Lazily recording CPU-hotplug events at the beginning of the next |
|
||||
| grace period greatly simplifies maintenance of the CPU-tracking |
|
||||
| bitmasks in the ``rcu_node`` tree. |
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
Expedited Grace Period Refinements
|
||||
----------------------------------
|
||||
|
||||
Idle-CPU Checks
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Each expedited grace period checks for idle CPUs when initially forming
|
||||
the mask of CPUs to be IPIed and again just before IPIing a CPU (both
|
||||
checks are carried out by ``sync_rcu_exp_select_cpus()``). If the CPU is
|
||||
idle at any time between those two times, the CPU will not be IPIed.
|
||||
Instead, the task pushing the grace period forward will include the idle
|
||||
CPUs in the mask passed to ``rcu_report_exp_cpu_mult()``.
|
||||
|
||||
For RCU-sched, there is an additional check: If the IPI has interrupted
|
||||
the idle loop, then ``rcu_exp_handler()`` invokes
|
||||
``rcu_report_exp_rdp()`` to report the corresponding quiescent state.
|
||||
|
||||
For RCU-preempt, there is no specific check for idle in the IPI handler
|
||||
(``rcu_exp_handler()``), but because RCU read-side critical sections are
|
||||
not permitted within the idle loop, if ``rcu_exp_handler()`` sees that
|
||||
the CPU is within RCU read-side critical section, the CPU cannot
|
||||
possibly be idle. Otherwise, ``rcu_exp_handler()`` invokes
|
||||
``rcu_report_exp_rdp()`` to report the corresponding quiescent state,
|
||||
regardless of whether or not that quiescent state was due to the CPU
|
||||
being idle.
|
||||
|
||||
In summary, RCU expedited grace periods check for idle when building the
|
||||
bitmask of CPUs that must be IPIed, just before sending each IPI, and
|
||||
(either explicitly or implicitly) within the IPI handler.
|
||||
|
||||
Batching via Sequence Counter
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If each grace-period request was carried out separately, expedited grace
|
||||
periods would have abysmal scalability and problematic high-load
|
||||
characteristics. Because each grace-period operation can serve an
|
||||
unlimited number of updates, it is important to *batch* requests, so
|
||||
that a single expedited grace-period operation will cover all requests
|
||||
in the corresponding batch.
|
||||
|
||||
This batching is controlled by a sequence counter named
|
||||
``->expedited_sequence`` in the ``rcu_state`` structure. This counter
|
||||
has an odd value when there is an expedited grace period in progress and
|
||||
an even value otherwise, so that dividing the counter value by two gives
|
||||
the number of completed grace periods. During any given update request,
|
||||
the counter must transition from even to odd and then back to even, thus
|
||||
indicating that a grace period has elapsed. Therefore, if the initial
|
||||
value of the counter is ``s``, the updater must wait until the counter
|
||||
reaches at least the value ``(s+3)&~0x1``. This counter is managed by
|
||||
the following access functions:
|
||||
|
||||
#. ``rcu_exp_gp_seq_start()``, which marks the start of an expedited
|
||||
grace period.
|
||||
#. ``rcu_exp_gp_seq_end()``, which marks the end of an expedited grace
|
||||
period.
|
||||
#. ``rcu_exp_gp_seq_snap()``, which obtains a snapshot of the counter.
|
||||
#. ``rcu_exp_gp_seq_done()``, which returns ``true`` if a full expedited
|
||||
grace period has elapsed since the corresponding call to
|
||||
``rcu_exp_gp_seq_snap()``.
|
||||
|
||||
Again, only one request in a given batch need actually carry out a
|
||||
grace-period operation, which means there must be an efficient way to
|
||||
identify which of many concurrent reqeusts will initiate the grace
|
||||
period, and that there be an efficient way for the remaining requests to
|
||||
wait for that grace period to complete. However, that is the topic of
|
||||
the next section.
|
||||
|
||||
Funnel Locking and Wait/Wakeup
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The natural way to sort out which of a batch of updaters will initiate
|
||||
the expedited grace period is to use the ``rcu_node`` combining tree, as
|
||||
implemented by the ``exp_funnel_lock()`` function. The first updater
|
||||
corresponding to a given grace period arriving at a given ``rcu_node``
|
||||
structure records its desired grace-period sequence number in the
|
||||
``->exp_seq_rq`` field and moves up to the next level in the tree.
|
||||
Otherwise, if the ``->exp_seq_rq`` field already contains the sequence
|
||||
number for the desired grace period or some later one, the updater
|
||||
blocks on one of four wait queues in the ``->exp_wq[]`` array, using the
|
||||
second-from-bottom and third-from bottom bits as an index. An
|
||||
``->exp_lock`` field in the ``rcu_node`` structure synchronizes access
|
||||
to these fields.
|
||||
|
||||
An empty ``rcu_node`` tree is shown in the following diagram, with the
|
||||
white cells representing the ``->exp_seq_rq`` field and the red cells
|
||||
representing the elements of the ``->exp_wq[]`` array.
|
||||
|
||||
.. kernel-figure:: Funnel0.svg
|
||||
|
||||
The next diagram shows the situation after the arrival of Task A and
|
||||
Task B at the leftmost and rightmost leaf ``rcu_node`` structures,
|
||||
respectively. The current value of the ``rcu_state`` structure's
|
||||
``->expedited_sequence`` field is zero, so adding three and clearing the
|
||||
bottom bit results in the value two, which both tasks record in the
|
||||
``->exp_seq_rq`` field of their respective ``rcu_node`` structures:
|
||||
|
||||
.. kernel-figure:: Funnel1.svg
|
||||
|
||||
Each of Tasks A and B will move up to the root ``rcu_node`` structure.
|
||||
Suppose that Task A wins, recording its desired grace-period sequence
|
||||
number and resulting in the state shown below:
|
||||
|
||||
.. kernel-figure:: Funnel2.svg
|
||||
|
||||
Task A now advances to initiate a new grace period, while Task B moves
|
||||
up to the root ``rcu_node`` structure, and, seeing that its desired
|
||||
sequence number is already recorded, blocks on ``->exp_wq[1]``.
|
||||
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Quick Quiz**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Why ``->exp_wq[1]``? Given that the value of these tasks' desired |
|
||||
| sequence number is two, so shouldn't they instead block on |
|
||||
| ``->exp_wq[2]``? |
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Answer**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| No. |
|
||||
| Recall that the bottom bit of the desired sequence number indicates |
|
||||
| whether or not a grace period is currently in progress. It is |
|
||||
| therefore necessary to shift the sequence number right one bit |
|
||||
| position to obtain the number of the grace period. This results in |
|
||||
| ``->exp_wq[1]``. |
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
If Tasks C and D also arrive at this point, they will compute the same
|
||||
desired grace-period sequence number, and see that both leaf
|
||||
``rcu_node`` structures already have that value recorded. They will
|
||||
therefore block on their respective ``rcu_node`` structures'
|
||||
``->exp_wq[1]`` fields, as shown below:
|
||||
|
||||
.. kernel-figure:: Funnel3.svg
|
||||
|
||||
Task A now acquires the ``rcu_state`` structure's ``->exp_mutex`` and
|
||||
initiates the grace period, which increments ``->expedited_sequence``.
|
||||
Therefore, if Tasks E and F arrive, they will compute a desired sequence
|
||||
number of 4 and will record this value as shown below:
|
||||
|
||||
.. kernel-figure:: Funnel4.svg
|
||||
|
||||
Tasks E and F will propagate up the ``rcu_node`` combining tree, with
|
||||
Task F blocking on the root ``rcu_node`` structure and Task E wait for
|
||||
Task A to finish so that it can start the next grace period. The
|
||||
resulting state is as shown below:
|
||||
|
||||
.. kernel-figure:: Funnel5.svg
|
||||
|
||||
Once the grace period completes, Task A starts waking up the tasks
|
||||
waiting for this grace period to complete, increments the
|
||||
``->expedited_sequence``, acquires the ``->exp_wake_mutex`` and then
|
||||
releases the ``->exp_mutex``. This results in the following state:
|
||||
|
||||
.. kernel-figure:: Funnel6.svg
|
||||
|
||||
Task E can then acquire ``->exp_mutex`` and increment
|
||||
``->expedited_sequence`` to the value three. If new tasks G and H arrive
|
||||
and moves up the combining tree at the same time, the state will be as
|
||||
follows:
|
||||
|
||||
.. kernel-figure:: Funnel7.svg
|
||||
|
||||
Note that three of the root ``rcu_node`` structure's waitqueues are now
|
||||
occupied. However, at some point, Task A will wake up the tasks blocked
|
||||
on the ``->exp_wq`` waitqueues, resulting in the following state:
|
||||
|
||||
.. kernel-figure:: Funnel8.svg
|
||||
|
||||
Execution will continue with Tasks E and H completing their grace
|
||||
periods and carrying out their wakeups.
|
||||
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Quick Quiz**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| What happens if Task A takes so long to do its wakeups that Task E's |
|
||||
| grace period completes? |
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Answer**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Then Task E will block on the ``->exp_wake_mutex``, which will also |
|
||||
| prevent it from releasing ``->exp_mutex``, which in turn will prevent |
|
||||
| the next grace period from starting. This last is important in |
|
||||
| preventing overflow of the ``->exp_wq[]`` array. |
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
Use of Workqueues
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
In earlier implementations, the task requesting the expedited grace
|
||||
period also drove it to completion. This straightforward approach had
|
||||
the disadvantage of needing to account for POSIX signals sent to user
|
||||
tasks, so more recent implemementations use the Linux kernel's
|
||||
`workqueues <https://www.kernel.org/doc/Documentation/core-api/workqueue.rst>`__.
|
||||
|
||||
The requesting task still does counter snapshotting and funnel-lock
|
||||
processing, but the task reaching the top of the funnel lock does a
|
||||
``schedule_work()`` (from ``_synchronize_rcu_expedited()`` so that a
|
||||
workqueue kthread does the actual grace-period processing. Because
|
||||
workqueue kthreads do not accept POSIX signals, grace-period-wait
|
||||
processing need not allow for POSIX signals. In addition, this approach
|
||||
allows wakeups for the previous expedited grace period to be overlapped
|
||||
with processing for the next expedited grace period. Because there are
|
||||
only four sets of waitqueues, it is necessary to ensure that the
|
||||
previous grace period's wakeups complete before the next grace period's
|
||||
wakeups start. This is handled by having the ``->exp_mutex`` guard
|
||||
expedited grace-period processing and the ``->exp_wake_mutex`` guard
|
||||
wakeups. The key point is that the ``->exp_mutex`` is not released until
|
||||
the first wakeup is complete, which means that the ``->exp_wake_mutex``
|
||||
has already been acquired at that point. This approach ensures that the
|
||||
previous grace period's wakeups can be carried out while the current
|
||||
grace period is in process, but that these wakeups will complete before
|
||||
the next grace period starts. This means that only three waitqueues are
|
||||
required, guaranteeing that the four that are provided are sufficient.
|
||||
|
||||
Stall Warnings
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Expediting grace periods does nothing to speed things up when RCU
|
||||
readers take too long, and therefore expedited grace periods check for
|
||||
stalls just as normal grace periods do.
|
||||
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Quick Quiz**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| But why not just let the normal grace-period machinery detect the |
|
||||
| stalls, given that a given reader must block both normal and |
|
||||
| expedited grace periods? |
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Answer**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Because it is quite possible that at a given time there is no normal |
|
||||
| grace period in progress, in which case the normal grace period |
|
||||
| cannot emit a stall warning. |
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
The ``synchronize_sched_expedited_wait()`` function loops waiting for
|
||||
the expedited grace period to end, but with a timeout set to the current
|
||||
RCU CPU stall-warning time. If this time is exceeded, any CPUs or
|
||||
``rcu_node`` structures blocking the current grace period are printed.
|
||||
Each stall warning results in another pass through the loop, but the
|
||||
second and subsequent passes use longer stall times.
|
||||
|
||||
Mid-boot operation
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The use of workqueues has the advantage that the expedited grace-period
|
||||
code need not worry about POSIX signals. Unfortunately, it has the
|
||||
corresponding disadvantage that workqueues cannot be used until they are
|
||||
initialized, which does not happen until some time after the scheduler
|
||||
spawns the first task. Given that there are parts of the kernel that
|
||||
really do want to execute grace periods during this mid-boot “dead
|
||||
zone”, expedited grace periods must do something else during thie time.
|
||||
|
||||
What they do is to fall back to the old practice of requiring that the
|
||||
requesting task drive the expedited grace period, as was the case before
|
||||
the use of workqueues. However, the requesting task is only required to
|
||||
drive the grace period during the mid-boot dead zone. Before mid-boot, a
|
||||
synchronous grace period is a no-op. Some time after mid-boot,
|
||||
workqueues are used.
|
||||
|
||||
Non-expedited non-SRCU synchronous grace periods must also operate
|
||||
normally during mid-boot. This is handled by causing non-expedited grace
|
||||
periods to take the expedited code path during mid-boot.
|
||||
|
||||
The current code assumes that there are no POSIX signals during the
|
||||
mid-boot dead zone. However, if an overwhelming need for POSIX signals
|
||||
somehow arises, appropriate adjustments can be made to the expedited
|
||||
stall-warning code. One such adjustment would reinstate the
|
||||
pre-workqueue stall-warning checks, but only during the mid-boot dead
|
||||
zone.
|
||||
|
||||
With this refinement, synchronous grace periods can now be used from
|
||||
task context pretty much any time during the life of the kernel. That
|
||||
is, aside from some points in the suspend, hibernate, or shutdown code
|
||||
path.
|
||||
|
||||
Summary
|
||||
~~~~~~~
|
||||
|
||||
Expedited grace periods use a sequence-number approach to promote
|
||||
batching, so that a single grace-period operation can serve numerous
|
||||
requests. A funnel lock is used to efficiently identify the one task out
|
||||
of a concurrent group that will request the grace period. All members of
|
||||
the group will block on waitqueues provided in the ``rcu_node``
|
||||
structure. The actual grace-period processing is carried out by a
|
||||
workqueue.
|
||||
|
||||
CPU-hotplug operations are noted lazily in order to prevent the need for
|
||||
tight synchronization between expedited grace periods and CPU-hotplug
|
||||
operations. The dyntick-idle counters are used to avoid sending IPIs to
|
||||
idle CPUs, at least in the common case. RCU-preempt and RCU-sched use
|
||||
different IPI handlers and different code to respond to the state
|
||||
changes carried out by those handlers, but otherwise use common code.
|
||||
|
||||
Quiescent states are tracked using the ``rcu_node`` tree, and once all
|
||||
necessary quiescent states have been reported, all tasks waiting on this
|
||||
expedited grace period are awakened. A pair of mutexes are used to allow
|
||||
one grace period's wakeups to proceed concurrently with the next grace
|
||||
period's processing.
|
||||
|
||||
This combination of mechanisms allows expedited grace periods to run
|
||||
reasonably efficiently. However, for non-time-critical tasks, normal
|
||||
grace periods should be used instead because their longer duration
|
||||
permits much higher degrees of batching, and thus much lower per-request
|
||||
overheads.
|
@ -1,9 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head><title>A Diagram of TREE_RCU's Grace-Period Memory Ordering</title>
|
||||
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
|
||||
<p><img src="TreeRCU-gp.svg" alt="TreeRCU-gp.svg">
|
||||
|
||||
</body></html>
|
@ -1,704 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head><title>A Tour Through TREE_RCU's Grace-Period Memory Ordering</title>
|
||||
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
|
||||
<p>August 8, 2017</p>
|
||||
<p>This article was contributed by Paul E. McKenney</p>
|
||||
|
||||
<h3>Introduction</h3>
|
||||
|
||||
<p>This document gives a rough visual overview of how Tree RCU's
|
||||
grace-period memory ordering guarantee is provided.
|
||||
|
||||
<ol>
|
||||
<li> <a href="#What Is Tree RCU's Grace Period Memory Ordering Guarantee?">
|
||||
What Is Tree RCU's Grace Period Memory Ordering Guarantee?</a>
|
||||
<li> <a href="#Tree RCU Grace Period Memory Ordering Building Blocks">
|
||||
Tree RCU Grace Period Memory Ordering Building Blocks</a>
|
||||
<li> <a href="#Tree RCU Grace Period Memory Ordering Components">
|
||||
Tree RCU Grace Period Memory Ordering Components</a>
|
||||
<li> <a href="#Putting It All Together">Putting It All Together</a>
|
||||
</ol>
|
||||
|
||||
<h3><a name="What Is Tree RCU's Grace Period Memory Ordering Guarantee?">
|
||||
What Is Tree RCU's Grace Period Memory Ordering Guarantee?</a></h3>
|
||||
|
||||
<p>RCU grace periods provide extremely strong memory-ordering guarantees
|
||||
for non-idle non-offline code.
|
||||
Any code that happens after the end of a given RCU grace period is guaranteed
|
||||
to see the effects of all accesses prior to the beginning of that grace
|
||||
period that are within RCU read-side critical sections.
|
||||
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
|
||||
of that grace period that are within RCU read-side critical sections.
|
||||
|
||||
<p>Note well that RCU-sched read-side critical sections include any region
|
||||
of code for which preemption is disabled.
|
||||
Given that each individual machine instruction can be thought of as
|
||||
an extremely small region of preemption-disabled code, one can think of
|
||||
<tt>synchronize_rcu()</tt> as <tt>smp_mb()</tt> on steroids.
|
||||
|
||||
<p>RCU updaters use this guarantee by splitting their updates into
|
||||
two phases, one of which is executed before the grace period and
|
||||
the other of which is executed after the grace period.
|
||||
In the most common use case, phase one removes an element from
|
||||
a linked RCU-protected data structure, and phase two frees that element.
|
||||
For this to work, any readers that have witnessed state prior to the
|
||||
phase-one update (in the common case, removal) must not witness state
|
||||
following the phase-two update (in the common case, freeing).
|
||||
|
||||
<p>The RCU implementation provides this guarantee using a network
|
||||
of lock-based critical sections, memory barriers, and per-CPU
|
||||
processing, as is described in the following sections.
|
||||
|
||||
<h3><a name="Tree RCU Grace Period Memory Ordering Building Blocks">
|
||||
Tree RCU Grace Period Memory Ordering Building Blocks</a></h3>
|
||||
|
||||
<p>The workhorse for RCU's grace-period memory ordering is the
|
||||
critical section for the <tt>rcu_node</tt> structure's
|
||||
<tt>->lock</tt>.
|
||||
These critical sections use helper functions for lock acquisition, including
|
||||
<tt>raw_spin_lock_rcu_node()</tt>,
|
||||
<tt>raw_spin_lock_irq_rcu_node()</tt>, and
|
||||
<tt>raw_spin_lock_irqsave_rcu_node()</tt>.
|
||||
Their lock-release counterparts are
|
||||
<tt>raw_spin_unlock_rcu_node()</tt>,
|
||||
<tt>raw_spin_unlock_irq_rcu_node()</tt>, and
|
||||
<tt>raw_spin_unlock_irqrestore_rcu_node()</tt>,
|
||||
respectively.
|
||||
For completeness, a
|
||||
<tt>raw_spin_trylock_rcu_node()</tt>
|
||||
is also provided.
|
||||
The key point is that the lock-acquisition functions, including
|
||||
<tt>raw_spin_trylock_rcu_node()</tt>, all invoke
|
||||
<tt>smp_mb__after_unlock_lock()</tt> immediately after successful
|
||||
acquisition of the lock.
|
||||
|
||||
<p>Therefore, for any given <tt>rcu_node</tt> structure, any access
|
||||
happening before one of the above lock-release functions will be seen
|
||||
by all CPUs as happening before any access happening after a later
|
||||
one of the above lock-acquisition functions.
|
||||
Furthermore, any access happening before one of the
|
||||
above lock-release function on any given CPU will be seen by all
|
||||
CPUs as happening before any access happening after a later one
|
||||
of the above lock-acquisition functions executing on that same CPU,
|
||||
even if the lock-release and lock-acquisition functions are operating
|
||||
on different <tt>rcu_node</tt> structures.
|
||||
Tree RCU uses these two ordering guarantees to form an ordering
|
||||
network among all CPUs that were in any way involved in the grace
|
||||
period, including any CPUs that came online or went offline during
|
||||
the grace period in question.
|
||||
|
||||
<p>The following litmus test exhibits the ordering effects of these
|
||||
lock-acquisition and lock-release functions:
|
||||
|
||||
<pre>
|
||||
1 int x, y, z;
|
||||
2
|
||||
3 void task0(void)
|
||||
4 {
|
||||
5 raw_spin_lock_rcu_node(rnp);
|
||||
6 WRITE_ONCE(x, 1);
|
||||
7 r1 = READ_ONCE(y);
|
||||
8 raw_spin_unlock_rcu_node(rnp);
|
||||
9 }
|
||||
10
|
||||
11 void task1(void)
|
||||
12 {
|
||||
13 raw_spin_lock_rcu_node(rnp);
|
||||
14 WRITE_ONCE(y, 1);
|
||||
15 r2 = READ_ONCE(z);
|
||||
16 raw_spin_unlock_rcu_node(rnp);
|
||||
17 }
|
||||
18
|
||||
19 void task2(void)
|
||||
20 {
|
||||
21 WRITE_ONCE(z, 1);
|
||||
22 smp_mb();
|
||||
23 r3 = READ_ONCE(x);
|
||||
24 }
|
||||
25
|
||||
26 WARN_ON(r1 == 0 && r2 == 0 && r3 == 0);
|
||||
</pre>
|
||||
|
||||
<p>The <tt>WARN_ON()</tt> is evaluated at “the end of time”,
|
||||
after all changes have propagated throughout the system.
|
||||
Without the <tt>smp_mb__after_unlock_lock()</tt> provided by the
|
||||
acquisition functions, this <tt>WARN_ON()</tt> could trigger, for example
|
||||
on PowerPC.
|
||||
The <tt>smp_mb__after_unlock_lock()</tt> invocations prevent this
|
||||
<tt>WARN_ON()</tt> from triggering.
|
||||
|
||||
<p>This approach must be extended to include idle CPUs, which need
|
||||
RCU's grace-period memory ordering guarantee to extend to any
|
||||
RCU read-side critical sections preceding and following the current
|
||||
idle sojourn.
|
||||
This case is handled by calls to the strongly ordered
|
||||
<tt>atomic_add_return()</tt> read-modify-write atomic operation that
|
||||
is invoked within <tt>rcu_dynticks_eqs_enter()</tt> at idle-entry
|
||||
time and within <tt>rcu_dynticks_eqs_exit()</tt> at idle-exit time.
|
||||
The grace-period kthread invokes <tt>rcu_dynticks_snap()</tt> and
|
||||
<tt>rcu_dynticks_in_eqs_since()</tt> (both of which invoke
|
||||
an <tt>atomic_add_return()</tt> of zero) to detect idle CPUs.
|
||||
|
||||
<table>
|
||||
<tr><th> </th></tr>
|
||||
<tr><th align="left">Quick Quiz:</th></tr>
|
||||
<tr><td>
|
||||
But what about CPUs that remain offline for the entire
|
||||
grace period?
|
||||
</td></tr>
|
||||
<tr><th align="left">Answer:</th></tr>
|
||||
<tr><td bgcolor="#ffffff"><font color="ffffff">
|
||||
Such CPUs will be offline at the beginning of the grace period,
|
||||
so the grace period won't expect quiescent states from them.
|
||||
Races between grace-period start and CPU-hotplug operations
|
||||
are mediated by the CPU's leaf <tt>rcu_node</tt> structure's
|
||||
<tt>->lock</tt> as described above.
|
||||
</font></td></tr>
|
||||
<tr><td> </td></tr>
|
||||
</table>
|
||||
|
||||
<p>The approach must be extended to handle one final case, that
|
||||
of waking a task blocked in <tt>synchronize_rcu()</tt>.
|
||||
This task might be affinitied to a CPU that is not yet aware that
|
||||
the grace period has ended, and thus might not yet be subject to
|
||||
the grace period's memory ordering.
|
||||
Therefore, there is an <tt>smp_mb()</tt> after the return from
|
||||
<tt>wait_for_completion()</tt> in the <tt>synchronize_rcu()</tt>
|
||||
code path.
|
||||
|
||||
<table>
|
||||
<tr><th> </th></tr>
|
||||
<tr><th align="left">Quick Quiz:</th></tr>
|
||||
<tr><td>
|
||||
What? Where???
|
||||
I don't see any <tt>smp_mb()</tt> after the return from
|
||||
<tt>wait_for_completion()</tt>!!!
|
||||
</td></tr>
|
||||
<tr><th align="left">Answer:</th></tr>
|
||||
<tr><td bgcolor="#ffffff"><font color="ffffff">
|
||||
That would be because I spotted the need for that
|
||||
<tt>smp_mb()</tt> during the creation of this documentation,
|
||||
and it is therefore unlikely to hit mainline before v4.14.
|
||||
Kudos to Lance Roy, Will Deacon, Peter Zijlstra, and
|
||||
Jonathan Cameron for asking questions that sensitized me
|
||||
to the rather elaborate sequence of events that demonstrate
|
||||
the need for this memory barrier.
|
||||
</font></td></tr>
|
||||
<tr><td> </td></tr>
|
||||
</table>
|
||||
|
||||
<p>Tree RCU's grace--period memory-ordering guarantees rely most
|
||||
heavily on the <tt>rcu_node</tt> structure's <tt>->lock</tt>
|
||||
field, so much so that it is necessary to abbreviate this pattern
|
||||
in the diagrams in the next section.
|
||||
For example, consider the <tt>rcu_prepare_for_idle()</tt> function
|
||||
shown below, which is one of several functions that enforce ordering
|
||||
of newly arrived RCU callbacks against future grace periods:
|
||||
|
||||
<pre>
|
||||
1 static void rcu_prepare_for_idle(void)
|
||||
2 {
|
||||
3 bool needwake;
|
||||
4 struct rcu_data *rdp;
|
||||
5 struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks);
|
||||
6 struct rcu_node *rnp;
|
||||
7 struct rcu_state *rsp;
|
||||
8 int tne;
|
||||
9
|
||||
10 if (IS_ENABLED(CONFIG_RCU_NOCB_CPU_ALL) ||
|
||||
11 rcu_is_nocb_cpu(smp_processor_id()))
|
||||
12 return;
|
||||
13 tne = READ_ONCE(tick_nohz_active);
|
||||
14 if (tne != rdtp->tick_nohz_enabled_snap) {
|
||||
15 if (rcu_cpu_has_callbacks(NULL))
|
||||
16 invoke_rcu_core();
|
||||
17 rdtp->tick_nohz_enabled_snap = tne;
|
||||
18 return;
|
||||
19 }
|
||||
20 if (!tne)
|
||||
21 return;
|
||||
22 if (rdtp->all_lazy &&
|
||||
23 rdtp->nonlazy_posted != rdtp->nonlazy_posted_snap) {
|
||||
24 rdtp->all_lazy = false;
|
||||
25 rdtp->nonlazy_posted_snap = rdtp->nonlazy_posted;
|
||||
26 invoke_rcu_core();
|
||||
27 return;
|
||||
28 }
|
||||
29 if (rdtp->last_accelerate == jiffies)
|
||||
30 return;
|
||||
31 rdtp->last_accelerate = jiffies;
|
||||
32 for_each_rcu_flavor(rsp) {
|
||||
33 rdp = this_cpu_ptr(rsp->rda);
|
||||
34 if (rcu_segcblist_pend_cbs(&rdp->cblist))
|
||||
35 continue;
|
||||
36 rnp = rdp->mynode;
|
||||
37 raw_spin_lock_rcu_node(rnp);
|
||||
38 needwake = rcu_accelerate_cbs(rsp, rnp, rdp);
|
||||
39 raw_spin_unlock_rcu_node(rnp);
|
||||
40 if (needwake)
|
||||
41 rcu_gp_kthread_wake(rsp);
|
||||
42 }
|
||||
43 }
|
||||
</pre>
|
||||
|
||||
<p>But the only part of <tt>rcu_prepare_for_idle()</tt> that really
|
||||
matters for this discussion are lines 37–39.
|
||||
We will therefore abbreviate this function as follows:
|
||||
|
||||
</p><p><img src="rcu_node-lock.svg" alt="rcu_node-lock.svg">
|
||||
|
||||
<p>The box represents the <tt>rcu_node</tt> structure's <tt>->lock</tt>
|
||||
critical section, with the double line on top representing the additional
|
||||
<tt>smp_mb__after_unlock_lock()</tt>.
|
||||
|
||||
<h3><a name="Tree RCU Grace Period Memory Ordering Components">
|
||||
Tree RCU Grace Period Memory Ordering Components</a></h3>
|
||||
|
||||
<p>Tree RCU's grace-period memory-ordering guarantee is provided by
|
||||
a number of RCU components:
|
||||
|
||||
<ol>
|
||||
<li> <a href="#Callback Registry">Callback Registry</a>
|
||||
<li> <a href="#Grace-Period Initialization">Grace-Period Initialization</a>
|
||||
<li> <a href="#Self-Reported Quiescent States">
|
||||
Self-Reported Quiescent States</a>
|
||||
<li> <a href="#Dynamic Tick Interface">Dynamic Tick Interface</a>
|
||||
<li> <a href="#CPU-Hotplug Interface">CPU-Hotplug Interface</a>
|
||||
<li> <a href="Forcing Quiescent States">Forcing Quiescent States</a>
|
||||
<li> <a href="Grace-Period Cleanup">Grace-Period Cleanup</a>
|
||||
<li> <a href="Callback Invocation">Callback Invocation</a>
|
||||
</ol>
|
||||
|
||||
<p>Each of the following section looks at the corresponding component
|
||||
in detail.
|
||||
|
||||
<h4><a name="Callback Registry">Callback Registry</a></h4>
|
||||
|
||||
<p>If RCU's grace-period guarantee is to mean anything at all, any
|
||||
access that happens before a given invocation of <tt>call_rcu()</tt>
|
||||
must also happen before the corresponding grace period.
|
||||
The implementation of this portion of RCU's grace period guarantee
|
||||
is shown in the following figure:
|
||||
|
||||
</p><p><img src="TreeRCU-callback-registry.svg" alt="TreeRCU-callback-registry.svg">
|
||||
|
||||
<p>Because <tt>call_rcu()</tt> normally acts only on CPU-local state,
|
||||
it provides no ordering guarantees, either for itself or for
|
||||
phase one of the update (which again will usually be removal of
|
||||
an element from an RCU-protected data structure).
|
||||
It simply enqueues the <tt>rcu_head</tt> structure on a per-CPU list,
|
||||
which cannot become associated with a grace period until a later
|
||||
call to <tt>rcu_accelerate_cbs()</tt>, as shown in the diagram above.
|
||||
|
||||
<p>One set of code paths shown on the left invokes
|
||||
<tt>rcu_accelerate_cbs()</tt> via
|
||||
<tt>note_gp_changes()</tt>, either directly from <tt>call_rcu()</tt> (if
|
||||
the current CPU is inundated with queued <tt>rcu_head</tt> structures)
|
||||
or more likely from an <tt>RCU_SOFTIRQ</tt> handler.
|
||||
Another code path in the middle is taken only in kernels built with
|
||||
<tt>CONFIG_RCU_FAST_NO_HZ=y</tt>, which invokes
|
||||
<tt>rcu_accelerate_cbs()</tt> via <tt>rcu_prepare_for_idle()</tt>.
|
||||
The final code path on the right is taken only in kernels built with
|
||||
<tt>CONFIG_HOTPLUG_CPU=y</tt>, which invokes
|
||||
<tt>rcu_accelerate_cbs()</tt> via
|
||||
<tt>rcu_advance_cbs()</tt>, <tt>rcu_migrate_callbacks</tt>,
|
||||
<tt>rcutree_migrate_callbacks()</tt>, and <tt>takedown_cpu()</tt>,
|
||||
which in turn is invoked on a surviving CPU after the outgoing
|
||||
CPU has been completely offlined.
|
||||
|
||||
<p>There are a few other code paths within grace-period processing
|
||||
that opportunistically invoke <tt>rcu_accelerate_cbs()</tt>.
|
||||
However, either way, all of the CPU's recently queued <tt>rcu_head</tt>
|
||||
structures are associated with a future grace-period number under
|
||||
the protection of the CPU's lead <tt>rcu_node</tt> structure's
|
||||
<tt>->lock</tt>.
|
||||
In all cases, there is full ordering against any prior critical section
|
||||
for that same <tt>rcu_node</tt> structure's <tt>->lock</tt>, and
|
||||
also full ordering against any of the current task's or CPU's prior critical
|
||||
sections for any <tt>rcu_node</tt> structure's <tt>->lock</tt>.
|
||||
|
||||
<p>The next section will show how this ordering ensures that any
|
||||
accesses prior to the <tt>call_rcu()</tt> (particularly including phase
|
||||
one of the update)
|
||||
happen before the start of the corresponding grace period.
|
||||
|
||||
<table>
|
||||
<tr><th> </th></tr>
|
||||
<tr><th align="left">Quick Quiz:</th></tr>
|
||||
<tr><td>
|
||||
But what about <tt>synchronize_rcu()</tt>?
|
||||
</td></tr>
|
||||
<tr><th align="left">Answer:</th></tr>
|
||||
<tr><td bgcolor="#ffffff"><font color="ffffff">
|
||||
The <tt>synchronize_rcu()</tt> passes <tt>call_rcu()</tt>
|
||||
to <tt>wait_rcu_gp()</tt>, which invokes it.
|
||||
So either way, it eventually comes down to <tt>call_rcu()</tt>.
|
||||
</font></td></tr>
|
||||
<tr><td> </td></tr>
|
||||
</table>
|
||||
|
||||
<h4><a name="Grace-Period Initialization">Grace-Period Initialization</a></h4>
|
||||
|
||||
<p>Grace-period initialization is carried out by
|
||||
the grace-period kernel thread, which makes several passes over the
|
||||
<tt>rcu_node</tt> tree within the <tt>rcu_gp_init()</tt> function.
|
||||
This means that showing the full flow of ordering through the
|
||||
grace-period computation will require duplicating this tree.
|
||||
If you find this confusing, please note that the state of the
|
||||
<tt>rcu_node</tt> changes over time, just like Heraclitus's river.
|
||||
However, to keep the <tt>rcu_node</tt> river tractable, the
|
||||
grace-period kernel thread's traversals are presented in multiple
|
||||
parts, starting in this section with the various phases of
|
||||
grace-period initialization.
|
||||
|
||||
<p>The first ordering-related grace-period initialization action is to
|
||||
advance the <tt>rcu_state</tt> structure's <tt>->gp_seq</tt>
|
||||
grace-period-number counter, as shown below:
|
||||
|
||||
</p><p><img src="TreeRCU-gp-init-1.svg" alt="TreeRCU-gp-init-1.svg" width="75%">
|
||||
|
||||
<p>The actual increment is carried out using <tt>smp_store_release()</tt>,
|
||||
which helps reject false-positive RCU CPU stall detection.
|
||||
Note that only the root <tt>rcu_node</tt> structure is touched.
|
||||
|
||||
<p>The first pass through the <tt>rcu_node</tt> tree updates bitmasks
|
||||
based on CPUs having come online or gone offline since the start of
|
||||
the previous grace period.
|
||||
In the common case where the number of online CPUs for this <tt>rcu_node</tt>
|
||||
structure has not transitioned to or from zero,
|
||||
this pass will scan only the leaf <tt>rcu_node</tt> structures.
|
||||
However, if the number of online CPUs for a given leaf <tt>rcu_node</tt>
|
||||
structure has transitioned from zero,
|
||||
<tt>rcu_init_new_rnp()</tt> will be invoked for the first incoming CPU.
|
||||
Similarly, if the number of online CPUs for a given leaf <tt>rcu_node</tt>
|
||||
structure has transitioned to zero,
|
||||
<tt>rcu_cleanup_dead_rnp()</tt> will be invoked for the last outgoing CPU.
|
||||
The diagram below shows the path of ordering if the leftmost
|
||||
<tt>rcu_node</tt> structure onlines its first CPU and if the next
|
||||
<tt>rcu_node</tt> structure has no online CPUs
|
||||
(or, alternatively if the leftmost <tt>rcu_node</tt> structure offlines
|
||||
its last CPU and if the next <tt>rcu_node</tt> structure has no online CPUs).
|
||||
|
||||
</p><p><img src="TreeRCU-gp-init-2.svg" alt="TreeRCU-gp-init-1.svg" width="75%">
|
||||
|
||||
<p>The final <tt>rcu_gp_init()</tt> pass through the <tt>rcu_node</tt>
|
||||
tree traverses breadth-first, setting each <tt>rcu_node</tt> structure's
|
||||
<tt>->gp_seq</tt> field to the newly advanced value from the
|
||||
<tt>rcu_state</tt> structure, as shown in the following diagram.
|
||||
|
||||
</p><p><img src="TreeRCU-gp-init-3.svg" alt="TreeRCU-gp-init-1.svg" width="75%">
|
||||
|
||||
<p>This change will also cause each CPU's next call to
|
||||
<tt>__note_gp_changes()</tt>
|
||||
to notice that a new grace period has started, as described in the next
|
||||
section.
|
||||
But because the grace-period kthread started the grace period at the
|
||||
root (with the advancing of the <tt>rcu_state</tt> structure's
|
||||
<tt>->gp_seq</tt> field) before setting each leaf <tt>rcu_node</tt>
|
||||
structure's <tt>->gp_seq</tt> field, each CPU's observation of
|
||||
the start of the grace period will happen after the actual start
|
||||
of the grace period.
|
||||
|
||||
<table>
|
||||
<tr><th> </th></tr>
|
||||
<tr><th align="left">Quick Quiz:</th></tr>
|
||||
<tr><td>
|
||||
But what about the CPU that started the grace period?
|
||||
Why wouldn't it see the start of the grace period right when
|
||||
it started that grace period?
|
||||
</td></tr>
|
||||
<tr><th align="left">Answer:</th></tr>
|
||||
<tr><td bgcolor="#ffffff"><font color="ffffff">
|
||||
In some deep philosophical and overly anthromorphized
|
||||
sense, yes, the CPU starting the grace period is immediately
|
||||
aware of having done so.
|
||||
However, if we instead assume that RCU is not self-aware,
|
||||
then even the CPU starting the grace period does not really
|
||||
become aware of the start of this grace period until its
|
||||
first call to <tt>__note_gp_changes()</tt>.
|
||||
On the other hand, this CPU potentially gets early notification
|
||||
because it invokes <tt>__note_gp_changes()</tt> during its
|
||||
last <tt>rcu_gp_init()</tt> pass through its leaf
|
||||
<tt>rcu_node</tt> structure.
|
||||
</font></td></tr>
|
||||
<tr><td> </td></tr>
|
||||
</table>
|
||||
|
||||
<h4><a name="Self-Reported Quiescent States">
|
||||
Self-Reported Quiescent States</a></h4>
|
||||
|
||||
<p>When all entities that might block the grace period have reported
|
||||
quiescent states (or as described in a later section, had quiescent
|
||||
states reported on their behalf), the grace period can end.
|
||||
Online non-idle CPUs report their own quiescent states, as shown
|
||||
in the following diagram:
|
||||
|
||||
</p><p><img src="TreeRCU-qs.svg" alt="TreeRCU-qs.svg" width="75%">
|
||||
|
||||
<p>This is for the last CPU to report a quiescent state, which signals
|
||||
the end of the grace period.
|
||||
Earlier quiescent states would push up the <tt>rcu_node</tt> tree
|
||||
only until they encountered an <tt>rcu_node</tt> structure that
|
||||
is waiting for additional quiescent states.
|
||||
However, ordering is nevertheless preserved because some later quiescent
|
||||
state will acquire that <tt>rcu_node</tt> structure's <tt>->lock</tt>.
|
||||
|
||||
<p>Any number of events can lead up to a CPU invoking
|
||||
<tt>note_gp_changes</tt> (or alternatively, directly invoking
|
||||
<tt>__note_gp_changes()</tt>), at which point that CPU will notice
|
||||
the start of a new grace period while holding its leaf
|
||||
<tt>rcu_node</tt> lock.
|
||||
Therefore, all execution shown in this diagram happens after the
|
||||
start of the grace period.
|
||||
In addition, this CPU will consider any RCU read-side critical
|
||||
section that started before the invocation of <tt>__note_gp_changes()</tt>
|
||||
to have started before the grace period, and thus a critical
|
||||
section that the grace period must wait on.
|
||||
|
||||
<table>
|
||||
<tr><th> </th></tr>
|
||||
<tr><th align="left">Quick Quiz:</th></tr>
|
||||
<tr><td>
|
||||
But a RCU read-side critical section might have started
|
||||
after the beginning of the grace period
|
||||
(the advancing of <tt>->gp_seq</tt> from earlier), so why should
|
||||
the grace period wait on such a critical section?
|
||||
</td></tr>
|
||||
<tr><th align="left">Answer:</th></tr>
|
||||
<tr><td bgcolor="#ffffff"><font color="ffffff">
|
||||
It is indeed not necessary for the grace period to wait on such
|
||||
a critical section.
|
||||
However, it is permissible to wait on it.
|
||||
And it is furthermore important to wait on it, as this
|
||||
lazy approach is far more scalable than a “big bang”
|
||||
all-at-once grace-period start could possibly be.
|
||||
</font></td></tr>
|
||||
<tr><td> </td></tr>
|
||||
</table>
|
||||
|
||||
<p>If the CPU does a context switch, a quiescent state will be
|
||||
noted by <tt>rcu_node_context_switch()</tt> on the left.
|
||||
On the other hand, if the CPU takes a scheduler-clock interrupt
|
||||
while executing in usermode, a quiescent state will be noted by
|
||||
<tt>rcu_sched_clock_irq()</tt> on the right.
|
||||
Either way, the passage through a quiescent state will be noted
|
||||
in a per-CPU variable.
|
||||
|
||||
<p>The next time an <tt>RCU_SOFTIRQ</tt> handler executes on
|
||||
this CPU (for example, after the next scheduler-clock
|
||||
interrupt), <tt>rcu_core()</tt> will invoke
|
||||
<tt>rcu_check_quiescent_state()</tt>, which will notice the
|
||||
recorded quiescent state, and invoke
|
||||
<tt>rcu_report_qs_rdp()</tt>.
|
||||
If <tt>rcu_report_qs_rdp()</tt> verifies that the quiescent state
|
||||
really does apply to the current grace period, it invokes
|
||||
<tt>rcu_report_rnp()</tt> which traverses up the <tt>rcu_node</tt>
|
||||
tree as shown at the bottom of the diagram, clearing bits from
|
||||
each <tt>rcu_node</tt> structure's <tt>->qsmask</tt> field,
|
||||
and propagating up the tree when the result is zero.
|
||||
|
||||
<p>Note that traversal passes upwards out of a given <tt>rcu_node</tt>
|
||||
structure only if the current CPU is reporting the last quiescent
|
||||
state for the subtree headed by that <tt>rcu_node</tt> structure.
|
||||
A key point is that if a CPU's traversal stops at a given <tt>rcu_node</tt>
|
||||
structure, then there will be a later traversal by another CPU
|
||||
(or perhaps the same one) that proceeds upwards
|
||||
from that point, and the <tt>rcu_node</tt> <tt>->lock</tt>
|
||||
guarantees that the first CPU's quiescent state happens before the
|
||||
remainder of the second CPU's traversal.
|
||||
Applying this line of thought repeatedly shows that all CPUs'
|
||||
quiescent states happen before the last CPU traverses through
|
||||
the root <tt>rcu_node</tt> structure, the “last CPU”
|
||||
being the one that clears the last bit in the root <tt>rcu_node</tt>
|
||||
structure's <tt>->qsmask</tt> field.
|
||||
|
||||
<h4><a name="Dynamic Tick Interface">Dynamic Tick Interface</a></h4>
|
||||
|
||||
<p>Due to energy-efficiency considerations, RCU is forbidden from
|
||||
disturbing idle CPUs.
|
||||
CPUs are therefore required to notify RCU when entering or leaving idle
|
||||
state, which they do via fully ordered value-returning atomic operations
|
||||
on a per-CPU variable.
|
||||
The ordering effects are as shown below:
|
||||
|
||||
</p><p><img src="TreeRCU-dyntick.svg" alt="TreeRCU-dyntick.svg" width="50%">
|
||||
|
||||
<p>The RCU grace-period kernel thread samples the per-CPU idleness
|
||||
variable while holding the corresponding CPU's leaf <tt>rcu_node</tt>
|
||||
structure's <tt>->lock</tt>.
|
||||
This means that any RCU read-side critical sections that precede the
|
||||
idle period (the oval near the top of the diagram above) will happen
|
||||
before the end of the current grace period.
|
||||
Similarly, the beginning of the current grace period will happen before
|
||||
any RCU read-side critical sections that follow the
|
||||
idle period (the oval near the bottom of the diagram above).
|
||||
|
||||
<p>Plumbing this into the full grace-period execution is described
|
||||
<a href="#Forcing Quiescent States">below</a>.
|
||||
|
||||
<h4><a name="CPU-Hotplug Interface">CPU-Hotplug Interface</a></h4>
|
||||
|
||||
<p>RCU is also forbidden from disturbing offline CPUs, which might well
|
||||
be powered off and removed from the system completely.
|
||||
CPUs are therefore required to notify RCU of their comings and goings
|
||||
as part of the corresponding CPU hotplug operations.
|
||||
The ordering effects are shown below:
|
||||
|
||||
</p><p><img src="TreeRCU-hotplug.svg" alt="TreeRCU-hotplug.svg" width="50%">
|
||||
|
||||
<p>Because CPU hotplug operations are much less frequent than idle transitions,
|
||||
they are heavier weight, and thus acquire the CPU's leaf <tt>rcu_node</tt>
|
||||
structure's <tt>->lock</tt> and update this structure's
|
||||
<tt>->qsmaskinitnext</tt>.
|
||||
The RCU grace-period kernel thread samples this mask to detect CPUs
|
||||
having gone offline since the beginning of this grace period.
|
||||
|
||||
<p>Plumbing this into the full grace-period execution is described
|
||||
<a href="#Forcing Quiescent States">below</a>.
|
||||
|
||||
<h4><a name="Forcing Quiescent States">Forcing Quiescent States</a></h4>
|
||||
|
||||
<p>As noted above, idle and offline CPUs cannot report their own
|
||||
quiescent states, and therefore the grace-period kernel thread
|
||||
must do the reporting on their behalf.
|
||||
This process is called “forcing quiescent states”, it is
|
||||
repeated every few jiffies, and its ordering effects are shown below:
|
||||
|
||||
</p><p><img src="TreeRCU-gp-fqs.svg" alt="TreeRCU-gp-fqs.svg" width="100%">
|
||||
|
||||
<p>Each pass of quiescent state forcing is guaranteed to traverse the
|
||||
leaf <tt>rcu_node</tt> structures, and if there are no new quiescent
|
||||
states due to recently idled and/or offlined CPUs, then only the
|
||||
leaves are traversed.
|
||||
However, if there is a newly offlined CPU as illustrated on the left
|
||||
or a newly idled CPU as illustrated on the right, the corresponding
|
||||
quiescent state will be driven up towards the root.
|
||||
As with self-reported quiescent states, the upwards driving stops
|
||||
once it reaches an <tt>rcu_node</tt> structure that has quiescent
|
||||
states outstanding from other CPUs.
|
||||
|
||||
<table>
|
||||
<tr><th> </th></tr>
|
||||
<tr><th align="left">Quick Quiz:</th></tr>
|
||||
<tr><td>
|
||||
The leftmost drive to root stopped before it reached
|
||||
the root <tt>rcu_node</tt> structure, which means that
|
||||
there are still CPUs subordinate to that structure on
|
||||
which the current grace period is waiting.
|
||||
Given that, how is it possible that the rightmost drive
|
||||
to root ended the grace period?
|
||||
</td></tr>
|
||||
<tr><th align="left">Answer:</th></tr>
|
||||
<tr><td bgcolor="#ffffff"><font color="ffffff">
|
||||
Good analysis!
|
||||
It is in fact impossible in the absence of bugs in RCU.
|
||||
But this diagram is complex enough as it is, so simplicity
|
||||
overrode accuracy.
|
||||
You can think of it as poetic license, or you can think of
|
||||
it as misdirection that is resolved in the
|
||||
<a href="#Putting It All Together">stitched-together diagram</a>.
|
||||
</font></td></tr>
|
||||
<tr><td> </td></tr>
|
||||
</table>
|
||||
|
||||
<h4><a name="Grace-Period Cleanup">Grace-Period Cleanup</a></h4>
|
||||
|
||||
<p>Grace-period cleanup first scans the <tt>rcu_node</tt> tree
|
||||
breadth-first advancing all the <tt>->gp_seq</tt> fields, then it
|
||||
advances the <tt>rcu_state</tt> structure's <tt>->gp_seq</tt> field.
|
||||
The ordering effects are shown below:
|
||||
|
||||
</p><p><img src="TreeRCU-gp-cleanup.svg" alt="TreeRCU-gp-cleanup.svg" width="75%">
|
||||
|
||||
<p>As indicated by the oval at the bottom of the diagram, once
|
||||
grace-period cleanup is complete, the next grace period can begin.
|
||||
|
||||
<table>
|
||||
<tr><th> </th></tr>
|
||||
<tr><th align="left">Quick Quiz:</th></tr>
|
||||
<tr><td>
|
||||
But when precisely does the grace period end?
|
||||
</td></tr>
|
||||
<tr><th align="left">Answer:</th></tr>
|
||||
<tr><td bgcolor="#ffffff"><font color="ffffff">
|
||||
There is no useful single point at which the grace period
|
||||
can be said to end.
|
||||
The earliest reasonable candidate is as soon as the last
|
||||
CPU has reported its quiescent state, but it may be some
|
||||
milliseconds before RCU becomes aware of this.
|
||||
The latest reasonable candidate is once the <tt>rcu_state</tt>
|
||||
structure's <tt>->gp_seq</tt> field has been updated,
|
||||
but it is quite possible that some CPUs have already completed
|
||||
phase two of their updates by that time.
|
||||
In short, if you are going to work with RCU, you need to
|
||||
learn to embrace uncertainty.
|
||||
</font></td></tr>
|
||||
<tr><td> </td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
<h4><a name="Callback Invocation">Callback Invocation</a></h4>
|
||||
|
||||
<p>Once a given CPU's leaf <tt>rcu_node</tt> structure's
|
||||
<tt>->gp_seq</tt> field has been updated, that CPU can begin
|
||||
invoking its RCU callbacks that were waiting for this grace period
|
||||
to end.
|
||||
These callbacks are identified by <tt>rcu_advance_cbs()</tt>,
|
||||
which is usually invoked by <tt>__note_gp_changes()</tt>.
|
||||
As shown in the diagram below, this invocation can be triggered by
|
||||
the scheduling-clock interrupt (<tt>rcu_sched_clock_irq()</tt> on
|
||||
the left) or by idle entry (<tt>rcu_cleanup_after_idle()</tt> on
|
||||
the right, but only for kernels build with
|
||||
<tt>CONFIG_RCU_FAST_NO_HZ=y</tt>).
|
||||
Either way, <tt>RCU_SOFTIRQ</tt> is raised, which results in
|
||||
<tt>rcu_do_batch()</tt> invoking the callbacks, which in turn
|
||||
allows those callbacks to carry out (either directly or indirectly
|
||||
via wakeup) the needed phase-two processing for each update.
|
||||
|
||||
</p><p><img src="TreeRCU-callback-invocation.svg" alt="TreeRCU-callback-invocation.svg" width="60%">
|
||||
|
||||
<p>Please note that callback invocation can also be prompted by any
|
||||
number of corner-case code paths, for example, when a CPU notes that
|
||||
it has excessive numbers of callbacks queued.
|
||||
In all cases, the CPU acquires its leaf <tt>rcu_node</tt> structure's
|
||||
<tt>->lock</tt> before invoking callbacks, which preserves the
|
||||
required ordering against the newly completed grace period.
|
||||
|
||||
<p>However, if the callback function communicates to other CPUs,
|
||||
for example, doing a wakeup, then it is that function's responsibility
|
||||
to maintain ordering.
|
||||
For example, if the callback function wakes up a task that runs on
|
||||
some other CPU, proper ordering must in place in both the callback
|
||||
function and the task being awakened.
|
||||
To see why this is important, consider the top half of the
|
||||
<a href="#Grace-Period Cleanup">grace-period cleanup</a> diagram.
|
||||
The callback might be running on a CPU corresponding to the leftmost
|
||||
leaf <tt>rcu_node</tt> structure, and awaken a task that is to run on
|
||||
a CPU corresponding to the rightmost leaf <tt>rcu_node</tt> structure,
|
||||
and the grace-period kernel thread might not yet have reached the
|
||||
rightmost leaf.
|
||||
In this case, the grace period's memory ordering might not yet have
|
||||
reached that CPU, so again the callback function and the awakened
|
||||
task must supply proper ordering.
|
||||
|
||||
<h3><a name="Putting It All Together">Putting It All Together</a></h3>
|
||||
|
||||
<p>A stitched-together diagram is
|
||||
<a href="Tree-RCU-Diagram.html">here</a>.
|
||||
|
||||
<h3><a name="Legal Statement">
|
||||
Legal Statement</a></h3>
|
||||
|
||||
<p>This work represents the view of the author and does not necessarily
|
||||
represent the view of IBM.
|
||||
|
||||
</p><p>Linux is a registered trademark of Linus Torvalds.
|
||||
|
||||
</p><p>Other company, product, and service names may be trademarks or
|
||||
service marks of others.
|
||||
|
||||
</body></html>
|
@ -0,0 +1,625 @@
|
||||
======================================================
|
||||
A Tour Through TREE_RCU's Grace-Period Memory Ordering
|
||||
======================================================
|
||||
|
||||
August 8, 2017
|
||||
|
||||
This article was contributed by Paul E. McKenney
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This document gives a rough visual overview of how Tree RCU's
|
||||
grace-period memory ordering guarantee is provided.
|
||||
|
||||
What Is Tree RCU's Grace Period Memory Ordering Guarantee?
|
||||
==========================================================
|
||||
|
||||
RCU grace periods provide extremely strong memory-ordering guarantees
|
||||
for non-idle non-offline code.
|
||||
Any code that happens after the end of a given RCU grace period is guaranteed
|
||||
to see the effects of all accesses prior to the beginning of that grace
|
||||
period that are within RCU read-side critical sections.
|
||||
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
|
||||
of that grace period that are within RCU read-side critical sections.
|
||||
|
||||
Note well that RCU-sched read-side critical sections include any region
|
||||
of code for which preemption is disabled.
|
||||
Given that each individual machine instruction can be thought of as
|
||||
an extremely small region of preemption-disabled code, one can think of
|
||||
``synchronize_rcu()`` as ``smp_mb()`` on steroids.
|
||||
|
||||
RCU updaters use this guarantee by splitting their updates into
|
||||
two phases, one of which is executed before the grace period and
|
||||
the other of which is executed after the grace period.
|
||||
In the most common use case, phase one removes an element from
|
||||
a linked RCU-protected data structure, and phase two frees that element.
|
||||
For this to work, any readers that have witnessed state prior to the
|
||||
phase-one update (in the common case, removal) must not witness state
|
||||
following the phase-two update (in the common case, freeing).
|
||||
|
||||
The RCU implementation provides this guarantee using a network
|
||||
of lock-based critical sections, memory barriers, and per-CPU
|
||||
processing, as is described in the following sections.
|
||||
|
||||
Tree RCU Grace Period Memory Ordering Building Blocks
|
||||
=====================================================
|
||||
|
||||
The workhorse for RCU's grace-period memory ordering is the
|
||||
critical section for the ``rcu_node`` structure's
|
||||
``->lock``. These critical sections use helper functions for lock
|
||||
acquisition, including ``raw_spin_lock_rcu_node()``,
|
||||
``raw_spin_lock_irq_rcu_node()``, and ``raw_spin_lock_irqsave_rcu_node()``.
|
||||
Their lock-release counterparts are ``raw_spin_unlock_rcu_node()``,
|
||||
``raw_spin_unlock_irq_rcu_node()``, and
|
||||
``raw_spin_unlock_irqrestore_rcu_node()``, respectively.
|
||||
For completeness, a ``raw_spin_trylock_rcu_node()`` is also provided.
|
||||
The key point is that the lock-acquisition functions, including
|
||||
``raw_spin_trylock_rcu_node()``, all invoke ``smp_mb__after_unlock_lock()``
|
||||
immediately after successful acquisition of the lock.
|
||||
|
||||
Therefore, for any given ``rcu_node`` structure, any access
|
||||
happening before one of the above lock-release functions will be seen
|
||||
by all CPUs as happening before any access happening after a later
|
||||
one of the above lock-acquisition functions.
|
||||
Furthermore, any access happening before one of the
|
||||
above lock-release function on any given CPU will be seen by all
|
||||
CPUs as happening before any access happening after a later one
|
||||
of the above lock-acquisition functions executing on that same CPU,
|
||||
even if the lock-release and lock-acquisition functions are operating
|
||||
on different ``rcu_node`` structures.
|
||||
Tree RCU uses these two ordering guarantees to form an ordering
|
||||
network among all CPUs that were in any way involved in the grace
|
||||
period, including any CPUs that came online or went offline during
|
||||
the grace period in question.
|
||||
|
||||
The following litmus test exhibits the ordering effects of these
|
||||
lock-acquisition and lock-release functions::
|
||||
|
||||
1 int x, y, z;
|
||||
2
|
||||
3 void task0(void)
|
||||
4 {
|
||||
5 raw_spin_lock_rcu_node(rnp);
|
||||
6 WRITE_ONCE(x, 1);
|
||||
7 r1 = READ_ONCE(y);
|
||||
8 raw_spin_unlock_rcu_node(rnp);
|
||||
9 }
|
||||
10
|
||||
11 void task1(void)
|
||||
12 {
|
||||
13 raw_spin_lock_rcu_node(rnp);
|
||||
14 WRITE_ONCE(y, 1);
|
||||
15 r2 = READ_ONCE(z);
|
||||
16 raw_spin_unlock_rcu_node(rnp);
|
||||
17 }
|
||||
18
|
||||
19 void task2(void)
|
||||
20 {
|
||||
21 WRITE_ONCE(z, 1);
|
||||
22 smp_mb();
|
||||
23 r3 = READ_ONCE(x);
|
||||
24 }
|
||||
25
|
||||
26 WARN_ON(r1 == 0 && r2 == 0 && r3 == 0);
|
||||
|
||||
The ``WARN_ON()`` is evaluated at “the end of time”,
|
||||
after all changes have propagated throughout the system.
|
||||
Without the ``smp_mb__after_unlock_lock()`` provided by the
|
||||
acquisition functions, this ``WARN_ON()`` could trigger, for example
|
||||
on PowerPC.
|
||||
The ``smp_mb__after_unlock_lock()`` invocations prevent this
|
||||
``WARN_ON()`` from triggering.
|
||||
|
||||
This approach must be extended to include idle CPUs, which need
|
||||
RCU's grace-period memory ordering guarantee to extend to any
|
||||
RCU read-side critical sections preceding and following the current
|
||||
idle sojourn.
|
||||
This case is handled by calls to the strongly ordered
|
||||
``atomic_add_return()`` read-modify-write atomic operation that
|
||||
is invoked within ``rcu_dynticks_eqs_enter()`` at idle-entry
|
||||
time and within ``rcu_dynticks_eqs_exit()`` at idle-exit time.
|
||||
The grace-period kthread invokes ``rcu_dynticks_snap()`` and
|
||||
``rcu_dynticks_in_eqs_since()`` (both of which invoke
|
||||
an ``atomic_add_return()`` of zero) to detect idle CPUs.
|
||||
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Quick Quiz**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| But what about CPUs that remain offline for the entire grace period? |
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Answer**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Such CPUs will be offline at the beginning of the grace period, so |
|
||||
| the grace period won't expect quiescent states from them. Races |
|
||||
| between grace-period start and CPU-hotplug operations are mediated |
|
||||
| by the CPU's leaf ``rcu_node`` structure's ``->lock`` as described |
|
||||
| above. |
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
The approach must be extended to handle one final case, that of waking a
|
||||
task blocked in ``synchronize_rcu()``. This task might be affinitied to
|
||||
a CPU that is not yet aware that the grace period has ended, and thus
|
||||
might not yet be subject to the grace period's memory ordering.
|
||||
Therefore, there is an ``smp_mb()`` after the return from
|
||||
``wait_for_completion()`` in the ``synchronize_rcu()`` code path.
|
||||
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Quick Quiz**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| What? Where??? I don't see any ``smp_mb()`` after the return from |
|
||||
| ``wait_for_completion()``!!! |
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Answer**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| That would be because I spotted the need for that ``smp_mb()`` during |
|
||||
| the creation of this documentation, and it is therefore unlikely to |
|
||||
| hit mainline before v4.14. Kudos to Lance Roy, Will Deacon, Peter |
|
||||
| Zijlstra, and Jonathan Cameron for asking questions that sensitized |
|
||||
| me to the rather elaborate sequence of events that demonstrate the |
|
||||
| need for this memory barrier. |
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
Tree RCU's grace--period memory-ordering guarantees rely most heavily on
|
||||
the ``rcu_node`` structure's ``->lock`` field, so much so that it is
|
||||
necessary to abbreviate this pattern in the diagrams in the next
|
||||
section. For example, consider the ``rcu_prepare_for_idle()`` function
|
||||
shown below, which is one of several functions that enforce ordering of
|
||||
newly arrived RCU callbacks against future grace periods:
|
||||
|
||||
::
|
||||
|
||||
1 static void rcu_prepare_for_idle(void)
|
||||
2 {
|
||||
3 bool needwake;
|
||||
4 struct rcu_data *rdp;
|
||||
5 struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks);
|
||||
6 struct rcu_node *rnp;
|
||||
7 struct rcu_state *rsp;
|
||||
8 int tne;
|
||||
9
|
||||
10 if (IS_ENABLED(CONFIG_RCU_NOCB_CPU_ALL) ||
|
||||
11 rcu_is_nocb_cpu(smp_processor_id()))
|
||||
12 return;
|
||||
13 tne = READ_ONCE(tick_nohz_active);
|
||||
14 if (tne != rdtp->tick_nohz_enabled_snap) {
|
||||
15 if (rcu_cpu_has_callbacks(NULL))
|
||||
16 invoke_rcu_core();
|
||||
17 rdtp->tick_nohz_enabled_snap = tne;
|
||||
18 return;
|
||||
19 }
|
||||
20 if (!tne)
|
||||
21 return;
|
||||
22 if (rdtp->all_lazy &&
|
||||
23 rdtp->nonlazy_posted != rdtp->nonlazy_posted_snap) {
|
||||
24 rdtp->all_lazy = false;
|
||||
25 rdtp->nonlazy_posted_snap = rdtp->nonlazy_posted;
|
||||
26 invoke_rcu_core();
|
||||
27 return;
|
||||
28 }
|
||||
29 if (rdtp->last_accelerate == jiffies)
|
||||
30 return;
|
||||
31 rdtp->last_accelerate = jiffies;
|
||||
32 for_each_rcu_flavor(rsp) {
|
||||
33 rdp = this_cpu_ptr(rsp->rda);
|
||||
34 if (rcu_segcblist_pend_cbs(&rdp->cblist))
|
||||
35 continue;
|
||||
36 rnp = rdp->mynode;
|
||||
37 raw_spin_lock_rcu_node(rnp);
|
||||
38 needwake = rcu_accelerate_cbs(rsp, rnp, rdp);
|
||||
39 raw_spin_unlock_rcu_node(rnp);
|
||||
40 if (needwake)
|
||||
41 rcu_gp_kthread_wake(rsp);
|
||||
42 }
|
||||
43 }
|
||||
|
||||
But the only part of ``rcu_prepare_for_idle()`` that really matters for
|
||||
this discussion are lines 37–39. We will therefore abbreviate this
|
||||
function as follows:
|
||||
|
||||
.. kernel-figure:: rcu_node-lock.svg
|
||||
|
||||
The box represents the ``rcu_node`` structure's ``->lock`` critical
|
||||
section, with the double line on top representing the additional
|
||||
``smp_mb__after_unlock_lock()``.
|
||||
|
||||
Tree RCU Grace Period Memory Ordering Components
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Tree RCU's grace-period memory-ordering guarantee is provided by a
|
||||
number of RCU components:
|
||||
|
||||
#. `Callback Registry <#Callback%20Registry>`__
|
||||
#. `Grace-Period Initialization <#Grace-Period%20Initialization>`__
|
||||
#. `Self-Reported Quiescent
|
||||
States <#Self-Reported%20Quiescent%20States>`__
|
||||
#. `Dynamic Tick Interface <#Dynamic%20Tick%20Interface>`__
|
||||
#. `CPU-Hotplug Interface <#CPU-Hotplug%20Interface>`__
|
||||
#. `Forcing Quiescent States <Forcing%20Quiescent%20States>`__
|
||||
#. `Grace-Period Cleanup <Grace-Period%20Cleanup>`__
|
||||
#. `Callback Invocation <Callback%20Invocation>`__
|
||||
|
||||
Each of the following section looks at the corresponding component in
|
||||
detail.
|
||||
|
||||
Callback Registry
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
If RCU's grace-period guarantee is to mean anything at all, any access
|
||||
that happens before a given invocation of ``call_rcu()`` must also
|
||||
happen before the corresponding grace period. The implementation of this
|
||||
portion of RCU's grace period guarantee is shown in the following
|
||||
figure:
|
||||
|
||||
.. kernel-figure:: TreeRCU-callback-registry.svg
|
||||
|
||||
Because ``call_rcu()`` normally acts only on CPU-local state, it
|
||||
provides no ordering guarantees, either for itself or for phase one of
|
||||
the update (which again will usually be removal of an element from an
|
||||
RCU-protected data structure). It simply enqueues the ``rcu_head``
|
||||
structure on a per-CPU list, which cannot become associated with a grace
|
||||
period until a later call to ``rcu_accelerate_cbs()``, as shown in the
|
||||
diagram above.
|
||||
|
||||
One set of code paths shown on the left invokes ``rcu_accelerate_cbs()``
|
||||
via ``note_gp_changes()``, either directly from ``call_rcu()`` (if the
|
||||
current CPU is inundated with queued ``rcu_head`` structures) or more
|
||||
likely from an ``RCU_SOFTIRQ`` handler. Another code path in the middle
|
||||
is taken only in kernels built with ``CONFIG_RCU_FAST_NO_HZ=y``, which
|
||||
invokes ``rcu_accelerate_cbs()`` via ``rcu_prepare_for_idle()``. The
|
||||
final code path on the right is taken only in kernels built with
|
||||
``CONFIG_HOTPLUG_CPU=y``, which invokes ``rcu_accelerate_cbs()`` via
|
||||
``rcu_advance_cbs()``, ``rcu_migrate_callbacks``,
|
||||
``rcutree_migrate_callbacks()``, and ``takedown_cpu()``, which in turn
|
||||
is invoked on a surviving CPU after the outgoing CPU has been completely
|
||||
offlined.
|
||||
|
||||
There are a few other code paths within grace-period processing that
|
||||
opportunistically invoke ``rcu_accelerate_cbs()``. However, either way,
|
||||
all of the CPU's recently queued ``rcu_head`` structures are associated
|
||||
with a future grace-period number under the protection of the CPU's lead
|
||||
``rcu_node`` structure's ``->lock``. In all cases, there is full
|
||||
ordering against any prior critical section for that same ``rcu_node``
|
||||
structure's ``->lock``, and also full ordering against any of the
|
||||
current task's or CPU's prior critical sections for any ``rcu_node``
|
||||
structure's ``->lock``.
|
||||
|
||||
The next section will show how this ordering ensures that any accesses
|
||||
prior to the ``call_rcu()`` (particularly including phase one of the
|
||||
update) happen before the start of the corresponding grace period.
|
||||
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Quick Quiz**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| But what about ``synchronize_rcu()``? |
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Answer**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| The ``synchronize_rcu()`` passes ``call_rcu()`` to ``wait_rcu_gp()``, |
|
||||
| which invokes it. So either way, it eventually comes down to |
|
||||
| ``call_rcu()``. |
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
Grace-Period Initialization
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Grace-period initialization is carried out by the grace-period kernel
|
||||
thread, which makes several passes over the ``rcu_node`` tree within the
|
||||
``rcu_gp_init()`` function. This means that showing the full flow of
|
||||
ordering through the grace-period computation will require duplicating
|
||||
this tree. If you find this confusing, please note that the state of the
|
||||
``rcu_node`` changes over time, just like Heraclitus's river. However,
|
||||
to keep the ``rcu_node`` river tractable, the grace-period kernel
|
||||
thread's traversals are presented in multiple parts, starting in this
|
||||
section with the various phases of grace-period initialization.
|
||||
|
||||
The first ordering-related grace-period initialization action is to
|
||||
advance the ``rcu_state`` structure's ``->gp_seq`` grace-period-number
|
||||
counter, as shown below:
|
||||
|
||||
.. kernel-figure:: TreeRCU-gp-init-1.svg
|
||||
|
||||
The actual increment is carried out using ``smp_store_release()``, which
|
||||
helps reject false-positive RCU CPU stall detection. Note that only the
|
||||
root ``rcu_node`` structure is touched.
|
||||
|
||||
The first pass through the ``rcu_node`` tree updates bitmasks based on
|
||||
CPUs having come online or gone offline since the start of the previous
|
||||
grace period. In the common case where the number of online CPUs for
|
||||
this ``rcu_node`` structure has not transitioned to or from zero, this
|
||||
pass will scan only the leaf ``rcu_node`` structures. However, if the
|
||||
number of online CPUs for a given leaf ``rcu_node`` structure has
|
||||
transitioned from zero, ``rcu_init_new_rnp()`` will be invoked for the
|
||||
first incoming CPU. Similarly, if the number of online CPUs for a given
|
||||
leaf ``rcu_node`` structure has transitioned to zero,
|
||||
``rcu_cleanup_dead_rnp()`` will be invoked for the last outgoing CPU.
|
||||
The diagram below shows the path of ordering if the leftmost
|
||||
``rcu_node`` structure onlines its first CPU and if the next
|
||||
``rcu_node`` structure has no online CPUs (or, alternatively if the
|
||||
leftmost ``rcu_node`` structure offlines its last CPU and if the next
|
||||
``rcu_node`` structure has no online CPUs).
|
||||
|
||||
.. kernel-figure:: TreeRCU-gp-init-1.svg
|
||||
|
||||
The final ``rcu_gp_init()`` pass through the ``rcu_node`` tree traverses
|
||||
breadth-first, setting each ``rcu_node`` structure's ``->gp_seq`` field
|
||||
to the newly advanced value from the ``rcu_state`` structure, as shown
|
||||
in the following diagram.
|
||||
|
||||
.. kernel-figure:: TreeRCU-gp-init-1.svg
|
||||
|
||||
This change will also cause each CPU's next call to
|
||||
``__note_gp_changes()`` to notice that a new grace period has started,
|
||||
as described in the next section. But because the grace-period kthread
|
||||
started the grace period at the root (with the advancing of the
|
||||
``rcu_state`` structure's ``->gp_seq`` field) before setting each leaf
|
||||
``rcu_node`` structure's ``->gp_seq`` field, each CPU's observation of
|
||||
the start of the grace period will happen after the actual start of the
|
||||
grace period.
|
||||
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Quick Quiz**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| But what about the CPU that started the grace period? Why wouldn't it |
|
||||
| see the start of the grace period right when it started that grace |
|
||||
| period? |
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Answer**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| In some deep philosophical and overly anthromorphized sense, yes, the |
|
||||
| CPU starting the grace period is immediately aware of having done so. |
|
||||
| However, if we instead assume that RCU is not self-aware, then even |
|
||||
| the CPU starting the grace period does not really become aware of the |
|
||||
| start of this grace period until its first call to |
|
||||
| ``__note_gp_changes()``. On the other hand, this CPU potentially gets |
|
||||
| early notification because it invokes ``__note_gp_changes()`` during |
|
||||
| its last ``rcu_gp_init()`` pass through its leaf ``rcu_node`` |
|
||||
| structure. |
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
Self-Reported Quiescent States
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When all entities that might block the grace period have reported
|
||||
quiescent states (or as described in a later section, had quiescent
|
||||
states reported on their behalf), the grace period can end. Online
|
||||
non-idle CPUs report their own quiescent states, as shown in the
|
||||
following diagram:
|
||||
|
||||
.. kernel-figure:: TreeRCU-qs.svg
|
||||
|
||||
This is for the last CPU to report a quiescent state, which signals the
|
||||
end of the grace period. Earlier quiescent states would push up the
|
||||
``rcu_node`` tree only until they encountered an ``rcu_node`` structure
|
||||
that is waiting for additional quiescent states. However, ordering is
|
||||
nevertheless preserved because some later quiescent state will acquire
|
||||
that ``rcu_node`` structure's ``->lock``.
|
||||
|
||||
Any number of events can lead up to a CPU invoking ``note_gp_changes``
|
||||
(or alternatively, directly invoking ``__note_gp_changes()``), at which
|
||||
point that CPU will notice the start of a new grace period while holding
|
||||
its leaf ``rcu_node`` lock. Therefore, all execution shown in this
|
||||
diagram happens after the start of the grace period. In addition, this
|
||||
CPU will consider any RCU read-side critical section that started before
|
||||
the invocation of ``__note_gp_changes()`` to have started before the
|
||||
grace period, and thus a critical section that the grace period must
|
||||
wait on.
|
||||
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Quick Quiz**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| But a RCU read-side critical section might have started after the |
|
||||
| beginning of the grace period (the advancing of ``->gp_seq`` from |
|
||||
| earlier), so why should the grace period wait on such a critical |
|
||||
| section? |
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Answer**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| It is indeed not necessary for the grace period to wait on such a |
|
||||
| critical section. However, it is permissible to wait on it. And it is |
|
||||
| furthermore important to wait on it, as this lazy approach is far |
|
||||
| more scalable than a “big bang” all-at-once grace-period start could |
|
||||
| possibly be. |
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
If the CPU does a context switch, a quiescent state will be noted by
|
||||
``rcu_node_context_switch()`` on the left. On the other hand, if the CPU
|
||||
takes a scheduler-clock interrupt while executing in usermode, a
|
||||
quiescent state will be noted by ``rcu_sched_clock_irq()`` on the right.
|
||||
Either way, the passage through a quiescent state will be noted in a
|
||||
per-CPU variable.
|
||||
|
||||
The next time an ``RCU_SOFTIRQ`` handler executes on this CPU (for
|
||||
example, after the next scheduler-clock interrupt), ``rcu_core()`` will
|
||||
invoke ``rcu_check_quiescent_state()``, which will notice the recorded
|
||||
quiescent state, and invoke ``rcu_report_qs_rdp()``. If
|
||||
``rcu_report_qs_rdp()`` verifies that the quiescent state really does
|
||||
apply to the current grace period, it invokes ``rcu_report_rnp()`` which
|
||||
traverses up the ``rcu_node`` tree as shown at the bottom of the
|
||||
diagram, clearing bits from each ``rcu_node`` structure's ``->qsmask``
|
||||
field, and propagating up the tree when the result is zero.
|
||||
|
||||
Note that traversal passes upwards out of a given ``rcu_node`` structure
|
||||
only if the current CPU is reporting the last quiescent state for the
|
||||
subtree headed by that ``rcu_node`` structure. A key point is that if a
|
||||
CPU's traversal stops at a given ``rcu_node`` structure, then there will
|
||||
be a later traversal by another CPU (or perhaps the same one) that
|
||||
proceeds upwards from that point, and the ``rcu_node`` ``->lock``
|
||||
guarantees that the first CPU's quiescent state happens before the
|
||||
remainder of the second CPU's traversal. Applying this line of thought
|
||||
repeatedly shows that all CPUs' quiescent states happen before the last
|
||||
CPU traverses through the root ``rcu_node`` structure, the “last CPU”
|
||||
being the one that clears the last bit in the root ``rcu_node``
|
||||
structure's ``->qsmask`` field.
|
||||
|
||||
Dynamic Tick Interface
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Due to energy-efficiency considerations, RCU is forbidden from
|
||||
disturbing idle CPUs. CPUs are therefore required to notify RCU when
|
||||
entering or leaving idle state, which they do via fully ordered
|
||||
value-returning atomic operations on a per-CPU variable. The ordering
|
||||
effects are as shown below:
|
||||
|
||||
.. kernel-figure:: TreeRCU-dyntick.svg
|
||||
|
||||
The RCU grace-period kernel thread samples the per-CPU idleness variable
|
||||
while holding the corresponding CPU's leaf ``rcu_node`` structure's
|
||||
``->lock``. This means that any RCU read-side critical sections that
|
||||
precede the idle period (the oval near the top of the diagram above)
|
||||
will happen before the end of the current grace period. Similarly, the
|
||||
beginning of the current grace period will happen before any RCU
|
||||
read-side critical sections that follow the idle period (the oval near
|
||||
the bottom of the diagram above).
|
||||
|
||||
Plumbing this into the full grace-period execution is described
|
||||
`below <#Forcing%20Quiescent%20States>`__.
|
||||
|
||||
CPU-Hotplug Interface
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
RCU is also forbidden from disturbing offline CPUs, which might well be
|
||||
powered off and removed from the system completely. CPUs are therefore
|
||||
required to notify RCU of their comings and goings as part of the
|
||||
corresponding CPU hotplug operations. The ordering effects are shown
|
||||
below:
|
||||
|
||||
.. kernel-figure:: TreeRCU-hotplug.svg
|
||||
|
||||
Because CPU hotplug operations are much less frequent than idle
|
||||
transitions, they are heavier weight, and thus acquire the CPU's leaf
|
||||
``rcu_node`` structure's ``->lock`` and update this structure's
|
||||
``->qsmaskinitnext``. The RCU grace-period kernel thread samples this
|
||||
mask to detect CPUs having gone offline since the beginning of this
|
||||
grace period.
|
||||
|
||||
Plumbing this into the full grace-period execution is described
|
||||
`below <#Forcing%20Quiescent%20States>`__.
|
||||
|
||||
Forcing Quiescent States
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
As noted above, idle and offline CPUs cannot report their own quiescent
|
||||
states, and therefore the grace-period kernel thread must do the
|
||||
reporting on their behalf. This process is called “forcing quiescent
|
||||
states”, it is repeated every few jiffies, and its ordering effects are
|
||||
shown below:
|
||||
|
||||
.. kernel-figure:: TreeRCU-gp-fqs.svg
|
||||
|
||||
Each pass of quiescent state forcing is guaranteed to traverse the leaf
|
||||
``rcu_node`` structures, and if there are no new quiescent states due to
|
||||
recently idled and/or offlined CPUs, then only the leaves are traversed.
|
||||
However, if there is a newly offlined CPU as illustrated on the left or
|
||||
a newly idled CPU as illustrated on the right, the corresponding
|
||||
quiescent state will be driven up towards the root. As with
|
||||
self-reported quiescent states, the upwards driving stops once it
|
||||
reaches an ``rcu_node`` structure that has quiescent states outstanding
|
||||
from other CPUs.
|
||||
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Quick Quiz**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| The leftmost drive to root stopped before it reached the root |
|
||||
| ``rcu_node`` structure, which means that there are still CPUs |
|
||||
| subordinate to that structure on which the current grace period is |
|
||||
| waiting. Given that, how is it possible that the rightmost drive to |
|
||||
| root ended the grace period? |
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Answer**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Good analysis! It is in fact impossible in the absence of bugs in |
|
||||
| RCU. But this diagram is complex enough as it is, so simplicity |
|
||||
| overrode accuracy. You can think of it as poetic license, or you can |
|
||||
| think of it as misdirection that is resolved in the |
|
||||
| `stitched-together diagram <#Putting%20It%20All%20Together>`__. |
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
Grace-Period Cleanup
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Grace-period cleanup first scans the ``rcu_node`` tree breadth-first
|
||||
advancing all the ``->gp_seq`` fields, then it advances the
|
||||
``rcu_state`` structure's ``->gp_seq`` field. The ordering effects are
|
||||
shown below:
|
||||
|
||||
.. kernel-figure:: TreeRCU-gp-cleanup.svg
|
||||
|
||||
As indicated by the oval at the bottom of the diagram, once grace-period
|
||||
cleanup is complete, the next grace period can begin.
|
||||
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Quick Quiz**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| But when precisely does the grace period end? |
|
||||
+-----------------------------------------------------------------------+
|
||||
| **Answer**: |
|
||||
+-----------------------------------------------------------------------+
|
||||
| There is no useful single point at which the grace period can be said |
|
||||
| to end. The earliest reasonable candidate is as soon as the last CPU |
|
||||
| has reported its quiescent state, but it may be some milliseconds |
|
||||
| before RCU becomes aware of this. The latest reasonable candidate is |
|
||||
| once the ``rcu_state`` structure's ``->gp_seq`` field has been |
|
||||
| updated, but it is quite possible that some CPUs have already |
|
||||
| completed phase two of their updates by that time. In short, if you |
|
||||
| are going to work with RCU, you need to learn to embrace uncertainty. |
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
Callback Invocation
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Once a given CPU's leaf ``rcu_node`` structure's ``->gp_seq`` field has
|
||||
been updated, that CPU can begin invoking its RCU callbacks that were
|
||||
waiting for this grace period to end. These callbacks are identified by
|
||||
``rcu_advance_cbs()``, which is usually invoked by
|
||||
``__note_gp_changes()``. As shown in the diagram below, this invocation
|
||||
can be triggered by the scheduling-clock interrupt
|
||||
(``rcu_sched_clock_irq()`` on the left) or by idle entry
|
||||
(``rcu_cleanup_after_idle()`` on the right, but only for kernels build
|
||||
with ``CONFIG_RCU_FAST_NO_HZ=y``). Either way, ``RCU_SOFTIRQ`` is
|
||||
raised, which results in ``rcu_do_batch()`` invoking the callbacks,
|
||||
which in turn allows those callbacks to carry out (either directly or
|
||||
indirectly via wakeup) the needed phase-two processing for each update.
|
||||
|
||||
.. kernel-figure:: TreeRCU-callback-invocation.svg
|
||||
|
||||
Please note that callback invocation can also be prompted by any number
|
||||
of corner-case code paths, for example, when a CPU notes that it has
|
||||
excessive numbers of callbacks queued. In all cases, the CPU acquires
|
||||
its leaf ``rcu_node`` structure's ``->lock`` before invoking callbacks,
|
||||
which preserves the required ordering against the newly completed grace
|
||||
period.
|
||||
|
||||
However, if the callback function communicates to other CPUs, for
|
||||
example, doing a wakeup, then it is that function's responsibility to
|
||||
maintain ordering. For example, if the callback function wakes up a task
|
||||
that runs on some other CPU, proper ordering must in place in both the
|
||||
callback function and the task being awakened. To see why this is
|
||||
important, consider the top half of the `grace-period
|
||||
cleanup <#Grace-Period%20Cleanup>`__ diagram. The callback might be
|
||||
running on a CPU corresponding to the leftmost leaf ``rcu_node``
|
||||
structure, and awaken a task that is to run on a CPU corresponding to
|
||||
the rightmost leaf ``rcu_node`` structure, and the grace-period kernel
|
||||
thread might not yet have reached the rightmost leaf. In this case, the
|
||||
grace period's memory ordering might not yet have reached that CPU, so
|
||||
again the callback function and the awakened task must supply proper
|
||||
ordering.
|
||||
|
||||
Putting It All Together
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A stitched-together diagram is here:
|
||||
|
||||
.. kernel-figure:: TreeRCU-gp.svg
|
||||
|
||||
Legal Statement
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
This work represents the view of the author and does not necessarily
|
||||
represent the view of IBM.
|
||||
|
||||
Linux is a registered trademark of Linus Torvalds.
|
||||
|
||||
Other company, product, and service names may be trademarks or service
|
||||
marks of others.
|
File diff suppressed because it is too large
Load Diff
2662
Documentation/RCU/Design/Requirements/Requirements.rst
Normal file
2662
Documentation/RCU/Design/Requirements/Requirements.rst
Normal file
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,11 @@ RCU concepts
|
||||
listRCU
|
||||
UP
|
||||
|
||||
Design/Memory-Ordering/Tree-RCU-Memory-Ordering
|
||||
Design/Expedited-Grace-Periods/Expedited-Grace-Periods
|
||||
Design/Requirements/Requirements
|
||||
Design/Data-Structures/Data-Structures
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
Indices
|
||||
|
@ -302,7 +302,7 @@ rcu_dereference()
|
||||
must prohibit. The rcu_dereference_protected() variant takes
|
||||
a lockdep expression to indicate which locks must be acquired
|
||||
by the caller. If the indicated protection is not provided,
|
||||
a lockdep splat is emitted. See RCU/Design/Requirements/Requirements.html
|
||||
a lockdep splat is emitted. See Documentation/RCU/Design/Requirements/Requirements.rst
|
||||
and the API's code comments for more details and example usage.
|
||||
|
||||
The following diagram shows how each API communicates among the
|
||||
@ -630,7 +630,7 @@ been able to write-acquire the lock otherwise. The smp_mb__after_spinlock()
|
||||
promotes synchronize_rcu() to a full memory barrier in compliance with
|
||||
the "Memory-Barrier Guarantees" listed in:
|
||||
|
||||
Documentation/RCU/Design/Requirements/Requirements.html.
|
||||
Documentation/RCU/Design/Requirements/Requirements.rst
|
||||
|
||||
It is possible to nest rcu_read_lock(), since reader-writer locks may
|
||||
be recursively acquired. Note also that rcu_read_lock() is immune
|
||||
|
Loading…
Reference in New Issue
Block a user