[RFC/RFT] staging: rtl8192e: Fix kernel panics when skb allocation fails

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This driver uses skb's of O(2), thus it is possible for memory fragmentation
to prevent the allocation of a new one to replace a newly-received buffer.
When such a failure occurs, the kernel panics.

The fix is to drop an incoming packet whenever such an allocation fails. This
fix matches the one done in rtlwifi for other Realtek PCI devices.

Signed-off-by: Larry Finger <Larry.Finger@xxxxxxxxxxxx>
---

Mike,

I'm currently testing this patch under heavy network load. I will likely
remove the printk that occurs when allocation fails, but I'm leaving it in
for testing.

Larry
---

diff --git a/drivers/staging/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl_core.c
index d8504e4..9e2497a 100644
--- a/drivers/staging/rtl8192e/rtl_core.c
+++ b/drivers/staging/rtl8192e/rtl_core.c
@@ -2549,14 +2549,23 @@ void rtl8192_rx_normal(struct net_device *dev)
 	while (count--) {
 		rx_desc *pdesc = &priv->rx_ring[rx_queue_idx][priv->rx_idx[rx_queue_idx]];
 		struct sk_buff *skb = priv->rx_buf[rx_queue_idx][priv->rx_idx[rx_queue_idx]];
+		struct sk_buff *new_skb = NULL;
 
-		if (pdesc->OWN){
+		if (pdesc->OWN) {
 			return;
 		} else {
 
-			struct sk_buff *new_skb = NULL;
-			if (!priv->ops->rx_query_status_descriptor(dev, &stats, pdesc, skb))
+			if (!priv->ops->rx_query_status_descriptor(dev, &stats,
+			    pdesc, skb))
 				goto done;
+			new_skb = dev_alloc_skb(priv->rxbuffersize);
+			/* allocation of new skb failed - drop current packet
+			 * and reuse skb */
+			if (unlikely(!new_skb)) {
+				printk(KERN_ERR "==========>can't alloc skb"
+				       " for rx\n");
+				goto done;
+			}
 
 			pci_unmap_single(priv->pdev,
 					*((dma_addr_t *)skb->cb),
@@ -2564,24 +2573,24 @@ void rtl8192_rx_normal(struct net_device *dev)
 					PCI_DMA_FROMDEVICE);
 
 			skb_put(skb, pdesc->Length);
-			skb_reserve(skb, stats.RxDrvInfoSize + stats.RxBufShift);
+			skb_reserve(skb, stats.RxDrvInfoSize +
+				    stats.RxBufShift);
 			skb_trim(skb, skb->len - 4/*sCrcLng*/);
 			rtllib_hdr = (struct rtllib_hdr_1addr *)skb->data;
-			if (is_broadcast_ether_addr(rtllib_hdr->addr1)) {
-			}else if (is_multicast_ether_addr(rtllib_hdr->addr1)){
-			}else {
+			if (!is_broadcast_ether_addr(rtllib_hdr->addr1) &&
+			    !is_multicast_ether_addr(rtllib_hdr->addr1)) {
 				/* unicast packet */
 				unicast_packet = true;
 			}
 			fc = le16_to_cpu(rtllib_hdr->frame_ctl);
 			type = WLAN_FC_GET_TYPE(fc);
 			if (type == RTLLIB_FTYPE_MGMT)
-			{
 				bLedBlinking = false;
-			}
+
 			if (bLedBlinking)
 				if (priv->rtllib->LedControlHandler)
-				priv->rtllib->LedControlHandler(dev, LED_CTL_RX);
+					priv->rtllib->LedControlHandler(dev,
+								 LED_CTL_RX);
 
 			if (stats.bCRC) {
 				if (type != RTLLIB_FTYPE_MGMT)
@@ -2592,28 +2601,16 @@ void rtl8192_rx_normal(struct net_device *dev)
 
 			skb_len = skb->len;
 
-			if (1)
-			{
 			if (!rtllib_rx(priv->rtllib, skb, &stats)){
 				dev_kfree_skb_any(skb);
 			} else {
 				priv->stats.rxok++;
-				if (unicast_packet) {
+				if (unicast_packet)
 					priv->stats.rxbytesunicast += skb_len;
-				}
-			}
-			}else{
-				dev_kfree_skb_any(skb);
 			}
 
-			new_skb = dev_alloc_skb(priv->rxbuffersize);
-			if (unlikely(!new_skb))
-			{
-				printk("==========>can't alloc skb for rx\n");
-				goto done;
-			}
-			skb=new_skb;
-                        skb->dev = dev;
+			skb = new_skb;
+			skb->dev = dev;
 
 			priv->rx_buf[rx_queue_idx][priv->rx_idx[rx_queue_idx]] = skb;
 			*((dma_addr_t *) skb->cb) = pci_map_single(priv->pdev, skb_tail_pointer_rsl(skb), priv->rxbuffersize, PCI_DMA_FROMDEVICE);
_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/devel


[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux