USB: usbtmc can do IO to device after disconnect
authorOliver Neukum <oliver@neukum.org>
Thu, 2 Jul 2009 09:36:30 +0000 (11:36 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 23 Sep 2009 13:46:28 +0000 (06:46 -0700)
usbtmc will happily complete read/write requests even after disconnect
has returned. The fix is to introduce a flag.

Signed-off-by: Oliver Neukum <oliver@neukum.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/class/usbtmc.c

index b09a527f73411499e2ab712c0f4d1b6f7d2c1946..0c9df97f677594620379186a0a3ac6c2aafe125d 100644 (file)
@@ -86,6 +86,8 @@ struct usbtmc_device_data {
        bool TermCharEnabled;
        bool auto_abort;
 
+       bool zombie; /* fd of disconnected device */
+
        struct usbtmc_dev_capabilities  capabilities;
        struct kref kref;
        struct mutex io_mutex;  /* only one i/o function running at a time */
@@ -384,6 +386,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
                return -ENOMEM;
 
        mutex_lock(&data->io_mutex);
+       if (data->zombie) {
+               retval = -ENODEV;
+               goto exit;
+       }
 
        remaining = count;
        done = 0;
@@ -496,6 +502,10 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
                return -ENOMEM;
 
        mutex_lock(&data->io_mutex);
+       if (data->zombie) {
+               retval = -ENODEV;
+               goto exit;
+       }
 
        remaining = count;
        done = 0;
@@ -925,6 +935,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
        data = file->private_data;
        mutex_lock(&data->io_mutex);
+       if (data->zombie) {
+               retval = -ENODEV;
+               goto skip_io_on_zombie;
+       }
 
        switch (cmd) {
        case USBTMC_IOCTL_CLEAR_OUT_HALT:
@@ -952,6 +966,7 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                break;
        }
 
+skip_io_on_zombie:
        mutex_unlock(&data->io_mutex);
        return retval;
 }
@@ -995,6 +1010,7 @@ static int usbtmc_probe(struct usb_interface *intf,
        usb_set_intfdata(intf, data);
        kref_init(&data->kref);
        mutex_init(&data->io_mutex);
+       data->zombie = 0;
 
        /* Initialize USBTMC bTag and other fields */
        data->bTag      = 1;
@@ -1065,6 +1081,9 @@ static void usbtmc_disconnect(struct usb_interface *intf)
        usb_deregister_dev(intf, &usbtmc_class);
        sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
        sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
+       mutex_lock(&data->io_mutex);
+       data->zombie = 1;
+       mutex_unlock(&data->io_mutex);
        kref_put(&data->kref, usbtmc_delete);
 }