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:
+29
-18
@@ -1656,8 +1656,8 @@ sosend_dgram(struct socket *so, struct sockaddr *addr, struct uio *uio,
|
||||
* 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 @@ sosend_generic(struct socket *so, struct sockaddr *addr, struct uio *uio,
|
||||
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 @@ sosend_generic(struct socket *so, struct sockaddr *addr, struct uio *uio,
|
||||
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 @@ sosend_generic(struct socket *so, struct sockaddr *addr, struct uio *uio,
|
||||
error = ENOTCONN;
|
||||
else
|
||||
error = EDESTADDRREQ;
|
||||
goto release;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
space = sbspace(&so->so_snd);
|
||||
@@ -1777,7 +1776,7 @@ sosend_generic(struct socket *so, struct sockaddr *addr, struct uio *uio,
|
||||
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 @@ sosend_generic(struct socket *so, struct sockaddr *addr, struct uio *uio,
|
||||
(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 @@ sosend_generic(struct socket *so, struct sockaddr *addr, struct uio *uio,
|
||||
((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 @@ sosend_generic(struct socket *so, struct sockaddr *addr, struct uio *uio,
|
||||
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 @@ sosend_generic(struct socket *so, struct sockaddr *addr, struct uio *uio,
|
||||
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.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user