mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 03:27:30 -04:00
net: pch_gbe: handle TX skb allocation failure
pch_gbe_alloc_tx_buffers() allocates an skb for each TX descriptor and
then passes the returned pointer to skb_reserve(). If netdev_alloc_skb()
fails, skb_reserve() dereferences NULL.
Make pch_gbe_alloc_tx_buffers() return an error when an skb allocation
fails. On failure, let pch_gbe_alloc_tx_buffers() clean the partially
allocated TX ring before returning the error. While bringing the device
up, release the RX buffer pool through a shared cleanup helper before
unwinding the IRQ setup.
Cc: stable+noautosel@kernel.org # untested fix to unlikely error path
Fixes: 77555ee722 ("net: Add Gigabit Ethernet driver of Topcliff PCH")
Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260615125043.3537046-1-ruoyuw560@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
d31deeab70
commit
a0aa6bf985
@@ -1420,13 +1420,25 @@ pch_gbe_alloc_rx_buffers_pool(struct pch_gbe_adapter *adapter,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pch_gbe_free_rx_buffers_pool(struct pch_gbe_adapter *adapter,
|
||||
struct pch_gbe_rx_ring *rx_ring)
|
||||
{
|
||||
dma_free_coherent(&adapter->pdev->dev, rx_ring->rx_buff_pool_size,
|
||||
rx_ring->rx_buff_pool, rx_ring->rx_buff_pool_logic);
|
||||
rx_ring->rx_buff_pool_logic = 0;
|
||||
rx_ring->rx_buff_pool_size = 0;
|
||||
rx_ring->rx_buff_pool = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* pch_gbe_alloc_tx_buffers - Allocate transmit buffers
|
||||
* @adapter: Board private structure
|
||||
* @tx_ring: Tx descriptor ring
|
||||
*
|
||||
* Return: 0 on success, -ENOMEM if a TX skb allocation fails.
|
||||
*/
|
||||
static void pch_gbe_alloc_tx_buffers(struct pch_gbe_adapter *adapter,
|
||||
struct pch_gbe_tx_ring *tx_ring)
|
||||
static int pch_gbe_alloc_tx_buffers(struct pch_gbe_adapter *adapter,
|
||||
struct pch_gbe_tx_ring *tx_ring)
|
||||
{
|
||||
struct pch_gbe_buffer *buffer_info;
|
||||
struct sk_buff *skb;
|
||||
@@ -1440,12 +1452,17 @@ static void pch_gbe_alloc_tx_buffers(struct pch_gbe_adapter *adapter,
|
||||
for (i = 0; i < tx_ring->count; i++) {
|
||||
buffer_info = &tx_ring->buffer_info[i];
|
||||
skb = netdev_alloc_skb(adapter->netdev, bufsz);
|
||||
if (!skb) {
|
||||
pch_gbe_clean_tx_ring(adapter, tx_ring);
|
||||
return -ENOMEM;
|
||||
}
|
||||
skb_reserve(skb, PCH_GBE_DMA_ALIGN);
|
||||
buffer_info->skb = skb;
|
||||
tx_desc = PCH_GBE_TX_DESC(*tx_ring, i);
|
||||
tx_desc->gbec_status = (DSC_INIT16);
|
||||
}
|
||||
return;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1887,7 +1904,12 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter)
|
||||
"Error: can't bring device up - alloc rx buffers pool failed\n");
|
||||
goto freeirq;
|
||||
}
|
||||
pch_gbe_alloc_tx_buffers(adapter, tx_ring);
|
||||
err = pch_gbe_alloc_tx_buffers(adapter, tx_ring);
|
||||
if (err) {
|
||||
netdev_err(netdev,
|
||||
"Error: can't bring device up - alloc tx buffers failed\n");
|
||||
goto freebuf;
|
||||
}
|
||||
pch_gbe_alloc_rx_buffers(adapter, rx_ring, rx_ring->count);
|
||||
adapter->tx_queue_len = netdev->tx_queue_len;
|
||||
pch_gbe_enable_dma_rx(&adapter->hw);
|
||||
@@ -1901,6 +1923,8 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter)
|
||||
|
||||
return 0;
|
||||
|
||||
freebuf:
|
||||
pch_gbe_free_rx_buffers_pool(adapter, rx_ring);
|
||||
freeirq:
|
||||
pch_gbe_free_irq(adapter);
|
||||
out:
|
||||
@@ -1936,11 +1960,7 @@ void pch_gbe_down(struct pch_gbe_adapter *adapter)
|
||||
pch_gbe_clean_tx_ring(adapter, adapter->tx_ring);
|
||||
pch_gbe_clean_rx_ring(adapter, adapter->rx_ring);
|
||||
|
||||
dma_free_coherent(&adapter->pdev->dev, rx_ring->rx_buff_pool_size,
|
||||
rx_ring->rx_buff_pool, rx_ring->rx_buff_pool_logic);
|
||||
rx_ring->rx_buff_pool_logic = 0;
|
||||
rx_ring->rx_buff_pool_size = 0;
|
||||
rx_ring->rx_buff_pool = NULL;
|
||||
pch_gbe_free_rx_buffers_pool(adapter, rx_ring);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user