Index: sys/kern/uipc_usrreq.c =================================================================== --- sys/kern/uipc_usrreq.c +++ sys/kern/uipc_usrreq.c @@ -302,11 +302,13 @@ static void unp_scan(struct mbuf *, void (*)(struct filedescent **, int)); static void unp_discard(struct file *); static void unp_freerights(struct filedescent **, int); -static int unp_internalize(struct mbuf **, struct thread *); +static int unp_internalize(struct mbuf **, struct thread *, + struct mbuf **, u_int *, u_int *); static void unp_internalize_fp(struct file *); static int unp_externalize(struct mbuf *, struct mbuf **, int); static int unp_externalize_fp(struct file *); -static struct mbuf *unp_addsockcred(struct thread *, struct mbuf *, int); +static struct mbuf *unp_addsockcred(struct thread *, struct mbuf *, + int, struct mbuf **, u_int *, u_int *); static void unp_process_defers(void * __unused, int); static void @@ -1014,7 +1016,8 @@ error = EOPNOTSUPP; goto release; } - if (control != NULL && (error = unp_internalize(&control, td))) + if (control != NULL && + (error = unp_internalize(&control, td, NULL, NULL, NULL))) goto release; unp2 = NULL; @@ -1051,7 +1054,8 @@ * SOCK_SEQPACKET (LOCAL_CREDS => WANTCRED_ONESHOT), or * forever (LOCAL_CREDS_PERSISTENT => WANTCRED_ALWAYS). */ - control = unp_addsockcred(td, control, unp2->unp_flags); + control = unp_addsockcred(td, control, unp2->unp_flags, NULL, + NULL, NULL); unp2->unp_flags &= ~UNP_WANTCRED_ONESHOT; } @@ -1140,8 +1144,8 @@ const struct sockaddr *from; struct socket *so2; struct sockbuf *sb; - struct mbuf *f; - u_int space; + struct mbuf *f, *clast; + u_int space, mbcnt, dspace __diagused, dmbcnt __diagused; int error; MPASS((uio != NULL && m == NULL) || (m != NULL && uio == NULL)); @@ -1163,8 +1167,11 @@ error = EFAULT; goto out; } - f = m_get(M_WAITOK, MT_SONAME); - if (c != NULL && (error = unp_internalize(&c, td))) + f = m_gethdr(M_WAITOK, MT_SONAME); + space = m->m_pkthdr.len; + mbcnt = MSIZE + m->m_pkthdr.memlen; + if (c != NULL && + (error = unp_internalize(&c, td, &clast, &space, &mbcnt))) goto out; } else { /* pru_sosend() with mbuf usually is a kernel thread. */ @@ -1177,7 +1184,7 @@ error = EMSGSIZE; goto out; } - if ((f = m_get(M_NOWAIT, MT_SONAME)) == NULL) { + if ((f = m_gethdr(M_NOWAIT, MT_SONAME)) == NULL) { error = ENOBUFS; goto out; } @@ -1189,6 +1196,14 @@ m->m_pkthdr.csum_flags = 0; m->m_pkthdr.fibnum = 0; m->m_pkthdr.rsstype = 0; + + space = m->m_pkthdr.len; + mbcnt = MSIZE; + for (struct mbuf *mb = m; mb != NULL; mb = mb->m_next) { + mbcnt += MSIZE; + if (mb->m_flags & M_EXT) + mbcnt += mb->m_ext.ext_size; + } } unp = sotounpcb(so); @@ -1240,7 +1255,8 @@ } if (unp2->unp_flags & UNP_WANTCRED_MASK) - c = unp_addsockcred(td, c, unp2->unp_flags); + c = unp_addsockcred(td, c, unp2->unp_flags, &clast, &space, + &mbcnt); if (unp->unp_addr != NULL) from = (struct sockaddr *)unp->unp_addr; else @@ -1248,33 +1264,48 @@ f->m_len = from->sa_len; MPASS(from->sa_len <= MLEN); bcopy(from, mtod(f, void *), from->sa_len); - space = f->m_len + m->m_pkthdr.len; + space += f->m_len; - /* Concatenate: from -> control -> data. */ + /* + * Concatenate mbufs: from -> control -> data. + * Save overall space and mbcnt in "from" mbuf. + */ if (c != NULL) { - struct mbuf *clast; +#ifdef INVARIANTS + struct mbuf *mc; - space += m_length(c, &clast); + for (mc = c; mc->m_next != NULL; mc = mc->m_next); + MPASS(mc == clast); +#endif f->m_next = c; clast->m_next = m; c = NULL; } else f->m_next = m; m = NULL; + f->m_pkthdr.len = space; + f->m_pkthdr.memlen = mbcnt; +#ifdef INVARIANTS + dspace = dmbcnt = 0; + for (struct mbuf *mb = f; mb != NULL; mb = mb->m_next) { + dspace += mb->m_len; + dmbcnt += MSIZE; + if (mb->m_flags & M_EXT) + dmbcnt += mb->m_ext.ext_size; + } + MPASS(dspace == space); + MPASS(dmbcnt == mbcnt); +#endif so2 = unp2->unp_socket; sb = &so2->so_rcv; SOCK_RECVBUF_LOCK(so2); if (space <= sbspace(sb)) { STAILQ_INSERT_TAIL(&sb->uxdg_mb, f, m_stailqpkt); - /* XXX: would be nice if m_uiotombuf() returns count. */ - for (; f != NULL ; f = f->m_next) { - sb->sb_mbcnt += MSIZE; - if (f->m_flags & M_EXT) - sb->sb_mbcnt += f->m_ext.ext_size; - } sb->sb_ccc += space; + sb->sb_mbcnt += mbcnt; sorwakeup_locked(so2); + f = NULL; } else { soroverflow_locked(so2); error = (so->so_state & SS_NBIO) ? EAGAIN : ENOBUFS; @@ -1363,7 +1394,7 @@ uipc_soreceive_dgram(struct socket *so, struct sockaddr **psa, struct uio *uio, struct mbuf **mp0, struct mbuf **controlp, int *flagsp) { - struct mbuf *m, *m2; + struct mbuf *m; int flags, error; ssize_t len; bool nonblock; @@ -1416,7 +1447,9 @@ return (error); } } - SOCK_RECVBUF_LOCK_ASSERT(so); + + M_ASSERTPKTHDR(m); + KASSERT(m->m_type == MT_SONAME, ("m->m_type == %d", m->m_type)); if (uio->uio_td) uio->uio_td->td_ru.ru_msgrcv++; @@ -1425,15 +1458,10 @@ return (uipc_peek_dgram(so, psa, uio, controlp, flagsp)); STAILQ_REMOVE_HEAD(&so->so_rcv.uxdg_mb, m_stailqpkt); - for (m2 = m; m2 != NULL; m2 = m2->m_next) { - so->so_rcv.sb_ccc -= m2->m_len; - so->so_rcv.sb_mbcnt -= MSIZE; - if (m2->m_flags & M_EXT) - so->so_rcv.sb_mbcnt -= m2->m_ext.ext_size; - } + so->so_rcv.sb_ccc -= m->m_pkthdr.len; + so->so_rcv.sb_mbcnt -= m->m_pkthdr.memlen; SOCK_RECVBUF_UNLOCK(so); - KASSERT(m->m_type == MT_SONAME, ("m->m_type == %d", m->m_type)); if (psa != NULL) *psa = sodupsockaddr(mtod(m, struct sockaddr *), M_WAITOK); m = m_free(m); @@ -2504,7 +2532,8 @@ } static int -unp_internalize(struct mbuf **controlp, struct thread *td) +unp_internalize(struct mbuf **controlp, struct thread *td, + struct mbuf **clast, u_int *space, u_int *mbcnt) { struct mbuf *control, **initial_controlp; struct proc *p; @@ -2521,6 +2550,7 @@ int i, j, error, *fdp, oldfds; u_int newlen; + MPASS((*controlp)->m_next == NULL); /* COMPAT_OLDSOCK may violate */ UNP_LINK_UNLOCK_ASSERT(); p = td->td_proc; @@ -2667,6 +2697,13 @@ goto out; } + if (space != NULL) { + *space += (*controlp)->m_len; + *mbcnt += MSIZE; + if ((*controlp)->m_flags & M_EXT) + *mbcnt += (*controlp)->m_ext.ext_size; + *clast = *controlp; + } controlp = &(*controlp)->m_next; } if (clen > 0) @@ -2680,7 +2717,8 @@ } static struct mbuf * -unp_addsockcred(struct thread *td, struct mbuf *control, int mode) +unp_addsockcred(struct thread *td, struct mbuf *control, int mode, + struct mbuf **clast, u_int *space, u_int *mbcnt) { struct mbuf *m, *n, *n_prev; const struct cmsghdr *cm; @@ -2699,6 +2737,7 @@ m = sbcreatecontrol(NULL, ctrlsz, cmsgtype, SOL_SOCKET, M_NOWAIT); if (m == NULL) return (control); + MPASS((m->m_flags & M_EXT) == 0 && m->m_next == NULL); if (mode & UNP_WANTCRED_ALWAYS) { struct sockcred2 *sc; @@ -2740,6 +2779,25 @@ control = n->m_next; else n_prev->m_next = n->m_next; + if (space != NULL) { + MPASS(*space >= n->m_len); + *space -= n->m_len; + MPASS(*mbcnt >= MSIZE); + *mbcnt -= MSIZE; + if (n->m_flags & M_EXT) { + MPASS(*mbcnt >= + n->m_ext.ext_size); + *mbcnt -= n->m_ext.ext_size; + } + MPASS(clast); + if (*clast == n) { + MPASS(n->m_next == NULL); + if (n_prev == NULL) + *clast = m; + else + *clast = n_prev; + } + } n = m_free(n); } else { n_prev = n; @@ -2749,6 +2807,10 @@ /* Prepend it to the head. */ m->m_next = control; + if (space != NULL) { + *space += m->m_len; + *mbcnt += MSIZE; + } return (m); }