Commit a9e12869 authored by Larry Finger's avatar Larry Finger Committed by John W. Linville

rtlwifi: Fix kernel panic resulting from RX buffer allocation failure

To handle amsdu_8k capability, the PCI routine of this driver must
allocate receive buffers of order 2. Under heavy load, this causes
fragmentation of memory. The present code releases the current buffer
before checking to see if a new one is availble. Recovery from
allocation failures is not possible, which results in kernel panics.

The fix is to reorder the code to check that a new buffer can be
allocated before the old one is released. If not possible, the
received frame is dropped and the old one is reused. Without this
change, it is impossible to transfer a 2 GB file without a kernel panic.
Signed-off-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Cc: Stable <stable@vger.kernel.org>              [2.6.{37,38,39}]
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 208c72f4
......@@ -669,11 +669,6 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
&rx_status,
(u8 *) pdesc, skb);
pci_unmap_single(rtlpci->pdev,
*((dma_addr_t *) skb->cb),
rtlpci->rxbuffersize,
PCI_DMA_FROMDEVICE);
skb_put(skb, rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
false,
HW_DESC_RXPKT_LEN));
......@@ -690,6 +685,21 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
hdr = rtl_get_hdr(skb);
fc = rtl_get_fc(skb);
/* try for new buffer - if allocation fails, drop
* frame and reuse old buffer
*/
new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
if (unlikely(!new_skb)) {
RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
DBG_DMESG,
("can't alloc skb for rx\n"));
goto done;
}
pci_unmap_single(rtlpci->pdev,
*((dma_addr_t *) skb->cb),
rtlpci->rxbuffersize,
PCI_DMA_FROMDEVICE);
if (!stats.crc || !stats.hwerror) {
memcpy(IEEE80211_SKB_RXCB(skb), &rx_status,
sizeof(rx_status));
......@@ -758,15 +768,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
rtl_lps_leave(hw);
}
new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
if (unlikely(!new_skb)) {
RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
DBG_DMESG,
("can't alloc skb for rx\n"));
goto done;
}
skb = new_skb;
/*skb->dev = dev; */
rtlpci->rx_ring[rx_queue_idx].rx_buf[rtlpci->
rx_ring
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment