diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c --- a/sys/dev/netmap/netmap_generic.c +++ b/sys/dev/netmap/netmap_generic.c @@ -257,6 +257,7 @@ mtx_lock_spin(&kring->tx_event_lock); if (kring->tx_event) { SET_MBUF_DESTRUCTOR(kring->tx_event, NULL); + kring->tx_event->m_ext.ext_arg1 = NULL; } kring->tx_event = NULL; mtx_unlock_spin(&kring->tx_event_lock); @@ -278,7 +279,8 @@ for (i=0; inum_tx_desc; i++) { if (kring->tx_pool[i]) { - m_freem(kring->tx_pool[i]); + m_free(kring->tx_pool[i]); + kring->tx_pool[i] = NULL; } } nm_os_free(kring->tx_pool); @@ -434,7 +436,7 @@ static void generic_mbuf_dtor(struct mbuf *m) { - struct netmap_adapter *na = NA(GEN_TX_MBUF_IFP(m)); + struct netmap_adapter *na = (struct netmap_adapter *)m->m_ext.ext_arg1; struct netmap_kring *kring; unsigned int r = MBUF_TXQ(m); unsigned int r_orig = r; @@ -458,6 +460,18 @@ kring = na->tx_rings[r]; mtx_lock_spin(&kring->tx_event_lock); + + /* + * The netmap destructor can be called between us getting the + * reference and taking the lock, in that case the ring + * reference won't be valid. The destructor will free this mbuf + * so we can stop here. + */ + if (m->m_ext.ext_arg1 == NULL) { + mtx_unlock_spin(&kring->tx_event_lock); + return; + } + if (kring->tx_event == m) { kring->tx_event = NULL; match = true; @@ -639,6 +653,10 @@ } SET_MBUF_DESTRUCTOR(m, generic_mbuf_dtor); + + /* Take a reference to the adapter so we have it on free. */ + m->m_ext.ext_arg1 = kring->na; + kring->tx_event = m; #ifdef __FreeBSD__ /* @@ -664,7 +682,7 @@ /* Decrement the refcount. This will free it if we lose the race * with the driver. */ - m_freem(m); + m_free(m); } /*