On Wed, Mar 27, 2024 at 10:51:09PM +0100, Alexander Bluhm wrote: > On Wed, Mar 27, 2024 at 10:26:27PM +0300, Vitaliy Makkoveev wrote: > > On Wed, Mar 27, 2024 at 08:17:33AM +0100, Anton Lindqvist wrote: > > > > > > Observing two regress hangs in the kernel on netio. Both seems make use > > > of unix sockets. Could this be the culprit? > > > > > > regress/lib/libc/fread > > > regress/usr.bin/ssh (scp.sh) > > > > Sorry for delay. > > > > It was exposed that `sb_mtx' should not be released between `so_rcv' > > usage check and corresponding sbwait() sleep. Otherwise wakeup() could > > be lost sometimes. > > > > This diff fixed regress tests. It introduces sbunlock_locked() and > > sbwait_locked() to perform with `sb_mtx' held. > > Do we really need a restart_unlocked label? > Instead of goto restart_unlocked you could call solock_shared(so) > and fall through goto restart; >
This was the first version, but later I decided 'restart_unlocked' is better. No problems to return it back. > I don't like pr_protocol == AF_UNIX check in generic soreceive() > function. Could we check SB_MTXLOCK instead? > Me too. I used "pr_protocol == AF_UNIX" check because sosend() does the same. The existing SB_MTXLOCK used by some inet sockets and I strictly want to move them separately of this fix. I propose to introduce SB_OWNLOCK flag and check it. I wanted to use this flag for socket with standalone sblock() ability to modify sblock()/sbwait() behaviour. I need this flag to convert all SB_MTXLOCK'ed sockets separately. After conversion, both SB_MTXLOCK and SB_OWNLOCK will be removed. I propose to introduce SB_OWNLOCK right now and use it instead of "pr_protocol == AF_UNIX" check to keep inet sockets as is. I have no objections to convert them too, but separately. Index: sys/kern/uipc_socket.c =================================================================== RCS file: /cvs/src/sys/kern/uipc_socket.c,v retrieving revision 1.322 diff -u -p -r1.322 uipc_socket.c --- sys/kern/uipc_socket.c 26 Mar 2024 09:46:47 -0000 1.322 +++ sys/kern/uipc_socket.c 27 Mar 2024 22:12:55 -0000 @@ -161,7 +161,7 @@ soalloc(const struct protosw *prp, int w } break; case AF_UNIX: - so->so_rcv.sb_flags |= SB_MTXLOCK; + so->so_rcv.sb_flags |= SB_MTXLOCK | SB_OWNLOCK; break; } @@ -903,12 +903,23 @@ restart: } SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 1"); SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 1"); - sb_mtx_unlock(&so->so_rcv); - sbunlock(so, &so->so_rcv); - error = sbwait(so, &so->so_rcv); - if (error) { + + if (so->so_rcv.sb_flags & SB_OWNLOCK) { + sbunlock_locked(so, &so->so_rcv); sounlock_shared(so); - return (error); + error = sbwait_locked(so, &so->so_rcv); + sb_mtx_unlock(&so->so_rcv); + if (error) + return (error); + solock_shared(so); + } else { + sb_mtx_unlock(&so->so_rcv); + sbunlock(so, &so->so_rcv); + error = sbwait(so, &so->so_rcv); + if (error) { + sounlock_shared(so); + return (error); + } } goto restart; } Index: sys/kern/uipc_socket2.c =================================================================== RCS file: /cvs/src/sys/kern/uipc_socket2.c,v retrieving revision 1.145 diff -u -p -r1.145 uipc_socket2.c --- sys/kern/uipc_socket2.c 26 Mar 2024 09:46:47 -0000 1.145 +++ sys/kern/uipc_socket2.c 27 Mar 2024 22:12:55 -0000 @@ -523,6 +523,18 @@ sbmtxassertlocked(struct socket *so, str * Wait for data to arrive at/drain from a socket buffer. */ int +sbwait_locked(struct socket *so, struct sockbuf *sb) +{ + int prio = (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH; + + MUTEX_ASSERT_LOCKED(&sb->sb_mtx); + + sb->sb_flags |= SB_WAIT; + return msleep_nsec(&sb->sb_cc, &sb->sb_mtx, prio, "sbwait", + sb->sb_timeo_nsecs); +} + +int sbwait(struct socket *so, struct sockbuf *sb) { uint64_t timeo_nsecs; @@ -573,20 +585,23 @@ out: } void -sbunlock(struct socket *so, struct sockbuf *sb) +sbunlock_locked(struct socket *so, struct sockbuf *sb) { - int dowakeup = 0; + MUTEX_ASSERT_LOCKED(&sb->sb_mtx); - mtx_enter(&sb->sb_mtx); sb->sb_flags &= ~SB_LOCK; if (sb->sb_flags & SB_WANT) { sb->sb_flags &= ~SB_WANT; - dowakeup = 1; + wakeup(&sb->sb_flags); } - mtx_leave(&sb->sb_mtx); +} - if (dowakeup) - wakeup(&sb->sb_flags); +void +sbunlock(struct socket *so, struct sockbuf *sb) +{ + mtx_enter(&sb->sb_mtx); + sbunlock_locked(so, sb); + mtx_leave(&sb->sb_mtx); } /* Index: sys/sys/socketvar.h =================================================================== RCS file: /cvs/src/sys/sys/socketvar.h,v retrieving revision 1.126 diff -u -p -r1.126 socketvar.h --- sys/sys/socketvar.h 26 Mar 2024 09:46:47 -0000 1.126 +++ sys/sys/socketvar.h 27 Mar 2024 22:12:55 -0000 @@ -128,13 +128,14 @@ struct socket { struct klist sb_klist; /* process selecting read/write */ } so_rcv, so_snd; #define SB_MAX (2*1024*1024) /* default for max chars in sockbuf */ -#define SB_LOCK 0x01 /* lock on data queue */ -#define SB_WANT 0x02 /* someone is waiting to lock */ -#define SB_WAIT 0x04 /* someone is waiting for data/space */ -#define SB_ASYNC 0x10 /* ASYNC I/O, need signals */ -#define SB_SPLICE 0x20 /* buffer is splice source or drain */ -#define SB_NOINTR 0x40 /* operations not interruptible */ -#define SB_MTXLOCK 0x80 /* use sb_mtx for sockbuf protection */ +#define SB_LOCK 0x001 /* lock on data queue */ +#define SB_WANT 0x002 /* someone is waiting to lock */ +#define SB_WAIT 0x004 /* someone is waiting for data/space */ +#define SB_ASYNC 0x010 /* ASYNC I/O, need signals */ +#define SB_SPLICE 0x020 /* buffer is splice source or drain */ +#define SB_NOINTR 0x040 /* operations not interruptible */ +#define SB_MTXLOCK 0x080 /* use sb_mtx for sockbuf protection */ +#define SB_OWNLOCK 0x100 /* sb_mtx used standalone */ void (*so_upcall)(struct socket *so, caddr_t arg, int waitf); caddr_t so_upcallarg; /* Arg for above */ @@ -320,6 +321,7 @@ int sblock(struct socket *, struct sockb /* release lock on sockbuf sb */ void sbunlock(struct socket *, struct sockbuf *); +void sbunlock_locked(struct socket *, struct sockbuf *); #define SB_EMPTY_FIXUP(sb) do { \ if ((sb)->sb_mb == NULL) { \ @@ -367,6 +369,7 @@ int sbcheckreserve(u_long, u_long); int sbchecklowmem(void); int sbreserve(struct socket *, struct sockbuf *, u_long); int sbwait(struct socket *, struct sockbuf *); +int sbwait_locked(struct socket *, struct sockbuf *); void soinit(void); void soabort(struct socket *); int soaccept(struct socket *, struct mbuf *);