Fix mbuf leak caused by freeing packet zone clusters but not their associated mbufs
- Track packet zone mbufs separately from other mbufs - free packet zone buffers via m_free rather than trying to manage the refcount as with clusters - its refcount and management seems to be "special"
This commit is contained in:
parent
df0456225c
commit
c2f095f565
sys/dev/cxgb
@ -1409,7 +1409,7 @@ t3_encap(struct sge_qset *qs, struct mbuf **m, int count)
|
||||
((m0->m_flags & (M_EXT|M_NOFREE)) == M_EXT) &&
|
||||
(m0->m_ext.ext_type != EXT_PACKET)) {
|
||||
m0->m_flags &= ~M_EXT ;
|
||||
mbufs_outstanding--;
|
||||
cxgb_mbufs_outstanding--;
|
||||
m_free(m0);
|
||||
}
|
||||
|
||||
@ -3223,8 +3223,12 @@ t3_add_attach_sysctls(adapter_t *sc)
|
||||
0, "#times a cluster was freed through ext_free");
|
||||
SYSCTL_ADD_INT(ctx, children, OID_AUTO,
|
||||
"mbufs_outstanding",
|
||||
CTLFLAG_RD, &mbufs_outstanding,
|
||||
0, "#mbufs in flight in the driver");
|
||||
CTLFLAG_RD, &cxgb_mbufs_outstanding,
|
||||
0, "#mbufs in flight in the driver");
|
||||
SYSCTL_ADD_INT(ctx, children, OID_AUTO,
|
||||
"pack_outstanding",
|
||||
CTLFLAG_RD, &cxgb_pack_outstanding,
|
||||
0, "#packet in flight in the driver");
|
||||
}
|
||||
|
||||
|
||||
|
@ -45,7 +45,8 @@ void cxgb_cache_refill(void);
|
||||
extern int cxgb_cached_allocations;
|
||||
extern int cxgb_cached;
|
||||
extern int cxgb_ext_freed;
|
||||
extern int mbufs_outstanding;
|
||||
extern int cxgb_mbufs_outstanding;
|
||||
extern int cxgb_pack_outstanding;
|
||||
|
||||
#define mtomv(m) ((struct mbuf_vec *)((m)->m_pktdat))
|
||||
#define M_IOVEC 0x100000 /* mbuf immediate data area is used for cluster ptrs */
|
||||
@ -239,9 +240,13 @@ m_freem_iovec(struct mbuf_iovec *mi)
|
||||
#endif
|
||||
KASSERT((mi->mi_flags & M_NOFREE) == 0, ("no free set on mbuf"));
|
||||
KASSERT(m->m_next == NULL, ("freeing chain"));
|
||||
mbufs_outstanding--;
|
||||
cxgb_mbufs_outstanding--;
|
||||
m_free_fast(m);
|
||||
break;
|
||||
case EXT_PACKET:
|
||||
cxgb_pack_outstanding--;
|
||||
m_free(mi->mi_mbuf);
|
||||
break;
|
||||
case EXT_IOVEC:
|
||||
case EXT_CLIOVEC:
|
||||
case EXT_JMPIOVEC:
|
||||
@ -256,7 +261,6 @@ m_freem_iovec(struct mbuf_iovec *mi)
|
||||
case EXT_NET_DRV:
|
||||
case EXT_MOD_TYPE:
|
||||
case EXT_DISPOSABLE:
|
||||
case EXT_PACKET:
|
||||
case EXT_EXTREF:
|
||||
mb_free_ext_fast(mi, mi->mi_type, -1);
|
||||
break;
|
||||
@ -289,6 +293,9 @@ m_getzonefromtype(int type)
|
||||
case EXT_JUMBO16:
|
||||
zone = zone_jumbo16;
|
||||
break;
|
||||
case EXT_PACKET:
|
||||
zone = zone_pack;
|
||||
break;
|
||||
default:
|
||||
panic("%s: invalid cluster type %d", __func__, type);
|
||||
}
|
||||
@ -305,6 +312,7 @@ m_getsizefromtype(int type)
|
||||
size = MSIZE;
|
||||
break;
|
||||
case EXT_CLUSTER:
|
||||
case EXT_PACKET:
|
||||
size = MCLBYTES;
|
||||
break;
|
||||
#if MJUMPAGESIZE != MCLBYTES
|
||||
|
@ -75,7 +75,8 @@ extern uint32_t mb_free_vec_free;
|
||||
|
||||
uma_zone_t zone_miovec;
|
||||
static int mi_inited = 0;
|
||||
int mbufs_outstanding = 0;
|
||||
int cxgb_mbufs_outstanding = 0;
|
||||
int cxgb_pack_outstanding = 0;
|
||||
|
||||
void
|
||||
mi_init(void)
|
||||
@ -199,7 +200,7 @@ busdma_map_sg_collapse(struct mbuf **m, bus_dma_segment_t *segs, int *nsegs)
|
||||
struct mbuf *marray[TX_MAX_SEGS];
|
||||
int i, type, seg_count, defragged = 0, err = 0;
|
||||
struct mbuf_vec *mv;
|
||||
int skipped, freed, outstanding;
|
||||
int skipped, freed, outstanding, pack_outstanding, mbuf_outstanding;
|
||||
|
||||
|
||||
|
||||
@ -218,11 +219,14 @@ retry:
|
||||
if (n->m_next == NULL) {
|
||||
busdma_map_mbuf_fast(n, segs);
|
||||
*nsegs = 1;
|
||||
if ((n->m_flags & M_NOFREE) == 0)
|
||||
mbufs_outstanding++;
|
||||
if ((n->m_flags & M_EXT) &&
|
||||
(n->m_ext.ext_type == EXT_PACKET))
|
||||
cxgb_pack_outstanding++;
|
||||
else if ((n->m_flags & M_NOFREE) == 0)
|
||||
cxgb_mbufs_outstanding++;
|
||||
return (0);
|
||||
}
|
||||
skipped = freed = outstanding = 0;
|
||||
skipped = freed = outstanding = pack_outstanding = mbuf_outstanding = 0;
|
||||
while (n && seg_count < TX_MAX_SEGS) {
|
||||
marray[seg_count] = n;
|
||||
|
||||
@ -279,9 +283,14 @@ retry:
|
||||
while (n) {
|
||||
if (n->m_len == 0)
|
||||
/* do nothing - free if mbuf or cluster */;
|
||||
else if (((n->m_flags & M_EXT) == 0) ||
|
||||
((n->m_flags & M_EXT) && (n->m_ext.ext_type == EXT_PACKET)) ||
|
||||
(n->m_flags & M_NOFREE))
|
||||
else if ((n->m_flags & M_EXT) == 0) {
|
||||
mbuf_outstanding++;
|
||||
goto skip;
|
||||
} else if ((n->m_flags & M_EXT) &&
|
||||
(n->m_ext.ext_type == EXT_PACKET)) {
|
||||
pack_outstanding++;
|
||||
goto skip;
|
||||
} else if (n->m_flags & M_NOFREE)
|
||||
goto skip;
|
||||
else if ((n->m_flags & (M_EXT|M_NOFREE)) == M_EXT)
|
||||
n->m_flags &= ~M_EXT;
|
||||
@ -294,18 +303,13 @@ retry:
|
||||
/*
|
||||
* is an immediate mbuf or is from the packet zone
|
||||
*/
|
||||
outstanding++;
|
||||
n = n->m_next;
|
||||
}
|
||||
*nsegs = seg_count;
|
||||
*m = m0;
|
||||
DPRINTF("pktlen=%d m0=%p *m=%p m=%p\n", m0->m_pkthdr.len, m0, *m, m);
|
||||
mbufs_outstanding += outstanding;
|
||||
KASSERT(outstanding + freed == skipped + seg_count,
|
||||
("outstanding=%d freed=%d skipped=%d seg_count=%d",
|
||||
outstanding, freed, skipped, seg_count));
|
||||
|
||||
|
||||
cxgb_mbufs_outstanding += mbuf_outstanding;
|
||||
cxgb_pack_outstanding += pack_outstanding;
|
||||
return (0);
|
||||
err_out:
|
||||
m_freem(*m);
|
||||
@ -348,7 +352,7 @@ busdma_map_sg_vec(struct mbuf **m, struct mbuf **mret, bus_dma_segment_t *segs,
|
||||
(*mp)->m_next = (*mp)->m_nextpkt = NULL;
|
||||
if (((*mp)->m_flags & (M_EXT|M_NOFREE)) == M_EXT) {
|
||||
(*mp)->m_flags &= ~M_EXT;
|
||||
mbufs_outstanding--;
|
||||
cxgb_mbufs_outstanding--;
|
||||
m_free(*mp);
|
||||
}
|
||||
}
|
||||
@ -363,6 +367,12 @@ mb_free_ext_fast(struct mbuf_iovec *mi, int type, int idx)
|
||||
int dofree;
|
||||
caddr_t cl;
|
||||
|
||||
if (type == EXT_PACKET) {
|
||||
cxgb_pack_outstanding--;
|
||||
m_free(mi->mi_mbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Account for lazy ref count assign. */
|
||||
dofree = (mi->mi_refcnt == NULL);
|
||||
if (dofree == 0) {
|
||||
@ -379,7 +389,7 @@ mb_free_ext_fast(struct mbuf_iovec *mi, int type, int idx)
|
||||
switch (type) {
|
||||
case EXT_MBUF:
|
||||
KASSERT((mi->mi_flags & M_NOFREE) == 0, ("no free set on mbuf"));
|
||||
mbufs_outstanding--;
|
||||
cxgb_mbufs_outstanding--;
|
||||
m_free_fast((struct mbuf *)cl);
|
||||
break;
|
||||
case EXT_CLUSTER:
|
||||
@ -408,12 +418,6 @@ mb_free_ext_fast(struct mbuf_iovec *mi, int type, int idx)
|
||||
(*(mi->mi_ext.ext_free))(mi->mi_ext.ext_buf,
|
||||
mi->mi_ext.ext_args);
|
||||
break;
|
||||
case EXT_PACKET:
|
||||
mbufs_outstanding--;
|
||||
if (*(mi->mi_refcnt) == 0)
|
||||
*(mi->mi_refcnt) = 1;
|
||||
uma_zfree(zone_pack, mi->mi_mbuf);
|
||||
break;
|
||||
default:
|
||||
dump_mi(mi);
|
||||
panic("unknown mv type in m_free_vec type=%d idx=%d", type, idx);
|
||||
|
Loading…
x
Reference in New Issue
Block a user