diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2009-08-12 14:39:06 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2009-08-12 14:39:06 +0000 |
commit | 41f7beea342b39552a07eda8d3b742194d8e7d63 (patch) | |
tree | 32b74803f7554c6cd3660bd5b77eb8914c8cde9f | |
parent | a2ad26eeed1b3dec69c188b30427179069a1ca49 (diff) |
if we get dangerously low on clusters during interrupts, we need
to free some for use on the rx rings on network cards.
this modifies m_cluncount to advise callers when we're in such a
situation, and makes them responsible for freeing up the cluster
for allocation by MCLGETI later.
fixes an awesome lockup with sis(4) henning has been experiencing.
this is not the best fix, but it is better than the current situation.
yep deraadt@ tested by henning@
-rw-r--r-- | sys/dev/pci/if_em.c | 8 | ||||
-rw-r--r-- | sys/dev/pci/if_ix.c | 8 | ||||
-rw-r--r-- | sys/kern/uipc_mbuf.c | 58 | ||||
-rw-r--r-- | sys/net/if_ethersubr.c | 11 | ||||
-rw-r--r-- | sys/sys/mbuf.h | 4 |
5 files changed, 55 insertions, 34 deletions
diff --git a/sys/dev/pci/if_em.c b/sys/dev/pci/if_em.c index 394e0b1acef..9d7ef0b9f13 100644 --- a/sys/dev/pci/if_em.c +++ b/sys/dev/pci/if_em.c @@ -31,7 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ -/* $OpenBSD: if_em.c,v 1.217 2009/08/10 19:41:05 deraadt Exp $ */ +/* $OpenBSD: if_em.c,v 1.218 2009/08/12 14:39:05 dlg Exp $ */ /* $FreeBSD: if_em.c,v 1.46 2004/09/29 18:28:28 mlaier Exp $ */ #include <dev/pci/if_em.h> @@ -2649,10 +2649,12 @@ em_rxeof(struct em_softc *sc, int count) sc->last_rx_desc_filled); } - m_cluncount(m, 1); sc->rx_ndescs--; + if (m_cluncount(m) == 0) + accept_frame = 1; + else + accept_frame = 0; - accept_frame = 1; prev_len_adj = 0; desc_len = letoh16(desc->length); diff --git a/sys/dev/pci/if_ix.c b/sys/dev/pci/if_ix.c index b12507f6ac9..9a277f85ff5 100644 --- a/sys/dev/pci/if_ix.c +++ b/sys/dev/pci/if_ix.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ix.c,v 1.26 2009/08/10 19:41:05 deraadt Exp $ */ +/* $OpenBSD: if_ix.c,v 1.27 2009/08/12 14:39:05 dlg Exp $ */ /****************************************************************************** @@ -2631,10 +2631,12 @@ ixgbe_rxeof(struct rx_ring *rxr, int count) rxr->last_rx_desc_filled); } - m_cluncount(m, 1); rxr->rx_ndescs--; + if (m_cluncount(m) == 0) + accept_frame = 1; + else + accept_frame = 0; - accept_frame = 1; prev_len_adj = 0; desc_len = letoh16(rxdesc->wb.upper.length); diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c index b36711e74b0..a357f84a976 100644 --- a/sys/kern/uipc_mbuf.c +++ b/sys/kern/uipc_mbuf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_mbuf.c,v 1.130 2009/08/11 11:53:19 deraadt Exp $ */ +/* $OpenBSD: uipc_mbuf.c,v 1.131 2009/08/12 14:39:05 dlg Exp $ */ /* $NetBSD: uipc_mbuf.c,v 1.15.4.1 1996/06/13 17:11:44 cgd Exp $ */ /* @@ -372,20 +372,26 @@ m_clcount(struct ifnet *ifp, int pi) ifp->if_data.ifi_mclpool[pi].mcl_alive++; } -void -m_cluncount(struct mbuf *m, int all) +int +m_cluncount(struct mbuf *m) { - struct mbuf_ext *me; + struct mbuf_ext *me = &m->m_ext; + int pi; - do { - me = &m->m_ext; - if (((m->m_flags & (M_EXT|M_CLUSTER)) != (M_EXT|M_CLUSTER)) || - (me->ext_ifp == NULL)) - continue; - - me->ext_ifp->if_data.ifi_mclpool[me->ext_backend].mcl_alive--; - me->ext_ifp = NULL; - } while (all && (m = m->m_next)); + splassert(IPL_NET); + + if (((m->m_flags & (M_EXT|M_CLUSTER)) != (M_EXT|M_CLUSTER)) || + (me->ext_ifp == NULL)) + return (0); + + pi = me->ext_backend; + me->ext_ifp->if_data.ifi_mclpool[pi].mcl_alive--; + me->ext_ifp = NULL; + + if (mclpools[pi].pr_nitems <= mclpools[pi].pr_minitems) + return (1); + + return (0); } struct mbuf * @@ -468,21 +474,25 @@ m_free(struct mbuf *m) void m_extfree(struct mbuf *m) { + struct mbuf_ext *me = &m->m_ext; + int pi; + if (MCLISREFERENCED(m)) { - m->m_ext.ext_nextref->m_ext.ext_prevref = - m->m_ext.ext_prevref; - m->m_ext.ext_prevref->m_ext.ext_nextref = - m->m_ext.ext_nextref; + me->ext_nextref->m_ext.ext_prevref = me->ext_prevref; + me->ext_prevref->m_ext.ext_nextref = me->ext_nextref; } else if (m->m_flags & M_CLUSTER) { - m_cluncount(m, 0); - pool_put(&mclpools[m->m_ext.ext_backend], - m->m_ext.ext_buf); - } else if (m->m_ext.ext_free) - (*(m->m_ext.ext_free))(m->m_ext.ext_buf, - m->m_ext.ext_size, m->m_ext.ext_arg); + pi = me->ext_backend; + if (me->ext_ifp != NULL) { + me->ext_ifp->if_data.ifi_mclpool[pi].mcl_alive--; + me->ext_ifp = NULL; + } + pool_put(&mclpools[pi], me->ext_buf); + } else if (me->ext_free) + me->ext_free(me->ext_buf, me->ext_size, me->ext_arg); else panic("unknown type of extension buffer"); - m->m_ext.ext_size = 0; + + me->ext_size = 0; m->m_flags &= ~(M_EXT|M_CLUSTER); } diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index d0166e2e84a..ba971536e3c 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ethersubr.c,v 1.133 2009/06/05 00:05:21 claudio Exp $ */ +/* $OpenBSD: if_ethersubr.c,v 1.134 2009/08/12 14:39:05 dlg Exp $ */ /* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */ /* @@ -542,7 +542,14 @@ ether_input(ifp0, eh, m) struct ether_header *eh_tmp; #endif - m_cluncount(m, 1); + /* + * the cluster is no longer on the ring, so don't count it against the + * ring. if the system wants the packet back we should give it back. + */ + if (m_cluncount(m) != 0) { + m_freem(m); + return; + } /* mark incomming routing domain */ m->m_pkthdr.rdomain = ifp->if_rdomain; diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index a8cec5ffbd8..a8b21454744 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mbuf.h,v 1.131 2009/08/09 21:26:45 deraadt Exp $ */ +/* $OpenBSD: mbuf.h,v 1.132 2009/08/12 14:39:05 dlg Exp $ */ /* $NetBSD: mbuf.h,v 1.19 1996/02/09 18:25:14 christos Exp $ */ /* @@ -420,7 +420,7 @@ struct mbuf *m_clget(struct mbuf *, int, struct ifnet *, u_int); void m_clsetwms(struct ifnet *, u_int, u_int, u_int); int m_cldrop(struct ifnet *, int); void m_clcount(struct ifnet *, int); -void m_cluncount(struct mbuf *, int); +int m_cluncount(struct mbuf *); void m_clinitifp(struct ifnet *); void m_adj(struct mbuf *, int); void m_copyback(struct mbuf *, int, int, const void *); |