]> xenbits.xensource.com Git - people/aperard/linux-chromebook.git/commitdiff
CHROMIUM: gobi: Take clients_lock in qc_deregister
authorMichael Spang <spang@chromium.org>
Wed, 14 Nov 2012 22:51:39 +0000 (17:51 -0500)
committerGerrit <chrome-bot@google.com>
Thu, 13 Dec 2012 22:10:37 +0000 (14:10 -0800)
It is not legal to access the clients list without taking
clients_lock. This change makes qc_deregister take the lock while
finding new clients to free.

This fixes a crash when qc_deregister races devqmi_release.

BUG=chrome-os-partner:15854
TEST=suspend_stress_test

Change-Id: I7c0c4c8dcb6b09c6a4414ee3e5878c56d5788d00
Signed-off-by: Michael Spang <spang@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/38066
Reviewed-by: Ben Chan <benchan@chromium.org>
drivers/net/usb/gobi/qmidevice.c

index 317c596e84dc7d2153ffa4d7e2c2dc29dae51a51..0d11bfa9a37e2ce98f54512884914ab16cc18a1b 100644 (file)
@@ -1606,14 +1606,22 @@ fail:
 
 void qc_deregister(struct qcusbnet *dev)
 {
-       struct list_head *node, *tmp;
        struct client *client;
        int sync_flags = SYNC_TIMEOUT;
+       unsigned long flags;
+       u16 cid;
 
-       list_for_each_safe(node, tmp, &dev->qmi.clients) {
-               client = list_entry(node, struct client, node);
-               client_free(dev, client->cid, sync_flags);
+       spin_lock_irqsave(&dev->qmi.clients_lock, flags);
+       while (!list_empty(&dev->qmi.clients)) {
+               client = list_first_entry(&dev->qmi.clients, struct client,
+                                         node);
+               cid = client->cid;
+
+               spin_unlock_irqrestore(&dev->qmi.clients_lock, flags);
+               client_free(dev, cid, sync_flags);
+               spin_lock_irqsave(&dev->qmi.clients_lock, flags);
        }
+       spin_unlock_irqrestore(&dev->qmi.clients_lock, flags);
 
        device_destroy(dev->qmi.devclass, dev->qmi.devnum);
        cdev_del(&dev->qmi.cdev);