mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02: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
					
				
					 1 changed files with 30 additions and 23 deletions
				
			
		| 
						 | 
				
			
			@ -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 a new issue