wl3501_cs: Add spinlock to wl3501_reset
authorPavel Andrianov <andrianov@ispras.ru>
Tue, 2 Aug 2016 09:41:53 +0000 (12:41 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Sat, 3 Sep 2016 10:01:18 +0000 (13:01 +0300)
Likely wl3501_reset should acquire spinlock as wl3501_{open, close}.
One of calls of wl3501_reset has been already protected.
The others were unprotected and might lead to a race condition.
The patch adds spinlock into the wl3501_reset and removes it from
wl3501_tx_timeout.

Found by Linux Driver Verification project (linuxtesting.org)

Signed-off-by: Pavel Andrianov <andrianov@ispras.ru>
Acked-by: Vaishali Thakkar <vaishali.thakkar@oracle.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/wl3501_cs.c

index 82d94f83b6b4f90443bc7c84265eed09a1c5f4f5..932f3f81e8cf3f3cb6b6a51e0e4904ecfc7c23fc 100644 (file)
@@ -1258,7 +1258,9 @@ static int wl3501_reset(struct net_device *dev)
 {
        struct wl3501_card *this = netdev_priv(dev);
        int rc = -ENODEV;
+       unsigned long flags;
 
+       spin_lock_irqsave(&this->lock, flags);
        wl3501_block_interrupt(this);
 
        if (wl3501_init_firmware(this)) {
@@ -1280,20 +1282,17 @@ static int wl3501_reset(struct net_device *dev)
        pr_debug("%s: device reset", dev->name);
        rc = 0;
 out:
+       spin_unlock_irqrestore(&this->lock, flags);
        return rc;
 }
 
 static void wl3501_tx_timeout(struct net_device *dev)
 {
-       struct wl3501_card *this = netdev_priv(dev);
        struct net_device_stats *stats = &dev->stats;
-       unsigned long flags;
        int rc;
 
        stats->tx_errors++;
-       spin_lock_irqsave(&this->lock, flags);
        rc = wl3501_reset(dev);
-       spin_unlock_irqrestore(&this->lock, flags);
        if (rc)
                printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n",
                       dev->name, rc);