aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/usb-serial.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2009-09-01 11:38:59 -0400
committerLive-CD User <linux@linux.site>2009-09-19 16:13:40 -0400
commit8bc2c1b2daf95029658868cb1427baea2da87139 (patch)
tree9895248e23de85d55a4d4ec9234aec7e58de285b /drivers/usb/serial/usb-serial.c
parentf5b0953a89fa3407fb293cc54ead7d8feec489e4 (diff)
usb-serial: change logic of serial lookups
This patch (as1286) changes usb_serial_get_by_index(). Now the routine will check whether the serial device has been disconnected; if it has then the return value will be NULL. If the device hasn't been disconnected then the routine will return with serial->disc_mutex held, so that the caller can use the structure without fear of racing against driver unloads. This permits the scope of table_mutex in destroy_serial() to be reduced. Instead of protecting the entire function, it suffices to protect the part that actually uses serial_table[], i.e., the call to return_serial(). There's no longer any danger of the refcount being incremented after it reaches 0 (which was the reason for having the large scope previously), because it can't reach 0 until the serial device has been disconnected. Also, the patch makes serial_install() check that serial is non-NULL before attempting to use it. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/usb-serial.c')
-rw-r--r--drivers/usb/serial/usb-serial.c31
1 files changed, 23 insertions, 8 deletions
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 266dc583867b..87802ea8bbc8 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -66,6 +66,11 @@ static struct usb_serial *serial_table[SERIAL_TTY_MINORS];
66static DEFINE_MUTEX(table_lock); 66static DEFINE_MUTEX(table_lock);
67static LIST_HEAD(usb_serial_driver_list); 67static LIST_HEAD(usb_serial_driver_list);
68 68
69/*
70 * Look up the serial structure. If it is found and it hasn't been
71 * disconnected, return with its disc_mutex held and its refcount
72 * incremented. Otherwise return NULL.
73 */
69struct usb_serial *usb_serial_get_by_index(unsigned index) 74struct usb_serial *usb_serial_get_by_index(unsigned index)
70{ 75{
71 struct usb_serial *serial; 76 struct usb_serial *serial;
@@ -73,8 +78,15 @@ struct usb_serial *usb_serial_get_by_index(unsigned index)
73 mutex_lock(&table_lock); 78 mutex_lock(&table_lock);
74 serial = serial_table[index]; 79 serial = serial_table[index];
75 80
76 if (serial) 81 if (serial) {
77 kref_get(&serial->kref); 82 mutex_lock(&serial->disc_mutex);
83 if (serial->disconnected) {
84 mutex_unlock(&serial->disc_mutex);
85 serial = NULL;
86 } else {
87 kref_get(&serial->kref);
88 }
89 }
78 mutex_unlock(&table_lock); 90 mutex_unlock(&table_lock);
79 return serial; 91 return serial;
80} 92}
@@ -123,8 +135,10 @@ static void return_serial(struct usb_serial *serial)
123 135
124 dbg("%s", __func__); 136 dbg("%s", __func__);
125 137
138 mutex_lock(&table_lock);
126 for (i = 0; i < serial->num_ports; ++i) 139 for (i = 0; i < serial->num_ports; ++i)
127 serial_table[serial->minor + i] = NULL; 140 serial_table[serial->minor + i] = NULL;
141 mutex_unlock(&table_lock);
128} 142}
129 143
130static void destroy_serial(struct kref *kref) 144static void destroy_serial(struct kref *kref)
@@ -158,9 +172,7 @@ static void destroy_serial(struct kref *kref)
158 172
159void usb_serial_put(struct usb_serial *serial) 173void usb_serial_put(struct usb_serial *serial)
160{ 174{
161 mutex_lock(&table_lock);
162 kref_put(&serial->kref, destroy_serial); 175 kref_put(&serial->kref, destroy_serial);
163 mutex_unlock(&table_lock);
164} 176}
165 177
166/***************************************************************************** 178/*****************************************************************************
@@ -190,9 +202,12 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
190 return retval; 202 return retval;
191 /* allow the driver to update it */ 203 /* allow the driver to update it */
192 serial = usb_serial_get_by_index(tty->index); 204 serial = usb_serial_get_by_index(tty->index);
193 if (serial->type->init_termios) 205 if (serial) {
194 serial->type->init_termios(tty); 206 if (serial->type->init_termios)
195 usb_serial_put(serial); 207 serial->type->init_termios(tty);
208 usb_serial_put(serial);
209 mutex_unlock(&serial->disc_mutex);
210 }
196 } 211 }
197 /* Final install (we use the default method) */ 212 /* Final install (we use the default method) */
198 tty_driver_kref_get(driver); 213 tty_driver_kref_get(driver);
@@ -218,7 +233,6 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
218 return -ENODEV; 233 return -ENODEV;
219 } 234 }
220 235
221 mutex_lock(&serial->disc_mutex);
222 portNumber = tty->index - serial->minor; 236 portNumber = tty->index - serial->minor;
223 port = serial->port[portNumber]; 237 port = serial->port[portNumber];
224 if (!port || serial->disconnected) 238 if (!port || serial->disconnected)
@@ -529,6 +543,7 @@ static int serial_proc_show(struct seq_file *m, void *v)
529 543
530 seq_putc(m, '\n'); 544 seq_putc(m, '\n');
531 usb_serial_put(serial); 545 usb_serial_put(serial);
546 mutex_unlock(&serial->disc_mutex);
532 } 547 }
533 return 0; 548 return 0;
534} 549}