diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -292,6 +292,8 @@ static int unp_connectat(int, struct socket *, struct sockaddr *, struct thread *, bool); static void unp_connect2(struct socket *so, struct socket *so2); +typedef STAILQ_HEAD(udxg_mbq, mbuf) uxdg_mbq_t; +static void unp_dispose_uxdg_mbq(uxdg_mbq_t *); static void unp_disconnect(struct unpcb *unp, struct unpcb *unp2); static void unp_dispose(struct socket *so); static void unp_shutdown(struct unpcb *); @@ -2099,20 +2101,24 @@ static void unp_disconnect(struct unpcb *unp, struct unpcb *unp2) { + uxdg_mbq_t mbq; struct socket *so, *so2; struct mbuf *m = NULL; #ifdef INVARIANTS struct unpcb *unptmp; #endif + int sotype; UNP_PCB_LOCK_ASSERT(unp); UNP_PCB_LOCK_ASSERT(unp2); KASSERT(unp->unp_conn == unp2, ("%s: unpcb %p is not connected to %p", __func__, unp, unp2)); + STAILQ_INIT(&mbq); unp->unp_conn = NULL; so = unp->unp_socket; so2 = unp2->unp_socket; + sotype = unp->unp_socket->so_type; switch (unp->unp_socket->so_type) { case SOCK_DGRAM: /* @@ -2136,7 +2142,7 @@ so2->so_rcv.uxdg_mbcnt += so->so_snd.uxdg_mbcnt; } else { m = STAILQ_FIRST(&so->so_snd.uxdg_mb); - STAILQ_INIT(&so->so_snd.uxdg_mb); + STAILQ_CONCAT(&mbq, &so->so_snd.uxdg_mb); so2->so_rcv.sb_acc -= so->so_snd.uxdg_cc; so2->so_rcv.sb_ccc -= so->so_snd.uxdg_cc; so2->so_rcv.sb_ctl -= so->so_snd.uxdg_ctl; @@ -2190,7 +2196,10 @@ if (m != NULL) { unp_scan(m, unp_freerights); - m_freem(m); + if (sotype == SOCK_DGRAM) + unp_dispose_uxdg_mbq(&mbq); + else + m_freem(m); } } @@ -3202,19 +3211,33 @@ free(unref, M_TEMP); } +static void +unp_dispose_uxdg_mbq(uxdg_mbq_t *mbq) +{ + struct mbuf *m; + + while ((m = STAILQ_FIRST(mbq)) != NULL) { + STAILQ_REMOVE(mbq, m, mbuf, m_stailqpkt); + m_freem(m); + } +} + /* * Synchronize against unp_gc, which can trip over data as we are freeing it. */ static void unp_dispose(struct socket *so) { + uxdg_mbq_t mbq; struct sockbuf *sb; struct unpcb *unp; struct mbuf *m; int error __diagused; + int sotype; MPASS(!SOLISTENING(so)); + STAILQ_INIT(&mbq); unp = sotounpcb(so); UNP_LINK_WLOCK(); unp->unp_gcflag |= UNPGC_IGNORE_RIGHTS; @@ -3226,7 +3249,8 @@ error = SOCK_IO_RECV_LOCK(so, SBL_WAIT | SBL_NOINTR); MPASS(!error); SOCK_RECVBUF_LOCK(so); - switch (so->so_type) { + sotype = so->so_type; + switch (sotype) { case SOCK_DGRAM: while ((sb = TAILQ_FIRST(&so->so_rcv.uxdg_conns)) != NULL) { STAILQ_CONCAT(&so->so_rcv.uxdg_mb, &sb->uxdg_mb); @@ -3241,7 +3265,7 @@ sb->uxdg_peeked = NULL; } m = STAILQ_FIRST(&sb->uxdg_mb); - STAILQ_INIT(&sb->uxdg_mb); + STAILQ_CONCAT(&mbq, &sb->uxdg_mb); /* XXX: our shortened sbrelease() */ (void)chgsbsize(so->so_cred->cr_uidinfo, &sb->sb_hiwat, 0, RLIM_INFINITY); @@ -3280,7 +3304,10 @@ if (m != NULL) { unp_scan(m, unp_freerights); - m_freem(m); + if (sotype == SOCK_DGRAM) + unp_dispose_uxdg_mbq(&mbq); + else + m_freem(m); } }