mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 22:02:28 +00:00
doc: Update memory-barriers.txt for read-to-write dependencies
The memory-barriers.txt document contains an obsolete passage stating that smp_read_barrier_depends() is required to force ordering for read-to-write dependencies. We now know that this is not required, even for DEC Alpha. This commit therefore updates this passage to state that read-to-write dependencies are respected even without smp_read_barrier_depends(). Reported-by: Lance Roy <ldr709@gmail.com> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: David Howells <dhowells@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Andrea Parri <parri.andrea@gmail.com> Cc: Jade Alglave <j.alglave@ucl.ac.uk> Cc: Luc Maranget <luc.maranget@inria.fr> [ paulmck: Reference control-dependencies sections and use WRITE_ONCE() per Will Deacon. Correctly place split-cache paragraph while there. ] Acked-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
parent
4de5f89ef8
commit
66ce3a4dcb
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user