From: Benoit Goby Date: Thu, 3 Mar 2011 23:02:40 +0000 (-0800) Subject: net: usb: qcusbnet: Fix kernel panic on probe/disconnect X-Git-Tag: firefly_0821_release~9834^2~64 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=047910a562d53be8aadf6559755cb3b29bb5fe36;p=firefly-linux-kernel-4.4.55.git net: usb: qcusbnet: Fix kernel panic on probe/disconnect 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 --- diff --git a/drivers/net/usb/qcusbnet/qmidevice.c b/drivers/net/usb/qcusbnet/qmidevice.c index dab417ddae39..a1b198152a84 100644 --- a/drivers/net/usb/qcusbnet/qmidevice.c +++ b/drivers/net/usb/qcusbnet/qmidevice.c @@ -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);