Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 156952 Details for
Bug 243067
Kernel panic using USB serial I/O
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
Test patch 1 - backport
linux-2.6.9-50.EL-243067-1.diff (text/plain), 15.95 KB, created by
Pete Zaitcev
on 2007-06-14 04:56:32 UTC
(
hide
)
Description:
Test patch 1 - backport
Filename:
MIME Type:
Creator:
Pete Zaitcev
Created:
2007-06-14 04:56:32 UTC
Size:
15.95 KB
patch
obsolete
>diff -urp -X dontdiff linux-2.6.9-50.EL/drivers/usb/serial/ftdi_sio.c linux-2.6.9-50.EL.z1/drivers/usb/serial/ftdi_sio.c >--- linux-2.6.9-50.EL/drivers/usb/serial/ftdi_sio.c 2007-03-06 18:45:52.000000000 -0800 >+++ linux-2.6.9-50.EL.z1/drivers/usb/serial/ftdi_sio.c 2007-06-13 19:54:55.000000000 -0700 >@@ -1392,7 +1392,6 @@ static void ftdi_shutdown (struct usb_se > > static int ftdi_open (struct usb_serial_port *port, struct file *filp) > { /* ftdi_open */ >- struct termios tmp_termios; > struct usb_device *dev = port->serial->dev; > struct ftdi_private *priv = usb_get_serial_port_data(port); > unsigned long flags; >@@ -1402,8 +1401,8 @@ static int ftdi_open (struct usb_serial > > dbg("%s", __FUNCTION__); > >- >- port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; >+ if (port->tty) >+ port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; > > /* No error checking for this (will get errors later anyway) */ > /* See ftdi_sio.h for description of what is reset */ >@@ -1417,7 +1416,8 @@ static int ftdi_open (struct usb_serial > This is same behaviour as serial.c/rs_open() - Kuba */ > > /* ftdi_set_termios will send usb control messages */ >- ftdi_set_termios(port, &tmp_termios); >+ if (port->tty) >+ ftdi_set_termios(port, NULL); > > /* FIXME: Flow control might be enabled, so it should be checked - > we have no control of defaults! */ >@@ -1488,14 +1488,7 @@ static void ftdi_close (struct usb_seria > > /* shutdown our bulk read */ > if (port->read_urb) { >- if (usb_unlink_urb (port->read_urb) < 0) { >- /* Generally, this isn't an error. If the previous >- read bulk callback occurred (or is about to occur) >- while the port was being closed or was throtted >- (and is still throttled), the read urb will not >- have been submitted. */ >- dbg("%s - failed to unlink read urb (generally not an error)", __FUNCTION__); >- } >+ usb_kill_urb(port->read_urb); > } > } /* ftdi_close */ > >diff -urp -X dontdiff linux-2.6.9-50.EL/drivers/usb/serial/usb-serial.c linux-2.6.9-50.EL.z1/drivers/usb/serial/usb-serial.c >--- linux-2.6.9-50.EL/drivers/usb/serial/usb-serial.c 2004-10-18 14:55:36.000000000 -0700 >+++ linux-2.6.9-50.EL.z1/drivers/usb/serial/usb-serial.c 2007-06-13 19:36:59.000000000 -0700 >@@ -332,8 +332,8 @@ > #include <linux/module.h> > #include <linux/moduleparam.h> > #include <linux/spinlock.h> >+#include <linux/mutex.h> > #include <linux/list.h> >-#include <linux/smp_lock.h> > #include <asm/uaccess.h> > #include <linux/usb.h> > #include "usb-serial.h" >@@ -346,6 +346,8 @@ > #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/" > #define DRIVER_DESC "USB Serial Driver core" > >+static void port_free(struct usb_serial_port *port); >+ > /* Driver structure we register with the USB core */ > static struct usb_driver usb_serial_driver = { > .owner = THIS_MODULE, >@@ -363,14 +365,20 @@ static struct usb_driver usb_serial_driv > > static int debug; > static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ >+static spinlock_t table_lock; > static LIST_HEAD(usb_serial_driver_list); >+static struct mutex port_mutex; > > struct usb_serial *usb_serial_get_by_index(unsigned index) > { >- struct usb_serial *serial = serial_table[index]; >+ struct usb_serial *serial; >+ >+ spin_lock(&table_lock); >+ serial = serial_table[index]; > > if (serial) > kref_get(&serial->kref); >+ spin_unlock(&table_lock); > return serial; > } > >@@ -382,13 +390,14 @@ static struct usb_serial *get_free_seria > dbg("%s %d", __FUNCTION__, num_ports); > > *minor = 0; >+ spin_lock(&table_lock); > for (i = 0; i < SERIAL_TTY_MINORS; ++i) { > if (serial_table[i]) > continue; > > good_spot = 1; > for (j = 1; j <= num_ports-1; ++j) >- if ((serial_table[i+j]) || (i+j >= SERIAL_TTY_MINORS)) { >+ if ((i+j >= SERIAL_TTY_MINORS) || (serial_table[i+j])) { > good_spot = 0; > i += j; > break; >@@ -398,10 +407,13 @@ static struct usb_serial *get_free_seria > > *minor = i; > dbg("%s - minor base = %d", __FUNCTION__, *minor); >- for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) >+ for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) { > serial_table[i] = serial; >+ } >+ spin_unlock(&table_lock); > return serial; > } >+ spin_unlock(&table_lock); > return NULL; > } > >@@ -414,11 +426,11 @@ static void return_serial (struct usb_se > if (serial == NULL) > return; > >+ spin_lock(&table_lock); > for (i = 0; i < serial->num_ports; ++i) { > serial_table[serial->minor + i] = NULL; > } >- >- return; >+ spin_unlock(&table_lock); > } > > static void destroy_serial(struct kref *kref) >@@ -454,21 +466,7 @@ static void destroy_serial(struct kref * > port = serial->port[i]; > if (!port) > continue; >- if (port->read_urb) { >- usb_unlink_urb(port->read_urb); >- usb_free_urb(port->read_urb); >- } >- if (port->write_urb) { >- usb_unlink_urb(port->write_urb); >- usb_free_urb(port->write_urb); >- } >- if (port->interrupt_in_urb) { >- usb_unlink_urb(port->interrupt_in_urb); >- usb_free_urb(port->interrupt_in_urb); >- } >- kfree(port->bulk_in_buffer); >- kfree(port->bulk_out_buffer); >- kfree(port->interrupt_in_buffer); >+ port_free(port); > } > } > >@@ -478,6 +476,11 @@ static void destroy_serial(struct kref * > kfree (serial); > } > >+void usb_serial_put(struct usb_serial *serial) >+{ >+ kref_put(&serial->kref, destroy_serial); >+} >+ > /***************************************************************************** > * Driver tty interface functions > *****************************************************************************/ >@@ -486,84 +489,115 @@ static int serial_open (struct tty_struc > struct usb_serial *serial; > struct usb_serial_port *port; > unsigned int portNumber; >- int retval = 0; >+ int retval; > > dbg("%s", __FUNCTION__); > >- /* initialize the pointer incase something fails */ >- tty->driver_data = NULL; >- > /* get the serial object associated with this tty pointer */ > serial = usb_serial_get_by_index(tty->index); > if (!serial) { >- retval = -ENODEV; >- goto bailout; >+ tty->driver_data = NULL; >+ return -ENODEV; > } > >- /* set up our port structure making the tty driver remember our port object, and us it */ > portNumber = tty->index - serial->minor; > port = serial->port[portNumber]; >- tty->driver_data = port; >- >- port->tty = tty; >- >- /* lock this module before we call it, >- this may, which means we must bail out, safe because we are called with BKL held */ >- if (!try_module_get(serial->type->owner)) { >+ if (!port) { > retval = -ENODEV; >- goto bailout; >+ goto bailout_kref_put; > } > >+ if (mutex_lock_interruptible(&port_mutex)) { >+ retval = -ERESTARTSYS; >+ goto bailout_kref_put; >+ } >+ > ++port->open_count; >+ >+ /* set up our port structure making the tty driver >+ * remember our port object, and us it */ >+ tty->driver_data = port; >+ port->tty = tty; >+ > if (port->open_count == 1) { >+ >+ /* lock this module before we call it >+ * this may fail, which means we must bail out, >+ * safe because we are called with BKL held */ >+ if (!try_module_get(serial->type->owner)) { >+ retval = -ENODEV; >+ goto bailout_mutex_unlock; >+ } >+ > /* only call the device specific open if this > * is the first time the port is opened */ > retval = serial->type->open(port, filp); >- if (retval) { >- port->open_count = 0; >- module_put(serial->type->owner); >- kref_put(&serial->kref, destroy_serial); >- } >+ if (retval) >+ goto bailout_module_put; > } >-bailout: >+ >+ mutex_unlock(&port_mutex); >+ return 0; >+ >+bailout_module_put: >+ module_put(serial->type->owner); >+bailout_mutex_unlock: >+ port->open_count = 0; >+ tty->driver_data = NULL; >+ port->tty = NULL; >+ mutex_unlock(&port_mutex); >+bailout_kref_put: >+ usb_serial_put(serial); > return retval; > } > > static void serial_close(struct tty_struct *tty, struct file * filp) > { >- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; >+ struct usb_serial_port *port = tty->driver_data; > > if (!port) > return; > > dbg("%s - port %d", __FUNCTION__, port->number); > >+ mutex_lock(&port_mutex); >+ >+ if (port->open_count == 0) { >+ mutex_unlock(&port_mutex); >+ return; >+ } >+ > --port->open_count; >- if (port->open_count <= 0) { >+ if (port->open_count == 0) { > /* only call the device specific close if this > * port is being closed by the last owner */ > port->serial->type->close(port, filp); >- port->open_count = 0; > > if (port->tty) { > if (port->tty->driver_data) > port->tty->driver_data = NULL; > port->tty = NULL; > } >+ >+ module_put(port->serial->type->owner); > } > >- module_put(port->serial->type->owner); >- kref_put(&port->serial->kref, destroy_serial); >+ mutex_unlock(&port_mutex); >+ usb_serial_put(port->serial); > } > > static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) > { >- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; >- int retval = -EINVAL; >+ struct usb_serial_port *port = tty->driver_data; >+ int retval = -ENODEV; >+ >+ if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED) >+ goto exit; > > dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); > > if (!port->open_count) { >+ retval = -EINVAL; > dbg("%s - port not opened", __FUNCTION__); > goto exit; > } >@@ -577,8 +611,11 @@ exit: > > static int serial_write_room (struct tty_struct *tty) > { >- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; >- int retval = -EINVAL; >+ struct usb_serial_port *port = tty->driver_data; >+ int retval = -ENODEV; >+ >+ if (!port) >+ goto exit; > > dbg("%s - port %d", __FUNCTION__, port->number); > >@@ -596,8 +633,11 @@ exit: > > static int serial_chars_in_buffer (struct tty_struct *tty) > { >- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; >- int retval = -EINVAL; >+ struct usb_serial_port *port = tty->driver_data; >+ int retval = -ENODEV; >+ >+ if (!port) >+ goto exit; > > dbg("%s = port %d", __FUNCTION__, port->number); > >@@ -615,47 +655,50 @@ exit: > > static void serial_throttle (struct tty_struct * tty) > { >- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; >+ struct usb_serial_port *port = tty->driver_data; >+ >+ if (!port) >+ return; > > dbg("%s - port %d", __FUNCTION__, port->number); > > if (!port->open_count) { > dbg ("%s - port not open", __FUNCTION__); >- goto exit; >+ return; > } > > /* pass on to the driver specific version of this function */ > if (port->serial->type->throttle) > port->serial->type->throttle(port); >- >-exit: >- ; > } > > static void serial_unthrottle (struct tty_struct * tty) > { >- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; >+ struct usb_serial_port *port = tty->driver_data; >+ >+ if (!port) >+ return; > > dbg("%s - port %d", __FUNCTION__, port->number); > > if (!port->open_count) { > dbg("%s - port not open", __FUNCTION__); >- goto exit; >+ return; > } > > /* pass on to the driver specific version of this function */ > if (port->serial->type->unthrottle) > port->serial->type->unthrottle(port); >- >-exit: >- ; > } > > static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) > { >- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; >+ struct usb_serial_port *port = tty->driver_data; > int retval = -ENODEV; > >+ if (!port) >+ goto exit; >+ > dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd); > > if (!port->open_count) { >@@ -675,40 +718,40 @@ exit: > > static void serial_set_termios (struct tty_struct *tty, struct termios * old) > { >- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; >+ struct usb_serial_port *port = tty->driver_data; >+ >+ if (!port) >+ return; > > dbg("%s - port %d", __FUNCTION__, port->number); > > if (!port->open_count) { > dbg("%s - port not open", __FUNCTION__); >- goto exit; >+ return; > } > > /* pass on to the driver specific version of this function if it is available */ > if (port->serial->type->set_termios) > port->serial->type->set_termios(port, old); >- >-exit: >- ; > } > > static void serial_break (struct tty_struct *tty, int break_state) > { >- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; >+ struct usb_serial_port *port = tty->driver_data; >+ >+ if (!port) >+ return; > > dbg("%s - port %d", __FUNCTION__, port->number); > > if (!port->open_count) { > dbg("%s - port not open", __FUNCTION__); >- goto exit; >+ return; > } > > /* pass on to the driver specific version of this function if it is available */ > if (port->serial->type->break_ctl) > port->serial->type->break_ctl(port, break_state); >- >-exit: >- ; > } > > static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) >@@ -738,13 +781,15 @@ static int serial_read_proc (char *page, > length += sprintf (page+length, " path:%s", tmp); > > length += sprintf (page+length, "\n"); >- if ((length + begin) > (off + count)) >+ if ((length + begin) > (off + count)) { >+ usb_serial_put(serial); > goto done; >+ } > if ((length + begin) < off) { > begin += length; > length = 0; > } >- kref_put(&serial->kref, destroy_serial); >+ usb_serial_put(serial); > } > *eof = 1; > done: >@@ -756,38 +801,42 @@ done: > > static int serial_tiocmget (struct tty_struct *tty, struct file *file) > { >- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; >+ struct usb_serial_port *port = tty->driver_data; >+ >+ if (!port) >+ return -ENODEV; > > dbg("%s - port %d", __FUNCTION__, port->number); > > if (!port->open_count) { > dbg("%s - port not open", __FUNCTION__); >- goto exit; >+ return -ENODEV; > } > > if (port->serial->type->tiocmget) > return port->serial->type->tiocmget(port, file); > >-exit: > return -EINVAL; > } > > static int serial_tiocmset (struct tty_struct *tty, struct file *file, > unsigned int set, unsigned int clear) > { >- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; >+ struct usb_serial_port *port = tty->driver_data; >+ >+ if (!port) >+ return -ENODEV; > > dbg("%s - port %d", __FUNCTION__, port->number); > > if (!port->open_count) { > dbg("%s - port not open", __FUNCTION__); >- goto exit; >+ return -ENODEV; > } > > if (port->serial->type->tiocmset) > return port->serial->type->tiocmset(port, file, set, clear); > >-exit: > return -EINVAL; > } > >@@ -813,21 +862,26 @@ static void port_release(struct device * > struct usb_serial_port *port = to_usb_serial_port(dev); > > dbg ("%s - %s", __FUNCTION__, dev->bus_id); >- if (port->read_urb) { >- usb_unlink_urb(port->read_urb); >- usb_free_urb(port->read_urb); >- } >- if (port->write_urb) { >- usb_unlink_urb(port->write_urb); >- usb_free_urb(port->write_urb); >- } >- if (port->interrupt_in_urb) { >- usb_unlink_urb(port->interrupt_in_urb); >- usb_free_urb(port->interrupt_in_urb); >- } >+ port_free(port); >+} >+ >+static void kill_traffic(struct usb_serial_port *port) >+{ >+ usb_kill_urb(port->read_urb); >+ usb_kill_urb(port->write_urb); >+ usb_kill_urb(port->interrupt_in_urb); >+} >+ >+static void port_free(struct usb_serial_port *port) >+{ >+ kill_traffic(port); >+ usb_free_urb(port->read_urb); >+ usb_free_urb(port->write_urb); >+ usb_free_urb(port->interrupt_in_urb); > kfree(port->bulk_in_buffer); > kfree(port->bulk_out_buffer); > kfree(port->interrupt_in_buffer); >+ flush_scheduled_work(); /* port->work */ > kfree(port); > } > >@@ -1189,16 +1243,26 @@ probe_error: > > void usb_serial_disconnect(struct usb_interface *interface) > { >+ int i; > struct usb_serial *serial = usb_get_intfdata (interface); > struct device *dev = &interface->dev; >+ struct usb_serial_port *port; > > dbg ("%s", __FUNCTION__); > > usb_set_intfdata (interface, NULL); > if (serial) { >+ for (i = 0; i < serial->num_ports; ++i) { >+ port = serial->port[i]; >+ if (port) { >+ if (port->tty) >+ tty_hangup(port->tty); >+ kill_traffic(port); >+ } >+ } > /* let the last holder of this object > * cause it to be cleaned up */ >- kref_put(&serial->kref, destroy_serial); >+ usb_serial_put(serial); > } > dev_info(dev, "device disconnected\n"); > } >@@ -1231,6 +1295,8 @@ static int __init usb_serial_init(void) > return -ENOMEM; > > /* Initialize our global data */ >+ spin_lock_init(&table_lock); >+ mutex_init(&port_mutex); > for (i = 0; i < SERIAL_TTY_MINORS; ++i) { > serial_table[i] = NULL; > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 243067
:
156429
|
156430
| 156952 |
157014
|
319713