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

Unified Diff: drivers/net/usb/gobi/qmidevice.c

Issue 6694028: CHROMIUM: qcusbnet: fix devqmi_close() races. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/kernel.git@master
Patch Set: Update comment to reflect reality. 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: drivers/net/usb/gobi/qmidevice.c
diff --git a/drivers/net/usb/gobi/qmidevice.c b/drivers/net/usb/gobi/qmidevice.c
index 82cb0fb3c1cad2227d14e146bf70c652639a459c..74512ac4ca67c581e6146b8e03ae41634a9fc309 100644
--- a/drivers/net/usb/gobi/qmidevice.c
+++ b/drivers/net/usb/gobi/qmidevice.c
@@ -70,7 +70,7 @@ static struct urb *client_delurb(struct qcusbnet *dev, u16 cid);
static int devqmi_open(struct inode *inode, struct file *file);
static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int devqmi_close(struct file *file, fl_owner_t ftable);
+static int devqmi_release(struct inode *inode, struct file *file);
static ssize_t devqmi_read(struct file *file, char __user *buf, size_t size,
loff_t *pos);
static ssize_t devqmi_write(struct file *file, const char __user *buf,
@@ -81,19 +81,20 @@ static void wds_callback(struct qcusbnet *dev, u16 cid, void *data);
static int setup_wds_callback(struct qcusbnet *dev);
static int qmidms_getmeid(struct qcusbnet *dev);
-#define IOCTL_QMI_GET_SERVICE_FILE (0x8BE0 + 1)
-#define IOCTL_QMI_GET_DEVICE_VIDPID (0x8BE0 + 2)
-#define IOCTL_QMI_GET_DEVICE_MEID (0x8BE0 + 3)
+#define IOCTL_QMI_GET_SERVICE_FILE (0x8BE0 + 1)
+#define IOCTL_QMI_GET_DEVICE_VIDPID (0x8BE0 + 2)
+#define IOCTL_QMI_GET_DEVICE_MEID (0x8BE0 + 3)
+#define IOCTL_QMI_CLOSE (0x8BE0 + 4)
#define CDC_GET_ENCAPSULATED_RESPONSE 0x01A1ll
#define CDC_CONNECTION_SPEED_CHANGE 0x08000000002AA1ll
static const struct file_operations devqmi_fops = {
- .owner = THIS_MODULE,
- .read = devqmi_read,
- .write = devqmi_write,
- .ioctl = devqmi_ioctl,
- .open = devqmi_open,
- .flush = devqmi_close,
+ .owner = THIS_MODULE,
+ .read = devqmi_read,
+ .write = devqmi_write,
+ .ioctl = devqmi_ioctl,
+ .open = devqmi_open,
+ .release = devqmi_release,
};
#ifdef CONFIG_SMP
@@ -679,11 +680,6 @@ static void client_free(struct qcusbnet *dev, u16 cid)
unsigned long flags;
u8 tid;
- if (!device_valid(dev)) {
- DBG("invalid device\n");
- return;
- }
-
DBG("releasing 0x%04X\n", cid);
if (cid != QMICTL) {
@@ -985,8 +981,7 @@ static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd
}
if (!device_valid(handle->dev)) {
- DBG("Invalid device! Updating f_ops\n");
- file->f_op = file->f_dentry->d_inode->i_fop;
+ DBG("Invalid device!\n");
return -ENXIO;
}
@@ -1012,6 +1007,31 @@ static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return 0;
break;
+ /* Okay, all aboard the nasty hack express. If we don't have this
+ * ioctl() (and we just rely on userspace to close() the file
+ * descriptors), if userspace has any refs left to this fd (like, say, a
+ * pending read()), then the read might hang around forever. Userspace
+ * needs a way to cause us to kick people off those waitqueues before
+ * closing the fd for good.
+ *
+ * If this driver used workqueues, the correct approach here would
+ * instead be to make the file descriptor select()able, and then just
+ * use select() instead of aio in userspace (thus allowing us to get
+ * away with one thread total and avoiding the recounting mess
+ * altogether).
+ */
Mandeep Singh Baines 2011/03/15 20:56:31 I've read the comment but I'm still not getting th
+ case IOCTL_QMI_CLOSE:
+ DBG("Tearing down QMI for service %lu", arg);
+ if (handle->cid == (u16)-1) {
+ DBG("no qmi cid");
+ return -EBADR;
+ }
+
+ file->private_data = NULL;
+ client_free(handle->dev, handle->cid);
+ kfree(handle);
+ return 0;
+ break;
case IOCTL_QMI_GET_DEVICE_VIDPID:
if (!arg) {
@@ -1056,60 +1076,14 @@ static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd
}
}
-static int devqmi_close(struct file *file, fl_owner_t ftable)
+static int devqmi_release(struct inode *inode, struct file *file)
{
struct qmihandle *handle = (struct qmihandle *)file->private_data;
- struct task_struct *task;
- struct fdtable *fdtable;
- int count = 0;
- int used = 0;
- unsigned long flags;
-
- if (!handle) {
- DBG("bad file data\n");
- return -EBADF;
- }
-
- if (file_count(file) != 1) {
- rcu_read_lock();
- for_each_process(task) {
- if (!task || !task->files)
- continue;
- spin_lock_irqsave(&task->files->file_lock, flags);
- fdtable = files_fdtable(task->files);
- for (count = 0; count < fdtable->max_fds; count++) {
- /* Before this function was called, this file was removed
- * from our task's file table so if we find it in a file
- * table then it is being used by another task
- */
- if (fdtable->fd[count] == file) {
- used++;
- break;
- }
- }
- spin_unlock_irqrestore(&task->files->file_lock, flags);
- }
- rcu_read_unlock();
-
- if (used > 0) {
- DBG("not closing, as this FD is open by %d other process\n", used);
- return 0;
- }
- }
-
- if (!device_valid(handle->dev)) {
- DBG("Invalid device! Updating f_ops\n");
- file->f_op = file->f_dentry->d_inode->i_fop;
- return -ENXIO;
- }
-
- DBG("0x%04X\n", handle->cid);
-
+ if (!handle)
+ return 0;
file->private_data = NULL;
-
if (handle->cid != (u16)-1)
client_free(handle->dev, handle->cid);
-
kfree(handle);
return 0;
}
@@ -1128,8 +1102,7 @@ static ssize_t devqmi_read(struct file *file, char __user *buf, size_t size,
}
if (!device_valid(handle->dev)) {
- DBG("Invalid device! Updating f_ops\n");
- file->f_op = file->f_dentry->d_inode->i_fop;
+ DBG("Invalid device!\n");
return -ENXIO;
}
@@ -1287,11 +1260,6 @@ void qc_deregister(struct qcusbnet *dev)
unsigned long flags;
int count = 0;
- if (!device_valid(dev)) {
- DBG("wrong device\n");
- return;
- }
-
list_for_each_safe(node, tmp, &dev->qmi.clients) {
client = list_entry(node, struct client, node);
DBG("release 0x%04X\n", client->cid);
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698