Skip to content

Commit

Permalink
rtlwifi: Fix kernel panic resulting from RX buffer allocation failure
Browse files Browse the repository at this point in the history
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: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Stable <stable@vger.kernel.org>              [2.6.{37,38,39}]
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Larry Finger authored and John W. Linville committed May 26, 2011
1 parent 208c72f commit a9e1286
Showing 1 changed file with 15 additions and 13 deletions.
28 changes: 15 additions & 13 deletions drivers/net/wireless/rtlwifi/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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));
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit a9e1286

Please sign in to comment.