USB: fix BUG: sleeping function called from invalid context at /home/jeremy/hg/xen/paravirt/linux/drivers/usb/core/urb.c:524, in_atomic():1, irqs_disabled():0
Clearly there's a bug in drivers/usb/serial/usb-serial.c:usb_serial_put(). It shouldn't call kref_put() while holding a spinlock. Signed-off-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
f424490031
commit
3ddad8232c
@@ -60,19 +60,19 @@ static struct usb_driver usb_serial_driver = {
|
|||||||
|
|
||||||
static int debug;
|
static int debug;
|
||||||
static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
|
static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
|
||||||
static spinlock_t table_lock;
|
static DEFINE_MUTEX(table_lock);
|
||||||
static LIST_HEAD(usb_serial_driver_list);
|
static LIST_HEAD(usb_serial_driver_list);
|
||||||
|
|
||||||
struct usb_serial *usb_serial_get_by_index(unsigned index)
|
struct usb_serial *usb_serial_get_by_index(unsigned index)
|
||||||
{
|
{
|
||||||
struct usb_serial *serial;
|
struct usb_serial *serial;
|
||||||
|
|
||||||
spin_lock(&table_lock);
|
mutex_lock(&table_lock);
|
||||||
serial = serial_table[index];
|
serial = serial_table[index];
|
||||||
|
|
||||||
if (serial)
|
if (serial)
|
||||||
kref_get(&serial->kref);
|
kref_get(&serial->kref);
|
||||||
spin_unlock(&table_lock);
|
mutex_unlock(&table_lock);
|
||||||
return serial;
|
return serial;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
|
|||||||
dbg("%s %d", __FUNCTION__, num_ports);
|
dbg("%s %d", __FUNCTION__, num_ports);
|
||||||
|
|
||||||
*minor = 0;
|
*minor = 0;
|
||||||
spin_lock(&table_lock);
|
mutex_lock(&table_lock);
|
||||||
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
|
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
|
||||||
if (serial_table[i])
|
if (serial_table[i])
|
||||||
continue;
|
continue;
|
||||||
@@ -106,10 +106,10 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
|
|||||||
serial_table[i] = serial;
|
serial_table[i] = serial;
|
||||||
serial->port[j++]->number = i;
|
serial->port[j++]->number = i;
|
||||||
}
|
}
|
||||||
spin_unlock(&table_lock);
|
mutex_unlock(&table_lock);
|
||||||
return serial;
|
return serial;
|
||||||
}
|
}
|
||||||
spin_unlock(&table_lock);
|
mutex_unlock(&table_lock);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,9 +172,9 @@ static void destroy_serial(struct kref *kref)
|
|||||||
|
|
||||||
void usb_serial_put(struct usb_serial *serial)
|
void usb_serial_put(struct usb_serial *serial)
|
||||||
{
|
{
|
||||||
spin_lock(&table_lock);
|
mutex_lock(&table_lock);
|
||||||
kref_put(&serial->kref, destroy_serial);
|
kref_put(&serial->kref, destroy_serial);
|
||||||
spin_unlock(&table_lock);
|
mutex_unlock(&table_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
@@ -1129,7 +1129,6 @@ static int __init usb_serial_init(void)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Initialize our global data */
|
/* Initialize our global data */
|
||||||
spin_lock_init(&table_lock);
|
|
||||||
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
|
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
|
||||||
serial_table[i] = NULL;
|
serial_table[i] = NULL;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user