Commit 73e487fd authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Greg Kroah-Hartman

[PATCH] USB console: fix disconnection issues

Prevent sending further output to a USB-serial console after the dongle is
disconnected, take care not to leak kref.
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent ca85485c
...@@ -202,7 +202,7 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun ...@@ -202,7 +202,7 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun
struct usb_serial *serial; struct usb_serial *serial;
int retval = -ENODEV; int retval = -ENODEV;
if (!port) if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
return; return;
serial = port->serial; serial = port->serial;
...@@ -255,6 +255,14 @@ static struct console usbcons = { ...@@ -255,6 +255,14 @@ static struct console usbcons = {
.index = -1, .index = -1,
}; };
void usb_serial_console_disconnect(struct usb_serial *serial)
{
if (serial && serial->port && serial->port[0] && serial->port[0] == usbcons_info.port) {
usb_serial_console_exit();
usb_serial_put(serial);
}
}
void usb_serial_console_init (int serial_debug, int minor) void usb_serial_console_init (int serial_debug, int minor)
{ {
debug = serial_debug; debug = serial_debug;
...@@ -280,6 +288,11 @@ void usb_serial_console_init (int serial_debug, int minor) ...@@ -280,6 +288,11 @@ void usb_serial_console_init (int serial_debug, int minor)
void usb_serial_console_exit (void) void usb_serial_console_exit (void)
{ {
unregister_console(&usbcons); if (usbcons_info.port) {
unregister_console(&usbcons);
if (usbcons_info.port->open_count)
usbcons_info.port->open_count--;
usbcons_info.port = NULL;
}
} }
...@@ -168,6 +168,11 @@ static void destroy_serial(struct kref *kref) ...@@ -168,6 +168,11 @@ static void destroy_serial(struct kref *kref)
kfree (serial); kfree (serial);
} }
void usb_serial_put(struct usb_serial *serial)
{
kref_put(&serial->kref, destroy_serial);
}
/***************************************************************************** /*****************************************************************************
* Driver tty interface functions * Driver tty interface functions
*****************************************************************************/ *****************************************************************************/
...@@ -232,7 +237,7 @@ bailout_mutex_unlock: ...@@ -232,7 +237,7 @@ bailout_mutex_unlock:
port->open_count = 0; port->open_count = 0;
mutex_unlock(&port->mutex); mutex_unlock(&port->mutex);
bailout_kref_put: bailout_kref_put:
kref_put(&serial->kref, destroy_serial); usb_serial_put(serial);
return retval; return retval;
} }
...@@ -268,7 +273,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp) ...@@ -268,7 +273,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
} }
mutex_unlock(&port->mutex); mutex_unlock(&port->mutex);
kref_put(&port->serial->kref, destroy_serial); usb_serial_put(port->serial);
} }
static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count) static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
...@@ -276,7 +281,7 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int ...@@ -276,7 +281,7 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
int retval = -EINVAL; int retval = -EINVAL;
if (!port) if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
goto exit; goto exit;
dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
...@@ -473,7 +478,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int ...@@ -473,7 +478,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int
begin += length; begin += length;
length = 0; length = 0;
} }
kref_put(&serial->kref, destroy_serial); usb_serial_put(serial);
} }
*eof = 1; *eof = 1;
done: done:
...@@ -985,6 +990,7 @@ void usb_serial_disconnect(struct usb_interface *interface) ...@@ -985,6 +990,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
struct device *dev = &interface->dev; struct device *dev = &interface->dev;
struct usb_serial_port *port; struct usb_serial_port *port;
usb_serial_console_disconnect(serial);
dbg ("%s", __FUNCTION__); dbg ("%s", __FUNCTION__);
usb_set_intfdata (interface, NULL); usb_set_intfdata (interface, NULL);
...@@ -996,7 +1002,7 @@ void usb_serial_disconnect(struct usb_interface *interface) ...@@ -996,7 +1002,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
} }
/* let the last holder of this object /* let the last holder of this object
* cause it to be cleaned up */ * cause it to be cleaned up */
kref_put(&serial->kref, destroy_serial); usb_serial_put(serial);
} }
dev_info(dev, "device disconnected\n"); dev_info(dev, "device disconnected\n");
} }
......
...@@ -248,13 +248,16 @@ extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit); ...@@ -248,13 +248,16 @@ extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
#ifdef CONFIG_USB_SERIAL_CONSOLE #ifdef CONFIG_USB_SERIAL_CONSOLE
extern void usb_serial_console_init (int debug, int minor); extern void usb_serial_console_init (int debug, int minor);
extern void usb_serial_console_exit (void); extern void usb_serial_console_exit (void);
extern void usb_serial_console_disconnect(struct usb_serial *serial);
#else #else
static inline void usb_serial_console_init (int debug, int minor) { } static inline void usb_serial_console_init (int debug, int minor) { }
static inline void usb_serial_console_exit (void) { } static inline void usb_serial_console_exit (void) { }
static inline void usb_serial_console_disconnect(struct usb_serial *serial) {}
#endif #endif
/* Functions needed by other parts of the usbserial core */ /* Functions needed by other parts of the usbserial core */
extern struct usb_serial *usb_serial_get_by_index (unsigned int minor); extern struct usb_serial *usb_serial_get_by_index (unsigned int minor);
extern void usb_serial_put(struct usb_serial *serial);
extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp); extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp);
extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count); extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count);
extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp); extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment