diff --git a/sys/dev/virtual/amazon/ena/ena.c b/sys/dev/virtual/amazon/ena/ena.c index 97aed1c..46f6fb8 100644 --- a/sys/dev/virtual/amazon/ena/ena.c +++ b/sys/dev/virtual/amazon/ena/ena.c @@ -1058,12 +1058,17 @@ ena_free_rx_bufs(struct ena_adapter *adapter, unsigned int qid) struct ena_ring *rx_ring = &adapter->rx_ring[qid]; unsigned int i; + /* DF-3796: the deferred RX cleanup task may be running concurrently + * (it takes this lock); serialize buffer freeing with it, exactly + * like ena_free_tx_bufs() does for the TX side. */ + ENA_RING_MTX_LOCK(rx_ring); for (i = 0; i < rx_ring->ring_size; i++) { struct ena_rx_buffer *rx_info = &rx_ring->rx_buffer_info[i]; if (rx_info->mbuf != NULL) ena_free_rx_mbuf(adapter, rx_ring, rx_info); } + ENA_RING_MTX_UNLOCK(rx_ring); } /** @@ -2610,6 +2615,20 @@ ena_down(struct ena_adapter *adapter) callout_drain(&adapter->timer_service); + /* + * DF-3796: drain any pending/running deferred RX cleanup tasks + * before tearing down the IO queues and buffers they operate on. + * Only the (now-drained) timer enqueues them, so they cannot + * reappear after this point. + */ + for (int i = 0; i < adapter->num_queues; i++) { + struct ena_ring *rx_ring = &adapter->rx_ring[i]; + while (taskqueue_cancel(rx_ring->cmpl_tq, + &rx_ring->cmpl_task, NULL) != 0) + taskqueue_drain(rx_ring->cmpl_tq, + &rx_ring->cmpl_task); + } + adapter->up = false; ifq_set_oactive(&adapter->ifp->if_snd); adapter->ifp->if_flags &= ~IFF_RUNNING;