mirror of
https://github.com/suyu-emu/horinux.git
synced 2026-09-21 14:15:21 -07:00
Merge branch 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull RCU updates from Ingo Molnad: "The main RCU related changes in this cycle were: - Removal of spin_unlock_wait() - SRCU updates - RCU torture-test updates - RCU Documentation updates - Extend the sys_membarrier() ABI with the MEMBARRIER_CMD_PRIVATE_EXPEDITED variant - Miscellaneous RCU fixes - CPU-hotplug fixes" * 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (63 commits) arch: Remove spin_unlock_wait() arch-specific definitions locking: Remove spin_unlock_wait() generic definitions drivers/ata: Replace spin_unlock_wait() with lock/unlock pair ipc: Replace spin_unlock_wait() with lock/unlock pair exit: Replace spin_unlock_wait() with lock/unlock pair completion: Replace spin_unlock_wait() with lock/unlock pair doc: Set down RCU's scheduling-clock-interrupt needs doc: No longer allowed to use rcu_dereference on non-pointers doc: Add RCU files to docbook-generation files doc: Update memory-barriers.txt for read-to-write dependencies doc: Update RCU documentation membarrier: Provide expedited private command rcu: Remove exports from rcu_idle_exit() and rcu_idle_enter() rcu: Add warning to rcu_idle_enter() for irqs enabled rcu: Make rcu_idle_enter() rely on callers disabling irqs rcu: Add assertions verifying blocked-tasks list rcu/tracing: Set disable_rcu_irq_enter on rcu_eqs_exit() rcu: Add TPS() protection for _rcu_barrier_trace strings rcu: Use idle versions of swait to make idle-hack clear swait: Add idle variants which don't contribute to load average ...
This commit is contained in:
@@ -2080,6 +2080,8 @@ Some of the relevant points of interest are as follows:
|
||||
<li> <a href="#Scheduler and RCU">Scheduler and RCU</a>.
|
||||
<li> <a href="#Tracing and RCU">Tracing and RCU</a>.
|
||||
<li> <a href="#Energy Efficiency">Energy Efficiency</a>.
|
||||
<li> <a href="#Scheduling-Clock Interrupts and RCU">
|
||||
Scheduling-Clock Interrupts and RCU</a>.
|
||||
<li> <a href="#Memory Efficiency">Memory Efficiency</a>.
|
||||
<li> <a href="#Performance, Scalability, Response Time, and Reliability">
|
||||
Performance, Scalability, Response Time, and Reliability</a>.
|
||||
@@ -2532,6 +2534,134 @@ I learned of many of these requirements via angry phone calls:
|
||||
Flaming me on the Linux-kernel mailing list was apparently not
|
||||
sufficient to fully vent their ire at RCU's energy-efficiency bugs!
|
||||
|
||||
<h3><a name="Scheduling-Clock Interrupts and RCU">
|
||||
Scheduling-Clock Interrupts and RCU</a></h3>
|
||||
|
||||
<p>
|
||||
The kernel transitions between in-kernel non-idle execution, userspace
|
||||
execution, and the idle loop.
|
||||
Depending on kernel configuration, RCU handles these states differently:
|
||||
|
||||
<table border=3>
|
||||
<tr><th><tt>HZ</tt> Kconfig</th>
|
||||
<th>In-Kernel</th>
|
||||
<th>Usermode</th>
|
||||
<th>Idle</th></tr>
|
||||
<tr><th align="left"><tt>HZ_PERIODIC</tt></th>
|
||||
<td>Can rely on scheduling-clock interrupt.</td>
|
||||
<td>Can rely on scheduling-clock interrupt and its
|
||||
detection of interrupt from usermode.</td>
|
||||
<td>Can rely on RCU's dyntick-idle detection.</td></tr>
|
||||
<tr><th align="left"><tt>NO_HZ_IDLE</tt></th>
|
||||
<td>Can rely on scheduling-clock interrupt.</td>
|
||||
<td>Can rely on scheduling-clock interrupt and its
|
||||
detection of interrupt from usermode.</td>
|
||||
<td>Can rely on RCU's dyntick-idle detection.</td></tr>
|
||||
<tr><th align="left"><tt>NO_HZ_FULL</tt></th>
|
||||
<td>Can only sometimes rely on scheduling-clock interrupt.
|
||||
In other cases, it is necessary to bound kernel execution
|
||||
times and/or use IPIs.</td>
|
||||
<td>Can rely on RCU's dyntick-idle detection.</td>
|
||||
<td>Can rely on RCU's dyntick-idle detection.</td></tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<tr><th> </th></tr>
|
||||
<tr><th align="left">Quick Quiz:</th></tr>
|
||||
<tr><td>
|
||||
Why can't <tt>NO_HZ_FULL</tt> in-kernel execution rely on the
|
||||
scheduling-clock interrupt, just like <tt>HZ_PERIODIC</tt>
|
||||
and <tt>NO_HZ_IDLE</tt> do?
|
||||
</td></tr>
|
||||
<tr><th align="left">Answer:</th></tr>
|
||||
<tr><td bgcolor="#ffffff"><font color="ffffff">
|
||||
Because, as a performance optimization, <tt>NO_HZ_FULL</tt>
|
||||
does not necessarily re-enable the scheduling-clock interrupt
|
||||
on entry to each and every system call.
|
||||
</font></td></tr>
|
||||
<tr><td> </td></tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
However, RCU must be reliably informed as to whether any given
|
||||
CPU is currently in the idle loop, and, for <tt>NO_HZ_FULL</tt>,
|
||||
also whether that CPU is executing in usermode, as discussed
|
||||
<a href="#Energy Efficiency">earlier</a>.
|
||||
It also requires that the scheduling-clock interrupt be enabled when
|
||||
RCU needs it to be:
|
||||
|
||||
<ol>
|
||||
<li> If a CPU is either idle or executing in usermode, and RCU believes
|
||||
it is non-idle, the scheduling-clock tick had better be running.
|
||||
Otherwise, you will get RCU CPU stall warnings. Or at best,
|
||||
very long (11-second) grace periods, with a pointless IPI waking
|
||||
the CPU from time to time.
|
||||
<li> If a CPU is in a portion of the kernel that executes RCU read-side
|
||||
critical sections, and RCU believes this CPU to be idle, you will get
|
||||
random memory corruption. <b>DON'T DO THIS!!!</b>
|
||||
|
||||
<br>This is one reason to test with lockdep, which will complain
|
||||
about this sort of thing.
|
||||
<li> If a CPU is in a portion of the kernel that is absolutely
|
||||
positively no-joking guaranteed to never execute any RCU read-side
|
||||
critical sections, and RCU believes this CPU to to be idle,
|
||||
no problem. This sort of thing is used by some architectures
|
||||
for light-weight exception handlers, which can then avoid the
|
||||
overhead of <tt>rcu_irq_enter()</tt> and <tt>rcu_irq_exit()</tt>
|
||||
at exception entry and exit, respectively.
|
||||
Some go further and avoid the entireties of <tt>irq_enter()</tt>
|
||||
and <tt>irq_exit()</tt>.
|
||||
|
||||
<br>Just make very sure you are running some of your tests with
|
||||
<tt>CONFIG_PROVE_RCU=y</tt>, just in case one of your code paths
|
||||
was in fact joking about not doing RCU read-side critical sections.
|
||||
<li> If a CPU is executing in the kernel with the scheduling-clock
|
||||
interrupt disabled and RCU believes this CPU to be non-idle,
|
||||
and if the CPU goes idle (from an RCU perspective) every few
|
||||
jiffies, no problem. It is usually OK for there to be the
|
||||
occasional gap between idle periods of up to a second or so.
|
||||
|
||||
<br>If the gap grows too long, you get RCU CPU stall warnings.
|
||||
<li> If a CPU is either idle or executing in usermode, and RCU believes
|
||||
it to be idle, of course no problem.
|
||||
<li> If a CPU is executing in the kernel, the kernel code
|
||||
path is passing through quiescent states at a reasonable
|
||||
frequency (preferably about once per few jiffies, but the
|
||||
occasional excursion to a second or so is usually OK) and the
|
||||
scheduling-clock interrupt is enabled, of course no problem.
|
||||
|
||||
<br>If the gap between a successive pair of quiescent states grows
|
||||
too long, you get RCU CPU stall warnings.
|
||||
</ol>
|
||||
|
||||
<table>
|
||||
<tr><th> </th></tr>
|
||||
<tr><th align="left">Quick Quiz:</th></tr>
|
||||
<tr><td>
|
||||
But what if my driver has a hardware interrupt handler
|
||||
that can run for many seconds?
|
||||
I cannot invoke <tt>schedule()</tt> from an hardware
|
||||
interrupt handler, after all!
|
||||
</td></tr>
|
||||
<tr><th align="left">Answer:</th></tr>
|
||||
<tr><td bgcolor="#ffffff"><font color="ffffff">
|
||||
One approach is to do <tt>rcu_irq_exit();rcu_irq_enter();</tt>
|
||||
every so often.
|
||||
But given that long-running interrupt handlers can cause
|
||||
other problems, not least for response time, shouldn't you
|
||||
work to keep your interrupt handler's runtime within reasonable
|
||||
bounds?
|
||||
</font></td></tr>
|
||||
<tr><td> </td></tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
But as long as RCU is properly informed of kernel state transitions between
|
||||
in-kernel execution, usermode execution, and idle, and as long as the
|
||||
scheduling-clock interrupt is enabled when RCU needs it to be, you
|
||||
can rest assured that the bugs you encounter will be in some other
|
||||
part of RCU or some other part of the kernel!
|
||||
|
||||
<h3><a name="Memory Efficiency">Memory Efficiency</a></h3>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -23,6 +23,14 @@ over a rather long period of time, but improvements are always welcome!
|
||||
Yet another exception is where the low real-time latency of RCU's
|
||||
read-side primitives is critically important.
|
||||
|
||||
One final exception is where RCU readers are used to prevent
|
||||
the ABA problem (https://en.wikipedia.org/wiki/ABA_problem)
|
||||
for lockless updates. This does result in the mildly
|
||||
counter-intuitive situation where rcu_read_lock() and
|
||||
rcu_read_unlock() are used to protect updates, however, this
|
||||
approach provides the same potential simplifications that garbage
|
||||
collectors do.
|
||||
|
||||
1. Does the update code have proper mutual exclusion?
|
||||
|
||||
RCU does allow -readers- to run (almost) naked, but -writers- must
|
||||
@@ -40,7 +48,9 @@ over a rather long period of time, but improvements are always welcome!
|
||||
explain how this single task does not become a major bottleneck on
|
||||
big multiprocessor machines (for example, if the task is updating
|
||||
information relating to itself that other tasks can read, there
|
||||
by definition can be no bottleneck).
|
||||
by definition can be no bottleneck). Note that the definition
|
||||
of "large" has changed significantly: Eight CPUs was "large"
|
||||
in the year 2000, but a hundred CPUs was unremarkable in 2017.
|
||||
|
||||
2. Do the RCU read-side critical sections make proper use of
|
||||
rcu_read_lock() and friends? These primitives are needed
|
||||
@@ -55,6 +65,12 @@ over a rather long period of time, but improvements are always welcome!
|
||||
Disabling of preemption can serve as rcu_read_lock_sched(), but
|
||||
is less readable.
|
||||
|
||||
Letting RCU-protected pointers "leak" out of an RCU read-side
|
||||
critical section is every bid as bad as letting them leak out
|
||||
from under a lock. Unless, of course, you have arranged some
|
||||
other means of protection, such as a lock or a reference count
|
||||
-before- letting them out of the RCU read-side critical section.
|
||||
|
||||
3. Does the update code tolerate concurrent accesses?
|
||||
|
||||
The whole point of RCU is to permit readers to run without
|
||||
@@ -78,10 +94,10 @@ over a rather long period of time, but improvements are always welcome!
|
||||
|
||||
This works quite well, also.
|
||||
|
||||
c. Make updates appear atomic to readers. For example,
|
||||
c. Make updates appear atomic to readers. For example,
|
||||
pointer updates to properly aligned fields will
|
||||
appear atomic, as will individual atomic primitives.
|
||||
Sequences of perations performed under a lock will -not-
|
||||
Sequences of operations performed under a lock will -not-
|
||||
appear to be atomic to RCU readers, nor will sequences
|
||||
of multiple atomic primitives.
|
||||
|
||||
@@ -168,8 +184,8 @@ over a rather long period of time, but improvements are always welcome!
|
||||
|
||||
5. If call_rcu(), or a related primitive such as call_rcu_bh(),
|
||||
call_rcu_sched(), or call_srcu() is used, the callback function
|
||||
must be written to be called from softirq context. In particular,
|
||||
it cannot block.
|
||||
will be called from softirq context. In particular, it cannot
|
||||
block.
|
||||
|
||||
6. Since synchronize_rcu() can block, it cannot be called from
|
||||
any sort of irq context. The same rule applies for
|
||||
@@ -178,11 +194,14 @@ over a rather long period of time, but improvements are always welcome!
|
||||
synchronize_sched_expedite(), and synchronize_srcu_expedited().
|
||||
|
||||
The expedited forms of these primitives have the same semantics
|
||||
as the non-expedited forms, but expediting is both expensive
|
||||
and unfriendly to real-time workloads. Use of the expedited
|
||||
primitives should be restricted to rare configuration-change
|
||||
operations that would not normally be undertaken while a real-time
|
||||
workload is running.
|
||||
as the non-expedited forms, but expediting is both expensive and
|
||||
(with the exception of synchronize_srcu_expedited()) unfriendly
|
||||
to real-time workloads. Use of the expedited primitives should
|
||||
be restricted to rare configuration-change operations that would
|
||||
not normally be undertaken while a real-time workload is running.
|
||||
However, real-time workloads can use rcupdate.rcu_normal kernel
|
||||
boot parameter to completely disable expedited grace periods,
|
||||
though this might have performance implications.
|
||||
|
||||
In particular, if you find yourself invoking one of the expedited
|
||||
primitives repeatedly in a loop, please do everyone a favor:
|
||||
@@ -193,11 +212,6 @@ over a rather long period of time, but improvements are always welcome!
|
||||
of the system, especially to real-time workloads running on
|
||||
the rest of the system.
|
||||
|
||||
In addition, it is illegal to call the expedited forms from
|
||||
a CPU-hotplug notifier, or while holding a lock that is acquired
|
||||
by a CPU-hotplug notifier. Failing to observe this restriction
|
||||
will result in deadlock.
|
||||
|
||||
7. If the updater uses call_rcu() or synchronize_rcu(), then the
|
||||
corresponding readers must use rcu_read_lock() and
|
||||
rcu_read_unlock(). If the updater uses call_rcu_bh() or
|
||||
@@ -321,7 +335,7 @@ over a rather long period of time, but improvements are always welcome!
|
||||
Similarly, disabling preemption is not an acceptable substitute
|
||||
for rcu_read_lock(). Code that attempts to use preemption
|
||||
disabling where it should be using rcu_read_lock() will break
|
||||
in real-time kernel builds.
|
||||
in CONFIG_PREEMPT=y kernel builds.
|
||||
|
||||
If you want to wait for interrupt handlers, NMI handlers, and
|
||||
code under the influence of preempt_disable(), you instead
|
||||
@@ -356,23 +370,22 @@ over a rather long period of time, but improvements are always welcome!
|
||||
not the case, a self-spawning RCU callback would prevent the
|
||||
victim CPU from ever going offline.)
|
||||
|
||||
14. SRCU (srcu_read_lock(), srcu_read_unlock(), srcu_dereference(),
|
||||
synchronize_srcu(), synchronize_srcu_expedited(), and call_srcu())
|
||||
may only be invoked from process context. Unlike other forms of
|
||||
RCU, it -is- permissible to block in an SRCU read-side critical
|
||||
section (demarked by srcu_read_lock() and srcu_read_unlock()),
|
||||
hence the "SRCU": "sleepable RCU". Please note that if you
|
||||
don't need to sleep in read-side critical sections, you should be
|
||||
using RCU rather than SRCU, because RCU is almost always faster
|
||||
and easier to use than is SRCU.
|
||||
14. Unlike other forms of RCU, it -is- permissible to block in an
|
||||
SRCU read-side critical section (demarked by srcu_read_lock()
|
||||
and srcu_read_unlock()), hence the "SRCU": "sleepable RCU".
|
||||
Please note that if you don't need to sleep in read-side critical
|
||||
sections, you should be using RCU rather than SRCU, because RCU
|
||||
is almost always faster and easier to use than is SRCU.
|
||||
|
||||
Also unlike other forms of RCU, explicit initialization
|
||||
and cleanup is required via init_srcu_struct() and
|
||||
cleanup_srcu_struct(). These are passed a "struct srcu_struct"
|
||||
that defines the scope of a given SRCU domain. Once initialized,
|
||||
the srcu_struct is passed to srcu_read_lock(), srcu_read_unlock()
|
||||
synchronize_srcu(), synchronize_srcu_expedited(), and call_srcu().
|
||||
A given synchronize_srcu() waits only for SRCU read-side critical
|
||||
Also unlike other forms of RCU, explicit initialization and
|
||||
cleanup is required either at build time via DEFINE_SRCU()
|
||||
or DEFINE_STATIC_SRCU() or at runtime via init_srcu_struct()
|
||||
and cleanup_srcu_struct(). These last two are passed a
|
||||
"struct srcu_struct" that defines the scope of a given
|
||||
SRCU domain. Once initialized, the srcu_struct is passed
|
||||
to srcu_read_lock(), srcu_read_unlock() synchronize_srcu(),
|
||||
synchronize_srcu_expedited(), and call_srcu(). A given
|
||||
synchronize_srcu() waits only for SRCU read-side critical
|
||||
sections governed by srcu_read_lock() and srcu_read_unlock()
|
||||
calls that have been passed the same srcu_struct. This property
|
||||
is what makes sleeping read-side critical sections tolerable --
|
||||
@@ -390,10 +403,16 @@ over a rather long period of time, but improvements are always welcome!
|
||||
Therefore, SRCU should be used in preference to rw_semaphore
|
||||
only in extremely read-intensive situations, or in situations
|
||||
requiring SRCU's read-side deadlock immunity or low read-side
|
||||
realtime latency.
|
||||
realtime latency. You should also consider percpu_rw_semaphore
|
||||
when you need lightweight readers.
|
||||
|
||||
Note that, rcu_assign_pointer() relates to SRCU just as it does
|
||||
to other forms of RCU.
|
||||
SRCU's expedited primitive (synchronize_srcu_expedited())
|
||||
never sends IPIs to other CPUs, so it is easier on
|
||||
real-time workloads than is synchronize_rcu_expedited(),
|
||||
synchronize_rcu_bh_expedited() or synchronize_sched_expedited().
|
||||
|
||||
Note that rcu_dereference() and rcu_assign_pointer() relate to
|
||||
SRCU just as they do to other forms of RCU.
|
||||
|
||||
15. The whole point of call_rcu(), synchronize_rcu(), and friends
|
||||
is to wait until all pre-existing readers have finished before
|
||||
@@ -435,3 +454,33 @@ over a rather long period of time, but improvements are always welcome!
|
||||
|
||||
These debugging aids can help you find problems that are
|
||||
otherwise extremely difficult to spot.
|
||||
|
||||
18. If you register a callback using call_rcu(), call_rcu_bh(),
|
||||
call_rcu_sched(), or call_srcu(), and pass in a function defined
|
||||
within a loadable module, then it in necessary to wait for
|
||||
all pending callbacks to be invoked after the last invocation
|
||||
and before unloading that module. Note that it is absolutely
|
||||
-not- sufficient to wait for a grace period! The current (say)
|
||||
synchronize_rcu() implementation waits only for all previous
|
||||
callbacks registered on the CPU that synchronize_rcu() is running
|
||||
on, but it is -not- guaranteed to wait for callbacks registered
|
||||
on other CPUs.
|
||||
|
||||
You instead need to use one of the barrier functions:
|
||||
|
||||
o call_rcu() -> rcu_barrier()
|
||||
o call_rcu_bh() -> rcu_barrier_bh()
|
||||
o call_rcu_sched() -> rcu_barrier_sched()
|
||||
o call_srcu() -> srcu_barrier()
|
||||
|
||||
However, these barrier functions are absolutely -not- guaranteed
|
||||
to wait for a grace period. In fact, if there are no call_rcu()
|
||||
callbacks waiting anywhere in the system, rcu_barrier() is within
|
||||
its rights to return immediately.
|
||||
|
||||
So if you need to wait for both an RCU grace period and for
|
||||
all pre-existing call_rcu() callbacks, you will need to execute
|
||||
both rcu_barrier() and synchronize_rcu(), if necessary, using
|
||||
something like workqueues to to execute them concurrently.
|
||||
|
||||
See rcubarrier.txt for more information.
|
||||
|
||||
@@ -76,15 +76,12 @@ o I hear that RCU is patented? What is with that?
|
||||
Of these, one was allowed to lapse by the assignee, and the
|
||||
others have been contributed to the Linux kernel under GPL.
|
||||
There are now also LGPL implementations of user-level RCU
|
||||
available (http://lttng.org/?q=node/18).
|
||||
available (http://liburcu.org/).
|
||||
|
||||
o I hear that RCU needs work in order to support realtime kernels?
|
||||
|
||||
This work is largely completed. Realtime-friendly RCU can be
|
||||
enabled via the CONFIG_PREEMPT_RCU kernel configuration
|
||||
parameter. However, work is in progress for enabling priority
|
||||
boosting of preempted RCU read-side critical sections. This is
|
||||
needed if you have CPU-bound realtime threads.
|
||||
Realtime-friendly RCU can be enabled via the CONFIG_PREEMPT_RCU
|
||||
kernel configuration parameter.
|
||||
|
||||
o Where can I find more information on RCU?
|
||||
|
||||
|
||||
@@ -25,35 +25,35 @@ o You must use one of the rcu_dereference() family of primitives
|
||||
for an example where the compiler can in fact deduce the exact
|
||||
value of the pointer, and thus cause misordering.
|
||||
|
||||
o You are only permitted to use rcu_dereference on pointer values.
|
||||
The compiler simply knows too much about integral values to
|
||||
trust it to carry dependencies through integer operations.
|
||||
There are a very few exceptions, namely that you can temporarily
|
||||
cast the pointer to uintptr_t in order to:
|
||||
|
||||
o Set bits and clear bits down in the must-be-zero low-order
|
||||
bits of that pointer. This clearly means that the pointer
|
||||
must have alignment constraints, for example, this does
|
||||
-not- work in general for char* pointers.
|
||||
|
||||
o XOR bits to translate pointers, as is done in some
|
||||
classic buddy-allocator algorithms.
|
||||
|
||||
It is important to cast the value back to pointer before
|
||||
doing much of anything else with it.
|
||||
|
||||
o Avoid cancellation when using the "+" and "-" infix arithmetic
|
||||
operators. For example, for a given variable "x", avoid
|
||||
"(x-x)". There are similar arithmetic pitfalls from other
|
||||
arithmetic operators, such as "(x*0)", "(x/(x+1))" or "(x%1)".
|
||||
The compiler is within its rights to substitute zero for all of
|
||||
these expressions, so that subsequent accesses no longer depend
|
||||
on the rcu_dereference(), again possibly resulting in bugs due
|
||||
to misordering.
|
||||
"(x-(uintptr_t)x)" for char* pointers. The compiler is within its
|
||||
rights to substitute zero for this sort of expression, so that
|
||||
subsequent accesses no longer depend on the rcu_dereference(),
|
||||
again possibly resulting in bugs due to misordering.
|
||||
|
||||
Of course, if "p" is a pointer from rcu_dereference(), and "a"
|
||||
and "b" are integers that happen to be equal, the expression
|
||||
"p+a-b" is safe because its value still necessarily depends on
|
||||
the rcu_dereference(), thus maintaining proper ordering.
|
||||
|
||||
o Avoid all-zero operands to the bitwise "&" operator, and
|
||||
similarly avoid all-ones operands to the bitwise "|" operator.
|
||||
If the compiler is able to deduce the value of such operands,
|
||||
it is within its rights to substitute the corresponding constant
|
||||
for the bitwise operation. Once again, this causes subsequent
|
||||
accesses to no longer depend on the rcu_dereference(), causing
|
||||
bugs due to misordering.
|
||||
|
||||
Please note that single-bit operands to bitwise "&" can also
|
||||
be dangerous. At this point, the compiler knows that the
|
||||
resulting value can only take on one of two possible values.
|
||||
Therefore, a very small amount of additional information will
|
||||
allow the compiler to deduce the exact value, which again can
|
||||
result in misordering.
|
||||
|
||||
o If you are using RCU to protect JITed functions, so that the
|
||||
"()" function-invocation operator is applied to a value obtained
|
||||
(directly or indirectly) from rcu_dereference(), you may need to
|
||||
@@ -61,25 +61,6 @@ o If you are using RCU to protect JITed functions, so that the
|
||||
This issue arises on some systems when a newly JITed function is
|
||||
using the same memory that was used by an earlier JITed function.
|
||||
|
||||
o Do not use the results from the boolean "&&" and "||" when
|
||||
dereferencing. For example, the following (rather improbable)
|
||||
code is buggy:
|
||||
|
||||
int *p;
|
||||
int *q;
|
||||
|
||||
...
|
||||
|
||||
p = rcu_dereference(gp)
|
||||
q = &global_q;
|
||||
q += p != &oom_p1 && p != &oom_p2;
|
||||
r1 = *q; /* BUGGY!!! */
|
||||
|
||||
The reason this is buggy is that "&&" and "||" are often compiled
|
||||
using branches. While weak-memory machines such as ARM or PowerPC
|
||||
do order stores after such branches, they can speculate loads,
|
||||
which can result in misordering bugs.
|
||||
|
||||
o Do not use the results from relational operators ("==", "!=",
|
||||
">", ">=", "<", or "<=") when dereferencing. For example,
|
||||
the following (quite strange) code is buggy:
|
||||
|
||||
@@ -263,6 +263,11 @@ Quick Quiz #2: What happens if CPU 0's rcu_barrier_func() executes
|
||||
are delayed for a full grace period? Couldn't this result in
|
||||
rcu_barrier() returning prematurely?
|
||||
|
||||
The current rcu_barrier() implementation is more complex, due to the need
|
||||
to avoid disturbing idle CPUs (especially on battery-powered systems)
|
||||
and the need to minimally disturb non-idle CPUs in real-time systems.
|
||||
However, the code above illustrates the concepts.
|
||||
|
||||
|
||||
rcu_barrier() Summary
|
||||
|
||||
|
||||
@@ -276,15 +276,17 @@ o "Free-Block Circulation": Shows the number of torture structures
|
||||
somehow gets incremented farther than it should.
|
||||
|
||||
Different implementations of RCU can provide implementation-specific
|
||||
additional information. For example, SRCU provides the following
|
||||
additional information. For example, Tree SRCU provides the following
|
||||
additional line:
|
||||
|
||||
srcu-torture: per-CPU(idx=1): 0(0,1) 1(0,1) 2(0,0) 3(0,1)
|
||||
srcud-torture: Tree SRCU per-CPU(idx=0): 0(35,-21) 1(-4,24) 2(1,1) 3(-26,20) 4(28,-47) 5(-9,4) 6(-10,14) 7(-14,11) T(1,6)
|
||||
|
||||
This line shows the per-CPU counter state. The numbers in parentheses are
|
||||
the values of the "old" and "current" counters for the corresponding CPU.
|
||||
The "idx" value maps the "old" and "current" values to the underlying
|
||||
array, and is useful for debugging.
|
||||
This line shows the per-CPU counter state, in this case for Tree SRCU
|
||||
using a dynamically allocated srcu_struct (hence "srcud-" rather than
|
||||
"srcu-"). The numbers in parentheses are the values of the "old" and
|
||||
"current" counters for the corresponding CPU. The "idx" value maps the
|
||||
"old" and "current" values to the underlying array, and is useful for
|
||||
debugging. The final "T" entry contains the totals of the counters.
|
||||
|
||||
|
||||
USAGE
|
||||
@@ -304,3 +306,9 @@ checked for such errors. The "rmmod" command forces a "SUCCESS",
|
||||
"FAILURE", or "RCU_HOTPLUG" indication to be printk()ed. The first
|
||||
two are self-explanatory, while the last indicates that while there
|
||||
were no RCU failures, CPU-hotplug problems were detected.
|
||||
|
||||
However, the tools/testing/selftests/rcutorture/bin/kvm.sh script
|
||||
provides better automation, including automatic failure analysis.
|
||||
It assumes a qemu/kvm-enabled platform, and runs guest OSes out of initrd.
|
||||
See tools/testing/selftests/rcutorture/doc/initrd.txt for instructions
|
||||
on setting up such an initrd.
|
||||
|
||||
@@ -890,6 +890,8 @@ SRCU: Critical sections Grace period Barrier
|
||||
srcu_read_lock_held
|
||||
|
||||
SRCU: Initialization/cleanup
|
||||
DEFINE_SRCU
|
||||
DEFINE_STATIC_SRCU
|
||||
init_srcu_struct
|
||||
cleanup_srcu_struct
|
||||
|
||||
@@ -913,7 +915,8 @@ a. Will readers need to block? If so, you need SRCU.
|
||||
b. What about the -rt patchset? If readers would need to block
|
||||
in an non-rt kernel, you need SRCU. If readers would block
|
||||
in a -rt kernel, but not in a non-rt kernel, SRCU is not
|
||||
necessary.
|
||||
necessary. (The -rt patchset turns spinlocks into sleeplocks,
|
||||
hence this distinction.)
|
||||
|
||||
c. Do you need to treat NMI handlers, hardirq handlers,
|
||||
and code segments with preemption disabled (whether
|
||||
|
||||
@@ -2633,9 +2633,10 @@
|
||||
In kernels built with CONFIG_NO_HZ_FULL=y, set
|
||||
the specified list of CPUs whose tick will be stopped
|
||||
whenever possible. The boot CPU will be forced outside
|
||||
the range to maintain the timekeeping.
|
||||
The CPUs in this range must also be included in the
|
||||
rcu_nocbs= set.
|
||||
the range to maintain the timekeeping. Any CPUs
|
||||
in this list will have their RCU callbacks offloaded,
|
||||
just as if they had also been called out in the
|
||||
rcu_nocbs= boot parameter.
|
||||
|
||||
noiotrap [SH] Disables trapped I/O port accesses.
|
||||
|
||||
|
||||
@@ -344,3 +344,52 @@ codecs, and devices with strict requirements for interface clocking.
|
||||
|
||||
.. kernel-doc:: include/linux/clk.h
|
||||
:internal:
|
||||
|
||||
Synchronization Primitives
|
||||
==========================
|
||||
|
||||
Read-Copy Update (RCU)
|
||||
----------------------
|
||||
|
||||
.. kernel-doc:: include/linux/rcupdate.h
|
||||
:external:
|
||||
|
||||
.. kernel-doc:: include/linux/rcupdate_wait.h
|
||||
:external:
|
||||
|
||||
.. kernel-doc:: include/linux/rcutree.h
|
||||
:external:
|
||||
|
||||
.. kernel-doc:: kernel/rcu/tree.c
|
||||
:external:
|
||||
|
||||
.. kernel-doc:: kernel/rcu/tree_plugin.h
|
||||
:external:
|
||||
|
||||
.. kernel-doc:: kernel/rcu/tree_exp.h
|
||||
:external:
|
||||
|
||||
.. kernel-doc:: kernel/rcu/update.c
|
||||
:external:
|
||||
|
||||
.. kernel-doc:: include/linux/srcu.h
|
||||
:external:
|
||||
|
||||
.. kernel-doc:: kernel/rcu/srcutree.c
|
||||
:external:
|
||||
|
||||
.. kernel-doc:: include/linux/rculist_bl.h
|
||||
:external:
|
||||
|
||||
.. kernel-doc:: include/linux/rculist.h
|
||||
:external:
|
||||
|
||||
.. kernel-doc:: include/linux/rculist_nulls.h
|
||||
:external:
|
||||
|
||||
.. kernel-doc:: include/linux/rcu_sync.h
|
||||
:external:
|
||||
|
||||
.. kernel-doc:: kernel/rcu/sync.c
|
||||
:external:
|
||||
|
||||
|
||||
@@ -594,29 +594,6 @@ between the address load and the data load:
|
||||
This enforces the occurrence of one of the two implications, and prevents the
|
||||
third possibility from arising.
|
||||
|
||||
A data-dependency barrier must also order against dependent writes:
|
||||
|
||||
CPU 1 CPU 2
|
||||
=============== ===============
|
||||
{ A == 1, B == 2, C = 3, P == &A, Q == &C }
|
||||
B = 4;
|
||||
<write barrier>
|
||||
WRITE_ONCE(P, &B);
|
||||
Q = READ_ONCE(P);
|
||||
<data dependency barrier>
|
||||
*Q = 5;
|
||||
|
||||
The data-dependency barrier must order the read into Q with the store
|
||||
into *Q. This prohibits this outcome:
|
||||
|
||||
(Q == &B) && (B == 4)
|
||||
|
||||
Please note that this pattern should be rare. After all, the whole point
|
||||
of dependency ordering is to -prevent- writes to the data structure, along
|
||||
with the expensive cache misses associated with those writes. This pattern
|
||||
can be used to record rare error conditions and the like, and the ordering
|
||||
prevents such records from being lost.
|
||||
|
||||
|
||||
[!] Note that this extremely counterintuitive situation arises most easily on
|
||||
machines with split caches, so that, for example, one cache bank processes
|
||||
@@ -628,6 +605,36 @@ odd-numbered bank is idle, one can see the new value of the pointer P (&B),
|
||||
but the old value of the variable B (2).
|
||||
|
||||
|
||||
A data-dependency barrier is not required to order dependent writes
|
||||
because the CPUs that the Linux kernel supports don't do writes
|
||||
until they are certain (1) that the write will actually happen, (2)
|
||||
of the location of the write, and (3) of the value to be written.
|
||||
But please carefully read the "CONTROL DEPENDENCIES" section and the
|
||||
Documentation/RCU/rcu_dereference.txt file: The compiler can and does
|
||||
break dependencies in a great many highly creative ways.
|
||||
|
||||
CPU 1 CPU 2
|
||||
=============== ===============
|
||||
{ A == 1, B == 2, C = 3, P == &A, Q == &C }
|
||||
B = 4;
|
||||
<write barrier>
|
||||
WRITE_ONCE(P, &B);
|
||||
Q = READ_ONCE(P);
|
||||
WRITE_ONCE(*Q, 5);
|
||||
|
||||
Therefore, no data-dependency barrier is required to order the read into
|
||||
Q with the store into *Q. In other words, this outcome is prohibited,
|
||||
even without a data-dependency barrier:
|
||||
|
||||
(Q == &B) && (B == 4)
|
||||
|
||||
Please note that this pattern should be rare. After all, the whole point
|
||||
of dependency ordering is to -prevent- writes to the data structure, along
|
||||
with the expensive cache misses associated with those writes. This pattern
|
||||
can be used to record rare error conditions and the like, and the CPUs'
|
||||
naturally occurring ordering prevents such records from being lost.
|
||||
|
||||
|
||||
The data dependency barrier is very important to the RCU system,
|
||||
for example. See rcu_assign_pointer() and rcu_dereference() in
|
||||
include/linux/rcupdate.h. This permits the current target of an RCU'd
|
||||
|
||||
+1
-1
@@ -8649,7 +8649,7 @@ M: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
||||
M: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Supported
|
||||
F: kernel/membarrier.c
|
||||
F: kernel/sched/membarrier.c
|
||||
F: include/uapi/linux/membarrier.h
|
||||
|
||||
MEMORY MANAGEMENT
|
||||
|
||||
@@ -16,11 +16,6 @@
|
||||
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
|
||||
#define arch_spin_is_locked(x) ((x)->lock != 0)
|
||||
|
||||
static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
|
||||
{
|
||||
smp_cond_load_acquire(&lock->lock, !VAL);
|
||||
}
|
||||
|
||||
static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
|
||||
{
|
||||
return lock.lock == 0;
|
||||
|
||||
@@ -16,11 +16,6 @@
|
||||
#define arch_spin_is_locked(x) ((x)->slock != __ARCH_SPIN_LOCK_UNLOCKED__)
|
||||
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
|
||||
|
||||
static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
|
||||
{
|
||||
smp_cond_load_acquire(&lock->slock, !VAL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARC_HAS_LLSC
|
||||
|
||||
static inline void arch_spin_lock(arch_spinlock_t *lock)
|
||||
|
||||
@@ -52,22 +52,6 @@ static inline void dsb_sev(void)
|
||||
* memory.
|
||||
*/
|
||||
|
||||
static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
|
||||
{
|
||||
u16 owner = READ_ONCE(lock->tickets.owner);
|
||||
|
||||
for (;;) {
|
||||
arch_spinlock_t tmp = READ_ONCE(*lock);
|
||||
|
||||
if (tmp.tickets.owner == tmp.tickets.next ||
|
||||
tmp.tickets.owner != owner)
|
||||
break;
|
||||
|
||||
wfe();
|
||||
}
|
||||
smp_acquire__after_ctrl_dep();
|
||||
}
|
||||
|
||||
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
|
||||
|
||||
static inline void arch_spin_lock(arch_spinlock_t *lock)
|
||||
|
||||
@@ -26,58 +26,6 @@
|
||||
* The memory barriers are implicit with the load-acquire and store-release
|
||||
* instructions.
|
||||
*/
|
||||
static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
|
||||
{
|
||||
unsigned int tmp;
|
||||
arch_spinlock_t lockval;
|
||||
u32 owner;
|
||||
|
||||
/*
|
||||
* Ensure prior spin_lock operations to other locks have completed
|
||||
* on this CPU before we test whether "lock" is locked.
|
||||
*/
|
||||
smp_mb();
|
||||
owner = READ_ONCE(lock->owner) << 16;
|
||||
|
||||
asm volatile(
|
||||
" sevl\n"
|
||||
"1: wfe\n"
|
||||
"2: ldaxr %w0, %2\n"
|
||||
/* Is the lock free? */
|
||||
" eor %w1, %w0, %w0, ror #16\n"
|
||||
" cbz %w1, 3f\n"
|
||||
/* Lock taken -- has there been a subsequent unlock->lock transition? */
|
||||
" eor %w1, %w3, %w0, lsl #16\n"
|
||||
" cbz %w1, 1b\n"
|
||||
/*
|
||||
* The owner has been updated, so there was an unlock->lock
|
||||
* transition that we missed. That means we can rely on the
|
||||
* store-release of the unlock operation paired with the
|
||||
* load-acquire of the lock operation to publish any of our
|
||||
* previous stores to the new lock owner and therefore don't
|
||||
* need to bother with the writeback below.
|
||||
*/
|
||||
" b 4f\n"
|
||||
"3:\n"
|
||||
/*
|
||||
* Serialise against any concurrent lockers by writing back the
|
||||
* unlocked lock value
|
||||
*/
|
||||
ARM64_LSE_ATOMIC_INSN(
|
||||
/* LL/SC */
|
||||
" stxr %w1, %w0, %2\n"
|
||||
__nops(2),
|
||||
/* LSE atomics */
|
||||
" mov %w1, %w0\n"
|
||||
" cas %w0, %w0, %2\n"
|
||||
" eor %w1, %w1, %w0\n")
|
||||
/* Somebody else wrote to the lock, GOTO 10 and reload the value */
|
||||
" cbnz %w1, 2b\n"
|
||||
"4:"
|
||||
: "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
|
||||
: "r" (owner)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
|
||||
|
||||
@@ -176,7 +124,11 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
|
||||
|
||||
static inline int arch_spin_is_locked(arch_spinlock_t *lock)
|
||||
{
|
||||
smp_mb(); /* See arch_spin_unlock_wait */
|
||||
/*
|
||||
* Ensure prior spin_lock operations to other locks have completed
|
||||
* on this CPU before we test whether "lock" is locked.
|
||||
*/
|
||||
smp_mb(); /* ^^^ */
|
||||
return !arch_spin_value_unlocked(READ_ONCE(*lock));
|
||||
}
|
||||
|
||||
|
||||
@@ -360,6 +360,8 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
|
||||
/*
|
||||
* Complete any pending TLB or cache maintenance on this CPU in case
|
||||
* the thread migrates to a different CPU.
|
||||
* This full barrier is also required by the membarrier system
|
||||
* call.
|
||||
*/
|
||||
dsb(ish);
|
||||
|
||||
|
||||
@@ -48,11 +48,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
|
||||
__raw_spin_unlock_asm(&lock->lock);
|
||||
}
|
||||
|
||||
static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
|
||||
{
|
||||
smp_cond_load_acquire(&lock->lock, !VAL);
|
||||
}
|
||||
|
||||
static inline int arch_read_can_lock(arch_rwlock_t *rw)
|
||||
{
|
||||
return __raw_uncached_fetch_asm(&rw->lock) > 0;
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
* Licensed under the GPL-2 or later
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "module %s: " fmt, mod->name
|
||||
|
||||
#include <linux/moduleloader.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/vmalloc.h>
|
||||
@@ -16,6 +14,11 @@
|
||||
#include <asm/cacheflush.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define mod_err(mod, fmt, ...) \
|
||||
pr_err("module %s: " fmt, (mod)->name, ##__VA_ARGS__)
|
||||
#define mod_debug(mod, fmt, ...) \
|
||||
pr_debug("module %s: " fmt, (mod)->name, ##__VA_ARGS__)
|
||||
|
||||
/* Transfer the section to the L1 memory */
|
||||
int
|
||||
module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
||||
@@ -44,7 +47,7 @@ module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
||||
dest = l1_inst_sram_alloc(s->sh_size);
|
||||
mod->arch.text_l1 = dest;
|
||||
if (dest == NULL) {
|
||||
pr_err("L1 inst memory allocation failed\n");
|
||||
mod_err(mod, "L1 inst memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
dma_memcpy(dest, (void *)s->sh_addr, s->sh_size);
|
||||
@@ -56,7 +59,7 @@ module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
||||
dest = l1_data_sram_alloc(s->sh_size);
|
||||
mod->arch.data_a_l1 = dest;
|
||||
if (dest == NULL) {
|
||||
pr_err("L1 data memory allocation failed\n");
|
||||
mod_err(mod, "L1 data memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
memcpy(dest, (void *)s->sh_addr, s->sh_size);
|
||||
@@ -68,7 +71,7 @@ module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
||||
dest = l1_data_sram_zalloc(s->sh_size);
|
||||
mod->arch.bss_a_l1 = dest;
|
||||
if (dest == NULL) {
|
||||
pr_err("L1 data memory allocation failed\n");
|
||||
mod_err(mod, "L1 data memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -77,7 +80,7 @@ module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
||||
dest = l1_data_B_sram_alloc(s->sh_size);
|
||||
mod->arch.data_b_l1 = dest;
|
||||
if (dest == NULL) {
|
||||
pr_err("L1 data memory allocation failed\n");
|
||||
mod_err(mod, "L1 data memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
memcpy(dest, (void *)s->sh_addr, s->sh_size);
|
||||
@@ -87,7 +90,7 @@ module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
||||
dest = l1_data_B_sram_alloc(s->sh_size);
|
||||
mod->arch.bss_b_l1 = dest;
|
||||
if (dest == NULL) {
|
||||
pr_err("L1 data memory allocation failed\n");
|
||||
mod_err(mod, "L1 data memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
memset(dest, 0, s->sh_size);
|
||||
@@ -99,7 +102,7 @@ module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
||||
dest = l2_sram_alloc(s->sh_size);
|
||||
mod->arch.text_l2 = dest;
|
||||
if (dest == NULL) {
|
||||
pr_err("L2 SRAM allocation failed\n");
|
||||
mod_err(mod, "L2 SRAM allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
memcpy(dest, (void *)s->sh_addr, s->sh_size);
|
||||
@@ -111,7 +114,7 @@ module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
||||
dest = l2_sram_alloc(s->sh_size);
|
||||
mod->arch.data_l2 = dest;
|
||||
if (dest == NULL) {
|
||||
pr_err("L2 SRAM allocation failed\n");
|
||||
mod_err(mod, "L2 SRAM allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
memcpy(dest, (void *)s->sh_addr, s->sh_size);
|
||||
@@ -123,7 +126,7 @@ module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
||||
dest = l2_sram_zalloc(s->sh_size);
|
||||
mod->arch.bss_l2 = dest;
|
||||
if (dest == NULL) {
|
||||
pr_err("L2 SRAM allocation failed\n");
|
||||
mod_err(mod, "L2 SRAM allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -157,8 +160,8 @@ apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
|
||||
Elf32_Sym *sym;
|
||||
unsigned long location, value, size;
|
||||
|
||||
pr_debug("applying relocate section %u to %u\n",
|
||||
relsec, sechdrs[relsec].sh_info);
|
||||
mod_debug(mod, "applying relocate section %u to %u\n",
|
||||
relsec, sechdrs[relsec].sh_info);
|
||||
|
||||
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
|
||||
/* This is where to make the change */
|
||||
@@ -174,14 +177,14 @@ apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
if (location >= COREB_L1_DATA_A_START) {
|
||||
pr_err("cannot relocate in L1: %u (SMP kernel)\n",
|
||||
mod_err(mod, "cannot relocate in L1: %u (SMP kernel)\n",
|
||||
ELF32_R_TYPE(rel[i].r_info));
|
||||
return -ENOEXEC;
|
||||
}
|
||||
#endif
|
||||
|
||||
pr_debug("location is %lx, value is %lx type is %d\n",
|
||||
location, value, ELF32_R_TYPE(rel[i].r_info));
|
||||
mod_debug(mod, "location is %lx, value is %lx type is %d\n",
|
||||
location, value, ELF32_R_TYPE(rel[i].r_info));
|
||||
|
||||
switch (ELF32_R_TYPE(rel[i].r_info)) {
|
||||
|
||||
@@ -200,12 +203,12 @@ apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
|
||||
case R_BFIN_PCREL12_JUMP:
|
||||
case R_BFIN_PCREL12_JUMP_S:
|
||||
case R_BFIN_PCREL10:
|
||||
pr_err("unsupported relocation: %u (no -mlong-calls?)\n",
|
||||
mod_err(mod, "unsupported relocation: %u (no -mlong-calls?)\n",
|
||||
ELF32_R_TYPE(rel[i].r_info));
|
||||
return -ENOEXEC;
|
||||
|
||||
default:
|
||||
pr_err("unknown relocation: %u\n",
|
||||
mod_err(mod, "unknown relocation: %u\n",
|
||||
ELF32_R_TYPE(rel[i].r_info));
|
||||
return -ENOEXEC;
|
||||
}
|
||||
@@ -222,7 +225,7 @@ apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
|
||||
isram_memcpy((void *)location, &value, size);
|
||||
break;
|
||||
default:
|
||||
pr_err("invalid relocation for %#lx\n", location);
|
||||
mod_err(mod, "invalid relocation for %#lx\n", location);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,11 +179,6 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock)
|
||||
*/
|
||||
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
|
||||
|
||||
static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
|
||||
{
|
||||
smp_cond_load_acquire(&lock->lock, !VAL);
|
||||
}
|
||||
|
||||
#define arch_spin_is_locked(x) ((x)->lock != 0)
|
||||
|
||||
#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
|
||||
|
||||
@@ -76,22 +76,6 @@ static __always_inline void __ticket_spin_unlock(arch_spinlock_t *lock)
|
||||
ACCESS_ONCE(*p) = (tmp + 2) & ~1;
|
||||
}
|
||||
|
||||
static __always_inline void __ticket_spin_unlock_wait(arch_spinlock_t *lock)
|
||||
{
|
||||
int *p = (int *)&lock->lock, ticket;
|
||||
|
||||
ia64_invala();
|
||||
|
||||
for (;;) {
|
||||
asm volatile ("ld4.c.nc %0=[%1]" : "=r"(ticket) : "r"(p) : "memory");
|
||||
if (!(((ticket >> TICKET_SHIFT) ^ ticket) & TICKET_MASK))
|
||||
return;
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
smp_acquire__after_ctrl_dep();
|
||||
}
|
||||
|
||||
static inline int __ticket_spin_is_locked(arch_spinlock_t *lock)
|
||||
{
|
||||
long tmp = ACCESS_ONCE(lock->lock);
|
||||
@@ -143,11 +127,6 @@ static __always_inline void arch_spin_lock_flags(arch_spinlock_t *lock,
|
||||
arch_spin_lock(lock);
|
||||
}
|
||||
|
||||
static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
|
||||
{
|
||||
__ticket_spin_unlock_wait(lock);
|
||||
}
|
||||
|
||||
#define arch_read_can_lock(rw) (*(volatile int *)(rw) >= 0)
|
||||
#define arch_write_can_lock(rw) (*(volatile int *)(rw) == 0)
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user