Don't require the socket lock for sorele().

Previously, sorele() always required the socket lock and dropped the
lock if the released reference was not the last reference.  Many
callers locked the socket lock just before calling sorele() resulting
in a wasted lock/unlock when not dropping the last reference.

Move the previous implementation of sorele() into a new
sorele_locked() function and use it instead of sorele() for various
places in uipc_socket.c that called sorele() while already holding the
socket lock.

The sorele() macro now uses refcount_release_if_not_last() try to drop
the socket reference without locking the socket.  If that shortcut
fails, it locks the socket and calls sorele_locked().

Reviewed by:	kib, markj
Sponsored by:	Chelsio Communications
Differential Revision:	https://reviews.freebsd.org/D32741
This commit is contained in:
John Baldwin 2021-11-09 10:50:12 -08:00
parent e818178e3a
commit e3ba94d4f3
9 changed files with 25 additions and 22 deletions

View file

@ -2372,7 +2372,6 @@ t4_aiotx_task(void *context, int pending)
NET_EPOCH_EXIT(et);
free_toepcb(toep);
SOCK_LOCK(so);
sorele(so);
CURVNET_RESTORE();
}

View file

@ -399,7 +399,6 @@ sendfile_iodone(void *arg, vm_page_t *pa, int count, int error)
(void)(so->so_proto->pr_usrreqs->pru_ready)(so, sfio->m,
sfio->npages);
SOCK_LOCK(so);
sorele(so);
#ifdef KERN_TLS
out_with_ref:

View file

@ -727,7 +727,6 @@ soaio_process_sb(struct socket *so, struct sockbuf *sb)
sb->sb_flags &= ~SB_AIO_RUNNING;
SOCKBUF_UNLOCK(sb);
SOCK_LOCK(so);
sorele(so);
CURVNET_RESTORE();
}

View file

@ -2077,7 +2077,6 @@ ktls_decrypt(struct socket *so)
SOCKBUF_UNLOCK_ASSERT(sb);
CURVNET_SET(so->so_vnet);
SOCK_LOCK(so);
sorele(so);
CURVNET_RESTORE();
}
@ -2427,7 +2426,6 @@ ktls_encrypt(struct ktls_wq *wq, struct mbuf *top)
mb_free_notready(top, total_pages);
}
SOCK_LOCK(so);
sorele(so);
CURVNET_RESTORE();
}
@ -2472,7 +2470,6 @@ ktls_encrypt_cb(struct ktls_ocf_encrypt_state *state, int error)
mb_free_notready(m, npages);
}
SOCK_LOCK(so);
sorele(so);
CURVNET_RESTORE();
}
@ -2523,7 +2520,6 @@ ktls_encrypt_async(struct ktls_wq *wq, struct mbuf *top)
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 @@ ktls_encrypt_async(struct ktls_wq *wq, struct mbuf *top)
mb_free_notready(m, total_pages - npages);
}
SOCK_LOCK(so);
sorele(so);
CURVNET_RESTORE();
}
@ -2732,7 +2727,6 @@ ktls_disable_ifnet_help(void *context, int pending __unused)
}
out:
SOCK_LOCK(so);
sorele(so);
if (!in_pcbrele_wlocked(inp))
INP_WUNLOCK(inp);

View file

@ -785,7 +785,7 @@ sonewconn(struct socket *head, int connstatus)
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 @@ solisten_dequeue(struct socket *head, struct socket **ret, int flags)
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 @@ sofree(struct socket *so)
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 @@ sofree(struct socket *so)
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 @@ soclose(struct socket *so)
}
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 @@ soisconnected(struct socket *so)
* The socket is about to soabort().
*/
SOCK_UNLOCK(so);
sorele(head);
sorele_locked(head);
return;
}
last = refcount_release(&head->so_count);

View file

@ -3911,7 +3911,6 @@ sysctl_switch_tls(SYSCTL_HANDLER_ARGS)
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

View file

@ -912,7 +912,6 @@ clnt_vc_destroy(CLIENT *cl)
}
/* Must sorele() to get rid of reference. */
CURVNET_SET(so->so_vnet);
SOCK_LOCK(so);
sorele(so);
CURVNET_RESTORE();
} else {

View file

@ -468,7 +468,6 @@ svc_vc_destroy_common(SVCXPRT *xprt)
}
/* 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

View file

@ -337,11 +337,11 @@ struct socket {
*/
#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_dgram(struct socket *so, struct sockaddr **paddr,
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,