tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: squid, DNS and no buffer space



> I'm no expert, but...is it normal to have lots more packet header mbufs
> than data mbufs?  It looks suspicious to me.  On my (much older)
> systems, either they're close to equal or there are more data mbufs.
Duno if it's related, but I found two mbuf leaks a while ago and just ported 
the patches to -10.
A huge one is in lltable_drop_entry_queue(), diff to sys/net/if_llatbl.c 
attached; another one (probably) in m_ext_free() (in sys/kern/uipc_mbuf.c),
replacement code attached (my diff contains additional instrumentation 
needing further patches).
Index: sys/net/if_llatbl.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_llatbl.c,v
retrieving revision 1.35
diff -u -r1.35 if_llatbl.c
--- sys/net/if_llatbl.c	19 Nov 2022 08:00:51 -0000	1.35
+++ sys/net/if_llatbl.c	3 Dec 2024 16:35:00 -0000
@@ -322,6 +322,8 @@
 	LLE_WLOCK_ASSERT(lle);
 
 	pkts_dropped = 0;
+
+#if 0 /* XXX la_numheld isn't (properly) incremented */
 	while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) {
 		next = lle->la_hold->m_nextpkt;
 		m_freem(lle->la_hold);
@@ -333,6 +335,15 @@
 	KASSERTMSG(lle->la_numheld == 0,
 		"la_numheld %d > 0, pkts_dropped %zd",
 		 lle->la_numheld, pkts_dropped);
+#else
+	while (lle->la_hold != NULL) {
+		next = lle->la_hold->m_nextpkt;
+		m_freem(lle->la_hold);
+		lle->la_hold = next;
+		pkts_dropped++;
+	}
+	lle->la_numheld = 0;
+#endif
 
 	return (pkts_dropped);
 }
/*
 * Release a reference to the mbuf external storage.
 *
 * => free the mbuf m itself as well.
 */
static void
m_ext_free(struct mbuf *m)
{
	struct mbuf *m1 = m->m_ext_ref; /* may well be m itself */
	u_int refcnt;

	KASSERT((m->m_flags & M_EXT) != 0);
	KASSERT(MEXT_ISEMBEDDED(m1));
	KASSERT((m1->m_flags & M_EXT) != 0);
	KASSERT((m->m_flags & M_EXT_CLUSTER) ==
	    (m1->m_flags & M_EXT_CLUSTER));
	if (__predict_false(m->m_type == MT_FREE)) {
		panic("mbuf %p already freed", m);
	}

	if (__predict_true(m1->m_ext_storage.ext_refcnt == 1)) {
		refcnt = m1->m_ext_storage.ext_refcnt = 0;
	} else {
#ifndef __HAVE_ATOMIC_AS_MEMBAR
		membar_release();
#endif
		refcnt = atomic_dec_uint_nv(&m1->m_ext_storage.ext_refcnt);
	}
	if (refcnt == 0) {
#ifndef __HAVE_ATOMIC_AS_MEMBAR
		membar_acquire();
#endif
		if ((m1->m_flags & M_EXT_CLUSTER) != 0) {
			pool_cache_put_paddr(mcl_cache,
			    m1->m_ext_storage.ext_buf, m1->m_ext_storage.ext_paddr);
			m1->m_type = MT_FREE;
			pool_cache_put(mb_cache, m1);
		} else if (m1->m_ext_storage.ext_free) {
			(*m1->m_ext_storage.ext_free)(m1,
			    m1->m_ext_storage.ext_buf, m1->m_ext_storage.ext_size,
			    m1->m_ext_storage.ext_arg);
			/*
			 * m1 is already freed by the ext_free callback.
			 */
		} else {
			free(m1->m_ext_storage.ext_buf, 0);
			m1->m_type = MT_FREE;
			pool_cache_put(mb_cache, m1);
		}
	}
	if (__predict_false(m1 != m)) {
		KASSERT(m->m_ext_storage.ext_refcnt == 0);
		m->m_type = MT_FREE;
		m->m_data = NULL;
		pool_cache_put(mb_cache, m);
	}
}


Home | Main Index | Thread Index | Old Index