dr_size % 4 = =3D=3D 0) { > + if (VTNET_ETHER_ALIGN !=3D 0 && sc->vtnet_hdr_size % 4 = =3D=3D 0) > m_adj(m, VTNET_ETHER_ALIGN); > + > + err =3D bus_dmamap_create(sc->vtnet_rx_dmat, 0, &dmap); > + if (err) { > + printf("Failed to create dmamap, err :%d\n", > + err); > + m_freem(m); > + return (NULL); > } > + > + nsegs =3D 0; > + err =3D bus_dmamap_load_mbuf_sg(sc->vtnet_rx_dmat, dmap, = m, segs, > + &nsegs, BUS_DMA_NOWAIT); > + if (err !=3D 0) { > + printf("Failed to map mbuf into DMA visible memor= y, err: %d\n", > + err); > + m_freem(m); > + bus_dmamap_destroy(sc->vtnet_rx_dmat, dmap); > + return (NULL); > + } > + KASSERT(nsegs =3D=3D 1, > + ("%s: unexpected number of DMA segments for rx buffer= : %d", > + __func__, nsegs)); > + > + vthdr->addr =3D segs[0].ds_addr; > + vthdr->dmap =3D dmap; > + > if (m_head !=3D NULL) { > m_tail->m_next =3D m; > m_tail =3D m; > @@ -1594,7 +1705,7 @@ vtnet_rxq_replace_lro_nomrg_buf(struct vtnet_rxq *r= xq, struct mbuf *m0, > int len, clustersz, nreplace, error; > > sc =3D rxq->vtnrx_sc; > - clustersz =3D sc->vtnet_rx_clustersz; > + clustersz =3D sc->vtnet_rx_clustersz - VTNET_RX_BUFFER_HEADER_OFF= SET; > /* > * Need to offset the mbuf if the header we're going to add will > * misalign, account for that here. > @@ -1709,9 +1820,12 @@ vtnet_rxq_replace_buf(struct vtnet_rxq *rxq, struc= t mbuf *m, int len) > static int > vtnet_rxq_enqueue_buf(struct vtnet_rxq *rxq, struct mbuf *m) > { > + struct vtnet_rx_buffer_header *hdr; > struct vtnet_softc *sc; > struct sglist *sg; > int header_inlined, error; > + bus_addr_t paddr; > + struct mbuf *mp; > > sc =3D rxq->vtnrx_sc; > sg =3D rxq->vtnrx_sg; > @@ -1724,28 +1838,38 @@ vtnet_rxq_enqueue_buf(struct vtnet_rxq *rxq, stru= ct mbuf *m) > header_inlined =3D vtnet_modern(sc) || > (sc->vtnet_flags & VTNET_FLAG_MRG_RXBUFS) !=3D 0; /* TODO: AN= Y_LAYOUT */ > > + hdr =3D vtnet_mbuf_to_rx_buffer_header(sc, m); > + paddr =3D hdr->addr; > + > /* > * Note: The mbuf has been already adjusted when we allocate it i= f we > * have to do strict alignment. > */ > - if (header_inlined) > - error =3D sglist_append_mbuf(sg, m); > - else { > - struct vtnet_rx_header *rxhdr =3D > - mtod(m, struct vtnet_rx_header *); > + if (header_inlined) { > + error =3D sglist_append_phys(sg, paddr, m->m_len); > + } else { > MPASS(sc->vtnet_hdr_size =3D=3D sizeof(struct virtio_net_= hdr)); > > /* Append the header and remaining mbuf data. */ > - error =3D sglist_append(sg, &rxhdr->vrh_hdr, sc->vtnet_hd= r_size); > + error =3D sglist_append_phys(sg, paddr, sc->vtnet_hdr_siz= e); > if (error) > return (error); > - error =3D sglist_append(sg, &rxhdr[1], > + error =3D sglist_append_phys(sg, > + paddr + sizeof(struct vtnet_rx_header), > m->m_len - sizeof(struct vtnet_rx_header)); > if (error) > return (error); > > - if (m->m_next !=3D NULL) > - error =3D sglist_append_mbuf(sg, m->m_next); > + mp =3D m->m_next; > + while (mp) { > + hdr =3D vtnet_mbuf_to_rx_buffer_header(sc, mp); > + paddr =3D hdr->addr; > + error =3D sglist_append_phys(sg, paddr, mp->m_len= ); > + if (error) > + return (error); > + > + mp =3D mp->m_next; > + } > } > > if (error) > @@ -1931,6 +2055,7 @@ vtnet_rxq_merged_eof(struct vtnet_rxq *rxq, struct = mbuf *m_head, int nbufs) > m_tail =3D m_head; > > while (--nbufs > 0) { > + struct vtnet_rx_buffer_header *vthdr; > struct mbuf *m; > uint32_t len; > > @@ -1940,6 +2065,10 @@ vtnet_rxq_merged_eof(struct vtnet_rxq *rxq, struct= mbuf *m_head, int nbufs) > goto fail; > } > > + vthdr =3D vtnet_mbuf_to_rx_buffer_header(sc, m); > + bus_dmamap_sync(sc->vtnet_rx_dmat, vthdr->dmap, > + BUS_DMASYNC_POSTREAD); > + > if (vtnet_rxq_new_buf(rxq) !=3D 0) { > rxq->vtnrx_stats.vrxs_iqdrops++; > vtnet_rxq_discard_buf(rxq, m); > @@ -2060,6 +2189,7 @@ static int > vtnet_rxq_eof(struct vtnet_rxq *rxq) > { > struct virtio_net_hdr lhdr, *hdr; > + struct vtnet_rx_buffer_header *vthdr; > struct vtnet_softc *sc; > if_t ifp; > struct virtqueue *vq; > @@ -2075,14 +2205,31 @@ vtnet_rxq_eof(struct vtnet_rxq *rxq) > > CURVNET_SET(if_getvnet(ifp)); > while (count-- > 0) { > - struct mbuf *m; > + struct mbuf *m, *mp; > uint32_t len, nbufs, adjsz; > + uint32_t synced; > > m =3D virtqueue_dequeue(vq, &len); > if (m =3D=3D NULL) > break; > deq++; > > + mp =3D m; > + > + /* > + * Sync all mbufs in this packet. There will only be a si= ngle > + * mbuf unless LRO is in use. > + */ > + synced =3D 0; > + while (mp && synced < len) { > + vthdr =3D vtnet_mbuf_to_rx_buffer_header(sc, mp); > + bus_dmamap_sync(sc->vtnet_rx_dmat, vthdr->dmap, > + BUS_DMASYNC_POSTREAD); > + > + synced +=3D mp->m_len; > + mp =3D mp->m_next; > + } > + > if (len < sc->vtnet_hdr_size + ETHER_HDR_LEN) { > rxq->vtnrx_stats.vrxs_ierrors++; > vtnet_rxq_discard_buf(rxq, m); > @@ -2342,6 +2489,14 @@ vtnet_txq_free_mbufs(struct vtnet_txq *txq) > > while ((txhdr =3D virtqueue_drain(vq, &last)) !=3D NULL) { > if (kring =3D=3D NULL) { > + bus_dmamap_unload(txq->vtntx_sc->vtnet_tx_dmat, > + txhdr->dmap); > + bus_dmamap_destroy(txq->vtntx_sc->vtnet_tx_dmat, > + txhdr->dmap); > + bus_dmamap_unload(txq->vtntx_sc->vtnet_tx_dmat, > + txhdr->hdr_dmap); > + bus_dmamap_destroy(txq->vtntx_sc->vtnet_tx_dmat, > + txhdr->hdr_dmap); > m_freem(txhdr->vth_mbuf); > uma_zfree(vtnet_tx_header_zone, txhdr); > } > @@ -2511,15 +2666,36 @@ drop: > return (NULL); > } > > +static void > +vtnet_txq_enqueue_callback(void *arg, bus_dma_segment_t *segs, > + int nsegs, int error) > +{ > + vm_paddr_t *hdr_paddr; > + > + if (error !=3D 0) > + return; > + > + KASSERT(nsegs =3D=3D 1, ("%s: %d segments returned!", __func__, n= segs)); > + > + hdr_paddr =3D (vm_paddr_t *)arg; > + *hdr_paddr =3D segs[0].ds_addr; > +} > + > static int > vtnet_txq_enqueue_buf(struct vtnet_txq *txq, struct mbuf **m_head, > struct vtnet_tx_header *txhdr) > { > + bus_dma_segment_t segs[VTNET_TX_SEGS_MAX]; > + int nsegs; > struct vtnet_softc *sc; > struct virtqueue *vq; > struct sglist *sg; > struct mbuf *m; > int error; > + vm_paddr_t hdr_paddr; > + bus_dmamap_t hdr_dmap; > + bus_dmamap_t dmap; > + int i; > > sc =3D txq->vtntx_sc; > vq =3D txq->vtntx_vq; > @@ -2527,15 +2703,55 @@ vtnet_txq_enqueue_buf(struct vtnet_txq *txq, stru= ct mbuf **m_head, > m =3D *m_head; > > sglist_reset(sg); > - error =3D sglist_append(sg, &txhdr->vth_uhdr, sc->vtnet_hdr_size)= ; > + > + error =3D bus_dmamap_create(sc->vtnet_tx_dmat, 0, &hdr_dmap); > + if (error) > + goto fail; > + > + error =3D bus_dmamap_load(sc->vtnet_tx_dmat, hdr_dmap, &txhdr->vt= h_uhdr, > + sc->vtnet_hdr_size, vtnet_txq_enqueue_callback, &hdr_paddr, > + BUS_DMA_NOWAIT); > + if (error) > + goto fail_hdr_dmamap_destroy; > + > + error =3D sglist_append_phys(sg, hdr_paddr, sc->vtnet_hdr_size); > if (error !=3D 0 || sg->sg_nseg !=3D 1) { > KASSERT(0, ("%s: cannot add header to sglist error %d nse= g %d", > __func__, error, sg->sg_nseg)); > - goto fail; > + goto fail_hdr_dmamap_unload; > } > > - error =3D sglist_append_mbuf(sg, m); > + bus_dmamap_sync(sc->vtnet_tx_dmat, hdr_dmap, BUS_DMASYNC_PREWRITE= ); > + > + error =3D bus_dmamap_create(sc->vtnet_tx_dmat, 0, &dmap); > + if (error) > + goto fail_hdr_dmamap_unload; > + > + nsegs =3D 0; > + error =3D bus_dmamap_load_mbuf_sg(sc->vtnet_tx_dmat, dmap, m, seg= s, > + &nsegs, BUS_DMA_NOWAIT); > + if (error !=3D 0) > + goto fail_dmamap_destroy; > + KASSERT(nsegs <=3D sc->vtnet_tx_nsegs, > + ("%s: unexpected number of DMA segments for tx buffer: %d (ma= x %d)", > + __func__, nsegs, sc->vtnet_tx_nsegs)); > + > + bus_dmamap_sync(sc->vtnet_tx_dmat, dmap, BUS_DMASYNC_PREWRITE); > + > + for (i =3D 0; i < nsegs && !error; i++) > + error =3D sglist_append_phys(sg, segs[i].ds_addr, segs[i]= .ds_len); > + > if (error) { > + sglist_reset(sg); > + bus_dmamap_unload(sc->vtnet_tx_dmat, dmap); > + > + error =3D sglist_append_phys(sg, hdr_paddr, sc->vtnet_hdr= _size); > + if (error !=3D 0 || sg->sg_nseg !=3D 1) { > + KASSERT(0, ("%s: cannot add header to sglist erro= r %d nseg %d", > + __func__, error, sg->sg_nseg)); > + goto fail_dmamap_destroy; > + } > + > m =3D m_defrag(m, M_NOWAIT); > if (m =3D=3D NULL) { > sc->vtnet_stats.tx_defrag_failed++; > @@ -2545,16 +2761,41 @@ vtnet_txq_enqueue_buf(struct vtnet_txq *txq, stru= ct mbuf **m_head, > *m_head =3D m; > sc->vtnet_stats.tx_defragged++; > > - error =3D sglist_append_mbuf(sg, m); > + nsegs =3D 0; > + error =3D bus_dmamap_load_mbuf_sg(sc->vtnet_tx_dmat, dmap= , m, > + segs, &nsegs, BUS_DMA_NOWAIT); > + if (error !=3D 0) > + goto fail_dmamap_destroy; > + KASSERT(nsegs <=3D sc->vtnet_tx_nsegs, > + ("%s: unexpected number of DMA segments for tx buffer= : %d (max %d)", > + __func__, nsegs, sc->vtnet_tx_nsegs)); > + > + bus_dmamap_sync(sc->vtnet_tx_dmat, dmap, BUS_DMASYNC_PREW= RITE); > + > + for (i =3D 0; i < nsegs && !error; i++) > + error =3D sglist_append_phys(sg, segs[i].ds_addr, > + segs[i].ds_len); > + > if (error) > - goto fail; > + goto fail_dmamap_unload; > } > > txhdr->vth_mbuf =3D m; > + txhdr->dmap =3D dmap; > + txhdr->hdr_dmap =3D hdr_dmap; > + > error =3D virtqueue_enqueue(vq, txhdr, sg, sg->sg_nseg, 0); > > return (error); > > +fail_dmamap_unload: > + bus_dmamap_unload(sc->vtnet_tx_dmat, dmap); > +fail_dmamap_destroy: > + bus_dmamap_destroy(sc->vtnet_tx_dmat, dmap); > +fail_hdr_dmamap_unload: > + bus_dmamap_unload(sc->vtnet_tx_dmat, hdr_dmap); > +fail_hdr_dmamap_destroy: > + bus_dmamap_destroy(sc->vtnet_tx_dmat, hdr_dmap); > fail: > m_freem(*m_head); > *m_head =3D NULL; > diff --git a/sys/dev/virtio/network/if_vtnetvar.h b/sys/dev/virtio/networ= k/if_vtnetvar.h > index eb5e6784b07f..6cafe827d733 100644 > --- a/sys/dev/virtio/network/if_vtnetvar.h > +++ b/sys/dev/virtio/network/if_vtnetvar.h > @@ -190,6 +190,12 @@ struct vtnet_softc { > struct mtx vtnet_mtx; > char vtnet_mtx_name[16]; > uint8_t vtnet_hwaddr[ETHER_ADDR_LEN]; > + > + bus_dma_tag_t vtnet_rx_dmat; > + struct mtx vtnet_rx_mtx; > + > + bus_dma_tag_t vtnet_tx_dmat; > + struct mtx vtnet_tx_mtx; > }; > /* vtnet flag descriptions for use with printf(9) %b identifier. */ > #define VTNET_FLAGS_BITS \ > @@ -273,6 +279,10 @@ struct vtnet_tx_header { > } vth_uhdr; > > struct mbuf *vth_mbuf; > + > + bus_dmamap_t dmap; > + > + bus_dmamap_t hdr_dmap; > }; > > /* > I believe this is causing a massive memory leak in the devbuf malloc type. I can't even get through a build over nfs on a VM without hitting OOM. Reverting b5bad6df467cc95bea641afe674c55cd5b9f1510 and c16c95192f01237a876eb7bc336e3bbda9310171 fixes the leak. Can you please fix or revert this? You can monitor the leak with something like vmstat -m | grep devbuf > @@ -1562,13 +1643,43 @@ vtnet_rx_alloc_buf(struct vtnet_softc *sc, int nb= ufs, struct mbuf **m_tailp) > } > > m->m_len =3D size; > + vthdr =3D (struct vtnet_rx_buffer_header *)m->m_data; > + > + /* Reserve space for header */ > + m_adj(m, VTNET_RX_BUFFER_HEADER_OFFSET); > + > /* > * Need to offset the mbuf if the header we're going to a= dd > * will misalign. > */ > - if (VTNET_ETHER_ALIGN !=3D 0 && sc->vtnet_hdr_size % 4 = =3D=3D 0) { > + if (VTNET_ETHER_ALIGN !=3D 0 && sc->vtnet_hdr_size % 4 = =3D=3D 0) > m_adj(m, VTNET_ETHER_ALIGN); > + > + err =3D bus_dmamap_create(sc->vtnet_rx_dmat, 0, &dmap); > + if (err) { > + printf("Failed to create dmamap, err :%d\n", > + err); > + m_freem(m); > + return (NULL); > } > + > + nsegs =3D 0; > + err =3D bus_dmamap_load_mbuf_sg(sc->vtnet_rx_dmat, dmap, = m, segs, > + &nsegs, BUS_DMA_NOWAIT); Where is the bus_dmamap_unload and bus_dmamap_destroy for the rx bufs? Ryan