diff --git a/sys/dev/cxgbe/tom/t4_cpl_io.c b/sys/dev/cxgbe/tom/t4_cpl_io.c --- a/sys/dev/cxgbe/tom/t4_cpl_io.c +++ b/sys/dev/cxgbe/tom/t4_cpl_io.c @@ -2372,7 +2372,6 @@ NET_EPOCH_EXIT(et); free_toepcb(toep); - SOCK_LOCK(so); sorele(so); CURVNET_RESTORE(); } diff --git a/sys/kern/kern_sendfile.c b/sys/kern/kern_sendfile.c --- a/sys/kern/kern_sendfile.c +++ b/sys/kern/kern_sendfile.c @@ -399,7 +399,6 @@ (void)(so->so_proto->pr_usrreqs->pru_ready)(so, sfio->m, sfio->npages); - SOCK_LOCK(so); sorele(so); #ifdef KERN_TLS out_with_ref: diff --git a/sys/kern/sys_socket.c b/sys/kern/sys_socket.c --- a/sys/kern/sys_socket.c +++ b/sys/kern/sys_socket.c @@ -727,7 +727,6 @@ sb->sb_flags &= ~SB_AIO_RUNNING; SOCKBUF_UNLOCK(sb); - SOCK_LOCK(so); sorele(so); CURVNET_RESTORE(); } diff --git a/sys/kern/uipc_ktls.c b/sys/kern/uipc_ktls.c --- a/sys/kern/uipc_ktls.c +++ b/sys/kern/uipc_ktls.c @@ -2077,7 +2077,6 @@ SOCKBUF_UNLOCK_ASSERT(sb); CURVNET_SET(so->so_vnet); - SOCK_LOCK(so); sorele(so); CURVNET_RESTORE(); } @@ -2427,7 +2426,6 @@ mb_free_notready(top, total_pages); } - SOCK_LOCK(so); sorele(so); CURVNET_RESTORE(); } @@ -2472,7 +2470,6 @@ mb_free_notready(m, npages); } - SOCK_LOCK(so); sorele(so); CURVNET_RESTORE(); } @@ -2523,7 +2520,6 @@ counter_u64_add(ktls_offload_failed_crypto, 1); free(state, M_KTLS); CURVNET_SET(so->so_vnet); - SOCK_LOCK(so); sorele(so); CURVNET_RESTORE(); break; @@ -2539,7 +2535,6 @@ mb_free_notready(m, total_pages - npages); } - SOCK_LOCK(so); sorele(so); CURVNET_RESTORE(); } @@ -2732,7 +2727,6 @@ } out: - SOCK_LOCK(so); sorele(so); if (!in_pcbrele_wlocked(inp)) INP_WUNLOCK(inp); diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -785,7 +785,7 @@ sp->so_qstate = SQ_NONE; sp->so_listen = NULL; SOCK_UNLOCK(sp); - sorele(head); /* does SOLISTEN_UNLOCK, head stays */ + sorele_locked(head); /* does SOLISTEN_UNLOCK, head stays */ soabort(sp); SOLISTEN_LOCK(head); } @@ -1090,7 +1090,7 @@ else so->so_state |= (flags & SOCK_NONBLOCK) ? SS_NBIO : 0; SOCK_UNLOCK(so); - sorele(head); + sorele_locked(head); *ret = so; return (0); @@ -1170,7 +1170,7 @@ KASSERT(so->so_listen == NULL, ("%s: so %p not on (in)comp with so_listen", __func__, so)); - sorele(sol); + sorele_locked(sol); KASSERT(refcount_load(&so->so_count) == 1, ("%s: so %p count %u", __func__, so, so->so_count)); so->so_count = 0; @@ -1213,6 +1213,20 @@ sodealloc(so); } +/* + * Release a reference on a socket while holding the socket lock. + * Unlocks the socket lock before returning. + */ +void +sorele_locked(struct socket *so) +{ + SOCK_LOCK_ASSERT(so); + if (refcount_release(&so->so_count)) + sofree(so); + else + SOCK_UNLOCK(so); +} + /* * Close a socket on last file table reference removal. Initiate disconnect * if connected. Free socket when disconnect complete. @@ -1282,7 +1296,7 @@ } KASSERT((so->so_state & SS_NOFDREF) == 0, ("soclose: NOFDREF")); so->so_state |= SS_NOFDREF; - sorele(so); + sorele_locked(so); if (listening) { struct socket *sp, *tsp; @@ -4060,7 +4074,7 @@ * The socket is about to soabort(). */ SOCK_UNLOCK(so); - sorele(head); + sorele_locked(head); return; } last = refcount_release(&head->so_count); diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -3911,7 +3911,6 @@ error = ktls_set_tx_mode(so, arg2 == 0 ? TCP_TLS_MODE_SW : TCP_TLS_MODE_IFNET); INP_WUNLOCK(inp); - SOCK_LOCK(so); sorele(so); } } else diff --git a/sys/rpc/clnt_vc.c b/sys/rpc/clnt_vc.c --- a/sys/rpc/clnt_vc.c +++ b/sys/rpc/clnt_vc.c @@ -912,7 +912,6 @@ } /* Must sorele() to get rid of reference. */ CURVNET_SET(so->so_vnet); - SOCK_LOCK(so); sorele(so); CURVNET_RESTORE(); } else { diff --git a/sys/rpc/svc_vc.c b/sys/rpc/svc_vc.c --- a/sys/rpc/svc_vc.c +++ b/sys/rpc/svc_vc.c @@ -468,7 +468,6 @@ } /* Must sorele() to get rid of reference. */ CURVNET_SET(xprt->xp_socket->so_vnet); - SOCK_LOCK(xprt->xp_socket); sorele(xprt->xp_socket); CURVNET_RESTORE(); } else diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h --- a/sys/sys/socketvar.h +++ b/sys/sys/socketvar.h @@ -337,11 +337,11 @@ */ #define soref(so) refcount_acquire(&(so)->so_count) #define sorele(so) do { \ - SOCK_LOCK_ASSERT(so); \ - if (refcount_release(&(so)->so_count)) \ - sofree(so); \ - else \ - SOCK_UNLOCK(so); \ + SOCK_UNLOCK_ASSERT(so); \ + if (!refcount_release_if_not_last(&(so)->so_count)) { \ + SOCK_LOCK(so); \ + sorele_locked(so); \ + } \ } while (0) /* @@ -503,6 +503,7 @@ int soreceive_generic(struct socket *so, struct sockaddr **paddr, struct uio *uio, struct mbuf **mp0, struct mbuf **controlp, int *flagsp); +void sorele_locked(struct socket *so); int soreserve(struct socket *so, u_long sndcc, u_long rcvcc); void sorflush(struct socket *so); int sosend(struct socket *so, struct sockaddr *addr, struct uio *uio,