diff options
author | Oliver Neukum <oliver@neukum.org> | 2007-07-24 09:13:42 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-30 16:27:46 -0400 |
commit | 3ddad8232c3802f7a602d1ea24938a8067114479 (patch) | |
tree | ba648621b4c4df0846e222c6c81843bca6077b55 /drivers/usb | |
parent | f42449003114cc17cda0458c14f2deadfadf9f63 (diff) |
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>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 17 |
1 files changed, 8 insertions, 9 deletions
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 5e1cf78c7786..9bf01a5efc84 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
@@ -60,19 +60,19 @@ static struct usb_driver usb_serial_driver = { | |||
60 | 60 | ||
61 | static int debug; | 61 | static int debug; |
62 | static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ | 62 | static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ |
63 | static spinlock_t table_lock; | 63 | static DEFINE_MUTEX(table_lock); |
64 | static LIST_HEAD(usb_serial_driver_list); | 64 | static LIST_HEAD(usb_serial_driver_list); |
65 | 65 | ||
66 | struct usb_serial *usb_serial_get_by_index(unsigned index) | 66 | struct usb_serial *usb_serial_get_by_index(unsigned index) |
67 | { | 67 | { |
68 | struct usb_serial *serial; | 68 | struct usb_serial *serial; |
69 | 69 | ||
70 | spin_lock(&table_lock); | 70 | mutex_lock(&table_lock); |
71 | serial = serial_table[index]; | 71 | serial = serial_table[index]; |
72 | 72 | ||
73 | if (serial) | 73 | if (serial) |
74 | kref_get(&serial->kref); | 74 | kref_get(&serial->kref); |
75 | spin_unlock(&table_lock); | 75 | mutex_unlock(&table_lock); |
76 | return serial; | 76 | return serial; |
77 | } | 77 | } |
78 | 78 | ||
@@ -84,7 +84,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po | |||
84 | dbg("%s %d", __FUNCTION__, num_ports); | 84 | dbg("%s %d", __FUNCTION__, num_ports); |
85 | 85 | ||
86 | *minor = 0; | 86 | *minor = 0; |
87 | spin_lock(&table_lock); | 87 | mutex_lock(&table_lock); |
88 | for (i = 0; i < SERIAL_TTY_MINORS; ++i) { | 88 | for (i = 0; i < SERIAL_TTY_MINORS; ++i) { |
89 | if (serial_table[i]) | 89 | if (serial_table[i]) |
90 | continue; | 90 | continue; |
@@ -106,10 +106,10 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po | |||
106 | serial_table[i] = serial; | 106 | serial_table[i] = serial; |
107 | serial->port[j++]->number = i; | 107 | serial->port[j++]->number = i; |
108 | } | 108 | } |
109 | spin_unlock(&table_lock); | 109 | mutex_unlock(&table_lock); |
110 | return serial; | 110 | return serial; |
111 | } | 111 | } |
112 | spin_unlock(&table_lock); | 112 | mutex_unlock(&table_lock); |
113 | return NULL; | 113 | return NULL; |
114 | } | 114 | } |
115 | 115 | ||
@@ -172,9 +172,9 @@ static void destroy_serial(struct kref *kref) | |||
172 | 172 | ||
173 | void usb_serial_put(struct usb_serial *serial) | 173 | void usb_serial_put(struct usb_serial *serial) |
174 | { | 174 | { |
175 | spin_lock(&table_lock); | 175 | mutex_lock(&table_lock); |
176 | kref_put(&serial->kref, destroy_serial); | 176 | kref_put(&serial->kref, destroy_serial); |
177 | spin_unlock(&table_lock); | 177 | mutex_unlock(&table_lock); |
178 | } | 178 | } |
179 | 179 | ||
180 | /***************************************************************************** | 180 | /***************************************************************************** |
@@ -1129,7 +1129,6 @@ static int __init usb_serial_init(void) | |||
1129 | return -ENOMEM; | 1129 | return -ENOMEM; |
1130 | 1130 | ||
1131 | /* Initialize our global data */ | 1131 | /* Initialize our global data */ |
1132 | spin_lock_init(&table_lock); | ||
1133 | for (i = 0; i < SERIAL_TTY_MINORS; ++i) { | 1132 | for (i = 0; i < SERIAL_TTY_MINORS; ++i) { |
1134 | serial_table[i] = NULL; | 1133 | serial_table[i] = NULL; |
1135 | } | 1134 | } |