socket: Split up sosend_generic()

Factor out the bits that run with the sock I/O lock held into a separate
function.  In this implementation, we are doing a bit more work under
the I/O lock than before.  However, lock contention is only a problem
when multiple threads are transmitting on the same socket, which is an
unusual case that is not expected to perform well in any case.

No functional change intended.

Reviewed by:	gallatin, glebius
MFC after:	2 weeks
Sponsored by:	Klara, Inc.
Sponsored by:	Stormshield
Differential Revision:	https://reviews.freebsd.org/D46305
This commit is contained in:
Mark Johnston 2024-08-19 14:20:43 +00:00
parent 0a68f644dc
commit fb901935f2

View file

@ -1656,8 +1656,8 @@ out:
* counts if EINTR/ERESTART are returned. Data and control buffers are freed
* on return.
*/
int
sosend_generic(struct socket *so, struct sockaddr *addr, struct uio *uio,
static int
sosend_generic_locked(struct socket *so, struct sockaddr *addr, struct uio *uio,
struct mbuf *top, struct mbuf *control, int flags, struct thread *td)
{
long space;
@ -1673,6 +1673,9 @@ sosend_generic(struct socket *so, struct sockaddr *addr, struct uio *uio,
tls = NULL;
tls_rtype = TLS_RLTYPE_APP;
#endif
SOCK_IO_SEND_ASSERT_LOCKED(so);
if (uio != NULL)
resid = uio->uio_resid;
else if ((top->m_flags & M_PKTHDR) != 0)
@ -1702,10 +1705,6 @@ sosend_generic(struct socket *so, struct sockaddr *addr, struct uio *uio,
if (control != NULL)
clen = control->m_len;
error = SOCK_IO_SEND_LOCK(so, SBLOCKWAIT(flags));
if (error)
goto out;
#ifdef KERN_TLS
tls_send_flag = 0;
tls = ktls_hold(so->so_snd.sb_tls_info);
@ -1728,7 +1727,7 @@ sosend_generic(struct socket *so, struct sockaddr *addr, struct uio *uio,
if (resid == 0 && !ktls_permit_empty_frames(tls)) {
error = EINVAL;
goto release;
goto out;
}
}
#endif
@ -1739,13 +1738,13 @@ restart:
if (so->so_snd.sb_state & SBS_CANTSENDMORE) {
SOCKBUF_UNLOCK(&so->so_snd);
error = EPIPE;
goto release;
goto out;
}
if (so->so_error) {
error = so->so_error;
so->so_error = 0;
SOCKBUF_UNLOCK(&so->so_snd);
goto release;
goto out;
}
if ((so->so_state & SS_ISCONNECTED) == 0) {
/*
@ -1759,7 +1758,7 @@ restart:
if (!(resid == 0 && clen != 0)) {
SOCKBUF_UNLOCK(&so->so_snd);
error = ENOTCONN;
goto release;
goto out;
}
} else if (addr == NULL) {
SOCKBUF_UNLOCK(&so->so_snd);
@ -1767,7 +1766,7 @@ restart:
error = ENOTCONN;
else
error = EDESTADDRREQ;
goto release;
goto out;
}
}
space = sbspace(&so->so_snd);
@ -1777,7 +1776,7 @@ restart:
clen > so->so_snd.sb_hiwat) {
SOCKBUF_UNLOCK(&so->so_snd);
error = EMSGSIZE;
goto release;
goto out;
}
if (space < resid + clen &&
(atomic || space < so->so_snd.sb_lowat || space < clen)) {
@ -1785,12 +1784,12 @@ restart:
(flags & (MSG_NBIO | MSG_DONTWAIT)) != 0) {
SOCKBUF_UNLOCK(&so->so_snd);
error = EWOULDBLOCK;
goto release;
goto out;
}
error = sbwait(so, SO_SND);
SOCKBUF_UNLOCK(&so->so_snd);
if (error)
goto release;
goto out;
goto restart;
}
SOCKBUF_UNLOCK(&so->so_snd);
@ -1835,7 +1834,7 @@ restart:
((flags & MSG_EOR) ? M_EOR : 0));
if (top == NULL) {
error = EFAULT; /* only possible error */
goto release;
goto out;
}
space -= resid - uio->uio_resid;
resid = uio->uio_resid;
@ -1899,12 +1898,10 @@ restart:
control = NULL;
top = NULL;
if (error)
goto release;
goto out;
} while (resid && space > 0);
} while (resid);
release:
SOCK_IO_SEND_UNLOCK(so);
out:
#ifdef KERN_TLS
if (tls != NULL)
@ -1917,6 +1914,20 @@ out:
return (error);
}
int
sosend_generic(struct socket *so, struct sockaddr *addr, struct uio *uio,
struct mbuf *top, struct mbuf *control, int flags, struct thread *td)
{
int error;
error = SOCK_IO_SEND_LOCK(so, 0);
if (error)
return (error);
error = sosend_generic_locked(so, addr, uio, top, control, flags, td);
SOCK_IO_SEND_UNLOCK(so);
return (error);
}
/*
* Send to a socket from a kernel thread.
*