From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753554AbbFQM3o (ORCPT ); Wed, 17 Jun 2015 08:29:44 -0400 Received: from casper.infradead.org ([85.118.1.10]:58994 "EHLO casper.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752410AbbFQM3j (ORCPT ); Wed, 17 Jun 2015 08:29:39 -0400 Date: Wed, 17 Jun 2015 14:29:24 +0200 From: Peter Zijlstra To: "Paul E. McKenney" Cc: umgwanakikbuti@gmail.com, mingo@elte.hu, ktkhai@parallels.com, rostedt@goodmis.org, tglx@linutronix.de, juri.lelli@gmail.com, pang.xunlei@linaro.org, oleg@redhat.com, wanpeng.li@linux.intel.com, linux-kernel@vger.kernel.org, Al Viro , Linus Torvalds Subject: Re: [PATCH 11/18] seqcount: Introduce raw_write_seqcount_barrier() Message-ID: <20150617122924.GP3644@twins.programming.kicks-ass.net> References: <20150611124636.448700267@infradead.org> <20150611124743.374180021@infradead.org> <20150611153341.GK3913@linux.vnet.ibm.com> <20150611214557.GA4249@linux.vnet.ibm.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20150611214557.GA4249@linux.vnet.ibm.com> User-Agent: Mutt/1.5.21 (2012-12-30) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Thu, Jun 11, 2015 at 02:45:57PM -0700, Paul E. McKenney wrote: > Color me slow and stupid. Maybe due to reviewing a patch too early in > the morning, who knows? > > There is nothing above that prevents the compiler and the CPU from > reordering the assignments to X and Y with the increment of s->sequence++. > One fix would be as follows: > > static inline void raw_write_seqcount_barrier(seqcount_t *s) > { > smp_wmb(); > s->sequence++; > smp_wmb(); > s->sequence++; > smp_wmb(); > } > > Of course, this assumes that the accesses surrounding the call to > raw_write_seqcount_barrier() are writes. If they can be a reads, > the two added smp_wmb() calls need to be full barriers. I have updated the Changelog to hopefully explain things better. I did leave off the READ/WRITE ONCE stuff, because I could not come up with a scenario where it makes a difference -- I appreciate paranoia, but I also think we should not overdo the thing. --- Subject: seqcount: Introduce raw_write_seqcount_barrier() From: Peter Zijlstra Date: Thu Jun 11 12:35:48 CEST 2015 Introduce raw_write_seqcount_barrier(), a new construct that can be used to provide write barrier semantics in seqcount read loops instead of the usual consistency guarantee. raw_write_seqcount_barier() is equivalent to: raw_write_seqcount_begin(); raw_write_seqcount_end(); But avoids issueing two back-to-back smp_wmb() instructions. This construct works because the read side will 'stall' when observing odd values. This means that -- referring to the example in the comment below -- even though there is no (matching) read barrier between the loads of X and Y, we cannot observe !x && !y, because: - if we observe Y == false we must observe the first sequence increment, which makes us loop, until - we observe !(seq & 1) -- the second sequence increment -- at which time we must also observe T == true. Cc: Al Viro Cc: Linus Torvalds Cc: Paul McKenney Suggested-by: Oleg Nesterov Signed-off-by: Peter Zijlstra (Intel) --- include/linux/seqlock.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) --- a/include/linux/seqlock.h +++ b/include/linux/seqlock.h @@ -233,6 +233,47 @@ static inline void raw_write_seqcount_en s->sequence++; } +/** + * raw_write_seqcount_barrier - do a seq write barrier + * @s: pointer to seqcount_t + * + * This can be used to provide an ordering guarantee instead of the + * usual consistency guarantee. It is one wmb cheaper, because we can + * collapse the two back-to-back wmb()s. + * + * seqcount_t seq; + * bool X = true, Y = false; + * + * void read(void) + * { + * bool x, y; + * + * do { + * int s = read_seqcount_begin(&seq); + * + * x = X; y = Y; + * + * } while (read_seqcount_retry(&seq, s)); + * + * BUG_ON(!x && !y); + * } + * + * void write(void) + * { + * Y = true; + * + * raw_write_seqcount_barrier(seq); + * + * X = false; + * } + */ +static inline void raw_write_seqcount_barrier(seqcount_t *s) +{ + s->sequence++; + smp_wmb(); + s->sequence++; +} + /* * raw_write_seqcount_latch - redirect readers to even/odd copy * @s: pointer to seqcount_t