On Thu, Jan 26, 2023 at 01:17:49PM +0100, Jonas Oberhauser wrote:
[...]Good point that the existing smp_mb__after_unlock_lock() can be used for
Note that this interpretation is analogous to the promise of smp_mb__after_unlock_lock(), which says that an
UNLOCK+LOCK pair act as a full fence: here the read-side unlock+gp act as a
full memory barrier.
any use cases relying on the more literal interpretation of this promise.
We already have the work-around! ;-)
[...] I suppose you might be able to writeThe usual litmus test is shown at the end of this email [...]
some absurd client that inspects every store of the reader thread and sees
that there is no line in the reader side code that acts like a full fence.
But it would take a lot of effort to discern this.
[...] I hope few people would have this unhealthy idea. But youGiven that the more literal interpretation is not unreasonable, we should
never know.
assume that someone somewhere might have interpreted it that way.
But I agree that the odds of someone actually relying on this are low,
and any such use case can be fixed with smp_mb__before_srcu_read_unlock(),
similar to smp_mb__after_srcu_read_unlock() that you note is already in use.
It would still be good to scan SRCU use for this sort of pattern, maybe
manually, maybe via something like coccinelle. Alternatively, I could
post on my blog (with right of first refusal to LWN and you guys as
co-authors) telling the community of our intent to change this and see
what people say. Probably both rather than either/or.
Thoughts?
Thanx, Paul
------------------------------------------------------------------------
C C-srcu-observed-6
(*
* Result: Sometimes
*
* The result is Never if any of the smp_mb() calls is uncommented.
*)
{}
P0(int *a, int *b, int *c, int *d, struct srcu_struct *s)
{
int r1;
int r2;
int r3;
int r4;
r1 = srcu_read_lock(s);
WRITE_ONCE(*b, 2);
r2 = READ_ONCE(*a);
// smp_mb();
srcu_read_unlock(s, r1);
// smp_mb();
r3 = READ_ONCE(*c);
// smp_mb();
r4 = READ_ONCE(*d);
}
P1(int *a, int *b, int *c, int *d, struct srcu_struct *s)
{
WRITE_ONCE(*b, 1);
synchronize_srcu(s);
WRITE_ONCE(*c, 1);
}
P2(int *a, int *b, int *c, int *d, struct srcu_struct *s)
{
WRITE_ONCE(*d, 1);
smp_mb();
WRITE_ONCE(*a, 1);
}
exists (0:r2=1 /\ 0:r3=1 /\ 0:r4=0 /\ b=1)