aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.de>2007-01-13 01:29:26 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2007-02-07 18:44:38 -0500
commit34ef50e5b1f96c2d8c0f3d28b7d407743806256c (patch)
treebdf5fe45a270ebd77c895c7563c3fbf4c230019a /drivers/usb/serial
parentfdcba53e2d58272bcdb5f1fad694602ccf02ad46 (diff)
USB: race fixes for usb-serial step 1
- introduce a spinlock for serial_table to eliminate the window between looking up a device and getting a reference - delay inscription of a new device into serial_table until it is fully initialised - make sure disconnect() kills all URBs to avoid leckage across a soft unbind Signed-off-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/usb-serial.c44
1 files changed, 31 insertions, 13 deletions
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 90beb5c50e59..3780362eb9f0 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -59,14 +59,19 @@ static struct usb_driver usb_serial_driver = {
59 59
60static int debug; 60static int debug;
61static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ 61static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
62static spinlock_t table_lock;
62static LIST_HEAD(usb_serial_driver_list); 63static LIST_HEAD(usb_serial_driver_list);
63 64
64struct usb_serial *usb_serial_get_by_index(unsigned index) 65struct usb_serial *usb_serial_get_by_index(unsigned index)
65{ 66{
66 struct usb_serial *serial = serial_table[index]; 67 struct usb_serial *serial;
68
69 spin_lock(&table_lock);
70 serial = serial_table[index];
67 71
68 if (serial) 72 if (serial)
69 kref_get(&serial->kref); 73 kref_get(&serial->kref);
74 spin_unlock(&table_lock);
70 return serial; 75 return serial;
71} 76}
72 77
@@ -78,6 +83,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
78 dbg("%s %d", __FUNCTION__, num_ports); 83 dbg("%s %d", __FUNCTION__, num_ports);
79 84
80 *minor = 0; 85 *minor = 0;
86 spin_lock(&table_lock);
81 for (i = 0; i < SERIAL_TTY_MINORS; ++i) { 87 for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
82 if (serial_table[i]) 88 if (serial_table[i])
83 continue; 89 continue;
@@ -96,8 +102,10 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
96 dbg("%s - minor base = %d", __FUNCTION__, *minor); 102 dbg("%s - minor base = %d", __FUNCTION__, *minor);
97 for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) 103 for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
98 serial_table[i] = serial; 104 serial_table[i] = serial;
105 spin_unlock(&table_lock);
99 return serial; 106 return serial;
100 } 107 }
108 spin_unlock(&table_lock);
101 return NULL; 109 return NULL;
102} 110}
103 111
@@ -110,9 +118,11 @@ static void return_serial(struct usb_serial *serial)
110 if (serial == NULL) 118 if (serial == NULL)
111 return; 119 return;
112 120
121 spin_lock(&table_lock);
113 for (i = 0; i < serial->num_ports; ++i) { 122 for (i = 0; i < serial->num_ports; ++i) {
114 serial_table[serial->minor + i] = NULL; 123 serial_table[serial->minor + i] = NULL;
115 } 124 }
125 spin_unlock(&table_lock);
116} 126}
117 127
118static void destroy_serial(struct kref *kref) 128static void destroy_serial(struct kref *kref)
@@ -559,15 +569,20 @@ static void port_release(struct device *dev)
559 port_free(port); 569 port_free(port);
560} 570}
561 571
562static void port_free(struct usb_serial_port *port) 572static void kill_traffic(struct usb_serial_port *port)
563{ 573{
564 usb_kill_urb(port->read_urb); 574 usb_kill_urb(port->read_urb);
565 usb_free_urb(port->read_urb);
566 usb_kill_urb(port->write_urb); 575 usb_kill_urb(port->write_urb);
567 usb_free_urb(port->write_urb);
568 usb_kill_urb(port->interrupt_in_urb); 576 usb_kill_urb(port->interrupt_in_urb);
569 usb_free_urb(port->interrupt_in_urb);
570 usb_kill_urb(port->interrupt_out_urb); 577 usb_kill_urb(port->interrupt_out_urb);
578}
579
580static void port_free(struct usb_serial_port *port)
581{
582 kill_traffic(port);
583 usb_free_urb(port->read_urb);
584 usb_free_urb(port->write_urb);
585 usb_free_urb(port->interrupt_in_urb);
571 usb_free_urb(port->interrupt_out_urb); 586 usb_free_urb(port->interrupt_out_urb);
572 kfree(port->bulk_in_buffer); 587 kfree(port->bulk_in_buffer);
573 kfree(port->bulk_out_buffer); 588 kfree(port->bulk_out_buffer);
@@ -802,12 +817,6 @@ int usb_serial_probe(struct usb_interface *interface,
802 num_ports = type->num_ports; 817 num_ports = type->num_ports;
803 } 818 }
804 819
805 if (get_free_serial (serial, num_ports, &minor) == NULL) {
806 dev_err(&interface->dev, "No more free serial devices\n");
807 kfree (serial);
808 return -ENOMEM;
809 }
810
811 serial->minor = minor; 820 serial->minor = minor;
812 serial->num_ports = num_ports; 821 serial->num_ports = num_ports;
813 serial->num_bulk_in = num_bulk_in; 822 serial->num_bulk_in = num_bulk_in;
@@ -956,6 +965,11 @@ int usb_serial_probe(struct usb_interface *interface,
956 } 965 }
957 } 966 }
958 967
968 if (get_free_serial (serial, num_ports, &minor) == NULL) {
969 dev_err(&interface->dev, "No more free serial devices\n");
970 goto probe_error;
971 }
972
959 /* register all of the individual ports with the driver core */ 973 /* register all of the individual ports with the driver core */
960 for (i = 0; i < num_ports; ++i) { 974 for (i = 0; i < num_ports; ++i) {
961 port = serial->port[i]; 975 port = serial->port[i];
@@ -1033,8 +1047,11 @@ void usb_serial_disconnect(struct usb_interface *interface)
1033 if (serial) { 1047 if (serial) {
1034 for (i = 0; i < serial->num_ports; ++i) { 1048 for (i = 0; i < serial->num_ports; ++i) {
1035 port = serial->port[i]; 1049 port = serial->port[i];
1036 if (port && port->tty) 1050 if (port) {
1037 tty_hangup(port->tty); 1051 if (port->tty)
1052 tty_hangup(port->tty);
1053 kill_traffic(port);
1054 }
1038 } 1055 }
1039 /* let the last holder of this object 1056 /* let the last holder of this object
1040 * cause it to be cleaned up */ 1057 * cause it to be cleaned up */
@@ -1071,6 +1088,7 @@ static int __init usb_serial_init(void)
1071 return -ENOMEM; 1088 return -ENOMEM;
1072 1089
1073 /* Initialize our global data */ 1090 /* Initialize our global data */
1091 spin_lock_init(&table_lock);
1074 for (i = 0; i < SERIAL_TTY_MINORS; ++i) { 1092 for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
1075 serial_table[i] = NULL; 1093 serial_table[i] = NULL;
1076 } 1094 }