Index: sys/kern/uipc_socket.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/kern/uipc_socket.c,v diff -u -p -u -p -r1.350 uipc_socket.c --- sys/kern/uipc_socket.c 27 Dec 2024 13:08:11 -0000 1.350 +++ sys/kern/uipc_socket.c 29 Dec 2024 12:46:58 -0000 @@ -62,8 +62,6 @@ int sosplice(struct socket *, int, off_t void sounsplice(struct socket *, struct socket *, int); void soidle(void *); void sotask(void *); -void soreaper(void *); -void soput(void *); int somove(struct socket *, int); void sorflush(struct socket *); @@ -270,6 +268,43 @@ solisten(struct socket *so, int backlog) return (0); } +void +sorele(struct socket *so, int keep_lock) +{ + int need_lock = (((so->so_snd.sb_flags & SB_MTXLOCK) == 0) && + keep_lock == 0); + + if (keep_lock == 0) + sounlock(so); + + if (refcnt_rele(&so->so_refcnt) == 0) { + return; + } + + sigio_free(&so->so_sigio); + klist_free(&so->so_rcv.sb_klist); + klist_free(&so->so_snd.sb_klist); + + if (need_lock) + solock(so); + mtx_enter(&so->so_snd.sb_mtx); + sbrelease(so, &so->so_snd); + mtx_leave(&so->so_snd.sb_mtx); + if (need_lock) + sounlock(so); + + 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); + +#ifdef SOCKET_SPLICE + if (so->so_sp) + pool_put(&sosplice_pool, so->so_sp); +#endif + pool_put(&socket_pool, so); +} + #define SOSP_FREEING_READ 1 #define SOSP_FREEING_WRITE 2 void @@ -299,79 +334,25 @@ sofree(struct socket *so, int keep_lock) } if (persocket) { - /* - * Concurrent close of `head' could - * abort `so' due to re-lock. - */ - soref(so); soref(head); sounlock(so); solock(head); solock(so); if (so->so_onq != &head->so_q0) { - sounlock(head); sounlock(so); - sorele(head); - sorele(so); + sorele(head, 0); return; } - - sorele(head); - sorele(so); } soqremque(so, 0); if (persocket) - sounlock(head); - } - - switch (so->so_proto->pr_domain->dom_family) { - case AF_INET: - case AF_INET6: - if (so->so_proto->pr_type == SOCK_STREAM) - break; - /* FALLTHROUGH */ - default: - sounlock(so); - refcnt_finalize(&so->so_refcnt, "sofinal"); - solock(so); - break; + sorele(head, 0); } - sigio_free(&so->so_sigio); - klist_free(&so->so_rcv.sb_klist); - klist_free(&so->so_snd.sb_klist); - - mtx_enter(&so->so_snd.sb_mtx); - sbrelease(so, &so->so_snd); - mtx_leave(&so->so_snd.sb_mtx); - - /* - * 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 (!keep_lock) - sounlock(so); - -#ifdef SOCKET_SPLICE - if (so->so_sp) { - /* Reuse splice idle, sounsplice() has been called before. */ - timeout_set_flags(&so->so_sp->ssp_idleto, soreaper, so, - KCLOCK_NONE, TIMEOUT_PROC | TIMEOUT_MPSAFE); - timeout_add(&so->so_sp->ssp_idleto, 0); - } else -#endif /* SOCKET_SPLICE */ - { - pool_put(&socket_pool, so); - } + sorele(so, keep_lock); } static inline uint64_t @@ -450,39 +431,10 @@ drop: } } discard: - if (so->so_state & SS_NOFDREF) - panic("soclose NOFDREF: so %p, so_type %d", so, so->so_type); - so->so_state |= SS_NOFDREF; - #ifdef SOCKET_SPLICE if (so->so_sp) { struct socket *soback; - if (so->so_proto->pr_flags & PR_WANTRCVD) { - /* - * Copy - Paste, but can't relock and sleep in - * sofree() in tcp(4) case. That's why tcp(4) - * still rely on solock() for splicing and - * unsplicing. - */ - - if (issplicedback(so)) { - int freeing = SOSP_FREEING_WRITE; - - if (so->so_sp->ssp_soback == so) - freeing |= SOSP_FREEING_READ; - sounsplice(so->so_sp->ssp_soback, so, freeing); - } - if (isspliced(so)) { - int freeing = SOSP_FREEING_READ; - - if (so == so->so_sp->ssp_socket) - freeing |= SOSP_FREEING_WRITE; - sounsplice(so, so->so_sp->ssp_socket, freeing); - } - goto free; - } - sounlock(so); mtx_enter(&so->so_snd.sb_mtx); /* @@ -513,7 +465,8 @@ discard: sounlock(soback); } sbunlock(&soback->so_rcv); - sorele(soback); + solock(soback); + sorele(soback, 0); notsplicedback: sblock(&so->so_rcv, SBL_WAIT | SBL_NOINTR); @@ -528,10 +481,18 @@ notsplicedback: } sbunlock(&so->so_rcv); + timeout_del_barrier(&so->so_sp->ssp_idleto); + task_del(sosplice_taskq, &so->so_sp->ssp_task); + taskq_barrier(sosplice_taskq); + solock(so); } -free: #endif /* SOCKET_SPLICE */ + + if (so->so_state & SS_NOFDREF) + panic("soclose NOFDREF: so %p, so_type %d", so, so->so_type); + so->so_state |= SS_NOFDREF; + /* sofree() calls sounlock(). */ sofree(so, 0); return (error); @@ -1532,8 +1493,7 @@ sosplice(struct socket *so, int fd, off_ void sounsplice(struct socket *so, struct socket *sosp, int freeing) { - if ((so->so_proto->pr_flags & PR_WANTRCVD) == 0) - sbassertlocked(&so->so_rcv); + sbassertlocked(&so->so_rcv); soassertlocked(so); task_del(sosplice_taskq, &so->so_splicetask); @@ -1587,17 +1547,23 @@ sotask(void *arg) */ sblock(&so->so_rcv, SBL_WAIT | SBL_NOINTR); - if (sockstream) - solock(so); - if (so->so_rcv.sb_flags & SB_SPLICE) { - if (sockstream) + struct socket *sosp = so->so_sp->ssp_socket; + + if (sockstream) { + sblock(&sosp->so_snd, SBL_WAIT | SBL_NOINTR); + solock(so); doyield = 1; + } + somove(so, M_DONTWAIT); + + if (sockstream) { + sounlock(so); + sbunlock(&sosp->so_snd); + } } - if (sockstream) - sounlock(so); sbunlock(&so->so_rcv); if (doyield) { @@ -1607,32 +1573,6 @@ sotask(void *arg) } /* - * The socket splicing task or idle timeout may sleep while grabbing the net - * lock. As sofree() can be called anytime, sotask() or soidle() could access - * the socket memory of a freed socket after wakeup. So delay the pool_put() - * after all pending socket splicing tasks or timeouts have finished. Do this - * by scheduling it on the same threads. - */ -void -soreaper(void *arg) -{ - struct socket *so = arg; - - /* Reuse splice task, sounsplice() has been called before. */ - task_set(&so->so_sp->ssp_task, soput, so); - task_add(sosplice_taskq, &so->so_sp->ssp_task); -} - -void -soput(void *arg) -{ - struct socket *so = arg; - - pool_put(&sosplice_pool, so->so_sp); - pool_put(&socket_pool, so); -} - -/* * Move data from receive buffer of spliced source socket to send * buffer of drain socket. Try to move as much as possible in one * big chunk. It is a TCP only implementation. @@ -1652,8 +1592,10 @@ somove(struct socket *so, int wait) if (sockdgram) sbassertlocked(&so->so_rcv); - else + else { + sbassertlocked(&sosp->so_snd); soassertlocked(so); + } mtx_enter(&so->so_rcv.sb_mtx); mtx_enter(&sosp->so_snd.sb_mtx); Index: sys/kern/uipc_socket2.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/kern/uipc_socket2.c,v diff -u -p -u -p -r1.161 uipc_socket2.c --- sys/kern/uipc_socket2.c 26 Dec 2024 12:16:17 -0000 1.161 +++ sys/kern/uipc_socket2.c 29 Dec 2024 12:46:58 -0000 @@ -103,7 +103,6 @@ soisconnected(struct socket *so) int persocket = solock_persocket(so); if (persocket) { - soref(so); soref(head); sounlock(so); @@ -111,15 +110,10 @@ soisconnected(struct socket *so) solock(so); if (so->so_onq != &head->so_q0) { - sounlock(head); - sorele(head); - sorele(so); - + sorele(head, 0); return; } - sorele(head); - sorele(so); } soqremque(so, 0); @@ -128,7 +122,7 @@ soisconnected(struct socket *so) wakeup_one(&head->so_timeo); if (persocket) - sounlock(head); + sorele(head, 0); } else { wakeup(&so->so_timeo); sorwakeup(so); Index: sys/sys/socketvar.h =================================================================== RCS file: /mount/openbsd/cvs/src/sys/sys/socketvar.h,v diff -u -p -u -p -r1.134 socketvar.h --- sys/sys/socketvar.h 9 Sep 2024 07:38:45 -0000 1.134 +++ sys/sys/socketvar.h 29 Dec 2024 12:46:58 -0000 @@ -215,12 +215,6 @@ soref(struct socket *so) refcnt_take(&so->so_refcnt); } -static inline void -sorele(struct socket *so) -{ - refcnt_rele_wake(&so->so_refcnt); -} - /* * Macros for sockets and socket buffering. */ @@ -428,6 +422,7 @@ int socreate(int, struct socket **, int, int sodisconnect(struct socket *); struct socket *soalloc(const struct protosw *, int); void sofree(struct socket *, int); +void sorele(struct socket *, int); int sogetopt(struct socket *, int, int, struct mbuf *); void sohasoutofband(struct socket *); void soisconnected(struct socket *);