Index | Thread | Search

From:
Alexander Bluhm <alexander.bluhm@gmx.net>
Subject:
Re: Please test: shared solock for all intet sockets within knote(9) routines
To:
Vitaliy Makkoveev <mvs@openbsd.org>
Cc:
tech@openbsd.org
Date:
Wed, 31 Jan 2024 22:25:47 +0100

Download raw body.

Thread
On Tue, Jan 30, 2024 at 05:39:43PM +0300, Vitaliy Makkoveev wrote:
> Please test it, but keep in mind, soassertlocked_readonly() could be
> required in some more places.

I panics on i386 during regress.  From the timestamps of the logs
I think it is one of these.  Not that they run on two machines and
the remote one crashes.

-rw-r--r--  1 root     wsrc          4863 Jan 31 13:06 sys/kern/sosplice/error/make.log
-rw-r--r--  1 root     wsrc          4510 Jan 31 13:07 sys/kern/sosplice/loop/make.log
-rw-r--r--  1 root     wsrc          8872 Jan 31 13:08 sys/kern/sosplice/perf/make.log
-rw-r--r--  1 root     wsrc          1490 Jan 31 14:08 sys/kern/sosplice/scapy/make.log
-rw-r--r--  1 root     wsrc         40256 Jan 31 14:09 sys/kern/sosplice/tcp/make.log
-rw-r--r--  1 root     wsrc          9162 Jan 31 14:10 sys/kern/sosplice/udp/make.log

[-- MARK -- Wed Jan 31 13:05:00 2024]
panic: mutex 0xd7dfd9a0 not held in klist_rcv_soassertlk
Stopped at      db_enter+0x4:   popl    %ebp
    TID    PID    UID     PRFLAGS     PFLAGS  CPU  COMMAND
* 70542  31548      0     0x14000      0x200    1  softnet0
db_enter() at db_enter+0x4
panic(d0cbc0e4) at panic+0x7a
klist_rcv_soassertlk(d7dfd92c) at klist_rcv_soassertlk+0x3b
knote_locked(d7dfd9f0,0) at knote_locked+0x1a
sohasoutofband(d7dfd92c) at sohasoutofband+0x25
tcp_input(f5802ea4,f5802ea0,6,2) at tcp_input+0x290d
ip_deliver(f5802ea4,f5802ea0,6,2) at ip_deliver+0xf4
ipintr() at ipintr+0x52
if_netisr(0) at if_netisr+0xd2
taskq_thread(d82f5000) at taskq_thread+0x84
https://www.openbsd.org/ddb.html describes the minimum info required in bug
reports.  Insufficient info makes it difficult to find and fix bugs.
ddb{1}> [-- MARK -- Wed Jan 31 13:10:00 2024]

ddb{1}> trace
db_enter() at db_enter+0x4
panic(d0cbc0e4) at panic+0x7a
klist_rcv_soassertlk(d7dfd92c) at klist_rcv_soassertlk+0x3b
knote_locked(d7dfd9f0,0) at knote_locked+0x1a
sohasoutofband(d7dfd92c) at sohasoutofband+0x25
tcp_input(f5802ea4,f5802ea0,6,2) at tcp_input+0x290d
ip_deliver(f5802ea4,f5802ea0,6,2) at ip_deliver+0xf4
ipintr() at ipintr+0x52
if_netisr(0) at if_netisr+0xd2
taskq_thread(d82f5000) at taskq_thread+0x84

ddb{1}> show panic
*cpu1: mutex 0xd7dfd9a0 not held in klist_rcv_soassertlk

ddb{1}> ps
   PID     TID   PPID    UID  S       FLAGS  WAIT          COMMAND
 33821  430179  72439      0  3  0x18000080  kqread        perl
 72439   85098   2270      0  3  0x18000082  nanoslp       perl
  2270   66435  91013      0  3   0x810008a  sigsusp       ksh
 91013  468133  21885      0  3  0x1800009a  kqread        sshd
 64251  467022      0      0  3     0x14200  bored         sosplice
  9320  326846      1      0  3  0x18100083  ttyin         getty
 35392  127174      1      0  3  0x18100083  ttyin         getty
 10539  445346      1      0  3  0x18100083  ttyin         getty
 69170  204127      1      0  3  0x18100083  ttyin         getty
 74889  176546      1      0  3  0x18100083  ttyin         getty
 54557  309338      1      0  3  0x18100083  ttyin         getty
 72820  218516      1      0  3  0x18100098  kqread        cron
 61729  496486      1     99  3  0x19100090  kqread        sndiod
 57746  452154      1    110  3  0x18100090  kqread        sndiod
 67789  418348      1      0  3  0x18100090  kqread        inetd
 42191  333292  16121     95  3  0x19100092  kqread        smtpd
 93475   54660  16121    103  3  0x19100092  kqread        smtpd
 83475  437999  16121     95  3  0x19100092  kqread        smtpd
 98829   69987  16121     95  3  0x18100092  kqread        smtpd
 78254  203427  16121     95  3  0x19100092  kqread        smtpd
 21246  167470  16121     95  3  0x19100092  kqread        smtpd
 16121    4669      1      0  3  0x18100080  kqread        smtpd
 81490  303280  70200     91  3  0x18000092  kqread        snmpd_metrics
 70200  361674      1      0  3  0x18100080  kqread        snmpd
 96626  136899      1     91  3  0x19100092  kqread        snmpd
 21885  411308      1      0  3  0x18000088  kqread        sshd
 37505  382412      0      0  3     0x14200  acct          acct
 56649  159907      0      0  3     0x14280  nfsidl        nfsio
  4116  120586      0      0  3     0x14280  nfsidl        nfsio
 72620   54685      0      0  3     0x14280  nfsidl        nfsio
 29121  302945      0      0  3     0x14280  nfsidl        nfsio
 34934  157798      1      0  3  0x18100080  kqread        ntpd
 38552  212157  56073     83  3  0x18100092  kqread        ntpd
 56073  223794      1     83  3  0x19100092  kqread        ntpd
 26595  370479  97754     74  3  0x19100092  bpf           pflogd
 97754  425118      1      0  3  0x18000080  netio         pflogd
 75792  233839  67399     73  3  0x19100090  kqread        syslogd
 67399  100208      1      0  3  0x18100082  netio         syslogd
  4765   57128  61338     77  3  0x18100092  kqread        dhcpleased
 68691  312270  61338     77  3  0x18100092  kqread        dhcpleased
 61338  374213      1      0  3  0x18000080  kqread        dhcpleased
 83483   92240   7393    115  3  0x18100092  kqread        slaacd
 52363  505486   7393    115  3  0x18100092  kqread        slaacd
  7393  383214      1      0  3  0x18100080  kqread        slaacd
 44149    1575      0      0  3     0x14200  bored         smr
 63153   12976      0      0  3     0x14200  pgzero        zerothread
  4242  209353      0      0  3     0x14200  aiodoned      aiodoned
 24241  217704      0      0  3     0x14200  syncer        update
  6943   12123      0      0  3     0x14200  cleaner       cleaner
 99116  172045      0      0  3     0x14200  reaper        reaper
 53902   79358      0      0  3     0x14200  pgdaemon      pagedaemon
  2943  241684      0      0  3     0x14200  bored         wsdisplay0
 69988  448119      0      0  3     0x14200  usbtsk        usbtask
 37311  173195      0      0  3     0x14200  usbatsk       usbatsk
 36678   79722      0      0  3     0x14200  bored         sensors
 73770  446641      0      0  3  0x40014200  acpi0         acpi0
 92248  310035      0      0  7  0x40014200                idle7
 67293  358588      0      0  7  0x40014200                idle6
 66898  111169      0      0  7  0x40014200                idle5
  4293  126154      0      0  7  0x40014200                idle4
  4414  270352      0      0  7  0x40014200                idle3
 68914  204664      0      0  7  0x40014200                idle2
 91318   33572      0      0  3  0x40014200                idle1
 32025  410254      0      0  3     0x14200  bored         softnet3
 88050  248985      0      0  3     0x14200  bored         softnet2
 12644  456866      0      0  3     0x14200  bored         softnet1
*31548   70542      0      0  7     0x14200                softnet0
 30395  235408      0      0  3     0x14200  bored         systqmp
 47861  432958      0      0  3     0x14200  bored         systq
 49949   66059      0      0  3     0x14200  tmoslp        softclockmp
 30081  350770      0      0  3  0x40014200  tmoslp        softclock
 28312  521561      0      0  7  0x40014200                idle0
 12934  232778      0      0  3     0x14200  kmalloc       kmthread
     1  166358      0      0  3   0x8000082  wait          init
     0       0     -1      0  3     0x10200  scheduler     swapper

ddb{1}> show register
ds                  0x10
es                  0x10
fs                  0x20
gs                     0
edi           0xd0cbc0e4        apollo_udma33_tim+0x3d24d
esi                    0
ebp           0xf5802d24
ebx           0xf55365d8
edx                0x3fd
ecx           0x79e68b36
eax                 0x39
eip           0xd0761854        db_enter+0x4
cs                   0x8
eflags             0x202
esp           0xf5802d24
ss                  0x10
db_enter+0x4:   popl    %ebp

ddb{1}> show locks
exclusive rwlock netlock r = 0 (0xd0ee12d4)
shared rwlock softnet0 r = 0 (0xd82f5048)

> Index: sys/kern/uipc_socket.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/uipc_socket.c,v
> retrieving revision 1.315
> diff -u -p -r1.315 uipc_socket.c
> --- sys/kern/uipc_socket.c	26 Jan 2024 18:24:23 -0000	1.315
> +++ sys/kern/uipc_socket.c	30 Jan 2024 14:24:45 -0000
> @@ -72,26 +72,20 @@ int	filt_soread(struct knote *kn, long h
>  void	filt_sowdetach(struct knote *kn);
>  int	filt_sowrite(struct knote *kn, long hint);
>  int	filt_soexcept(struct knote *kn, long hint);
> -int	filt_solisten(struct knote *kn, long hint);
> -int	filt_somodify(struct kevent *kev, struct knote *kn);
> -int	filt_soprocess(struct knote *kn, struct kevent *kev);
>  
> -const struct filterops solisten_filtops = {
> -	.f_flags	= FILTEROP_ISFD | FILTEROP_MPSAFE,
> -	.f_attach	= NULL,
> -	.f_detach	= filt_sordetach,
> -	.f_event	= filt_solisten,
> -	.f_modify	= filt_somodify,
> -	.f_process	= filt_soprocess,
> -};
> +int	filt_snd_somodify(struct kevent *kev, struct knote *kn);
> +int	filt_snd_soprocess(struct knote *kn, struct kevent *kev);
> +
> +int	filt_rcv_somodify(struct kevent *kev, struct knote *kn);
> +int	filt_rcv_soprocess(struct knote *kn, struct kevent *kev);
>  
>  const struct filterops soread_filtops = {
>  	.f_flags	= FILTEROP_ISFD | FILTEROP_MPSAFE,
>  	.f_attach	= NULL,
>  	.f_detach	= filt_sordetach,
>  	.f_event	= filt_soread,
> -	.f_modify	= filt_somodify,
> -	.f_process	= filt_soprocess,
> +	.f_modify	= filt_rcv_somodify,
> +	.f_process	= filt_rcv_soprocess,
>  };
>  
>  const struct filterops sowrite_filtops = {
> @@ -99,8 +93,8 @@ const struct filterops sowrite_filtops =
>  	.f_attach	= NULL,
>  	.f_detach	= filt_sowdetach,
>  	.f_event	= filt_sowrite,
> -	.f_modify	= filt_somodify,
> -	.f_process	= filt_soprocess,
> +	.f_modify	= filt_snd_somodify,
> +	.f_process	= filt_snd_soprocess,
>  };
>  
>  const struct filterops soexcept_filtops = {
> @@ -108,18 +102,28 @@ const struct filterops soexcept_filtops 
>  	.f_attach	= NULL,
>  	.f_detach	= filt_sordetach,
>  	.f_event	= filt_soexcept,
> -	.f_modify	= filt_somodify,
> -	.f_process	= filt_soprocess,
> +	.f_modify	= filt_rcv_somodify,
> +	.f_process	= filt_rcv_soprocess,
> +};
> +
> +void	klist_snd_soassertlk(void *);
> +int	klist_snd_solock(void *);
> +void	klist_snd_sounlock(void *, int);
> +
> +const struct klistops socket_snd_klistops = {
> +	.klo_assertlk	= klist_snd_soassertlk,
> +	.klo_lock	= klist_snd_solock,
> +	.klo_unlock	= klist_snd_sounlock,
>  };
>  
> -void	klist_soassertlk(void *);
> -int	klist_solock(void *);
> -void	klist_sounlock(void *, int);
> -
> -const struct klistops socket_klistops = {
> -	.klo_assertlk	= klist_soassertlk,
> -	.klo_lock	= klist_solock,
> -	.klo_unlock	= klist_sounlock,
> +void	klist_rcv_soassertlk(void *);
> +int	klist_rcv_solock(void *);
> +void	klist_rcv_sounlock(void *, int);
> +
> +const struct klistops socket_rcv_klistops = {
> +	.klo_assertlk	= klist_rcv_soassertlk,
> +	.klo_lock	= klist_rcv_solock,
> +	.klo_unlock	= klist_rcv_sounlock,
>  };
>  
>  #ifndef SOMINCONN
> @@ -158,8 +162,10 @@ soalloc(const struct domain *dp, int wai
>  		return (NULL);
>  	rw_init_flags(&so->so_lock, dp->dom_name, RWL_DUPOK);
>  	refcnt_init(&so->so_refcnt);
> -	klist_init(&so->so_rcv.sb_klist, &socket_klistops, so);
> -	klist_init(&so->so_snd.sb_klist, &socket_klistops, so);
> +	mtx_init(&so->so_rcv.sb_mtx, IPL_MPFLOOR);
> +	mtx_init(&so->so_snd.sb_mtx, IPL_MPFLOOR);
> +	klist_init(&so->so_rcv.sb_klist, &socket_rcv_klistops, so);
> +	klist_init(&so->so_snd.sb_klist, &socket_snd_klistops, so);
>  	sigio_init(&so->so_sigio);
>  	TAILQ_INIT(&so->so_q0);
>  	TAILQ_INIT(&so->so_q);
> @@ -1757,7 +1763,7 @@ somove(struct socket *so, int wait)
>  void
>  sorwakeup(struct socket *so)
>  {
> -	soassertlocked(so);
> +	soassertlocked_readonly(so);
>  
>  #ifdef SOCKET_SPLICE
>  	if (so->so_rcv.sb_flags & SB_SPLICE) {
> @@ -1785,7 +1791,7 @@ sorwakeup(struct socket *so)
>  void
>  sowwakeup(struct socket *so)
>  {
> -	soassertlocked(so);
> +	soassertlocked_readonly(so);
>  
>  #ifdef SOCKET_SPLICE
>  	if (so->so_snd.sb_flags & SB_SPLICE)
> @@ -2137,19 +2143,54 @@ sohasoutofband(struct socket *so)
>  	knote_locked(&so->so_rcv.sb_klist, 0);
>  }
>  
> +void
> +sofilt_lock(struct socket *so, struct sockbuf *sb)
> +{
> +	switch (so->so_proto->pr_domain->dom_family) {
> +	case PF_INET:
> +	case PF_INET6:
> +		NET_LOCK_SHARED();
> +		break;
> +	default:
> +		rw_enter_write(&so->so_lock);
> +		break;
> +	}
> +
> +	mtx_enter(&sb->sb_mtx);
> +}
> +
> +void
> +sofilt_unlock(struct socket *so, struct sockbuf *sb)
> +{
> +	mtx_leave(&sb->sb_mtx);
> +
> +	switch (so->so_proto->pr_domain->dom_family) {
> +	case PF_INET:
> +	case PF_INET6:
> +		NET_UNLOCK_SHARED();
> +		break;
> +	default:
> +		rw_exit_write(&so->so_lock);
> +		break;
> +	}
> +}
> +
> +static inline void
> +sofilt_assert_locked(struct socket *so, struct sockbuf *sb)
> +{
> +	MUTEX_ASSERT_LOCKED(&sb->sb_mtx);
> +	soassertlocked_readonly(so);
> +}
> +
>  int
>  soo_kqfilter(struct file *fp, struct knote *kn)
>  {
>  	struct socket *so = kn->kn_fp->f_data;
>  	struct sockbuf *sb;
>  
> -	solock(so);
>  	switch (kn->kn_filter) {
>  	case EVFILT_READ:
> -		if (so->so_options & SO_ACCEPTCONN)
> -			kn->kn_fop = &solisten_filtops;
> -		else
> -			kn->kn_fop = &soread_filtops;
> +		kn->kn_fop = &soread_filtops;
>  		sb = &so->so_rcv;
>  		break;
>  	case EVFILT_WRITE:
> @@ -2161,12 +2202,12 @@ soo_kqfilter(struct file *fp, struct kno
>  		sb = &so->so_rcv;
>  		break;
>  	default:
> -		sounlock(so);
>  		return (EINVAL);
>  	}
>  
> +	mtx_enter(&sb->sb_mtx);
>  	klist_insert_locked(&sb->sb_klist, kn);
> -	sounlock(so);
> +	mtx_leave(&sb->sb_mtx);
>  
>  	return (0);
>  }
> @@ -2185,7 +2226,23 @@ filt_soread(struct knote *kn, long hint)
>  	struct socket *so = kn->kn_fp->f_data;
>  	int rv = 0;
>  
> -	soassertlocked(so);
> +	sofilt_assert_locked(so, &so->so_rcv);
> +
> +	if (so->so_options & SO_ACCEPTCONN) {
> +		kn->kn_data = so->so_qlen;
> +		rv = (kn->kn_data != 0);
> +
> +		if (kn->kn_flags & (__EV_POLL | __EV_SELECT)) {
> +			if (so->so_state & SS_ISDISCONNECTED) {
> +				kn->kn_flags |= __EV_HUP;
> +				rv = 1;
> +			} else {
> +				rv = soreadable(so);
> +			}
> +		}
> +
> +		return rv;
> +	}
>  
>  	kn->kn_data = so->so_rcv.sb_cc;
>  #ifdef SOCKET_SPLICE
> @@ -2226,7 +2283,7 @@ filt_sowrite(struct knote *kn, long hint
>  	struct socket *so = kn->kn_fp->f_data;
>  	int rv;
>  
> -	soassertlocked(so);
> +	sofilt_assert_locked(so, &so->so_snd);
>  
>  	kn->kn_data = sbspace(so, &so->so_snd);
>  	if (so->so_snd.sb_state & SS_CANTSENDMORE) {
> @@ -2257,7 +2314,7 @@ filt_soexcept(struct knote *kn, long hin
>  	struct socket *so = kn->kn_fp->f_data;
>  	int rv = 0;
>  
> -	soassertlocked(so);
> +	sofilt_assert_locked(so, &so->so_rcv);
>  
>  #ifdef SOCKET_SPLICE
>  	if (isspliced(so)) {
> @@ -2283,77 +2340,105 @@ filt_soexcept(struct knote *kn, long hin
>  }
>  
>  int
> -filt_solisten(struct knote *kn, long hint)
> +filt_snd_somodify(struct kevent *kev, struct knote *kn)
>  {
>  	struct socket *so = kn->kn_fp->f_data;
> -	int active;
> +	int rv;
>  
> -	soassertlocked(so);
> +	sofilt_lock(so, &so->so_snd);
> +	rv = knote_modify(kev, kn);
> +	sofilt_unlock(so, &so->so_snd);
>  
> -	kn->kn_data = so->so_qlen;
> -	active = (kn->kn_data != 0);
> +	return (rv);
> +}
>  
> -	if (kn->kn_flags & (__EV_POLL | __EV_SELECT)) {
> -		if (so->so_state & SS_ISDISCONNECTED) {
> -			kn->kn_flags |= __EV_HUP;
> -			active = 1;
> -		} else {
> -			active = soreadable(so);
> -		}
> -	}
> +int
> +filt_snd_soprocess(struct knote *kn, struct kevent *kev)
> +{
> +	struct socket *so = kn->kn_fp->f_data;
> +	int rv;
> +
> +	sofilt_lock(so, &so->so_snd);
> +	rv = knote_process(kn, kev);
> +	sofilt_unlock(so, &so->so_snd);
>  
> -	return (active);
> +	return (rv);
>  }
>  
>  int
> -filt_somodify(struct kevent *kev, struct knote *kn)
> +filt_rcv_somodify(struct kevent *kev, struct knote *kn)
>  {
>  	struct socket *so = kn->kn_fp->f_data;
>  	int rv;
>  
> -	solock(so);
> +	sofilt_lock(so, &so->so_rcv);
>  	rv = knote_modify(kev, kn);
> -	sounlock(so);
> +	sofilt_unlock(so, &so->so_rcv);
>  
>  	return (rv);
>  }
>  
>  int
> -filt_soprocess(struct knote *kn, struct kevent *kev)
> +filt_rcv_soprocess(struct knote *kn, struct kevent *kev)
>  {
>  	struct socket *so = kn->kn_fp->f_data;
>  	int rv;
>  
> -	solock(so);
> +	sofilt_lock(so, &so->so_rcv);
>  	rv = knote_process(kn, kev);
> -	sounlock(so);
> +	sofilt_unlock(so, &so->so_rcv);
>  
>  	return (rv);
>  }
>  
>  void
> -klist_soassertlk(void *arg)
> +klist_snd_soassertlk(void *arg)
>  {
>  	struct socket *so = arg;
>  
> -	soassertlocked(so);
> +	MUTEX_ASSERT_LOCKED(&so->so_snd.sb_mtx);
>  }
>  
>  int
> -klist_solock(void *arg)
> +klist_snd_solock(void *arg)
>  {
>  	struct socket *so = arg;
>  
> -	solock(so);
> +	mtx_enter(&so->so_snd.sb_mtx);
>  	return (1);
>  }
>  
>  void
> -klist_sounlock(void *arg, int ls)
> +klist_snd_sounlock(void *arg, int ls)
>  {
>  	struct socket *so = arg;
>  
> -	sounlock(so);
> +	mtx_leave(&so->so_snd.sb_mtx);
> +}
> +
> +void
> +klist_rcv_soassertlk(void *arg)
> +{
> +	struct socket *so = arg;
> +
> +	MUTEX_ASSERT_LOCKED(&so->so_rcv.sb_mtx);
> +}
> +
> +int
> +klist_rcv_solock(void *arg)
> +{
> +	struct socket *so = arg;
> +
> +	mtx_enter(&so->so_rcv.sb_mtx);
> +	return (1);
> +}
> +
> +void
> +klist_rcv_sounlock(void *arg, int ls)
> +{
> +	struct socket *so = arg;
> +
> +	mtx_leave(&so->so_rcv.sb_mtx);
>  }
>  
>  #ifdef DDB
> Index: sys/kern/uipc_socket2.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/uipc_socket2.c,v
> retrieving revision 1.140
> diff -u -p -r1.140 uipc_socket2.c
> --- sys/kern/uipc_socket2.c	11 Jan 2024 14:15:11 -0000	1.140
> +++ sys/kern/uipc_socket2.c	30 Jan 2024 14:24:45 -0000
> @@ -439,7 +439,7 @@ sounlock_shared(struct socket *so)
>  }
>  
>  void
> -soassertlocked(struct socket *so)
> +soassertlocked_readonly(struct socket *so)
>  {
>  	switch (so->so_proto->pr_domain->dom_family) {
>  	case PF_INET:
> @@ -452,6 +452,27 @@ soassertlocked(struct socket *so)
>  	}
>  }
>  
> +void
> +soassertlocked(struct socket *so)
> +{
> +	switch (so->so_proto->pr_domain->dom_family) {
> +	case PF_INET:
> +	case PF_INET6:
> +		if (rw_status(&netlock) == RW_READ) {
> +			NET_ASSERT_LOCKED();
> +
> +			if (splassert_ctl > 0 && pru_locked(so) == 0 &&
> +			    rw_status(&so->so_lock) != RW_WRITE)
> +				splassert_fail(0, RW_WRITE, __func__);
> +		} else
> +			NET_ASSERT_LOCKED_EXCLUSIVE();
> +		break;
> +	default:
> +		rw_assert_wrlock(&so->so_lock);
> +		break;
> +	}
> +}
> +
>  int
>  sosleep_nsec(struct socket *so, void *ident, int prio, const char *wmesg,
>      uint64_t nsecs)
> @@ -489,46 +510,62 @@ sbwait(struct socket *so, struct sockbuf
>  
>  	soassertlocked(so);
>  
> +	mtx_enter(&sb->sb_mtx);
>  	sb->sb_flags |= SB_WAIT;
> +	mtx_leave(&sb->sb_mtx);
> +
>  	return sosleep_nsec(so, &sb->sb_cc, prio, "netio", sb->sb_timeo_nsecs);
>  }
>  
>  int
>  sblock(struct socket *so, struct sockbuf *sb, int flags)
>  {
> -	int error, prio = PSOCK;
> +	int error = 0, prio = PSOCK;
>  
>  	soassertlocked(so);
>  
> +	mtx_enter(&sb->sb_mtx);
>  	if ((sb->sb_flags & SB_LOCK) == 0) {
>  		sb->sb_flags |= SB_LOCK;
> -		return (0);
> +		goto out;
> +	}
> +	if ((flags & SBL_WAIT) == 0) {
> +		error = EWOULDBLOCK;
> +		goto out;
>  	}
> -	if ((flags & SBL_WAIT) == 0)
> -		return (EWOULDBLOCK);
>  	if (!(flags & SBL_NOINTR || sb->sb_flags & SB_NOINTR))
>  		prio |= PCATCH;
>  
>  	while (sb->sb_flags & SB_LOCK) {
>  		sb->sb_flags |= SB_WANT;
> +		mtx_leave(&sb->sb_mtx);
>  		error = sosleep_nsec(so, &sb->sb_flags, prio, "netlck", INFSLP);
>  		if (error)
>  			return (error);
> +		mtx_enter(&sb->sb_mtx);
>  	}
>  	sb->sb_flags |= SB_LOCK;
> +out:
> +	mtx_leave(&sb->sb_mtx);
> +
>  	return (0);
>  }
>  
>  void
>  sbunlock(struct socket *so, struct sockbuf *sb)
>  {
> -	soassertlocked(so);
> +	int dowakeup = 0;
>  
> +	mtx_enter(&sb->sb_mtx);
>  	sb->sb_flags &= ~SB_LOCK;
>  	if (sb->sb_flags & SB_WANT) {
>  		sb->sb_flags &= ~SB_WANT;
> -		wakeup(&sb->sb_flags);
> +		dowakeup = 1;
>  	}
> +	mtx_leave(&sb->sb_mtx);
> +
> +	if (dowakeup)
> +		wakeup(&sb->sb_flags);
>  }
>  
>  /*
> @@ -539,15 +576,24 @@ sbunlock(struct socket *so, struct sockb
>  void
>  sowakeup(struct socket *so, struct sockbuf *sb)
>  {
> -	soassertlocked(so);
> +	int dowakeup = 0, dopgsigio = 0;
>  
> +	mtx_enter(&sb->sb_mtx);
>  	if (sb->sb_flags & SB_WAIT) {
>  		sb->sb_flags &= ~SB_WAIT;
> -		wakeup(&sb->sb_cc);
> +		dowakeup = 1;
>  	}
>  	if (sb->sb_flags & SB_ASYNC)
> -		pgsigio(&so->so_sigio, SIGIO, 0);
> +		dopgsigio = 1;
> +
>  	knote_locked(&sb->sb_klist, 0);
> +	mtx_leave(&sb->sb_mtx);
> +
> +	if (dowakeup)
> +		wakeup(&sb->sb_cc);
> +
> +	if (dopgsigio)
> +		pgsigio(&so->so_sigio, SIGIO, 0);
>  }
>  
>  /*
> Index: sys/kern/uipc_syscalls.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/uipc_syscalls.c,v
> retrieving revision 1.216
> diff -u -p -r1.216 uipc_syscalls.c
> --- sys/kern/uipc_syscalls.c	3 Jan 2024 11:07:04 -0000	1.216
> +++ sys/kern/uipc_syscalls.c	30 Jan 2024 14:24:45 -0000
> @@ -326,7 +326,9 @@ doaccept(struct proc *p, int sock, struc
>  	    : (flags & SOCK_NONBLOCK ? FNONBLOCK : 0);
>  
>  	/* connection has been removed from the listen queue */
> +	mtx_enter(&head->so_rcv.sb_mtx);
>  	knote_locked(&head->so_rcv.sb_klist, 0);
> +	mtx_leave(&head->so_rcv.sb_mtx);
>  
>  	if (persocket)
>  		sounlock(head);
> Index: sys/netinet/ip_divert.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet/ip_divert.c,v
> retrieving revision 1.92
> diff -u -p -r1.92 ip_divert.c
> --- sys/netinet/ip_divert.c	16 Sep 2023 09:33:27 -0000	1.92
> +++ sys/netinet/ip_divert.c	30 Jan 2024 14:24:45 -0000
> @@ -67,6 +67,7 @@ const struct pr_usrreqs divert_usrreqs =
>  	.pru_detach	= divert_detach,
>  	.pru_lock	= divert_lock,
>  	.pru_unlock	= divert_unlock,
> +	.pru_locked	= divert_locked,
>  	.pru_bind	= divert_bind,
>  	.pru_shutdown	= divert_shutdown,
>  	.pru_send	= divert_send,
> @@ -311,6 +312,14 @@ divert_unlock(struct socket *so)
>  
>  	NET_ASSERT_LOCKED();
>  	mtx_leave(&inp->inp_mtx);
> +}
> +
> +int
> +divert_locked(struct socket *so)
> +{
> +	struct inpcb *inp = sotoinpcb(so);
> +
> +	return mtx_owned(&inp->inp_mtx);
>  }
>  
>  int
> Index: sys/netinet/ip_divert.h
> ===================================================================
> RCS file: /cvs/src/sys/netinet/ip_divert.h,v
> retrieving revision 1.24
> diff -u -p -r1.24 ip_divert.h
> --- sys/netinet/ip_divert.h	17 Oct 2022 14:49:02 -0000	1.24
> +++ sys/netinet/ip_divert.h	30 Jan 2024 14:24:45 -0000
> @@ -74,6 +74,7 @@ int	 divert_attach(struct socket *, int,
>  int	 divert_detach(struct socket *);
>  void	 divert_lock(struct socket *);
>  void	 divert_unlock(struct socket *);
> +int	 divert_locked(struct socket *);
>  int	 divert_bind(struct socket *, struct mbuf *, struct proc *);
>  int	 divert_shutdown(struct socket *);
>  int	 divert_send(struct socket *, struct mbuf *, struct mbuf *,
> Index: sys/netinet/ip_var.h
> ===================================================================
> RCS file: /cvs/src/sys/netinet/ip_var.h,v
> retrieving revision 1.110
> diff -u -p -r1.110 ip_var.h
> --- sys/netinet/ip_var.h	26 Nov 2023 22:08:10 -0000	1.110
> +++ sys/netinet/ip_var.h	30 Jan 2024 14:24:45 -0000
> @@ -260,6 +260,7 @@ int	 rip_attach(struct socket *, int, in
>  int	 rip_detach(struct socket *);
>  void	 rip_lock(struct socket *);
>  void	 rip_unlock(struct socket *);
> +int	 rip_locked(struct socket *);
>  int	 rip_bind(struct socket *, struct mbuf *, struct proc *);
>  int	 rip_connect(struct socket *, struct mbuf *);
>  int	 rip_disconnect(struct socket *);
> Index: sys/netinet/raw_ip.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet/raw_ip.c,v
> retrieving revision 1.154
> diff -u -p -r1.154 raw_ip.c
> --- sys/netinet/raw_ip.c	21 Jan 2024 01:17:20 -0000	1.154
> +++ sys/netinet/raw_ip.c	30 Jan 2024 14:24:45 -0000
> @@ -108,6 +108,7 @@ const struct pr_usrreqs rip_usrreqs = {
>  	.pru_detach	= rip_detach,
>  	.pru_lock	= rip_lock,
>  	.pru_unlock	= rip_unlock,
> +	.pru_locked	= rip_locked,
>  	.pru_bind	= rip_bind,
>  	.pru_connect	= rip_connect,
>  	.pru_disconnect	= rip_disconnect,
> @@ -522,6 +523,14 @@ rip_unlock(struct socket *so)
>  
>  	NET_ASSERT_LOCKED();
>  	mtx_leave(&inp->inp_mtx);
> +}
> +
> +int
> +rip_locked(struct socket *so)
> +{
> +	struct inpcb *inp = sotoinpcb(so);
> +
> +	return mtx_owned(&inp->inp_mtx);
>  }
>  
>  int
> Index: sys/netinet/udp_usrreq.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet/udp_usrreq.c,v
> retrieving revision 1.316
> diff -u -p -r1.316 udp_usrreq.c
> --- sys/netinet/udp_usrreq.c	28 Jan 2024 20:34:25 -0000	1.316
> +++ sys/netinet/udp_usrreq.c	30 Jan 2024 14:24:45 -0000
> @@ -127,6 +127,7 @@ const struct pr_usrreqs udp_usrreqs = {
>  	.pru_detach	= udp_detach,
>  	.pru_lock	= udp_lock,
>  	.pru_unlock	= udp_unlock,
> +	.pru_locked	= udp_locked,
>  	.pru_bind	= udp_bind,
>  	.pru_connect	= udp_connect,
>  	.pru_disconnect	= udp_disconnect,
> @@ -143,6 +144,7 @@ const struct pr_usrreqs udp6_usrreqs = {
>  	.pru_detach	= udp_detach,
>  	.pru_lock	= udp_lock,
>  	.pru_unlock	= udp_unlock,
> +	.pru_locked	= udp_locked,
>  	.pru_bind	= udp_bind,
>  	.pru_connect	= udp_connect,
>  	.pru_disconnect	= udp_disconnect,
> @@ -1154,6 +1156,14 @@ udp_unlock(struct socket *so)
>  
>  	NET_ASSERT_LOCKED();
>  	mtx_leave(&inp->inp_mtx);
> +}
> +
> +int
> +udp_locked(struct socket *so)
> +{
> +	struct inpcb *inp = sotoinpcb(so);
> +
> +	return mtx_owned(&inp->inp_mtx);
>  }
>  
>  int
> Index: sys/netinet/udp_var.h
> ===================================================================
> RCS file: /cvs/src/sys/netinet/udp_var.h,v
> retrieving revision 1.50
> diff -u -p -r1.50 udp_var.h
> --- sys/netinet/udp_var.h	10 Jan 2024 16:44:30 -0000	1.50
> +++ sys/netinet/udp_var.h	30 Jan 2024 14:24:45 -0000
> @@ -147,6 +147,7 @@ int	 udp_attach(struct socket *, int, in
>  int	 udp_detach(struct socket *);
>  void	 udp_lock(struct socket *);
>  void	 udp_unlock(struct socket *);
> +int	 udp_locked(struct socket *);
>  int	 udp_bind(struct socket *, struct mbuf *, struct proc *);
>  int	 udp_connect(struct socket *, struct mbuf *);
>  int	 udp_disconnect(struct socket *);
> Index: sys/netinet6/ip6_mroute.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet6/ip6_mroute.c,v
> retrieving revision 1.138
> diff -u -p -r1.138 ip6_mroute.c
> --- sys/netinet6/ip6_mroute.c	6 Dec 2023 09:27:17 -0000	1.138
> +++ sys/netinet6/ip6_mroute.c	30 Jan 2024 14:24:45 -0000
> @@ -861,12 +861,12 @@ socket6_send(struct socket *so, struct m
>  
>  		mtx_enter(&inp->inp_mtx);
>  		ret = sbappendaddr(so, &so->so_rcv, sin6tosa(src), mm, NULL);
> +		if (ret != 0)
> +			sorwakeup(so);
>  		mtx_leave(&inp->inp_mtx);
>  
> -		if (ret != 0) {
> -			sorwakeup(so);
> +		if (ret != 0)
>  			return 0;
> -		}
>  	}
>  	m_freem(mm);
>  	return -1;
> Index: sys/netinet6/ip6_var.h
> ===================================================================
> RCS file: /cvs/src/sys/netinet6/ip6_var.h,v
> retrieving revision 1.109
> diff -u -p -r1.109 ip6_var.h
> --- sys/netinet6/ip6_var.h	3 Dec 2023 20:36:24 -0000	1.109
> +++ sys/netinet6/ip6_var.h	30 Jan 2024 14:24:45 -0000
> @@ -353,6 +353,7 @@ int	rip6_attach(struct socket *, int, in
>  int	rip6_detach(struct socket *);
>  void	rip6_lock(struct socket *);
>  void	rip6_unlock(struct socket *);
> +int	rip6_locked(struct socket *);
>  int	rip6_bind(struct socket *, struct mbuf *, struct proc *);
>  int	rip6_connect(struct socket *, struct mbuf *);
>  int	rip6_disconnect(struct socket *);
> Index: sys/netinet6/raw_ip6.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet6/raw_ip6.c,v
> retrieving revision 1.179
> diff -u -p -r1.179 raw_ip6.c
> --- sys/netinet6/raw_ip6.c	21 Jan 2024 01:17:20 -0000	1.179
> +++ sys/netinet6/raw_ip6.c	30 Jan 2024 14:24:45 -0000
> @@ -110,6 +110,7 @@ const struct pr_usrreqs rip6_usrreqs = {
>  	.pru_detach	= rip6_detach,
>  	.pru_lock	= rip6_lock,
>  	.pru_unlock	= rip6_unlock,
> +	.pru_locked	= rip6_locked,
>  	.pru_bind	= rip6_bind,
>  	.pru_connect	= rip6_connect,
>  	.pru_disconnect	= rip6_disconnect,
> @@ -651,6 +652,14 @@ rip6_unlock(struct socket *so)
>  
>  	NET_ASSERT_LOCKED();
>  	mtx_leave(&inp->inp_mtx);
> +}
> +
> +int
> +rip6_locked(struct socket *so)
> +{
> +	struct inpcb *inp = sotoinpcb(so);
> +
> +	return mtx_owned(&inp->inp_mtx);
>  }
>  
>  int
> Index: sys/sys/mutex.h
> ===================================================================
> RCS file: /cvs/src/sys/sys/mutex.h,v
> retrieving revision 1.19
> diff -u -p -r1.19 mutex.h
> --- sys/sys/mutex.h	1 Dec 2023 14:37:22 -0000	1.19
> +++ sys/sys/mutex.h	30 Jan 2024 14:24:46 -0000
> @@ -127,6 +127,9 @@ void	mtx_leave(struct mutex *);
>  
>  #define mtx_init(m, ipl)	mtx_init_flags(m, ipl, NULL, 0)
>  
> +#define mtx_owned(mtx) \
> +	(((mtx)->mtx_owner == curcpu()) || panicstr || db_active)
> +
>  #ifdef WITNESS
>  
>  void	_mtx_init_flags(struct mutex *, int, const char *, int,
> Index: sys/sys/protosw.h
> ===================================================================
> RCS file: /cvs/src/sys/sys/protosw.h,v
> retrieving revision 1.64
> diff -u -p -r1.64 protosw.h
> --- sys/sys/protosw.h	11 Jan 2024 14:15:12 -0000	1.64
> +++ sys/sys/protosw.h	30 Jan 2024 14:24:46 -0000
> @@ -69,6 +69,7 @@ struct pr_usrreqs {
>  	int	(*pru_detach)(struct socket *);
>  	void	(*pru_lock)(struct socket *);
>  	void	(*pru_unlock)(struct socket *);
> +	int	(*pru_locked)(struct socket *so);
>  	int	(*pru_bind)(struct socket *, struct mbuf *, struct proc *);
>  	int	(*pru_listen)(struct socket *);
>  	int	(*pru_connect)(struct socket *, struct mbuf *);
> @@ -294,6 +295,14 @@ pru_unlock(struct socket *so)
>  {
>  	if (so->so_proto->pr_usrreqs->pru_unlock)
>  		(*so->so_proto->pr_usrreqs->pru_unlock)(so);
> +}
> +
> +static inline int
> +pru_locked(struct socket *so)
> +{
> +	if (so->so_proto->pr_usrreqs->pru_locked)
> +		return (*so->so_proto->pr_usrreqs->pru_locked)(so);
> +	return (0);
>  }
>  
>  static inline int
> Index: sys/sys/socketvar.h
> ===================================================================
> RCS file: /cvs/src/sys/sys/socketvar.h,v
> retrieving revision 1.121
> diff -u -p -r1.121 socketvar.h
> --- sys/sys/socketvar.h	11 Jan 2024 14:15:12 -0000	1.121
> +++ sys/sys/socketvar.h	30 Jan 2024 14:24:46 -0000
> @@ -40,6 +40,7 @@
>  #include <sys/sigio.h>				/* for struct sigio_ref */
>  #include <sys/task.h>
>  #include <sys/timeout.h>
> +#include <sys/mutex.h>
>  #include <sys/rwlock.h>
>  #include <sys/refcnt.h>
>  
> @@ -105,6 +106,7 @@ struct socket {
>   * Variables for socket buffering.
>   */
>  	struct	sockbuf {
> +		struct mutex sb_mtx;
>  /* The following fields are all zeroed on flush. */
>  #define	sb_startzero	sb_cc
>  		u_long	sb_cc;		/* actual chars in buffer */
> @@ -174,6 +176,7 @@ struct socket {
>  #include <lib/libkern/libkern.h>
>  
>  void	soassertlocked(struct socket *);
> +void	soassertlocked_readonly(struct socket *);
>  
>  static inline void
>  soref(struct socket *so)
> @@ -211,10 +214,12 @@ sb_notify(struct socket *so, struct sock
>   * still be negative (cc > hiwat or mbcnt > mbmax).  Should detect
>   * overflow and return 0.
>   */
> +
>  static inline long
>  sbspace(struct socket *so, struct sockbuf *sb)
>  {
> -	soassertlocked(so);
> +	soassertlocked_readonly(so);
> +
>  	return lmin(sb->sb_hiwat - sb->sb_cc, sb->sb_mbmax - sb->sb_mbcnt);
>  }
>  
> @@ -230,7 +235,7 @@ sbspace(struct socket *so, struct sockbu
>  static inline int
>  soreadable(struct socket *so)
>  {
> -	soassertlocked(so);
> +	soassertlocked_readonly(so);
>  	if (isspliced(so))
>  		return 0;
>  	return (so->so_rcv.sb_state & SS_CANTRCVMORE) || so->so_qlen ||
> @@ -241,7 +246,7 @@ soreadable(struct socket *so)
>  static inline int
>  sowriteable(struct socket *so)
>  {
> -	soassertlocked(so);
> +	soassertlocked_readonly(so);
>  	return ((sbspace(so, &so->so_snd) >= so->so_snd.sb_lowat &&
>  	    ((so->so_state & SS_ISCONNECTED) ||
>  	    (so->so_proto->pr_flags & PR_CONNREQUIRED)==0)) ||