Merge branches 'work.misc' and 'work.dcache' of git://git.kernel.org/pub/scm/linux...
[sfrench/cifs-2.6.git] / include / linux / spinlock.h
index fd57888d4942e10166440da41d449a52fc8e1730..3190997df9cac8dd931c904cc112442a172d5888 100644 (file)
@@ -114,29 +114,48 @@ do {                                                              \
 #endif /*arch_spin_is_contended*/
 
 /*
- * This barrier must provide two things:
+ * smp_mb__after_spinlock() provides the equivalent of a full memory barrier
+ * between program-order earlier lock acquisitions and program-order later
+ * memory accesses.
  *
- *   - it must guarantee a STORE before the spin_lock() is ordered against a
- *     LOAD after it, see the comments at its two usage sites.
+ * This guarantees that the following two properties hold:
  *
- *   - it must ensure the critical section is RCsc.
+ *   1) Given the snippet:
  *
- * The latter is important for cases where we observe values written by other
- * CPUs in spin-loops, without barriers, while being subject to scheduling.
+ *       { X = 0;  Y = 0; }
  *
- * CPU0                        CPU1                    CPU2
+ *       CPU0                          CPU1
  *
- *                     for (;;) {
- *                       if (READ_ONCE(X))
- *                         break;
- *                     }
- * X=1
- *                     <sched-out>
- *                                             <sched-in>
- *                                             r = X;
+ *       WRITE_ONCE(X, 1);             WRITE_ONCE(Y, 1);
+ *       spin_lock(S);                 smp_mb();
+ *       smp_mb__after_spinlock();     r1 = READ_ONCE(X);
+ *       r0 = READ_ONCE(Y);
+ *       spin_unlock(S);
  *
- * without transitivity it could be that CPU1 observes X!=0 breaks the loop,
- * we get migrated and CPU2 sees X==0.
+ *      it is forbidden that CPU0 does not observe CPU1's store to Y (r0 = 0)
+ *      and CPU1 does not observe CPU0's store to X (r1 = 0); see the comments
+ *      preceding the call to smp_mb__after_spinlock() in __schedule() and in
+ *      try_to_wake_up().
+ *
+ *   2) Given the snippet:
+ *
+ *  { X = 0;  Y = 0; }
+ *
+ *  CPU0               CPU1                            CPU2
+ *
+ *  spin_lock(S);      spin_lock(S);                   r1 = READ_ONCE(Y);
+ *  WRITE_ONCE(X, 1);  smp_mb__after_spinlock();       smp_rmb();
+ *  spin_unlock(S);    r0 = READ_ONCE(X);              r2 = READ_ONCE(X);
+ *                     WRITE_ONCE(Y, 1);
+ *                     spin_unlock(S);
+ *
+ *      it is forbidden that CPU0's critical section executes before CPU1's
+ *      critical section (r0 = 1), CPU2 observes CPU1's store to Y (r1 = 1)
+ *      and CPU2 does not observe CPU0's store to X (r2 = 0); see the comments
+ *      preceding the calls to smp_rmb() in try_to_wake_up() for similar
+ *      snippets but "projected" onto two CPUs.
+ *
+ * Property (2) upgrades the lock to an RCsc lock.
  *
  * Since most load-store architectures implement ACQUIRE with an smp_mb() after
  * the LL/SC loop, they need no further barriers. Similarly all our TSO