seqlock: Require WRITE_ONCE surrounding raw_seqcount_barrier
This patch proposes to require marked atomic accesses surrounding raw_write_seqcount_barrier. We reason that otherwise there is no way to guarantee propagation nor atomicity of writes before/after the barrier [1]. For example, consider the compiler tears stores either before or after the barrier; in this case, readers may observe a partial value, and because readers are unaware that writes are going on (writes are not in a seq-writer critical section), will complete the seq-reader critical section while having observed some partial state. [1] https://lwn.net/Articles/793253/ This came up when designing and implementing KCSAN, because KCSAN would flag these accesses as data-races. After careful analysis, our reasoning as above led us to conclude that the best thing to do is to propose an amendment to the raw_seqcount_barrier usage. Signed-off-by: Marco Elver <elver@google.com> Acked-by: Paul E. McKenney <paulmck@kernel.org> Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
This commit is contained in:
parent
88ecd153be
commit
bf07132f96
|
@ -265,6 +265,13 @@ static inline void raw_write_seqcount_end(seqcount_t *s)
|
||||||
* usual consistency guarantee. It is one wmb cheaper, because we can
|
* usual consistency guarantee. It is one wmb cheaper, because we can
|
||||||
* collapse the two back-to-back wmb()s.
|
* collapse the two back-to-back wmb()s.
|
||||||
*
|
*
|
||||||
|
* Note that, writes surrounding the barrier should be declared atomic (e.g.
|
||||||
|
* via WRITE_ONCE): a) to ensure the writes become visible to other threads
|
||||||
|
* atomically, avoiding compiler optimizations; b) to document which writes are
|
||||||
|
* meant to propagate to the reader critical section. This is necessary because
|
||||||
|
* neither writes before and after the barrier are enclosed in a seq-writer
|
||||||
|
* critical section that would ensure readers are aware of ongoing writes.
|
||||||
|
*
|
||||||
* seqcount_t seq;
|
* seqcount_t seq;
|
||||||
* bool X = true, Y = false;
|
* bool X = true, Y = false;
|
||||||
*
|
*
|
||||||
|
@ -284,11 +291,11 @@ static inline void raw_write_seqcount_end(seqcount_t *s)
|
||||||
*
|
*
|
||||||
* void write(void)
|
* void write(void)
|
||||||
* {
|
* {
|
||||||
* Y = true;
|
* WRITE_ONCE(Y, true);
|
||||||
*
|
*
|
||||||
* raw_write_seqcount_barrier(seq);
|
* raw_write_seqcount_barrier(seq);
|
||||||
*
|
*
|
||||||
* X = false;
|
* WRITE_ONCE(X, false);
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
static inline void raw_write_seqcount_barrier(seqcount_t *s)
|
static inline void raw_write_seqcount_barrier(seqcount_t *s)
|
||||||
|
|
Loading…
Reference in New Issue