This diff refactors the uio to mbuf code to make use of bigger buffers (up to 64k) and also switches the MCLGET to use M_WAIT like the MGET calls in the same function. I see no point in not waiting for a cluster and instead chain lots of mbufs together as a consequence.
This makes in my opinion the code easier to read and allows for further optimizations (like using non-DMA reachable mbufs for AF_UNIX sockets). This increased the preformance of loopback connections significantly when I tested this at n2k16. -- :wq Claudio Index: kern//uipc_socket.c =================================================================== RCS file: /cvs/src/sys/kern/uipc_socket.c,v retrieving revision 1.152 diff -u -p -r1.152 uipc_socket.c --- kern//uipc_socket.c 13 Jun 2016 21:24:43 -0000 1.152 +++ kern//uipc_socket.c 12 Aug 2016 14:07:36 -0000 @@ -373,6 +373,8 @@ bad: return (error); } +int m_getuio(struct mbuf **, int, long, struct uio *); + #define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK) /* * Send on a socket. @@ -395,10 +397,7 @@ int sosend(struct socket *so, struct mbuf *addr, struct uio *uio, struct mbuf *top, struct mbuf *control, int flags) { - struct mbuf **mp; - struct mbuf *m; long space, clen = 0; - u_long len, mlen; size_t resid; int error, s; int atomic = sosendallatonce(so) || top; @@ -475,7 +474,6 @@ restart: goto restart; } splx(s); - mp = ⊤ space -= clen; do { if (uio == NULL) { @@ -485,52 +483,14 @@ restart: resid = 0; if (flags & MSG_EOR) top->m_flags |= M_EOR; - } else do { - if (top == 0) { - MGETHDR(m, M_WAIT, MT_DATA); - mlen = MHLEN; - m->m_pkthdr.len = 0; - m->m_pkthdr.ph_ifidx = 0; - } else { - MGET(m, M_WAIT, MT_DATA); - mlen = MLEN; - } - if (resid >= MINCLSIZE && space >= MCLBYTES) { - MCLGET(m, M_NOWAIT); - if ((m->m_flags & M_EXT) == 0) - goto nopages; - if (atomic && top == 0) { - len = ulmin(MCLBYTES - max_hdr, - resid); - m->m_data += max_hdr; - } else - len = ulmin(MCLBYTES, resid); - space -= len; - } else { -nopages: - len = ulmin(ulmin(mlen, resid), space); - space -= len; - /* - * For datagram protocols, leave room - * for protocol headers in first mbuf. - */ - if (atomic && top == 0 && len < mlen) - MH_ALIGN(m, len); - } - error = uiomove(mtod(m, caddr_t), len, uio); + } else { + error = m_getuio(&top, atomic, + space, uio); + space -= top->m_pkthdr.len; resid = uio->uio_resid; - m->m_len = len; - *mp = m; - top->m_pkthdr.len += len; - if (error) - goto release; - mp = &m->m_next; - if (resid == 0) { - if (flags & MSG_EOR) - top->m_flags |= M_EOR; - break; - } - } while (space > 0 && atomic); + if (flags & MSG_EOR) + top->m_flags |= M_EOR; + } s = splsoftnet(); /* XXX */ if (resid == 0) so->so_state &= ~SS_ISSENDING; @@ -539,9 +499,8 @@ nopages: top, addr, control, curproc); splx(s); clen = 0; - control = 0; - top = 0; - mp = ⊤ + control = NULL; + top = NULL; if (error) goto release; } while (resid && space > 0); @@ -556,6 +515,76 @@ out: if (control) m_freem(control); return (error); +} + +int +m_getuio(struct mbuf **mp, int atomic, long space, struct uio *uio) +{ + struct mbuf *m, *top = NULL; + struct mbuf **nextp = ⊤ + u_long len, mlen; + size_t resid = uio->uio_resid; + int error; + + do { + if (top == NULL) { + MGETHDR(m, M_WAIT, MT_DATA); + mlen = MHLEN; + m->m_pkthdr.len = 0; + m->m_pkthdr.ph_ifidx = 0; + } else { + MGET(m, M_WAIT, MT_DATA); + mlen = MLEN; + } + /* chain mbuf together */ + *nextp = m; + nextp = &m->m_next; + + resid = ulmin(resid, space); + if (resid >= MINCLSIZE) { + mlen = ulmin(resid, MAXMCLBYTES); + MCLGETI(m, M_WAIT, NULL, mlen); + + if ((m->m_flags & M_EXT) == 0) { + /* should not happen */ + m_freem(top); + return (ENOBUFS); + } + mlen = m->m_ext.ext_size; + len = ulmin(mlen, resid); + /* + * For datagram protocols, leave room + * for protocol headers in first mbuf. + */ + if (atomic && top == NULL && len < mlen - max_hdr) + m->m_data += max_hdr; + } else { + len = ulmin(mlen, resid); + /* + * For datagram protocols, leave room + * for protocol headers in first mbuf. + */ + if (atomic && top == NULL && len < mlen - max_hdr) + MH_ALIGN(m, len); + } + + error = uiomove(mtod(m, caddr_t), len, uio); + if (error) { + m_freem(top); + return (error); + } + + /* adjust counters */ + resid = uio->uio_resid; + space -= len; + m->m_len = len; + top->m_pkthdr.len += len; + + /* Is there more space and more data? */ + } while (space > 0 && resid > 0); + + *mp = top; + return 0; } /*