unix(4) sockets.
Push solock() deep down to sosend() and remove it from soreceive() paths
for unix(4) sockets.
The transmission of unix(4) sockets already half-unlocked because
connected peer is not locked by solock() during sbappend*() call. Use
`sb_mtx' mutex(9) and `sb_lock' rwlock(9) to protect both `so_snd' and
`so_rcv'.
Since the `so_snd' is protected by `sb_mtx' mutex(9) the re-locking
is not required in uipc_rcvd().
Do direct `so_rcv' dispose and cleanup in sofree(). This sockets is
almost dead and unlinked from everywhere include spliced peer, so
concurrent sotask() thread will just exit. This required to keep locks
order between `i_lock' and `sb_lock'. Also this removes re-locking from
sofree() for all sockets.
SB_OWNLOCK became redundant with SB_MTXLOCK, so remove it. SB_MTXLOCK
was kept because checks against SB_MTXLOCK within sb*() routines are mor
consistent.
Feedback and ok bluhm
-/* $OpenBSD: uipc_socket.c,v 1.332 2024/05/02 11:55:31 mvs Exp $ */
+/* $OpenBSD: uipc_socket.c,v 1.333 2024/05/03 17:43:09 mvs Exp $ */
/* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */
/*
case AF_INET6:
switch (prp->pr_type) {
case SOCK_RAW:
- so->so_snd.sb_flags |= SB_MTXLOCK | SB_OWNLOCK;
+ so->so_snd.sb_flags |= SB_MTXLOCK;
/* FALLTHROUGH */
case SOCK_DGRAM:
- so->so_rcv.sb_flags |= SB_MTXLOCK | SB_OWNLOCK;
+ so->so_rcv.sb_flags |= SB_MTXLOCK;
break;
}
break;
case AF_UNIX:
+ so->so_snd.sb_flags |= SB_MTXLOCK;
so->so_rcv.sb_flags |= SB_MTXLOCK;
break;
}
mtx_leave(&so->so_snd.sb_mtx);
/*
- * Regardless on '_locked' postfix, must release solock() before
- * call sorflush_locked() for SB_OWNLOCK marked socket. Can't
- * release solock() and call sorflush() because solock() release
- * is unwanted for tcp(4) socket.
+ * Unlocked dispose and cleanup is safe. Socket is unlinked
+ * from everywhere. Even concurrent sotask() thread will not
+ * call somove().
*/
+ if (so->so_proto->pr_flags & PR_RIGHTS &&
+ so->so_proto->pr_domain->dom_dispose)
+ (*so->so_proto->pr_domain->dom_dispose)(so->so_rcv.sb_mb);
+ m_purge(so->so_rcv.sb_mb);
- if (so->so_rcv.sb_flags & SB_OWNLOCK)
- sounlock(so);
-
- sorflush_locked(so);
-
- if (!((so->so_rcv.sb_flags & SB_OWNLOCK) || keep_lock))
+ if (!keep_lock)
sounlock(so);
#ifdef SOCKET_SPLICE
size_t resid;
int error;
int atomic = sosendallatonce(so) || top;
- int dosolock = ((so->so_snd.sb_flags & SB_OWNLOCK) == 0);
+ int dosolock = ((so->so_snd.sb_flags & SB_MTXLOCK) == 0);
if (uio)
resid = uio->uio_resid;
const struct protosw *pr = so->so_proto;
struct mbuf *nextrecord;
size_t resid, orig_resid = uio->uio_resid;
- int dosolock = ((so->so_rcv.sb_flags & SB_OWNLOCK) == 0);
+ int dosolock = ((so->so_rcv.sb_flags & SB_MTXLOCK) == 0);
mp = mp0;
if (paddr)
SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 1");
SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 1");
- if (so->so_rcv.sb_flags & (SB_MTXLOCK | SB_OWNLOCK)) {
+ if (so->so_rcv.sb_flags & SB_MTXLOCK) {
sbunlock_locked(so, &so->so_rcv);
if (dosolock)
sounlock_shared(so);
SBLASTMBUFCHK(&so->so_rcv, "soreceive 4");
if (pr->pr_flags & PR_WANTRCVD) {
sb_mtx_unlock(&so->so_rcv);
+ if (!dosolock)
+ solock_shared(so);
pru_rcvd(so);
+ if (!dosolock)
+ sounlock_shared(so);
sb_mtx_lock(&so->so_rcv);
}
}
const struct protosw *pr = so->so_proto;
int error;
- if ((sb->sb_flags & SB_OWNLOCK) == 0)
+ if ((sb->sb_flags & SB_MTXLOCK) == 0)
soassertlocked(so);
error = sblock(so, sb, SBL_WAIT | SBL_NOINTR);
/* with SBL_WAIT and SLB_NOINTR sblock() must not fail */
KASSERT(error == 0);
- if (sb->sb_flags & SB_OWNLOCK)
+ if (sb->sb_flags & SB_MTXLOCK)
solock(so);
socantrcvmore(so);
- if (sb->sb_flags & SB_OWNLOCK)
+ if (sb->sb_flags & SB_MTXLOCK)
sounlock(so);
mtx_enter(&sb->sb_mtx);
void
sorflush(struct socket *so)
{
- if ((so->so_rcv.sb_flags & SB_OWNLOCK) == 0)
+ if ((so->so_rcv.sb_flags & SB_MTXLOCK) == 0)
solock_shared(so);
sorflush_locked(so);
- if ((so->so_rcv.sb_flags & SB_OWNLOCK) == 0)
+ if ((so->so_rcv.sb_flags & SB_MTXLOCK) == 0)
sounlock_shared(so);
}
membar_consumer();
}
- if (so->so_rcv.sb_flags & SB_OWNLOCK) {
+ if (so->so_rcv.sb_flags & SB_MTXLOCK) {
if ((error = sblock(so, &so->so_rcv, SBL_WAIT)) != 0)
return (error);
solock(so);
release:
sbunlock(sosp, &sosp->so_snd);
out:
- if (so->so_rcv.sb_flags & SB_OWNLOCK) {
+ if (so->so_rcv.sb_flags & SB_MTXLOCK) {
sounlock(so);
sbunlock(so, &so->so_rcv);
} else {
void
sowwakeup(struct socket *so)
{
- soassertlocked_readonly(so);
+ if ((so->so_snd.sb_flags & SB_MTXLOCK) == 0)
+ soassertlocked_readonly(so);
#ifdef SOCKET_SPLICE
if (so->so_snd.sb_flags & SB_SPLICE)
if ((long)cnt <= 0)
cnt = 1;
- if (((sb->sb_flags & SB_OWNLOCK) == 0))
+ if (((sb->sb_flags & SB_MTXLOCK) == 0))
solock(so);
mtx_enter(&sb->sb_mtx);
}
mtx_leave(&sb->sb_mtx);
- if (((sb->sb_flags & SB_OWNLOCK) == 0))
+ if (((sb->sb_flags & SB_MTXLOCK) == 0))
sounlock(so);
break;
int rv;
MUTEX_ASSERT_LOCKED(&so->so_snd.sb_mtx);
- soassertlocked_readonly(so);
+ if ((so->so_snd.sb_flags & SB_MTXLOCK) == 0)
+ soassertlocked_readonly(so);
kn->kn_data = sbspace(so, &so->so_snd);
if (so->so_snd.sb_state & SS_CANTSENDMORE) {
-/* $OpenBSD: uipc_socket2.c,v 1.152 2024/05/02 21:26:52 mvs Exp $ */
+/* $OpenBSD: uipc_socket2.c,v 1.153 2024/05/03 17:43:09 mvs Exp $ */
/* $NetBSD: uipc_socket2.c,v 1.11 1996/02/04 02:17:55 christos Exp $ */
/*
*/
if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat))
goto fail;
+
+ mtx_enter(&head->so_snd.sb_mtx);
so->so_snd.sb_wat = head->so_snd.sb_wat;
so->so_snd.sb_lowat = head->so_snd.sb_lowat;
- mtx_enter(&head->so_snd.sb_mtx);
so->so_snd.sb_timeo_nsecs = head->so_snd.sb_timeo_nsecs;
mtx_leave(&head->so_snd.sb_mtx);
{
int error = 0, prio = PSOCK;
- if (sb->sb_flags & SB_OWNLOCK) {
+ if (sb->sb_flags & SB_MTXLOCK) {
int rwflags = RW_WRITE;
if (!(flags & SBL_NOINTR || sb->sb_flags & SB_NOINTR))
void
sbunlock_locked(struct socket *so, struct sockbuf *sb)
{
- if (sb->sb_flags & SB_OWNLOCK) {
+ if (sb->sb_flags & SB_MTXLOCK) {
rw_exit(&sb->sb_lock);
return;
}
void
sbunlock(struct socket *so, struct sockbuf *sb)
{
- if (sb->sb_flags & SB_OWNLOCK) {
+ if (sb->sb_flags & SB_MTXLOCK) {
rw_exit(&sb->sb_lock);
return;
}
-/* $OpenBSD: uipc_usrreq.c,v 1.205 2024/05/02 17:10:55 mvs Exp $ */
+/* $OpenBSD: uipc_usrreq.c,v 1.206 2024/05/03 17:43:09 mvs Exp $ */
/* $NetBSD: uipc_usrreq.c,v 1.18 1996/02/09 19:00:50 christos Exp $ */
/*
void
uipc_rcvd(struct socket *so)
{
+ struct unpcb *unp = sotounpcb(so);
struct socket *so2;
- if ((so2 = unp_solock_peer(so)) == NULL)
+ if (unp->unp_conn == NULL)
return;
+ so2 = unp->unp_conn->unp_socket;
+
/*
* Adjust backpressure on sender
* and wakeup any waiting to write.
*/
mtx_enter(&so->so_rcv.sb_mtx);
+ mtx_enter(&so2->so_snd.sb_mtx);
so2->so_snd.sb_mbcnt = so->so_rcv.sb_mbcnt;
so2->so_snd.sb_cc = so->so_rcv.sb_cc;
+ mtx_leave(&so2->so_snd.sb_mtx);
mtx_leave(&so->so_rcv.sb_mtx);
sowwakeup(so2);
- sounlock(so2);
}
int
goto out;
}
- if (so->so_snd.sb_state & SS_CANTSENDMORE) {
- error = EPIPE;
- goto dispose;
- }
if (unp->unp_conn == NULL) {
error = ENOTCONN;
goto dispose;
* send buffer counts to maintain backpressure.
* Wake up readers.
*/
+ /*
+ * sbappend*() should be serialized together
+ * with so_snd modification.
+ */
mtx_enter(&so2->so_rcv.sb_mtx);
+ mtx_enter(&so->so_snd.sb_mtx);
+ if (so->so_snd.sb_state & SS_CANTSENDMORE) {
+ mtx_leave(&so->so_snd.sb_mtx);
+ mtx_leave(&so2->so_rcv.sb_mtx);
+ error = EPIPE;
+ goto dispose;
+ }
if (control) {
if (sbappendcontrol(so2, &so2->so_rcv, m, control)) {
control = NULL;
} else {
+ mtx_leave(&so->so_snd.sb_mtx);
mtx_leave(&so2->so_rcv.sb_mtx);
error = ENOBUFS;
goto dispose;
so->so_snd.sb_cc = so2->so_rcv.sb_cc;
if (so2->so_rcv.sb_cc > 0)
dowakeup = 1;
+ mtx_leave(&so->so_snd.sb_mtx);
mtx_leave(&so2->so_rcv.sb_mtx);
if (dowakeup)
-/* $OpenBSD: fifo_vnops.c,v 1.104 2024/03/26 09:46:47 mvs Exp $ */
+/* $OpenBSD: fifo_vnops.c,v 1.105 2024/05/03 17:43:09 mvs Exp $ */
/* $NetBSD: fifo_vnops.c,v 1.18 1996/03/16 23:52:42 christos Exp $ */
/*
return (error);
}
fip->fi_readers = fip->fi_writers = 0;
- solock(wso);
+ mtx_enter(&wso->so_snd.sb_mtx);
wso->so_snd.sb_state |= SS_CANTSENDMORE;
wso->so_snd.sb_lowat = PIPE_BUF;
- sounlock(wso);
+ mtx_leave(&wso->so_snd.sb_mtx);
} else {
rso = fip->fi_readsock;
wso = fip->fi_writesock;
if (ap->a_mode & FREAD) {
fip->fi_readers++;
if (fip->fi_readers == 1) {
- solock(wso);
+ mtx_enter(&wso->so_snd.sb_mtx);
wso->so_snd.sb_state &= ~SS_CANTSENDMORE;
- sounlock(wso);
+ mtx_leave(&wso->so_snd.sb_mtx);
if (fip->fi_writers > 0)
wakeup(&fip->fi_writers);
}
struct socket *so = kn->kn_hook;
int rv;
- soassertlocked(so);
MUTEX_ASSERT_LOCKED(&so->so_snd.sb_mtx);
kn->kn_data = sbspace(so, &so->so_snd);
struct socket *so = kn->kn_hook;
int rv;
- solock(so);
mtx_enter(&so->so_snd.sb_mtx);
rv = knote_modify(kev, kn);
mtx_leave(&so->so_snd.sb_mtx);
- sounlock(so);
return (rv);
}
struct socket *so = kn->kn_hook;
int rv;
- solock(so);
mtx_enter(&so->so_snd.sb_mtx);
rv = knote_process(kn, kev);
mtx_leave(&so->so_snd.sb_mtx);
- sounlock(so);
return (rv);
}
-/* $OpenBSD: socketvar.h,v 1.129 2024/04/11 13:32:51 mvs Exp $ */
+/* $OpenBSD: socketvar.h,v 1.130 2024/05/03 17:43:09 mvs Exp $ */
/* $NetBSD: socketvar.h,v 1.18 1996/02/09 18:25:38 christos Exp $ */
/*-
#define SB_ASYNC 0x0010 /* ASYNC I/O, need signals */
#define SB_SPLICE 0x0020 /* buffer is splice source or drain */
#define SB_NOINTR 0x0040 /* operations not interruptible */
-#define SB_MTXLOCK 0x0080 /* use sb_mtx for sockbuf protection */
-#define SB_OWNLOCK 0x0100 /* sblock() doesn't need solock() */
+#define SB_MTXLOCK 0x0080 /* sblock() doesn't need solock() */
void (*so_upcall)(struct socket *so, caddr_t arg, int waitf);
caddr_t so_upcallarg; /* Arg for above */