Received: by 2002:a25:4158:0:0:0:0:0 with SMTP id o85csp1318103yba; Sat, 6 Apr 2019 09:05:32 -0700 (PDT) X-Google-Smtp-Source: APXvYqyFGhYsgwpULwWNTfkEqnX3tjMmyt/drhGWOmWqcW4gFkSOU5biqWHn9ut6xJlPWTF2fPpj X-Received: by 2002:a17:902:7c94:: with SMTP id y20mr19965367pll.263.1554566731941; Sat, 06 Apr 2019 09:05:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1554566731; cv=none; d=google.com; s=arc-20160816; b=isEPfZkGUangeLHWCN7LKLRdeM8uFg0C0lEkdnnub8I3vuSobwg9d1dhCB3qKEupCa 4Dg2C9rOX2d9fZ/fe8W6SRDj8W8udmJWMiK8+HY3/S2JvgoislsZ+78e9V0DMtNiX9fx BX3WhhuzEInWy08hVxx8Hq4Xs8XGiyef4Ae7Mz9pD/jQjv3rBa4n7/We8it9Wgcc609A I7a+tlL1aCNszQ0wu3Cgsh0QJTkBScvreUTKWg2v6B0Fkg7PG9CbnyYvveclHh3v2UiL R2d7bTlPxrIjNt7u/TV9skzRs6H/p1H6Xg6Go8e9L6IO+aPt4GV7efd7+B4G2tQPISsh nNtA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:message-id:in-reply-to :subject:cc:to:from:date; bh=DlTLMNoJXNiNKCGgLiQAZXyhGM/1aBVZMkPPQeOrY78=; b=Chb6fPpzA6EjdFkozwhGIA5LVZobM0AttBdQkdKjJLPtzHTJA1efihhhqe4+QWIuF7 IgxlAbQ2QFy63oB2rHisaIFy6refo17/6dHyad4Jzf9MSJF3c1BF4GxvF9jJa6eoffQ6 PYpY8OJf+XfWouD4cEoC7PiapajikQvXxhD/baN4ssP/qe7jIrCGRJ5ypDDDcgA3pW68 OwcLZhs/DA8bT9ih6HssFm26o3sqdffCQdj5/DNqLqqVC1GeGNU76In36JEZ29gBpld+ LpKIRV2y/Ucxfud5S7Xk8RxbK8y+bel+MwZRm8KpMk+U1QcVTkPLu190dmV7dbRj3ZD9 xdtQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id u20si11244392pfh.211.2019.04.06.09.05.16; Sat, 06 Apr 2019 09:05:31 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726499AbfDFQDS (ORCPT + 99 others); Sat, 6 Apr 2019 12:03:18 -0400 Received: from netrider.rowland.org ([192.131.102.5]:51859 "HELO netrider.rowland.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1726435AbfDFQDS (ORCPT ); Sat, 6 Apr 2019 12:03:18 -0400 Received: (qmail 20181 invoked by uid 500); 6 Apr 2019 12:03:17 -0400 Received: from localhost (sendmail-bs@127.0.0.1) by localhost with SMTP; 6 Apr 2019 12:03:17 -0400 Date: Sat, 6 Apr 2019 12:03:17 -0400 (EDT) From: Alan Stern X-X-Sender: stern@netrider.rowland.org To: Andrea Parri cc: LKMM Maintainers -- Akira Yokosawa , Boqun Feng , Daniel Lustig , David Howells , Jade Alglave , Luc Maranget , Nicholas Piggin , "Paul E. McKenney" , Peter Zijlstra , Will Deacon , Daniel Kroening , Kernel development list Subject: Re: Adding plain accesses and detecting data races in the LKMM In-Reply-To: <20190406004913.GA3828@andrea> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Sat, 6 Apr 2019, Andrea Parri wrote: > > > I'd have: > > > > > > *x = 1; /* A */ > > > smp_mb__before_atomic(); > > > r0 = xchg_relaxed(x, 2); /* B (read or write part) */ > > > > > > => (A ->barrier B) > > > > Perhaps so. It wasn't clear initially how these should be treated, so > > I just ignored them. For example, what should happen here if there > > were other statements between the smp_mb__before_atomic and the > > xchg_relaxed? > > I'd say that the link "A ->barrier B" should still be present and that > no other barrier-links should appear. More formally, I am suggesting > that Before-atomic induced the following barrier-links: > > [M] ; fencerel(Before-atomic) ; [RMW] ; po? ; [M] Hmmm, maybe. But exactly where is the barrier introduced? Are you saying that on some architectures the barrier is contained in the smp_mb__before_atomic and on others it is contained in the xchg_relaxed? > > > smp_mb__after_unlock_lock() seems more tricky, given that it generates > > > inter-threads links. > > > > The inter-thread part is completely irrelevant as far as compiler > > barriers are concerned. > > > > > Intuitively, we would have a "barrier" that is a superset of "mb" (I'm > > > not saying that this is feasible, but this seems worth considering...) > > > > I don't understand that comment. > > I was suggesting to consider something like: > > let barrier = [...] | mb > > but I'm still not sure about those After-unlock-lock and After-spinlock. I don't see any point in saying that After-unlock-lock or After-spinlock contains a barrier, because spin_lock and spin_unlock already do. > > > I don't get the motivations for the component: > > > > > > (po ; [Acquire | Release]) | > > > ([Acquire | Release] ; po) > > > > > > in "barrier". Why did you write it? > > > > I was thinking that in situations like: > > > > A: z = 1; > > B: smp_store_release(z, 2); > > C: r = z; > > > > in addition to there being a compiler barrier between A and C, there > > effectively has to be a barrier between A and B (that is, the object > > code has to store first 1 and then 2 to z) and between B and C (that > > is, the object code can't skip doing the load from z and just set r to > > 2). > > > > The basic principle was the idea that load-acquire and store-release > > are special because each of them is both a memory access and a memory > > barrier at the same time. Now, I didn't give this a tremendous amount > > of thought and it's quite possible that the Cat code should be changed. > > For example, maybe there should be a compiler barrier immediately > > before a store-release but not immediately after, and vice versa for > > load-acquire. > > > > > Also, consider the snippets: > > > > > > WRITE_ONCE(*x, 1); > > > *x = 2; > > > > > > and > > > > > > smp_store_release(x, 1); > > > *x = 2; > > > > > > The first snippet would be flagged "mixed-accesses" by the patch while > > > the second snippet would not (thanks to the above component); was this > > > intentional? (Notice that some implementations map the latter to: > > > > > > barrier(); > > > WRITE_ONCE(*x, 1); > > > *x = 2; > > > > > > ) > > > > That last observation is a good reason for changing the Cat code. > > You mean in: > > po-rel | acq-po > > ? (together with the fencerel()-ifications of Release and Acquire already > present in the patch). No, I meant changing the definition of "barrier" to say: (po ; [Release]) | ([Acquire] ; po) (for example) instead of the code you quoted above. > > > > To avoid complications, the LKMM will consider only code in which > > > > plain writes are separated by a compiler barrier from any marked > > > > accesses of the same location. (Question: Can this restriction be > > > > removed?) As a consequence, if a region contains any marked accesses > > > > to a particular location then it cannot contain any plain writes to > > > > that location. > > > > > > I don't know if it can be removed... Said this, maybe we should go back > > > to the (simpler?) question: "What can go wrong without the restriction?", > > > ;-) IOW, what are those "complications", can you provide some examples? > > > > Here's an example I sent to Will a little while ago. Suppose we > > have: > > > > r = rcu_dereference(ptr); > > *r = 1; > > WRITE_ONCE(x, 2); > > > > Imagine if the compiler transformed this to: > > > > r = rcu_dereference(ptr); > > WRITE_ONCE(x, 2); > > if (r != &x) > > *r = 1; > > > > This is bad because it destroys the address dependency when ptr > > contains &x. > > Oh, indeed! (In fact, we discussed this example before... ;-/) BTW, > can you also point out an example which does not involve dependencies > (or destruction thereof)? I believe all the examples did involve dependencies. However, Paul has provided several use cases showing that one might have good reasons for mixing plain reads with marked acccesses -- but he didn't have any use cases for mixing plain writes. There are some open questions remaining. For instance, given: r1 = READ_ONCE(*x); r2 = *x; is the compiler allowed to replace the plain read with the value from the READ_ONCE? What if the statements were in the opposite order? What if the READ_ONCE was changed to WRITE_ONCE? At the moment, I think it's best if we can ignore these issues. > > > Looking at the patch, I see that a plain read can be "w-post-bounded": > > > should/can we prevent this from happening? > > > > It doesn't matter. w-post-bounded gets used only in situations where > > the left-hand access is a write. (Unless I made a mistake somewhere.) > > Well, we can enforce that "gets used only in..." by heading the relation > with [W] ; _ (this will also help us to prevent "mistakes" in the future) I suppose so. It shouldn't make any difference. > > > > As mentioned earlier, ww-vis is contained in ww-xb and wr-vis is > > > > contained in wr-xb. It turns out that the LKMM can almost prove that > > > > the ij-xb relations are transitive, in the following sense. If W is a > > > > write and R is a read, then: > > > > > > > > (A ->iw-xb W ->wj-xb C) implies (A ->ij-xb C), and > > > > > > > > (A ->ir-xb R ->rj-xb C) implies (A ->ij-xb C). > > > > > > > > To fully prove this requires adding one new term to the ppo relation: > > > > > > > > [Marked & R] ; addr ; [Plain & W] ; wmb ; [Marked & W] > > > > > > ... or removing any of these links, right? > > > > I don't understand. Remove any of which links? Remove it from the > > candidate execution or from the memory model? > > I meant removing the term [Marked & R] ; addr ; [Plain & W] or the term > [Plain & W] ; wmb ; [Marked & W] from the (interested) definitions of > {w,r}-{pre,post}-bounded. (And yes: IIUC, this also means to continue > to say "sorry, you're on your own" for some common patterns...) Yes, indeed it will. Many of the common patterns involved in RCU would then be considered to contain races. I don't think people would like that. > > > The proposed model is unsound w.r.t. (2); c.f., LB1 vs. LB2 from: > > > > > > http://lkml.kernel.org/r/20190116213658.GA3984@andrea > > > > Again, I don't understand. What's unsound about the proposed model? > > Let me try again... Consider the following two steps: > > - Start with a _race-free_ test program T1 (= LB1), > > - Apply a "reasonable" source-to-source transformation (2) to obtain a > new test T2 (LB2) (in particular, T2 must be race-free); > > Then the property that I had in mind is described as follows: > > If S is a valid state of T2 then S is also a valid state of T1; IOW, > the tranformation does not introduce new behaviors. > > (An infamously well-known paper about the study of this property, in the > context of the C11 memory model, is available at: > > http://plv.mpi-sws.org/c11comp/ ) > > This property does not hold in the proposed model (c.f., e.g., the state > specified in the "exists" clauses). I don't regard this as a serious drawback. We know that the memory model doesn't behave all that well when it comes to control dependencies to marked writes beyond the end of an "if" statement, for example. This is related to that. We also know that not all hardware exhibits all the behaviors allowed by the architecture. So it's reasonable that on some computer, T1 might never exhibit state S (even though it is architecturally allowed to) whereas T2 could exhibit S. > > > Let's look at your "non-transitive-wmb" test: I tend to read the write > > > "*x = 2" as nothing more than "write 2 to the 1st byte, write 0 to the > > > 2nd byte, write 0 to the next byte, ..."; and similarly for "*x = 1"; > > > maybe some of these writes aren't performed at all (the compiler knows > > > that the most significant byte, say, is never touched/modified); maybe > > > they intersect (overwrite) one another... what else? > > > > That's the thing. According to one of the assumptions listed earlier > > in this document, it's not possible that the "write 2 to the 1st byte" > > access isn't performed at all. The higher-order bytes, yes, they might > > not be touched. But if no writes are performed at all then at the end > > of the region *x will contain 1, not 2 -- and that would be a bug in > > the compiler. > > AFAICT, we agreed here. So consider the following test: > > C non-transitive-wmb-2 > > { > x=0x00010000; > } > > P0(int *x, int *y) > { > *x = 1; > smp_store_release(y, 1); > } > > P1(int *x, int *y, int *z) > { > int r1; > > r1 = smp_load_acquire(y); > if (r1) { > *x = 2; > 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); /* E */ > } > } > > exists (2:r3=1 /\ 2:r4=2) > > The proposed model says that this is race-free. Now suppose that the > compiler mapped the two plain writes above as follows: > > *x = 1; --> A:write 0x0001 at x > B:write 0x0000 at (x + 2) > > *x = 2; --> C:write 0x0002 at x > if ((D:read of 2 bytes at (x + 2)) != 0x0000) > write 0x0000 at (x + 2) > > and consider the execution where 1:r1=1 and 2:r3=1. We know that A and > B propagate to P1 before C and D execute (release/acquire) and that C > propagates to P2 before E executes (wmb/rmb). But what guarantees that > B, say, propagates to P2 before E executes? AFAICT, nothing prevent P2 > from reading the value 0x00010002 for x, that is, from reading the least > significant bits from P1's "write 0x0002 at x" and the most significant > bits from the initial write. However, the proposed model doesn't report > the corresponding execution/state. Ah, that is indeed an excellent example! I had not considered mixed-size accesses generated by the compiler. So perhaps it would be better to get rid of the whole notion of super and major writes, and declare that non-transitive-wmb is racy in all its variants. Alan