On Tue, 2013-10-01 at 16:01 -0400, Waiman Long wrote: > On 10/01/2013 12:48 PM, Tim Chen wrote: > > On Mon, 2013-09-30 at 12:36 -0400, Waiman Long wrote: > >> On 09/30/2013 12:10 PM, Jason Low wrote: > >>> On Mon, 2013-09-30 at 11:51 -0400, Waiman Long wrote: > >>>> On 09/28/2013 12:34 AM, Jason Low wrote: > >>>>>> Also, below is what the mcs_spin_lock() and mcs_spin_unlock() > >>>>>> functions would look like after applying the proposed changes. > >>>>>> > >>>>>> static noinline > >>>>>> void mcs_spin_lock(struct mcs_spin_node **lock, struct mcs_spin_node *node) > >>>>>> { > >>>>>> struct mcs_spin_node *prev; > >>>>>> > >>>>>> /* Init node */ > >>>>>> node->locked = 0; > >>>>>> node->next = NULL; > >>>>>> > >>>>>> prev = xchg(lock, node); > >>>>>> if (likely(prev == NULL)) { > >>>>>> /* Lock acquired. No need to set node->locked since it > >>>>>> won't be used */ > >>>>>> return; > >>>>>> } > >>>>>> ACCESS_ONCE(prev->next) = node; > >>>>>> /* Wait until the lock holder passes the lock down */ > >>>>>> while (!ACCESS_ONCE(node->locked)) > >>>>>> arch_mutex_cpu_relax(); > >>>>>> smp_mb(); > >>>> I wonder if a memory barrier is really needed here. > >>> If the compiler can reorder the while (!ACCESS_ONCE(node->locked)) check > >>> so that the check occurs after an instruction in the critical section, > >>> then the barrier may be necessary. > >>> > >> In that case, just a barrier() call should be enough. > > The cpu could still be executing out of order load instruction from the > > critical section before checking node->locked? Probably smp_mb() is > > still needed. > > > > Tim > > But this is the lock function, a barrier() call should be enough to > prevent the critical section from creeping up there. We certainly need > some kind of memory barrier at the end of the unlock function. I may be missing something. My understanding is that barrier only prevents the compiler from rearranging instructions, but not for cpu out of order execution (as in smp_mb). So cpu could read memory in the next critical section, before node->locked is true, (i.e. unlock has been completed). If we only have a simple barrier at end of mcs_lock, then say the code on CPU1 is mcs_lock x = 1; ... x = 2; mcs_unlock and CPU 2 is mcs_lock y = x; ... mcs_unlock We expect y to be 2 after the "y = x" assignment. But we we may execute the code as CPU1 CPU2 x = 1; ... y = x; ( y=1, out of order load) x = 2 mcs_unlock Check node->locked==true continue executing critical section (y=1 when we expect y=2) So we get y to be 1 when we expect that it should be 2. Adding smp_mb after the node->locked check in lock code ACCESS_ONCE(prev->next) = node; /* Wait until the lock holder passes the lock down */ while (!ACCESS_ONCE(node->locked)) arch_mutex_cpu_relax(); smp_mb(); should prevent this scenario. Thanks. Tim > > -Longman > -- > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > Please read the FAQ at http://www.tux.org/lkml/ -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxx. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@xxxxxxxxx"> email@xxxxxxxxx </a>