forked from luck/tmp_suning_uos_patched
USB: prevent char device open/deregister race
This patch (as908) adds central protection in usbcore for the prototypical race between opening and unregistering a char device. The spinlock used to protect the minor-numbers array is replaced with an rwsem, which can remain locked across a call to a driver's open() method. This guarantees that open() and deregister() will be mutually exclusive. The private locks currently used in several individual drivers for this purpose are no longer necessary, and the patch removes them. The following USB drivers are affected: usblcd, idmouse, auerswald, legousbtower, sisusbvga/sisusb, ldusb, adutux, iowarrior, and usb-skeleton. As a side effect of this change, usb_deregister_dev() must not be called while holding a lock that is acquired by open(). Unfortunately a number of drivers do this, but luckily the solution is simple: call usb_deregister_dev() before acquiring the lock. In addition to these changes (and their consequent code simplifications), the patch fixes a use-after-free bug in adutux and a race between open() and release() in iowarrior. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
55e5fdfa54
commit
d4ead16f50
@ -16,15 +16,15 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "usb.h"
|
||||
|
||||
#define MAX_USB_MINORS 256
|
||||
static const struct file_operations *usb_minors[MAX_USB_MINORS];
|
||||
static DEFINE_SPINLOCK(minor_lock);
|
||||
static DECLARE_RWSEM(minor_rwsem);
|
||||
|
||||
static int usb_open(struct inode * inode, struct file * file)
|
||||
{
|
||||
@ -33,14 +33,11 @@ static int usb_open(struct inode * inode, struct file * file)
|
||||
int err = -ENODEV;
|
||||
const struct file_operations *old_fops, *new_fops = NULL;
|
||||
|
||||
spin_lock (&minor_lock);
|
||||
down_read(&minor_rwsem);
|
||||
c = usb_minors[minor];
|
||||
|
||||
if (!c || !(new_fops = fops_get(c))) {
|
||||
spin_unlock(&minor_lock);
|
||||
return err;
|
||||
}
|
||||
spin_unlock(&minor_lock);
|
||||
if (!c || !(new_fops = fops_get(c)))
|
||||
goto done;
|
||||
|
||||
old_fops = file->f_op;
|
||||
file->f_op = new_fops;
|
||||
@ -52,6 +49,8 @@ static int usb_open(struct inode * inode, struct file * file)
|
||||
file->f_op = fops_get(old_fops);
|
||||
}
|
||||
fops_put(old_fops);
|
||||
done:
|
||||
up_read(&minor_rwsem);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -166,7 +165,7 @@ int usb_register_dev(struct usb_interface *intf,
|
||||
if (class_driver->fops == NULL)
|
||||
goto exit;
|
||||
|
||||
spin_lock (&minor_lock);
|
||||
down_write(&minor_rwsem);
|
||||
for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
|
||||
if (usb_minors[minor])
|
||||
continue;
|
||||
@ -176,7 +175,7 @@ int usb_register_dev(struct usb_interface *intf,
|
||||
retval = 0;
|
||||
break;
|
||||
}
|
||||
spin_unlock (&minor_lock);
|
||||
up_write(&minor_rwsem);
|
||||
|
||||
if (retval)
|
||||
goto exit;
|
||||
@ -197,9 +196,9 @@ int usb_register_dev(struct usb_interface *intf,
|
||||
intf->usb_dev = device_create(usb_class->class, &intf->dev,
|
||||
MKDEV(USB_MAJOR, minor), "%s", temp);
|
||||
if (IS_ERR(intf->usb_dev)) {
|
||||
spin_lock (&minor_lock);
|
||||
down_write(&minor_rwsem);
|
||||
usb_minors[intf->minor] = NULL;
|
||||
spin_unlock (&minor_lock);
|
||||
up_write(&minor_rwsem);
|
||||
retval = PTR_ERR(intf->usb_dev);
|
||||
}
|
||||
exit:
|
||||
@ -236,9 +235,9 @@ void usb_deregister_dev(struct usb_interface *intf,
|
||||
|
||||
dbg ("removing %d minor", intf->minor);
|
||||
|
||||
spin_lock (&minor_lock);
|
||||
down_write(&minor_rwsem);
|
||||
usb_minors[intf->minor] = NULL;
|
||||
spin_unlock (&minor_lock);
|
||||
up_write(&minor_rwsem);
|
||||
|
||||
snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
|
||||
device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
|
||||
@ -247,5 +246,3 @@ void usb_deregister_dev(struct usb_interface *intf,
|
||||
destroy_usb_class();
|
||||
}
|
||||
EXPORT_SYMBOL(usb_deregister_dev);
|
||||
|
||||
|
||||
|
@ -108,8 +108,6 @@ struct adu_device {
|
||||
struct urb* interrupt_out_urb;
|
||||
};
|
||||
|
||||
/* prevent races between open() and disconnect */
|
||||
static DEFINE_MUTEX(disconnect_mutex);
|
||||
static struct usb_driver adu_driver;
|
||||
|
||||
static void adu_debug_data(int level, const char *function, int size,
|
||||
@ -256,8 +254,6 @@ static int adu_open(struct inode *inode, struct file *file)
|
||||
|
||||
subminor = iminor(inode);
|
||||
|
||||
mutex_lock(&disconnect_mutex);
|
||||
|
||||
interface = usb_find_interface(&adu_driver, subminor);
|
||||
if (!interface) {
|
||||
err("%s - error, can't find device for minor %d",
|
||||
@ -306,7 +302,6 @@ static int adu_open(struct inode *inode, struct file *file)
|
||||
up(&dev->sem);
|
||||
|
||||
exit_no_device:
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
|
||||
|
||||
return retval;
|
||||
@ -318,12 +313,6 @@ static int adu_release_internal(struct adu_device *dev)
|
||||
|
||||
dbg(2," %s : enter", __FUNCTION__);
|
||||
|
||||
if (dev->udev == NULL) {
|
||||
/* the device was unplugged before the file was released */
|
||||
adu_delete(dev);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* decrement our usage count for the device */
|
||||
--dev->open_count;
|
||||
dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
|
||||
@ -332,7 +321,6 @@ static int adu_release_internal(struct adu_device *dev)
|
||||
dev->open_count = 0;
|
||||
}
|
||||
|
||||
exit:
|
||||
dbg(2," %s : leave", __FUNCTION__);
|
||||
return retval;
|
||||
}
|
||||
@ -367,8 +355,15 @@ static int adu_release(struct inode *inode, struct file *file)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* do the work */
|
||||
retval = adu_release_internal(dev);
|
||||
if (dev->udev == NULL) {
|
||||
/* the device was unplugged before the file was released */
|
||||
up(&dev->sem);
|
||||
adu_delete(dev);
|
||||
dev = NULL;
|
||||
} else {
|
||||
/* do the work */
|
||||
retval = adu_release_internal(dev);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (dev)
|
||||
@ -831,19 +826,17 @@ static void adu_disconnect(struct usb_interface *interface)
|
||||
|
||||
dbg(2," %s : enter", __FUNCTION__);
|
||||
|
||||
mutex_lock(&disconnect_mutex); /* not interruptible */
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
down(&dev->sem); /* not interruptible */
|
||||
|
||||
minor = dev->minor;
|
||||
|
||||
/* give back our minor */
|
||||
usb_deregister_dev(interface, &adu_class);
|
||||
dev->minor = 0;
|
||||
|
||||
down(&dev->sem); /* not interruptible */
|
||||
|
||||
/* if the device is not opened, then we clean up right now */
|
||||
dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
|
||||
if (!dev->open_count) {
|
||||
@ -854,8 +847,6 @@ static void adu_disconnect(struct usb_interface *interface)
|
||||
up(&dev->sem);
|
||||
}
|
||||
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
|
||||
dev_info(&interface->dev, "ADU device adutux%d now disconnected",
|
||||
(minor - ADU_MINOR_BASE));
|
||||
|
||||
|
@ -2034,12 +2034,12 @@ static void auerswald_disconnect (struct usb_interface *intf)
|
||||
if (!cp)
|
||||
return;
|
||||
|
||||
down (&cp->mutex);
|
||||
info ("device /dev/%s now disconnecting", cp->name);
|
||||
|
||||
/* give back our USB minor number */
|
||||
usb_deregister_dev(intf, &auerswald_class);
|
||||
|
||||
down (&cp->mutex);
|
||||
info ("device /dev/%s now disconnecting", cp->name);
|
||||
|
||||
/* Stop the interrupt endpoint */
|
||||
auerswald_int_release (cp);
|
||||
|
||||
|
@ -119,9 +119,6 @@ static struct usb_driver idmouse_driver = {
|
||||
.id_table = idmouse_table,
|
||||
};
|
||||
|
||||
/* prevent races between open() and disconnect() */
|
||||
static DEFINE_MUTEX(disconnect_mutex);
|
||||
|
||||
static int idmouse_create_image(struct usb_idmouse *dev)
|
||||
{
|
||||
int bytes_read;
|
||||
@ -211,21 +208,15 @@ static int idmouse_open(struct inode *inode, struct file *file)
|
||||
struct usb_interface *interface;
|
||||
int result;
|
||||
|
||||
/* prevent disconnects */
|
||||
mutex_lock(&disconnect_mutex);
|
||||
|
||||
/* get the interface from minor number and driver information */
|
||||
interface = usb_find_interface (&idmouse_driver, iminor (inode));
|
||||
if (!interface) {
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
if (!interface)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* get the device information block from the interface */
|
||||
dev = usb_get_intfdata(interface);
|
||||
if (!dev) {
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* lock this device */
|
||||
down(&dev->sem);
|
||||
@ -255,9 +246,6 @@ static int idmouse_open(struct inode *inode, struct file *file)
|
||||
|
||||
/* unlock this device */
|
||||
up(&dev->sem);
|
||||
|
||||
/* unlock the disconnect semaphore */
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -265,15 +253,10 @@ static int idmouse_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct usb_idmouse *dev;
|
||||
|
||||
/* prevent a race condition with open() */
|
||||
mutex_lock(&disconnect_mutex);
|
||||
|
||||
dev = file->private_data;
|
||||
|
||||
if (dev == NULL) {
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
if (dev == NULL)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* lock our device */
|
||||
down(&dev->sem);
|
||||
@ -281,7 +264,6 @@ static int idmouse_release(struct inode *inode, struct file *file)
|
||||
/* are we really open? */
|
||||
if (dev->open <= 0) {
|
||||
up(&dev->sem);
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -291,12 +273,9 @@ static int idmouse_release(struct inode *inode, struct file *file)
|
||||
/* the device was unplugged before the file was released */
|
||||
up(&dev->sem);
|
||||
idmouse_delete(dev);
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
return 0;
|
||||
} else {
|
||||
up(&dev->sem);
|
||||
}
|
||||
|
||||
up(&dev->sem);
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -391,30 +370,27 @@ static void idmouse_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_idmouse *dev;
|
||||
|
||||
/* prevent races with open() */
|
||||
mutex_lock(&disconnect_mutex);
|
||||
|
||||
/* get device structure */
|
||||
dev = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
/* lock it */
|
||||
down(&dev->sem);
|
||||
|
||||
/* give back our minor */
|
||||
usb_deregister_dev(interface, &idmouse_class);
|
||||
|
||||
/* lock it */
|
||||
down(&dev->sem);
|
||||
|
||||
/* prevent device read, write and ioctl */
|
||||
dev->present = 0;
|
||||
|
||||
/* unlock */
|
||||
up(&dev->sem);
|
||||
|
||||
/* if the device is opened, idmouse_release will clean this up */
|
||||
if (!dev->open)
|
||||
if (!dev->open) {
|
||||
up(&dev->sem);
|
||||
idmouse_delete(dev);
|
||||
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
} else {
|
||||
/* unlock */
|
||||
up(&dev->sem);
|
||||
}
|
||||
|
||||
info("%s disconnected", DRIVER_DESC);
|
||||
}
|
||||
|
@ -100,8 +100,6 @@ struct iowarrior {
|
||||
/*--------------*/
|
||||
/* globals */
|
||||
/*--------------*/
|
||||
/* prevent races between open() and disconnect() */
|
||||
static DECLARE_MUTEX(disconnect_sem);
|
||||
|
||||
/*
|
||||
* USB spec identifies 5 second timeouts.
|
||||
@ -600,22 +598,18 @@ static int iowarrior_open(struct inode *inode, struct file *file)
|
||||
|
||||
subminor = iminor(inode);
|
||||
|
||||
/* prevent disconnects */
|
||||
down(&disconnect_sem);
|
||||
|
||||
interface = usb_find_interface(&iowarrior_driver, subminor);
|
||||
if (!interface) {
|
||||
err("%s - error, can't find device for minor %d", __FUNCTION__,
|
||||
subminor);
|
||||
retval = -ENODEV;
|
||||
goto out;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
if (!dev) {
|
||||
retval = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
|
||||
/* Only one process can open each device, no sharing. */
|
||||
if (dev->opened) {
|
||||
@ -636,7 +630,7 @@ static int iowarrior_open(struct inode *inode, struct file *file)
|
||||
retval = 0;
|
||||
|
||||
out:
|
||||
up(&disconnect_sem);
|
||||
mutex_unlock(&dev->mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -868,19 +862,16 @@ static void iowarrior_disconnect(struct usb_interface *interface)
|
||||
struct iowarrior *dev;
|
||||
int minor;
|
||||
|
||||
/* prevent races with open() */
|
||||
down(&disconnect_sem);
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
|
||||
minor = dev->minor;
|
||||
|
||||
/* give back our minor */
|
||||
usb_deregister_dev(interface, &iowarrior_class);
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
|
||||
/* prevent device read, write and ioctl */
|
||||
dev->present = 0;
|
||||
|
||||
@ -898,7 +889,6 @@ static void iowarrior_disconnect(struct usb_interface *interface)
|
||||
/* no process is using the device, cleanup now */
|
||||
iowarrior_delete(dev);
|
||||
}
|
||||
up(&disconnect_sem);
|
||||
|
||||
dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n",
|
||||
minor - IOWARRIOR_MINOR_BASE);
|
||||
|
@ -176,9 +176,6 @@ struct ld_usb {
|
||||
int interrupt_out_busy;
|
||||
};
|
||||
|
||||
/* prevent races between open() and disconnect() */
|
||||
static DEFINE_MUTEX(disconnect_mutex);
|
||||
|
||||
static struct usb_driver ld_usb_driver;
|
||||
|
||||
/**
|
||||
@ -298,35 +295,28 @@ static int ld_usb_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ld_usb *dev;
|
||||
int subminor;
|
||||
int retval = 0;
|
||||
int retval;
|
||||
struct usb_interface *interface;
|
||||
|
||||
nonseekable_open(inode, file);
|
||||
subminor = iminor(inode);
|
||||
|
||||
mutex_lock(&disconnect_mutex);
|
||||
|
||||
interface = usb_find_interface(&ld_usb_driver, subminor);
|
||||
|
||||
if (!interface) {
|
||||
err("%s - error, can't find device for minor %d\n",
|
||||
__FUNCTION__, subminor);
|
||||
retval = -ENODEV;
|
||||
goto unlock_disconnect_exit;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
|
||||
if (!dev) {
|
||||
retval = -ENODEV;
|
||||
goto unlock_disconnect_exit;
|
||||
}
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
/* lock this device */
|
||||
if (down_interruptible(&dev->sem)) {
|
||||
retval = -ERESTARTSYS;
|
||||
goto unlock_disconnect_exit;
|
||||
}
|
||||
if (down_interruptible(&dev->sem))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
/* allow opening only once */
|
||||
if (dev->open_count) {
|
||||
@ -366,9 +356,6 @@ static int ld_usb_open(struct inode *inode, struct file *file)
|
||||
unlock_exit:
|
||||
up(&dev->sem);
|
||||
|
||||
unlock_disconnect_exit:
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -766,18 +753,16 @@ static void ld_usb_disconnect(struct usb_interface *intf)
|
||||
struct ld_usb *dev;
|
||||
int minor;
|
||||
|
||||
mutex_lock(&disconnect_mutex);
|
||||
|
||||
dev = usb_get_intfdata(intf);
|
||||
usb_set_intfdata(intf, NULL);
|
||||
|
||||
down(&dev->sem);
|
||||
|
||||
minor = intf->minor;
|
||||
|
||||
/* give back our minor */
|
||||
usb_deregister_dev(intf, &ld_usb_class);
|
||||
|
||||
down(&dev->sem);
|
||||
|
||||
/* if the device is not opened, then we clean up right now */
|
||||
if (!dev->open_count) {
|
||||
up(&dev->sem);
|
||||
@ -787,8 +772,6 @@ static void ld_usb_disconnect(struct usb_interface *intf)
|
||||
up(&dev->sem);
|
||||
}
|
||||
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
|
||||
dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
|
||||
(minor - USB_LD_MINOR_BASE));
|
||||
}
|
||||
|
@ -254,9 +254,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_devic
|
||||
static void tower_disconnect (struct usb_interface *interface);
|
||||
|
||||
|
||||
/* prevent races between open() and disconnect */
|
||||
static DEFINE_MUTEX (disconnect_mutex);
|
||||
|
||||
/* file operations needed when we register this driver */
|
||||
static const struct file_operations tower_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
@ -344,28 +341,26 @@ static int tower_open (struct inode *inode, struct file *file)
|
||||
nonseekable_open(inode, file);
|
||||
subminor = iminor(inode);
|
||||
|
||||
mutex_lock (&disconnect_mutex);
|
||||
|
||||
interface = usb_find_interface (&tower_driver, subminor);
|
||||
|
||||
if (!interface) {
|
||||
err ("%s - error, can't find device for minor %d",
|
||||
__FUNCTION__, subminor);
|
||||
retval = -ENODEV;
|
||||
goto unlock_disconnect_exit;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
|
||||
if (!dev) {
|
||||
retval = -ENODEV;
|
||||
goto unlock_disconnect_exit;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* lock this device */
|
||||
if (down_interruptible (&dev->sem)) {
|
||||
retval = -ERESTARTSYS;
|
||||
goto unlock_disconnect_exit;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* allow opening only once */
|
||||
@ -421,9 +416,7 @@ static int tower_open (struct inode *inode, struct file *file)
|
||||
unlock_exit:
|
||||
up (&dev->sem);
|
||||
|
||||
unlock_disconnect_exit:
|
||||
mutex_unlock (&disconnect_mutex);
|
||||
|
||||
exit:
|
||||
dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval);
|
||||
|
||||
return retval;
|
||||
@ -993,19 +986,16 @@ static void tower_disconnect (struct usb_interface *interface)
|
||||
|
||||
dbg(2, "%s: enter", __FUNCTION__);
|
||||
|
||||
mutex_lock (&disconnect_mutex);
|
||||
|
||||
dev = usb_get_intfdata (interface);
|
||||
usb_set_intfdata (interface, NULL);
|
||||
|
||||
|
||||
down (&dev->sem);
|
||||
|
||||
minor = dev->minor;
|
||||
|
||||
/* give back our minor */
|
||||
usb_deregister_dev (interface, &tower_class);
|
||||
|
||||
down (&dev->sem);
|
||||
|
||||
/* if the device is not opened, then we clean up right now */
|
||||
if (!dev->open_count) {
|
||||
up (&dev->sem);
|
||||
@ -1015,8 +1005,6 @@ static void tower_disconnect (struct usb_interface *interface)
|
||||
up (&dev->sem);
|
||||
}
|
||||
|
||||
mutex_unlock (&disconnect_mutex);
|
||||
|
||||
info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));
|
||||
|
||||
dbg(2, "%s: leave", __FUNCTION__);
|
||||
|
@ -72,8 +72,6 @@ MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES
|
||||
|
||||
static struct usb_driver sisusb_driver;
|
||||
|
||||
DEFINE_MUTEX(disconnect_mutex);
|
||||
|
||||
static void
|
||||
sisusb_free_buffers(struct sisusb_usb_data *sisusb)
|
||||
{
|
||||
@ -2511,31 +2509,24 @@ sisusb_open(struct inode *inode, struct file *file)
|
||||
struct usb_interface *interface;
|
||||
int subminor = iminor(inode);
|
||||
|
||||
mutex_lock(&disconnect_mutex);
|
||||
|
||||
if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
|
||||
printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
|
||||
subminor);
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!(sisusb = usb_get_intfdata(interface))) {
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
if (!(sisusb = usb_get_intfdata(interface)))
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mutex_lock(&sisusb->lock);
|
||||
|
||||
if (!sisusb->present || !sisusb->ready) {
|
||||
mutex_unlock(&sisusb->lock);
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (sisusb->isopen) {
|
||||
mutex_unlock(&sisusb->lock);
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@ -2543,7 +2534,6 @@ sisusb_open(struct inode *inode, struct file *file)
|
||||
if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
|
||||
if (sisusb_init_gfxdevice(sisusb, 0)) {
|
||||
mutex_unlock(&sisusb->lock);
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
printk(KERN_ERR
|
||||
"sisusbvga[%d]: Failed to initialize "
|
||||
"device\n",
|
||||
@ -2552,7 +2542,6 @@ sisusb_open(struct inode *inode, struct file *file)
|
||||
}
|
||||
} else {
|
||||
mutex_unlock(&sisusb->lock);
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
printk(KERN_ERR
|
||||
"sisusbvga[%d]: Device not attached to "
|
||||
"USB 2.0 hub\n",
|
||||
@ -2570,8 +2559,6 @@ sisusb_open(struct inode *inode, struct file *file)
|
||||
|
||||
mutex_unlock(&sisusb->lock);
|
||||
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2601,12 +2588,8 @@ sisusb_release(struct inode *inode, struct file *file)
|
||||
struct sisusb_usb_data *sisusb;
|
||||
int myminor;
|
||||
|
||||
mutex_lock(&disconnect_mutex);
|
||||
|
||||
if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mutex_lock(&sisusb->lock);
|
||||
|
||||
@ -2626,8 +2609,6 @@ sisusb_release(struct inode *inode, struct file *file)
|
||||
/* decrement the usage count on our device */
|
||||
kref_put(&sisusb->kref, sisusb_delete);
|
||||
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3383,12 +3364,9 @@ static void sisusb_disconnect(struct usb_interface *intf)
|
||||
sisusb_console_exit(sisusb);
|
||||
#endif
|
||||
|
||||
/* The above code doesn't need the disconnect
|
||||
* semaphore to be down; its meaning is to
|
||||
* protect all other routines from the disconnect
|
||||
* case, not the other way round.
|
||||
*/
|
||||
mutex_lock(&disconnect_mutex);
|
||||
minor = sisusb->minor;
|
||||
|
||||
usb_deregister_dev(intf, &usb_sisusb_class);
|
||||
|
||||
mutex_lock(&sisusb->lock);
|
||||
|
||||
@ -3396,12 +3374,8 @@ static void sisusb_disconnect(struct usb_interface *intf)
|
||||
if (!sisusb_wait_all_out_complete(sisusb))
|
||||
sisusb_kill_all_busy(sisusb);
|
||||
|
||||
minor = sisusb->minor;
|
||||
|
||||
usb_set_intfdata(intf, NULL);
|
||||
|
||||
usb_deregister_dev(intf, &usb_sisusb_class);
|
||||
|
||||
#ifdef SISUSB_OLD_CONFIG_COMPAT
|
||||
if (sisusb->ioctl32registered) {
|
||||
int ret;
|
||||
@ -3426,8 +3400,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
|
||||
/* decrement our usage count */
|
||||
kref_put(&sisusb->kref, sisusb_delete);
|
||||
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
|
||||
printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
|
||||
}
|
||||
|
||||
|
@ -214,18 +214,13 @@ sisusbcon_init(struct vc_data *c, int init)
|
||||
* are set up/restored.
|
||||
*/
|
||||
|
||||
mutex_lock(&disconnect_mutex);
|
||||
|
||||
if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
if (!(sisusb = sisusb_get_sisusb(c->vc_num)))
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&sisusb->lock);
|
||||
|
||||
if (!sisusb_sisusb_valid(sisusb)) {
|
||||
mutex_unlock(&sisusb->lock);
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -264,8 +259,6 @@ sisusbcon_init(struct vc_data *c, int init)
|
||||
|
||||
mutex_unlock(&sisusb->lock);
|
||||
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
|
||||
if (init) {
|
||||
c->vc_cols = cols;
|
||||
c->vc_rows = rows;
|
||||
@ -284,12 +277,8 @@ sisusbcon_deinit(struct vc_data *c)
|
||||
* and others, ie not under our control.
|
||||
*/
|
||||
|
||||
mutex_lock(&disconnect_mutex);
|
||||
|
||||
if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
if (!(sisusb = sisusb_get_sisusb(c->vc_num)))
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&sisusb->lock);
|
||||
|
||||
@ -314,8 +303,6 @@ sisusbcon_deinit(struct vc_data *c)
|
||||
|
||||
/* decrement the usage count on our sisusb */
|
||||
kref_put(&sisusb->kref, sisusb_delete);
|
||||
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
}
|
||||
|
||||
/* interface routine */
|
||||
@ -1490,14 +1477,11 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
|
||||
{
|
||||
int i, ret, minor = sisusb->minor;
|
||||
|
||||
mutex_lock(&disconnect_mutex);
|
||||
|
||||
mutex_lock(&sisusb->lock);
|
||||
|
||||
/* Erm.. that should not happen */
|
||||
if (sisusb->haveconsole || !sisusb->SiS_Pr) {
|
||||
mutex_unlock(&sisusb->lock);
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1508,14 +1492,12 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
|
||||
first > MAX_NR_CONSOLES ||
|
||||
last > MAX_NR_CONSOLES) {
|
||||
mutex_unlock(&sisusb->lock);
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If gfxcore not initialized or no consoles given, quit graciously */
|
||||
if (!sisusb->gfxinit || first < 1 || last < 1) {
|
||||
mutex_unlock(&sisusb->lock);
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1526,7 +1508,6 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
|
||||
/* Set up text mode (and upload default font) */
|
||||
if (sisusb_reset_text_mode(sisusb, 1)) {
|
||||
mutex_unlock(&sisusb->lock);
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
printk(KERN_ERR
|
||||
"sisusbvga[%d]: Failed to set up text mode\n",
|
||||
minor);
|
||||
@ -1550,7 +1531,6 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
|
||||
/* Allocate screen buffer */
|
||||
if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
|
||||
mutex_unlock(&sisusb->lock);
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
printk(KERN_ERR
|
||||
"sisusbvga[%d]: Failed to allocate screen buffer\n",
|
||||
minor);
|
||||
@ -1558,7 +1538,6 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
|
||||
}
|
||||
|
||||
mutex_unlock(&sisusb->lock);
|
||||
mutex_unlock(&disconnect_mutex);
|
||||
|
||||
/* Now grab the desired console(s) */
|
||||
ret = take_over_console(&sisusb_con, first - 1, last - 1, 0);
|
||||
|
@ -808,8 +808,6 @@ static const struct SiS_VCLKData SiSUSB_VCLKData[] =
|
||||
{ 0x2b,0xc2, 35} /* 0x71 768@576@60 */
|
||||
};
|
||||
|
||||
extern struct mutex disconnect_mutex;
|
||||
|
||||
int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
|
||||
int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
|
||||
|
||||
|
@ -51,7 +51,6 @@ struct usb_lcd {
|
||||
#define USB_LCD_CONCURRENT_WRITES 5
|
||||
|
||||
static struct usb_driver lcd_driver;
|
||||
static DEFINE_MUTEX(usb_lcd_open_mutex);
|
||||
|
||||
|
||||
static void lcd_delete(struct kref *kref)
|
||||
@ -69,24 +68,19 @@ static int lcd_open(struct inode *inode, struct file *file)
|
||||
struct usb_lcd *dev;
|
||||
struct usb_interface *interface;
|
||||
int subminor;
|
||||
int retval = 0;
|
||||
|
||||
subminor = iminor(inode);
|
||||
|
||||
mutex_lock(&usb_lcd_open_mutex);
|
||||
interface = usb_find_interface(&lcd_driver, subminor);
|
||||
if (!interface) {
|
||||
err ("USBLCD: %s - error, can't find device for minor %d",
|
||||
__FUNCTION__, subminor);
|
||||
retval = -ENODEV;
|
||||
goto exit;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
if (!dev) {
|
||||
retval = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
/* increment our usage count for the device */
|
||||
kref_get(&dev->kref);
|
||||
@ -94,9 +88,7 @@ static int lcd_open(struct inode *inode, struct file *file)
|
||||
/* save our object in the file's private structure */
|
||||
file->private_data = dev;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&usb_lcd_open_mutex);
|
||||
return retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lcd_release(struct inode *inode, struct file *file)
|
||||
@ -363,17 +355,12 @@ static void lcd_disconnect(struct usb_interface *interface)
|
||||
struct usb_lcd *dev;
|
||||
int minor = interface->minor;
|
||||
|
||||
/* prevent skel_open() from racing skel_disconnect() */
|
||||
mutex_lock(&usb_lcd_open_mutex);
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
/* give back our minor */
|
||||
usb_deregister_dev(interface, &lcd_class);
|
||||
|
||||
mutex_unlock(&usb_lcd_open_mutex);
|
||||
|
||||
/* decrement our usage count */
|
||||
kref_put(&dev->kref, lcd_delete);
|
||||
|
||||
|
@ -34,9 +34,6 @@ static struct usb_device_id skel_table [] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, skel_table);
|
||||
|
||||
/* to prevent a race between open and disconnect */
|
||||
static DEFINE_MUTEX(skel_open_lock);
|
||||
|
||||
|
||||
/* Get a minor range for your devices from the usb maintainer */
|
||||
#define USB_SKEL_MINOR_BASE 192
|
||||
@ -83,10 +80,8 @@ static int skel_open(struct inode *inode, struct file *file)
|
||||
|
||||
subminor = iminor(inode);
|
||||
|
||||
mutex_lock(&skel_open_lock);
|
||||
interface = usb_find_interface(&skel_driver, subminor);
|
||||
if (!interface) {
|
||||
mutex_unlock(&skel_open_lock);
|
||||
err ("%s - error, can't find device for minor %d",
|
||||
__FUNCTION__, subminor);
|
||||
retval = -ENODEV;
|
||||
@ -95,15 +90,12 @@ static int skel_open(struct inode *inode, struct file *file)
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
if (!dev) {
|
||||
mutex_unlock(&skel_open_lock);
|
||||
retval = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* increment our usage count for the device */
|
||||
kref_get(&dev->kref);
|
||||
/* now we can drop the lock */
|
||||
mutex_unlock(&skel_open_lock);
|
||||
|
||||
/* prevent the device from being autosuspended */
|
||||
retval = usb_autopm_get_interface(interface);
|
||||
@ -368,23 +360,17 @@ static void skel_disconnect(struct usb_interface *interface)
|
||||
struct usb_skel *dev;
|
||||
int minor = interface->minor;
|
||||
|
||||
/* prevent skel_open() from racing skel_disconnect() */
|
||||
mutex_lock(&skel_open_lock);
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
/* give back our minor */
|
||||
usb_deregister_dev(interface, &skel_class);
|
||||
mutex_unlock(&skel_open_lock);
|
||||
|
||||
/* prevent more I/O from starting */
|
||||
mutex_lock(&dev->io_mutex);
|
||||
dev->interface = NULL;
|
||||
mutex_unlock(&dev->io_mutex);
|
||||
|
||||
|
||||
|
||||
/* decrement our usage count */
|
||||
kref_put(&dev->kref, skel_delete);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user