Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(349)

Side by Side Diff: drivers/net/usb/gobi/qcusbnet.c

Issue 6612045: CHROMIUM: gobi: Fix races in qc_deregister() once and for all. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/kernel.git@master
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « drivers/net/usb/gobi/qcusbnet.h ('k') | drivers/net/usb/gobi/qmidevice.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* qcusbnet.c - gobi network device 1 /* qcusbnet.c - gobi network device
2 * Copyright (c) 2010, Code Aurora Forum. All rights reserved. 2 * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
3 3
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and 5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation. 6 * only version 2 as published by the Free Software Foundation.
7 7
8 * This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
(...skipping 10 matching lines...) Expand all
21 #include "qmi.h" 21 #include "qmi.h"
22 #include "qcusbnet.h" 22 #include "qcusbnet.h"
23 23
24 #define DRIVER_VERSION "1.0.110" 24 #define DRIVER_VERSION "1.0.110"
25 #define DRIVER_AUTHOR "Qualcomm Innovation Center" 25 #define DRIVER_AUTHOR "Qualcomm Innovation Center"
26 #define DRIVER_DESC "QCUSBNet2k" 26 #define DRIVER_DESC "QCUSBNet2k"
27 27
28 int qcusbnet_debug; 28 int qcusbnet_debug;
29 static struct class *devclass; 29 static struct class *devclass;
30 30
31 static void free_dev(struct kref *ref)
32 {
33 struct qcusbnet *dev = container_of(ref, struct qcusbnet, refcount);
34 kfree(dev);
35 }
36
37 void qcusbnet_put(struct qcusbnet *dev)
38 {
39 kref_put(&dev->refcount, free_dev);
40 }
41
42 struct qcusbnet *qcusbnet_get(struct qcusbnet *dev)
43 {
44 /* If we don't take dev->lock here, we can interleave with qc_deregister
45 * such that they set dying and drop their ref between our test and our
46 * kref_get(). Boo. :( */
47 mutex_lock(&dev->lock);
Jason Glasgow 2011/03/09 23:47:55 What if the other thread "wins" the race and sets
Elly Fong-Jones 2011/03/10 18:29:13 There is something to what you say. I will meditat
48 if (dev->dying || !dev->valid) {
49 mutex_unlock(&dev->lock);
50 return NULL;
51 }
52 kref_get(&dev->refcount);
53 mutex_unlock(&dev->lock);
54 return dev;
55 }
56
31 int qc_suspend(struct usb_interface *iface, pm_message_t event) 57 int qc_suspend(struct usb_interface *iface, pm_message_t event)
32 { 58 {
33 struct usbnet *usbnet; 59 struct usbnet *usbnet;
34 struct qcusbnet *dev; 60 struct qcusbnet *dev;
35 61
36 if (!iface) 62 if (!iface)
37 return -ENOMEM; 63 return -ENOMEM;
38 64
39 usbnet = usb_get_intfdata(iface); 65 usbnet = usb_get_intfdata(iface);
40 66
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 out->desc.bEndpointAddress); 199 out->desc.bEndpointAddress);
174 200
175 return 0; 201 return 0;
176 } 202 }
177 203
178 static void qcnet_unbind(struct usbnet *usbnet, struct usb_interface *iface) 204 static void qcnet_unbind(struct usbnet *usbnet, struct usb_interface *iface)
179 { 205 {
180 struct qcusbnet *dev = (struct qcusbnet *)usbnet->data[0]; 206 struct qcusbnet *dev = (struct qcusbnet *)usbnet->data[0];
181 207
182 netif_carrier_off(usbnet->net); 208 netif_carrier_off(usbnet->net);
209 /* See the comments in qcusbnet_get() for an explanation of why we need
210 * this lock. */
211 mutex_lock(&dev->lock);
183 qc_deregister(dev); 212 qc_deregister(dev);
213 mutex_unlock(&dev->lock);
184 214
215 usbnet->net->netdev_ops = NULL;
185 kfree(usbnet->net->netdev_ops); 216 kfree(usbnet->net->netdev_ops);
Jason Glasgow 2011/03/09 23:47:55 Like Olof said, kfree(NULL)?
Elly Fong-Jones 2011/03/10 18:29:13 Argh.
186 » usbnet->net->netdev_ops = NULL; 217 » qcusbnet_put(dev);
187
188 » kfree(dev);
189 } 218 }
190 219
191 static void qcnet_urbhook(struct urb *urb) 220 static void qcnet_urbhook(struct urb *urb)
192 { 221 {
193 unsigned long flags; 222 unsigned long flags;
194 struct worker *worker = urb->context; 223 struct worker *worker = urb->context;
195 if (!worker) { 224 if (!worker) {
196 DBG("bad context\n"); 225 DBG("bad context\n");
197 return; 226 return;
198 } 227 }
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after
583 usbnet->net->netdev_ops = netdevops; 612 usbnet->net->netdev_ops = netdevops;
584 613
585 memset(&(dev->usbnet->net->stats), 0, sizeof(struct net_device_stats)); 614 memset(&(dev->usbnet->net->stats), 0, sizeof(struct net_device_stats));
586 615
587 dev->iface = iface; 616 dev->iface = iface;
588 memset(&(dev->meid), '0', 14); 617 memset(&(dev->meid), '0', 14);
589 618
590 DBG("Mac Address: %pM\n", dev->usbnet->net->dev_addr); 619 DBG("Mac Address: %pM\n", dev->usbnet->net->dev_addr);
591 620
592 dev->valid = false; 621 dev->valid = false;
593 » memset(&dev->qmi, 0, sizeof(struct qmidev)); 622 » memset(&dev->qmi, 0, sizeof(dev->qmi));
594 623
595 dev->qmi.devclass = devclass; 624 dev->qmi.devclass = devclass;
596 625
626 kref_init(&dev->refcount);
627 mutex_init(&dev->lock);
597 INIT_LIST_HEAD(&dev->qmi.clients); 628 INIT_LIST_HEAD(&dev->qmi.clients);
598 init_completion(&dev->worker.work); 629 init_completion(&dev->worker.work);
599 spin_lock_init(&dev->qmi.clients_lock); 630 spin_lock_init(&dev->qmi.clients_lock);
600 631
601 dev->down = 0; 632 dev->down = 0;
602 qc_setdown(dev, DOWN_NO_NDIS_CONNECTION); 633 qc_setdown(dev, DOWN_NO_NDIS_CONNECTION);
603 qc_setdown(dev, DOWN_NET_IFACE_STOPPED); 634 qc_setdown(dev, DOWN_NET_IFACE_STOPPED);
604 635
605 status = qc_register(dev); 636 status = qc_register(dev);
606 if (status) { 637 if (status) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
640 } 671 }
641 module_exit(modexit); 672 module_exit(modexit);
642 673
643 MODULE_VERSION(DRIVER_VERSION); 674 MODULE_VERSION(DRIVER_VERSION);
644 MODULE_AUTHOR(DRIVER_AUTHOR); 675 MODULE_AUTHOR(DRIVER_AUTHOR);
645 MODULE_DESCRIPTION(DRIVER_DESC); 676 MODULE_DESCRIPTION(DRIVER_DESC);
646 MODULE_LICENSE("Dual BSD/GPL"); 677 MODULE_LICENSE("Dual BSD/GPL");
647 678
648 module_param(qcusbnet_debug, bool, S_IRUGO | S_IWUSR); 679 module_param(qcusbnet_debug, bool, S_IRUGO | S_IWUSR);
649 MODULE_PARM_DESC(qcusbnet_debug, "Debugging enabled or not"); 680 MODULE_PARM_DESC(qcusbnet_debug, "Debugging enabled or not");
OLDNEW
« no previous file with comments | « drivers/net/usb/gobi/qcusbnet.h ('k') | drivers/net/usb/gobi/qmidevice.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698