diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2013-06-04 19:10:53 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2013-06-04 19:10:53 +0000 |
commit | 90d6b0cf3afb714c27b88d247910182eadc2f01a (patch) | |
tree | 3f2666bd37285a5d2cf4a9cd5404fee771995461 /sys/dev | |
parent | cfc344e2f6251c9ba4a4d9ae67687414c1925c78 (diff) |
Prevent panic'ing on alpha after ifconfig'ing up an unplugged de interface,
by making tulip_txput() aware of whether or not the mbuf it is processing
is in if_snq or not, rather than abusing the TULIP_TXPROBE_ACTIVE flag.
Found the hard way by kurt@, tested on AlphaServer 1000A, I've been sleeping
on this diff for about 3 years.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_de.c | 51 |
1 files changed, 28 insertions, 23 deletions
diff --git a/sys/dev/pci/if_de.c b/sys/dev/pci/if_de.c index e2ce3371cd8..ccd36a16d5b 100644 --- a/sys/dev/pci/if_de.c +++ b/sys/dev/pci/if_de.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_de.c,v 1.109 2011/07/07 20:42:56 henning Exp $ */ +/* $OpenBSD: if_de.c,v 1.110 2013/06/04 19:10:52 miod Exp $ */ /* $NetBSD: if_de.c,v 1.58 1998/01/12 09:39:58 thorpej Exp $ */ /*- @@ -212,7 +212,7 @@ void tulip_intr_handler(tulip_softc_t * const sc, int *progress_p); int tulip_intr_shared(void *arg); int tulip_intr_normal(void *arg); struct mbuf *tulip_mbuf_compress(struct mbuf *m); -struct mbuf *tulip_txput(tulip_softc_t * const sc, struct mbuf *m); +struct mbuf *tulip_txput(tulip_softc_t * const sc, struct mbuf *m, int); void tulip_txput_setup(tulip_softc_t * const sc); int tulip_ifioctl(struct ifnet * ifp, u_long cmd, caddr_t data); void tulip_ifstart(struct ifnet *ifp); @@ -292,7 +292,7 @@ tulip_txprobe(tulip_softc_t * const sc) sc->tulip_flags |= TULIP_TXPROBE_ACTIVE; TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); - if ((m = tulip_txput(sc, m)) != NULL) + if ((m = tulip_txput(sc, m, 1)) != NULL) m_freem(m); sc->tulip_probe.probe_txprobes++; return (1); @@ -3225,6 +3225,10 @@ tulip_rx_intr(tulip_softc_t * const sc) */ TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop)); if ((((volatile tulip_desc_t *) eop)->d_status & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) { +#ifdef DIAGNOSTIC + if (IF_IS_EMPTY(&sc->tulip_rxq)) + panic("%s: tulip_rxq empty", sc->tulip_if.if_xname); +#endif IF_DEQUEUE(&sc->tulip_rxq, ms); me = ms; } else { @@ -3814,7 +3818,7 @@ tulip_mbuf_compress(struct mbuf *m) } struct mbuf * -tulip_txput(tulip_softc_t * const sc, struct mbuf *m) +tulip_txput(tulip_softc_t * const sc, struct mbuf *m, int notonqueue) { TULIP_PERFSTART(txput) tulip_ringinfo_t * const ri = &sc->tulip_txinfo; @@ -3824,7 +3828,9 @@ tulip_txput(tulip_softc_t * const sc, struct mbuf *m) bus_dmamap_t map; int error; struct ifnet *ifp = &sc->tulip_if; +#ifdef DIAGNOSTIC struct mbuf *ombuf = m; +#endif int compressed = 0; #if defined(TULIP_DEBUG) @@ -3887,24 +3893,17 @@ tulip_txput(tulip_softc_t * const sc, struct mbuf *m) * to recopy it into one mbuf and then try again. */ struct mbuf *tmp; - /* - * tulip_mbuf_compress() frees the original mbuf. - * thus, we have to remove the mbuf from the queue - * before calling it. - * we don't have to worry about space shortage - * after compressing the mbuf since the compressed - * mbuf will take only two segs. - */ - if (compressed) { - /* should not happen */ -#ifdef TULIP_DEBUG - printf("tulip_txput: compress called twice!\n"); + if (!notonqueue) { +#ifdef DIAGNOSTIC + if (IF_IS_EMPTY(&ifp->if_snd)) + panic("%s: if_snd queue empty", ifp->if_xname); +#endif + IFQ_DEQUEUE(&ifp->if_snd, tmp); +#ifdef DIAGNOSTIC + if (tmp != ombuf) + panic("tulip_txput: different mbuf dequeued!"); #endif - goto finish; } - IFQ_DEQUEUE(&ifp->if_snd, tmp); - if (tmp != ombuf) - panic("tulip_txput: different mbuf dequeued!"); compressed = 1; m = tulip_mbuf_compress(m); if (m == NULL) { @@ -3976,12 +3975,18 @@ tulip_txput(tulip_softc_t * const sc, struct mbuf *m) * The descriptors have been filled in. Now get ready * to transmit. */ - if (!compressed && (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) { + if (!compressed && !notonqueue) { /* remove the mbuf from the queue */ struct mbuf *tmp; +#ifdef DIAGNOSTIC + if (IF_IS_EMPTY(&ifp->if_snd)) + panic("%s: if_snd queue empty", ifp->if_xname); +#endif IFQ_DEQUEUE(&ifp->if_snd, tmp); +#ifdef DIAGNOSTIC if (tmp != ombuf) panic("tulip_txput: different mbuf dequeued!"); +#endif } IF_ENQUEUE(&sc->tulip_txq, m); @@ -4246,7 +4251,7 @@ tulip_ifstart(struct ifnet * const ifp) IFQ_POLL(&sc->tulip_if.if_snd, m); if (m == NULL) break; - if ((m0 = tulip_txput(sc, m)) != NULL) { + if ((m0 = tulip_txput(sc, m, 0)) != NULL) { if (m0 != m) /* should not happen */ printf("tulip_if_start: txput failed!\n"); @@ -4274,7 +4279,7 @@ tulip_ifstart_one(struct ifnet * const ifp) && !IFQ_IS_EMPTY(&sc->tulip_if.if_snd)) { struct mbuf *m, *m0; IFQ_POLL(&sc->tulip_if.if_snd, m); - if (m != NULL && (m0 = tulip_txput(sc, m)) != NULL) + if (m != NULL && (m0 = tulip_txput(sc, m, 0)) != NULL) if (m0 != m) /* should not happen */ printf("tulip_if_start_one: txput failed!\n"); |