Merge tag 'split-asm_system_h-for-linus-20120328' of git://git.kernel.org/pub/scm...
[firefly-linux-kernel-4.4.55.git] / drivers / net / usb / usbnet.c
index 81b96e303757a5bd99177b2a0f8b163cec4eb9c7..b7b3f5b0d40654c3c50b18ae56c969c03382c71c 100644 (file)
@@ -328,13 +328,13 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
        unsigned long           lockflags;
        size_t                  size = dev->rx_urb_size;
 
-       if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) {
+       skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
+       if (!skb) {
                netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
                usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
                usb_free_urb (urb);
                return -ENOMEM;
        }
-       skb_reserve (skb, NET_IP_ALIGN);
 
        entry = (struct skb_data *) skb->cb;
        entry->urb = urb;
@@ -493,6 +493,7 @@ block:
                if (netif_running (dev->net) &&
                    !test_bit (EVENT_RX_HALT, &dev->flags)) {
                        rx_submit (dev, urb, GFP_ATOMIC);
+                       usb_mark_last_busy(dev->udev);
                        return;
                }
                usb_free_urb (urb);
@@ -589,6 +590,14 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
                entry = (struct skb_data *) skb->cb;
                urb = entry->urb;
 
+               /*
+                * Get reference count of the URB to avoid it to be
+                * freed during usb_unlink_urb, which may trigger
+                * use-after-free problem inside usb_unlink_urb since
+                * usb_unlink_urb is always racing with .complete
+                * handler(include defer_bh).
+                */
+               usb_get_urb(urb);
                spin_unlock_irqrestore(&q->lock, flags);
                // during some PM-driven resume scenarios,
                // these (async) unlinks complete immediately
@@ -597,6 +606,7 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
                        netdev_dbg(dev->net, "unlink urb err, %d\n", retval);
                else
                        count++;
+               usb_put_urb(urb);
                spin_lock_irqsave(&q->lock, flags);
        }
        spin_unlock_irqrestore (&q->lock, flags);
@@ -1028,7 +1038,6 @@ static void tx_complete (struct urb *urb)
        }
 
        usb_autopm_put_interface_async(dev->intf);
-       urb->dev = NULL;
        entry->state = tx_done;
        defer_bh(dev, skb, &dev->txq);
 }
@@ -1336,10 +1345,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
 
        // set up our own records
        net = alloc_etherdev(sizeof(*dev));
-       if (!net) {
-               dbg ("can't kmalloc dev");
+       if (!net)
                goto out;
-       }
 
        /* netdev_printk() needs this so do it as early as possible */
        SET_NETDEV_DEV(net, &udev->dev);
@@ -1537,7 +1544,7 @@ int usbnet_resume (struct usb_interface *intf)
 
                if (test_bit(EVENT_DEV_OPEN, &dev->flags)) {
                        if (!(dev->txq.qlen >= TX_QLEN(dev)))
-                               netif_start_queue(dev->net);
+                               netif_tx_wake_all_queues(dev->net);
                        tasklet_schedule (&dev->bh);
                }
        }