tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
m_ext_free() (was: mbuf (cluster) leak?)
I'm trying to understand m_ext_free() (in kern/uipc_mbuf.c).
It approximately (MEXT_ISEMBEDDED() expanded and __predict_true() and KASSERT()s
removed) looks like this:
void
m_ext_free(struct mbuf *m)
{
bool embedded = (m->m_ext_ref == m);
bool dofree = true;
u_int refcnt;
if (m->m_ext.ext_refcnt == 1) {
refcnt = m->m_ext.ext_refcnt = 0;
} else {
refcnt = atomic_dec_uint_nv(&m->m_ext.ext_refcnt);
}
if (refcnt > 0) {
if (embedded) {
/*
* other mbuf's m_ext_ref still points to us.
*/
dofree = false;
} else {
m->m_ext_ref = m;
}
} else {
if (!embedded) {
m->m_ext.ext_refcnt++; /* XXX */
m_ext_free(m->m_ext_ref);
m->m_ext_ref = m;
} else if ((m->m_flags & M_EXT_CLUSTER) != 0) {
pool_cache_put_paddr((struct pool_cache *)
m->m_ext.ext_arg,
m->m_ext.ext_buf, m->m_ext.ext_paddr);
} else [...]
}
}
if (dofree) {
m->m_type = MT_FREE;
pool_cache_put(mb_cache, m);
}
}
What I don't understand are the two
m->m_ext_ref = m;
assignments and the ext_refcnt++ operation.
If I have two mbufs, m1 and m2, where both are M_EXT (and M_EXT_CLUSTER),
m1 is embedded (pointing to m2) while m2 isn't, then m_ext_free(m2) will not
actually free anything. If m_ext_free(m1) will then drop the reference count
from 2 to 1, it will not free anything, but the reference to m2 will be lost.
If then another m_ext_free(m1) drops the count to 0, m1 will be freed, but
m2 will hang around forever.
I guess I'm missing something.
I also noted that various custom ext_free routines (like bge_jfree(), sk_jfree()),
while performing pool_cache_put(), will not set m_type to MT_FREE.
Home |
Main Index |
Thread Index |
Old Index