Hi,

This has been in my tree for a while and I believe Yasuoka-san has
tested it in the scenario where it was crashing.

m_pulldown is done here with a zero offset which means that if
there's been no space reserved for the Ethernet header in the mbuf
or the cluster it will allocate a new chunk of memory and return a
new pointer that the vmx code ignores.  This can realistically
happen only during the bpf injection.

The diff below makes sure to keep the modified chain pointer around
and passes it back to the calling code so that it will get properly
accounted for.  m_pulldown with a zero offset is equivalent to a
m_pullup.

OK?


diff --git sys/dev/pci/if_vmx.c sys/dev/pci/if_vmx.c
index 055cfe1..50edb0b 100644
--- sys/dev/pci/if_vmx.c
+++ sys/dev/pci/if_vmx.c
@@ -164,11 +164,11 @@ void vmxnet3_stop(struct ifnet *);
 void vmxnet3_reset(struct vmxnet3_softc *);
 int vmxnet3_init(struct vmxnet3_softc *);
 int vmxnet3_ioctl(struct ifnet *, u_long, caddr_t);
 void vmxnet3_start(struct ifnet *);
 int vmxnet3_load_mbuf(struct vmxnet3_softc *, struct vmxnet3_txring *,
-    struct mbuf *);
+    struct mbuf **);
 void vmxnet3_watchdog(struct ifnet *);
 void vmxnet3_media_status(struct ifnet *, struct ifmediareq *);
 int vmxnet3_media_change(struct ifnet *);
 void *vmxnet3_dma_allocmem(struct vmxnet3_softc *, u_int, u_int, bus_addr_t *);
 
@@ -1063,11 +1063,11 @@ vmxnet3_start(struct ifnet *ifp)
 
                IFQ_DEQUEUE(&ifp->if_snd, m);
                if (m == NULL)
                        break;
 
-               n = vmxnet3_load_mbuf(sc, ring, m);
+               n = vmxnet3_load_mbuf(sc, ring, &m);
                if (n == -1) {
                        ifp->if_oerrors++;
                        continue;
                }
 
@@ -1087,13 +1087,14 @@ vmxnet3_start(struct ifnet *ifp)
        }
 }
 
 int
 vmxnet3_load_mbuf(struct vmxnet3_softc *sc, struct vmxnet3_txring *ring,
-    struct mbuf *m)
+    struct mbuf **mp)
 {
        struct vmxnet3_txdesc *txd, *sop;
+       struct mbuf *n, *m = *mp;
        bus_dmamap_t map;
        u_int hlen = ETHER_HDR_LEN, csum_off;
        u_int prod;
        int gen, i;
 
@@ -1105,29 +1106,29 @@ vmxnet3_load_mbuf(struct vmxnet3_softc *sc, struct 
vmxnet3_txring *ring,
                    sc->sc_dev.dv_xname);
                return -1;
        }
 #endif
        if (m->m_pkthdr.csum_flags & (M_TCP_CSUM_OUT|M_UDP_CSUM_OUT)) {
-               struct mbuf *mp;
                struct ip *ip;
                int offp;
 
                if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT)
                        csum_off = offsetof(struct tcphdr, th_sum);
                else
                        csum_off = offsetof(struct udphdr, uh_sum);
 
-               mp = m_pulldown(m, hlen, sizeof(*ip), &offp);
-               if (mp == NULL)
+               n = m_pulldown(m, hlen, sizeof(*ip), &offp);
+               if (n == NULL)
                        return (-1);
 
-               ip = (struct ip *)(mp->m_data + offp);
+               ip = (struct ip *)(n->m_data + offp);
                hlen += ip->ip_hl << 2;
 
-               mp = m_pulldown(m, 0, hlen + csum_off + 2, &offp);
-               if (mp == NULL)
+               *mp = m_pullup(m, hlen + csum_off + 2);
+               if (*mp == NULL)
                        return (-1);
+               m = *mp;
        }
 
        switch (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT)) {
        case 0:
                break;

Reply via email to