Messages in this thread | | | Date | Fri, 18 Jan 2019 11:43:02 -0500 (EST) | From | Alan Stern <> | Subject | Re: Plain accesses and data races in the Linux Kernel Memory Model |
| |
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)
| |