Fix r361037.

Reorder flag manipulations and use barrier to ensure that the program
order is followed by compiler and CPU, for unlocked reader of so_state.

In collaboration with:	markj
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D24842
This commit is contained in:
Konstantin Belousov 2020-05-14 20:17:09 +00:00
parent 134e17798c
commit 0532a7a2df

View File

@ -4016,8 +4016,17 @@ soisdisconnected(struct socket *so)
{ {
SOCK_LOCK(so); SOCK_LOCK(so);
so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
/*
* There is at least one reader of so_state that does not
* acquire socket lock, namely soreceive_generic(). Ensure
* that it never sees all flags that track connection status
* cleared, by ordering the update with a barrier semantic of
* our release thread fence.
*/
so->so_state |= SS_ISDISCONNECTED; so->so_state |= SS_ISDISCONNECTED;
atomic_thread_fence_rel();
so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
if (!SOLISTENING(so)) { if (!SOLISTENING(so)) {
SOCK_UNLOCK(so); SOCK_UNLOCK(so);