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

Side by Side Diff: drivers/net/usb/gobi/qmidevice.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: Remove bogus initializer. 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.c ('k') | drivers/net/usb/gobi/structs.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* qmidevice.c - gobi QMI device 1 /* qmidevice.c - gobi QMI 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 714 matching lines...) Expand 10 before | Expand all | Expand 10 after
725 urb = client_delurb(dev, cid); 725 urb = client_delurb(dev, cid);
726 } 726 }
727 727
728 while (client_delread(dev, cid, 0, &data, &size)) 728 while (client_delread(dev, cid, 0, &data, &size))
729 kfree(data); 729 kfree(data);
730 730
731 list_del(&client->node); 731 list_del(&client->node);
732 kfree(client); 732 kfree(client);
733 } 733 }
734 } 734 }
735
736 spin_unlock_irqrestore(&dev->qmi.clients_lock, flags); 735 spin_unlock_irqrestore(&dev->qmi.clients_lock, flags);
737 } 736 }
738 737
739 struct client *client_bycid(struct qcusbnet *dev, u16 cid) 738 struct client *client_bycid(struct qcusbnet *dev, u16 cid)
740 { 739 {
741 struct list_head *node; 740 struct list_head *node;
742 struct client *client; 741 struct client *client;
743 742
744 if (!device_valid(dev)) { 743 if (!device_valid(dev)) {
745 DBG("Invalid device\n"); 744 DBG("Invalid device\n");
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
939 kfree(req); 938 kfree(req);
940 return urb; 939 return urb;
941 } 940 }
942 941
943 static int devqmi_open(struct inode *inode, struct file *file) 942 static int devqmi_open(struct inode *inode, struct file *file)
944 { 943 {
945 struct qmihandle *handle; 944 struct qmihandle *handle;
946 struct qmidev *qmidev = container_of(inode->i_cdev, struct qmidev, cdev) ; 945 struct qmidev *qmidev = container_of(inode->i_cdev, struct qmidev, cdev) ;
947 struct qcusbnet *dev = container_of(qmidev, struct qcusbnet, qmi); 946 struct qcusbnet *dev = container_of(qmidev, struct qcusbnet, qmi);
948 947
949 » if (!device_valid(dev)) { 948 » /* We need an extra ref on the device per fd, since we stash a ref
950 » » DBG("Invalid device\n"); 949 » * inside the handle. If qcusbnet_get() returns NULL, that means the
950 » * device has been removed from the list - no new refs for us. */
951 » struct qcusbnet *ref = qcusbnet_get(dev);
952
953 » if (!ref)
951 return -ENXIO; 954 return -ENXIO;
952 }
953 955
954 file->private_data = kmalloc(sizeof(struct qmihandle), GFP_KERNEL); 956 file->private_data = kmalloc(sizeof(struct qmihandle), GFP_KERNEL);
955 if (!file->private_data) { 957 if (!file->private_data) {
956 DBG("Mem error\n"); 958 DBG("Mem error\n");
957 return -ENOMEM; 959 return -ENOMEM;
958 } 960 }
959 961
960 handle = (struct qmihandle *)file->private_data; 962 handle = (struct qmihandle *)file->private_data;
961 handle->cid = (u16)-1; 963 handle->cid = (u16)-1;
962 » handle->dev = dev; 964 » handle->dev = ref;
963 965
964 DBG("%p %04x", handle, handle->cid); 966 DBG("%p %04x", handle, handle->cid);
965 967
966 return 0; 968 return 0;
967 } 969 }
968 970
969 static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd , unsigned long arg) 971 static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd , unsigned long arg)
970 { 972 {
971 int result; 973 int result;
972 u32 vidpid; 974 u32 vidpid;
973 975
974 struct qmihandle *handle = (struct qmihandle *)file->private_data; 976 struct qmihandle *handle = (struct qmihandle *)file->private_data;
975 977
976 DBG("%p %04x %08x", handle, handle->cid, cmd); 978 DBG("%p %04x %08x", handle, handle->cid, cmd);
977 979
978 if (!handle) { 980 if (!handle) {
979 DBG("Bad file data\n"); 981 DBG("Bad file data\n");
980 return -EBADF; 982 return -EBADF;
981 } 983 }
982 984
985 if (handle->dev->dying) {
986 DBG("Dying device");
987 return -ENXIO;
988 }
989
983 if (!device_valid(handle->dev)) { 990 if (!device_valid(handle->dev)) {
984 DBG("Invalid device!\n"); 991 DBG("Invalid device!\n");
985 return -ENXIO; 992 return -ENXIO;
986 } 993 }
987 994
988 switch (cmd) { 995 switch (cmd) {
989 case IOCTL_QMI_GET_SERVICE_FILE: 996 case IOCTL_QMI_GET_SERVICE_FILE:
990 997
991 DBG("Setting up QMI for service %lu\n", arg); 998 DBG("Setting up QMI for service %lu\n", arg);
992 if (!(u8)arg) { 999 if (!(u8)arg) {
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
1077 } 1084 }
1078 1085
1079 static int devqmi_release(struct inode *inode, struct file *file) 1086 static int devqmi_release(struct inode *inode, struct file *file)
1080 { 1087 {
1081 struct qmihandle *handle = (struct qmihandle *)file->private_data; 1088 struct qmihandle *handle = (struct qmihandle *)file->private_data;
1082 if (!handle) 1089 if (!handle)
1083 return 0; 1090 return 0;
1084 file->private_data = NULL; 1091 file->private_data = NULL;
1085 if (handle->cid != (u16)-1) 1092 if (handle->cid != (u16)-1)
1086 client_free(handle->dev, handle->cid); 1093 client_free(handle->dev, handle->cid);
1094 qcusbnet_put(handle->dev);
1087 kfree(handle); 1095 kfree(handle);
1088 return 0; 1096 return 0;
1089 } 1097 }
1090 1098
1091 static ssize_t devqmi_read(struct file *file, char __user *buf, size_t size, 1099 static ssize_t devqmi_read(struct file *file, char __user *buf, size_t size,
1092 loff_t *pos) 1100 loff_t *pos)
1093 { 1101 {
1094 int result; 1102 int result;
1095 void *data = NULL; 1103 void *data = NULL;
1096 void *smalldata; 1104 void *smalldata;
1097 struct qmihandle *handle = (struct qmihandle *)file->private_data; 1105 struct qmihandle *handle = (struct qmihandle *)file->private_data;
1098 1106
1099 if (!handle) { 1107 if (!handle) {
1100 DBG("Bad file data\n"); 1108 DBG("Bad file data\n");
1101 return -EBADF; 1109 return -EBADF;
1102 } 1110 }
1103 1111
1112 if (handle->dev->dying) {
1113 DBG("Dying device");
1114 return -ENXIO;
1115 }
1116
1104 if (!device_valid(handle->dev)) { 1117 if (!device_valid(handle->dev)) {
1105 DBG("Invalid device!\n"); 1118 DBG("Invalid device!\n");
1106 return -ENXIO; 1119 return -ENXIO;
1107 } 1120 }
1108 1121
1109 if (handle->cid == (u16)-1) { 1122 if (handle->cid == (u16)-1) {
1110 DBG("Client ID must be set before reading 0x%04X\n", 1123 DBG("Client ID must be set before reading 0x%04X\n",
1111 handle->cid); 1124 handle->cid);
1112 return -EBADR; 1125 return -EBADR;
1113 } 1126 }
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
1178 } 1191 }
1179 1192
1180 int qc_register(struct qcusbnet *dev) 1193 int qc_register(struct qcusbnet *dev)
1181 { 1194 {
1182 int result; 1195 int result;
1183 int qmiidx = 0; 1196 int qmiidx = 0;
1184 dev_t devno; 1197 dev_t devno;
1185 char *name; 1198 char *name;
1186 1199
1187 dev->valid = true; 1200 dev->valid = true;
1201 dev->dying = false;
1188 result = client_alloc(dev, QMICTL); 1202 result = client_alloc(dev, QMICTL);
1189 if (result) { 1203 if (result) {
1190 dev->valid = false; 1204 dev->valid = false;
1191 return result; 1205 return result;
1192 } 1206 }
1193 atomic_set(&dev->qmi.qmitid, 1); 1207 atomic_set(&dev->qmi.qmitid, 1);
1194 1208
1195 result = qc_startread(dev); 1209 result = qc_startread(dev);
1196 if (result) { 1210 if (result) {
1197 dev->valid = false; 1211 dev->valid = false;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1245 device_create(dev->qmi.devclass, &dev->iface->dev, devno, NULL, "qcqmi%d ", qmiidx); 1259 device_create(dev->qmi.devclass, &dev->iface->dev, devno, NULL, "qcqmi%d ", qmiidx);
1246 1260
1247 dev->qmi.devnum = devno; 1261 dev->qmi.devnum = devno;
1248 return 0; 1262 return 0;
1249 } 1263 }
1250 1264
1251 void qc_deregister(struct qcusbnet *dev) 1265 void qc_deregister(struct qcusbnet *dev)
1252 { 1266 {
1253 struct list_head *node, *tmp; 1267 struct list_head *node, *tmp;
1254 struct client *client; 1268 struct client *client;
1255 struct inode *inode;
1256 struct list_head *inodes;
1257 struct task_struct *task;
1258 struct fdtable *fdtable;
1259 struct file *file;
1260 unsigned long flags;
1261 int count = 0;
1262 1269
1270 dev->dying = true;
1263 list_for_each_safe(node, tmp, &dev->qmi.clients) { 1271 list_for_each_safe(node, tmp, &dev->qmi.clients) {
1264 client = list_entry(node, struct client, node); 1272 client = list_entry(node, struct client, node);
1265 DBG("release 0x%04X\n", client->cid); 1273 DBG("release 0x%04X\n", client->cid);
1266 client_free(dev, client->cid); 1274 client_free(dev, client->cid);
1267 } 1275 }
1268 1276
1269 qc_stopread(dev); 1277 qc_stopread(dev);
1270 dev->valid = false; 1278 dev->valid = false;
1271 list_for_each(inodes, &dev->qmi.cdev.list) {
1272 inode = container_of(inodes, struct inode, i_devices);
1273 if (inode != NULL && !IS_ERR(inode)) {
1274 rcu_read_lock();
1275 for_each_process(task) {
1276 if (!task || !task->files)
1277 continue;
1278 spin_lock_irqsave(&task->files->file_lock, flags );
1279 fdtable = files_fdtable(task->files);
1280 for (count = 0; count < fdtable->max_fds; count+ +) {
1281 file = fdtable->fd[count];
1282 if (file != NULL && file->f_dentry != N ULL) {
1283 if (file->f_dentry->d_inode == i node) {
1284 rcu_assign_pointer(fdtab le->fd[count], NULL);
1285 spin_unlock_irqrestore(& task->files->file_lock, flags);
1286 DBG("forcing close of op en file handle\n");
1287 filp_close(file, task->f iles);
1288 spin_lock_irqsave(&task- >files->file_lock, flags);
1289 }
1290 }
1291 }
1292 spin_unlock_irqrestore(&task->files->file_lock, flags);
1293 }
1294 rcu_read_unlock();
1295 }
1296 }
1297
1298 if (!IS_ERR(dev->qmi.devclass)) 1279 if (!IS_ERR(dev->qmi.devclass))
1299 device_destroy(dev->qmi.devclass, dev->qmi.devnum); 1280 device_destroy(dev->qmi.devclass, dev->qmi.devnum);
1300 cdev_del(&dev->qmi.cdev); 1281 cdev_del(&dev->qmi.cdev);
1301 unregister_chrdev_region(dev->qmi.devnum, 1); 1282 unregister_chrdev_region(dev->qmi.devnum, 1);
1302 } 1283 }
1303 1284
1304 static bool qmi_ready(struct qcusbnet *dev, u16 timeout) 1285 static bool qmi_ready(struct qcusbnet *dev, u16 timeout)
1305 { 1286 {
1306 int result; 1287 int result;
1307 void *wbuf; 1288 void *wbuf;
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
1553 DBG("bad get MEID resp\n"); 1534 DBG("bad get MEID resp\n");
1554 memset(&dev->meid[0], '0', 14); 1535 memset(&dev->meid[0], '0', 14);
1555 } 1536 }
1556 1537
1557 client_free(dev, cid); 1538 client_free(dev, cid);
1558 return 0; 1539 return 0;
1559 } 1540 }
1560 1541
1561 module_param(qcusbnet2k_fwdelay, int, S_IRUGO | S_IWUSR); 1542 module_param(qcusbnet2k_fwdelay, int, S_IRUGO | S_IWUSR);
1562 MODULE_PARM_DESC(qcusbnet2k_fwdelay, "Delay for old firmware"); 1543 MODULE_PARM_DESC(qcusbnet2k_fwdelay, "Delay for old firmware");
OLDNEW
« no previous file with comments | « drivers/net/usb/gobi/qcusbnet.c ('k') | drivers/net/usb/gobi/structs.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698