summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2009-08-12 14:39:06 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2009-08-12 14:39:06 +0000
commit41f7beea342b39552a07eda8d3b742194d8e7d63 (patch)
tree32b74803f7554c6cd3660bd5b77eb8914c8cde9f /sys/kern
parenta2ad26eeed1b3dec69c188b30427179069a1ca49 (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@
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/uipc_mbuf.c58
1 files changed, 34 insertions, 24 deletions
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);
}