On Fri, 18 Jan 2019, Andrea Parri wrote: > > A relatively simple solution to this problem would be to say that > > smp_wmb doesn't order plain writes. > > It seems so; I don't have other solutions to suggest ATM. (But, TBH, > I'm still in the process of reviewing/testing these changes... ) > > And yes, this is a pain! : I don't have the exact statistics, but I'm > willing to believe that removing this order will take us back ~99% of > the current (~500!) uses of smp_wmb() ;-/ > > Oh, well, maybe we'll find a better solution one day: after all, that > one doesn't seem worse than what the current LKMM has to say! ;-) > > > > > > I think the rest of the memory model would then be okay. However, I am > > open to arguments that this approach is too complex and we should > > insist on the same kind of strict ordering for race avoidance that the > > C11 standard uses (i.e., conflicting accesses separated by full memory > > barriers or release & acquire barriers or locking). > > Indeed; maybe, we've just found another reason to obsolete smp_wmb()! ;-)
Here's another example of how smp_wmb can cause trouble. In this test, I have replaced "*x = 1" in P1 with "r2 = *x; if (r2 != 1) *x = 1", which is a perfectly valid transformation for the compiler to make. But as a result of this transformation, the MP pattern between P1 and P2 is now allowed! This shows that when plain accesses are involved, smp_wmb() in the writing thread is not sufficient to forbid MP. Alan C bad-wmb {} P0(int *x, int *y) { WRITE_ONCE(*x, 1); smp_store_release(y, 1); } P1(int *x, int *y, int *z) { int r1; int r2; r1 = smp_load_acquire(y); if (r1) { /* Instead of *x = 1 ... */ r2 = *x; if (r2 != 1) *x = 1; smp_wmb(); WRITE_ONCE(*z, 1); } } P2(int *x, int *z) { int r3; int r4 = 0; r3 = READ_ONCE(*z); if (r3) { smp_rmb(); r4 = READ_ONCE(*x); } } exists (2:r3=1 /\ 2:r4=0)