aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2011-05-19 11:17:04 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-05-26 15:43:29 -0400
commita9e12869758430424804dd4332e0d2afdfdf00b0 (patch)
treed56f68c680cec8c376017c66bbe5851f25218252 /drivers
parent208c72f4fe44fe09577e7975ba0e7fa0278f3d03 (diff)
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: 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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/rtlwifi/pci.c28
1 files changed, 15 insertions, 13 deletions
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index a40952845436..c2b83a57c581 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -669,11 +669,6 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
669 &rx_status, 669 &rx_status,
670 (u8 *) pdesc, skb); 670 (u8 *) pdesc, skb);
671 671
672 pci_unmap_single(rtlpci->pdev,
673 *((dma_addr_t *) skb->cb),
674 rtlpci->rxbuffersize,
675 PCI_DMA_FROMDEVICE);
676
677 skb_put(skb, rtlpriv->cfg->ops->get_desc((u8 *) pdesc, 672 skb_put(skb, rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
678 false, 673 false,
679 HW_DESC_RXPKT_LEN)); 674 HW_DESC_RXPKT_LEN));
@@ -690,6 +685,21 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
690 hdr = rtl_get_hdr(skb); 685 hdr = rtl_get_hdr(skb);
691 fc = rtl_get_fc(skb); 686 fc = rtl_get_fc(skb);
692 687
688 /* try for new buffer - if allocation fails, drop
689 * frame and reuse old buffer
690 */
691 new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
692 if (unlikely(!new_skb)) {
693 RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
694 DBG_DMESG,
695 ("can't alloc skb for rx\n"));
696 goto done;
697 }
698 pci_unmap_single(rtlpci->pdev,
699 *((dma_addr_t *) skb->cb),
700 rtlpci->rxbuffersize,
701 PCI_DMA_FROMDEVICE);
702
693 if (!stats.crc || !stats.hwerror) { 703 if (!stats.crc || !stats.hwerror) {
694 memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, 704 memcpy(IEEE80211_SKB_RXCB(skb), &rx_status,
695 sizeof(rx_status)); 705 sizeof(rx_status));
@@ -758,15 +768,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
758 rtl_lps_leave(hw); 768 rtl_lps_leave(hw);
759 } 769 }
760 770
761 new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
762 if (unlikely(!new_skb)) {
763 RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
764 DBG_DMESG,
765 ("can't alloc skb for rx\n"));
766 goto done;
767 }
768 skb = new_skb; 771 skb = new_skb;
769 /*skb->dev = dev; */
770 772
771 rtlpci->rx_ring[rx_queue_idx].rx_buf[rtlpci-> 773 rtlpci->rx_ring[rx_queue_idx].rx_buf[rtlpci->
772 rx_ring 774 rx_ring