Fix the handling of EOP in status descriptors for if_igb(4) and don't
double-free mbufs. Like ixgbe(4) chipsets, EOP is only set on the final descriptor in a chain of descriptors. So, to free the whole list of descriptors, we should free the current slot _and_ the assembled list of descriptors that make up the fragment list. The existing code was setting discard once it saw EOP + an error status; it then freed all the subsequent descriptors until the next EOP. That's totally the wrong order.
This commit is contained in:
parent
d2a707cdfa
commit
0936a8208b
@ -4495,7 +4495,6 @@ igb_setup_receive_ring(struct rx_ring *rxr)
|
||||
|
||||
rxr->fmp = NULL;
|
||||
rxr->lmp = NULL;
|
||||
rxr->discard = FALSE;
|
||||
|
||||
bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
|
||||
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
|
||||
@ -5039,15 +5038,16 @@ igb_rxeof(struct igb_queue *que, int count, int *done)
|
||||
pkt_info = le16toh(cur->wb.lower.lo_dword.hs_rss.pkt_info);
|
||||
eop = ((staterr & E1000_RXD_STAT_EOP) == E1000_RXD_STAT_EOP);
|
||||
|
||||
/* Make sure all segments of a bad packet are discarded */
|
||||
if (((staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) != 0) ||
|
||||
(rxr->discard)) {
|
||||
/*
|
||||
* Free the frame (all segments) if we're at EOP and
|
||||
* it's an error.
|
||||
*
|
||||
* The datasheet states that EOP + status is only valid for
|
||||
* the final segment in a multi-segment frame.
|
||||
*/
|
||||
if (eop && ((staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) != 0)) {
|
||||
adapter->dropped_pkts++;
|
||||
++rxr->rx_discarded;
|
||||
if (!eop) /* Catch subsequent segs */
|
||||
rxr->discard = TRUE;
|
||||
else
|
||||
rxr->discard = FALSE;
|
||||
igb_rx_discard(rxr, i);
|
||||
goto next_desc;
|
||||
}
|
||||
|
@ -336,7 +336,6 @@ struct rx_ring {
|
||||
struct lro_ctrl lro;
|
||||
bool lro_enabled;
|
||||
bool hdr_split;
|
||||
bool discard;
|
||||
struct mtx rx_mtx;
|
||||
char mtx_name[16];
|
||||
u32 next_to_refresh;
|
||||
|
Loading…
Reference in New Issue
Block a user