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

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: Rebase. 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
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
11 * GNU General Public License for more details. 11 * GNU General Public License for more details.
12 12
13 * You should have received a copy of the GNU General Public License 13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software 14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301, USA. 16 * 02110-1301, USA.
17 */ 17 */
18 18
19 #include "structs.h" 19 #include "structs.h"
20 #include "qmidevice.h" 20 #include "qmidevice.h"
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+google" 24 #define DRIVER_VERSION "1.0.110+google"
25 #define DRIVER_AUTHOR "Qualcomm Innovation Center" 25 #define DRIVER_AUTHOR "Qualcomm Innovation Center"
26 #define DRIVER_DESC "gobi" 26 #define DRIVER_DESC "gobi"
27 27
28 static LIST_HEAD(qcusbnet_list);
29 static DEFINE_MUTEX(qcusbnet_lock);
30
28 int qcusbnet_debug; 31 int qcusbnet_debug;
29 static struct class *devclass; 32 static struct class *devclass;
30 33
34 static void free_dev(struct kref *ref)
35 {
36 struct qcusbnet *dev = container_of(ref, struct qcusbnet, refcount);
37 list_del(&dev->node);
38 kfree(dev);
39 }
40
41 void qcusbnet_put(struct qcusbnet *dev)
42 {
43 mutex_lock(&qcusbnet_lock);
44 kref_put(&dev->refcount, free_dev);
45 mutex_unlock(&qcusbnet_lock);
46 }
47
48 struct qcusbnet *qcusbnet_get(struct qcusbnet *key)
49 {
50 /* Given a putative qcusbnet struct, return either the struct itself
51 * (with a ref taken) if the struct is still visible, or NULL if it's
52 * not. This prevents object-visibility races where someone is looking
53 * up an object as the last ref gets dropped; dropping the last ref and
54 * removing the object from the list are atomic with respect to getting
55 * a new ref. */
56 struct qcusbnet *entry = NULL;
Mandeep Singh Baines 2011/03/16 20:49:41 Why initialize this?
Elly Fong-Jones 2011/03/16 21:23:09 Done.
57 mutex_lock(&qcusbnet_lock);
58 list_for_each_entry(entry, &qcusbnet_list, node) {
59 if (entry == key) {
60 kref_get(&entry->refcount);
61 mutex_unlock(&qcusbnet_lock);
62 return entry;
63 }
64 }
65 mutex_unlock(&qcusbnet_lock);
66 return NULL;
67 }
68
31 int qc_suspend(struct usb_interface *iface, pm_message_t event) 69 int qc_suspend(struct usb_interface *iface, pm_message_t event)
32 { 70 {
33 struct usbnet *usbnet; 71 struct usbnet *usbnet;
34 struct qcusbnet *dev; 72 struct qcusbnet *dev;
35 73
36 if (!iface) 74 if (!iface)
37 return -ENOMEM; 75 return -ENOMEM;
38 76
39 usbnet = usb_get_intfdata(iface); 77 usbnet = usb_get_intfdata(iface);
40 78
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 216
179 static void qcnet_unbind(struct usbnet *usbnet, struct usb_interface *iface) 217 static void qcnet_unbind(struct usbnet *usbnet, struct usb_interface *iface)
180 { 218 {
181 struct qcusbnet *dev = (struct qcusbnet *)usbnet->data[0]; 219 struct qcusbnet *dev = (struct qcusbnet *)usbnet->data[0];
182 220
183 netif_carrier_off(usbnet->net); 221 netif_carrier_off(usbnet->net);
184 qc_deregister(dev); 222 qc_deregister(dev);
185 223
186 kfree(usbnet->net->netdev_ops); 224 kfree(usbnet->net->netdev_ops);
187 usbnet->net->netdev_ops = NULL; 225 usbnet->net->netdev_ops = NULL;
188 226 » /* drop the list's ref */
189 » kfree(dev); 227 » qcusbnet_put(dev);
190 } 228 }
191 229
192 static void qcnet_urbhook(struct urb *urb) 230 static void qcnet_urbhook(struct urb *urb)
193 { 231 {
194 unsigned long flags; 232 unsigned long flags;
195 struct worker *worker = urb->context; 233 struct worker *worker = urb->context;
196 if (!worker) { 234 if (!worker) {
197 DBG("bad context\n"); 235 DBG("bad context\n");
198 return; 236 return;
199 } 237 }
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after
587 usbnet->net->netdev_ops = netdevops; 625 usbnet->net->netdev_ops = netdevops;
588 626
589 memset(&(dev->usbnet->net->stats), 0, sizeof(struct net_device_stats)); 627 memset(&(dev->usbnet->net->stats), 0, sizeof(struct net_device_stats));
590 628
591 dev->iface = iface; 629 dev->iface = iface;
592 memset(&(dev->meid), '0', 14); 630 memset(&(dev->meid), '0', 14);
593 631
594 DBG("Mac Address: %pM\n", dev->usbnet->net->dev_addr); 632 DBG("Mac Address: %pM\n", dev->usbnet->net->dev_addr);
595 633
596 dev->valid = false; 634 dev->valid = false;
597 » memset(&dev->qmi, 0, sizeof(struct qmidev)); 635 » memset(&dev->qmi, 0, sizeof(dev->qmi));
598 636
599 dev->qmi.devclass = devclass; 637 dev->qmi.devclass = devclass;
600 638
639 kref_init(&dev->refcount);
640 INIT_LIST_HEAD(&dev->node);
601 INIT_LIST_HEAD(&dev->qmi.clients); 641 INIT_LIST_HEAD(&dev->qmi.clients);
602 init_completion(&dev->worker.work); 642 init_completion(&dev->worker.work);
603 spin_lock_init(&dev->qmi.clients_lock); 643 spin_lock_init(&dev->qmi.clients_lock);
604 644
605 dev->down = 0; 645 dev->down = 0;
606 qc_setdown(dev, DOWN_NO_NDIS_CONNECTION); 646 qc_setdown(dev, DOWN_NO_NDIS_CONNECTION);
607 qc_setdown(dev, DOWN_NET_IFACE_STOPPED); 647 qc_setdown(dev, DOWN_NET_IFACE_STOPPED);
608 648
609 status = qc_register(dev); 649 status = qc_register(dev);
610 if (status) { 650 if (status) {
611 qc_deregister(dev); 651 qc_deregister(dev);
652 } else {
653 mutex_lock(&qcusbnet_lock);
654 /* Give our initial ref to the list */
655 list_add(&dev->node, &qcusbnet_list);
656 mutex_unlock(&qcusbnet_lock);
612 } 657 }
613 658
614 return status; 659 return status;
615 } 660 }
616 EXPORT_SYMBOL_GPL(qcnet_probe); 661 EXPORT_SYMBOL_GPL(qcnet_probe);
617 662
618 static struct usb_driver qcusbnet = { 663 static struct usb_driver qcusbnet = {
619 .name = "gobi", 664 .name = "gobi",
620 .id_table = qc_vidpids, 665 .id_table = qc_vidpids,
621 .probe = qcnet_probe, 666 .probe = qcnet_probe,
(...skipping 22 matching lines...) Expand all
644 } 689 }
645 module_exit(modexit); 690 module_exit(modexit);
646 691
647 MODULE_VERSION(DRIVER_VERSION); 692 MODULE_VERSION(DRIVER_VERSION);
648 MODULE_AUTHOR(DRIVER_AUTHOR); 693 MODULE_AUTHOR(DRIVER_AUTHOR);
649 MODULE_DESCRIPTION(DRIVER_DESC); 694 MODULE_DESCRIPTION(DRIVER_DESC);
650 MODULE_LICENSE("Dual BSD/GPL"); 695 MODULE_LICENSE("Dual BSD/GPL");
651 696
652 module_param(qcusbnet_debug, bool, S_IRUGO | S_IWUSR); 697 module_param(qcusbnet_debug, bool, S_IRUGO | S_IWUSR);
653 MODULE_PARM_DESC(qcusbnet_debug, "Debugging enabled or not"); 698 MODULE_PARM_DESC(qcusbnet_debug, "Debugging enabled or not");
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698