net: usb: qcusbnet: Fix kernel panic on probe/disconnect
authorBenoit Goby <benoit@android.com>
Thu, 3 Mar 2011 23:02:40 +0000 (15:02 -0800)
committerBenoit Goby <benoit@android.com>
Fri, 4 Mar 2011 03:36:51 +0000 (19:36 -0800)
Use list_for_each_safe since the loop kfree the current list entry.

If qc_register fails, probe calls qc_deregister. qc_deregister accesses
the cdev struct, so make sure it has been initialized before returning
from qc_register.

Fix missing spin_unlock_irqrestore

Change-Id: I56db6ffaa0c7b258d383d0a6211f63318fa9c08f
Signed-off-by: Benoit Goby <benoit@android.com>
drivers/net/usb/qcusbnet/qmidevice.c

index dab417ddae39c3f590bddf58158d4c909dcbd261..a1b198152a84a570eda58a6fdedb7fa35041092e 100644 (file)
@@ -1236,7 +1236,7 @@ static unsigned int devqmi_poll(struct file *file, poll_table *wait)
        struct qmihandle *handle = (struct qmihandle *)file->private_data;
        struct client *client;
        unsigned int mask = 0;
-       unsigned int flags;
+       unsigned long flags;
 
        if (!handle) {
                DBG("Bad file data\n");
@@ -1281,7 +1281,10 @@ int qc_register(struct qcusbnet *dev)
        dev_t devno;
        char *name;
 
+       cdev_init(&dev->qmi.cdev, &devqmi_fops);
+       dev->qmi.cdev.owner = THIS_MODULE;
        dev->valid = true;
+
        result = client_alloc(dev, QMICTL);
        if (result) {
                dev->valid = false;
@@ -1316,10 +1319,6 @@ int qc_register(struct qcusbnet *dev)
        if (result < 0)
                return result;
 
-       cdev_init(&dev->qmi.cdev, &devqmi_fops);
-       dev->qmi.cdev.owner = THIS_MODULE;
-       dev->qmi.cdev.ops = &devqmi_fops;
-
        result = cdev_add(&dev->qmi.cdev, devno, 1);
        if (result) {
                DBG("error adding cdev\n");
@@ -1348,6 +1347,7 @@ int qc_register(struct qcusbnet *dev)
 void qc_deregister(struct qcusbnet *dev)
 {
        struct list_head *node;
+       struct list_head *next;
        struct client *client;
        struct inode *inode;
        struct list_head *inodes;
@@ -1363,7 +1363,7 @@ void qc_deregister(struct qcusbnet *dev)
                return;
        }
 
-       list_for_each(node, &dev->qmi.clients) {
+       list_for_each_safe(node, next, &dev->qmi.clients) {
                client = list_entry(node, struct client, node);
                DBG("release 0x%04X\n", client->cid);
                client_free(dev, client->cid);
@@ -1448,6 +1448,7 @@ static bool qmi_ready(struct qcusbnet *dev, u16 timeout)
                                kfree(rbuf);
                                break;
                        }
+                       spin_unlock_irqrestore(&dev->qmi.clients_lock, flags);
                } else {
                        spin_lock_irqsave(&dev->qmi.clients_lock, flags);
                        client_notify(dev, QMICTL, tid);