Skip to content

Commit 73e487f

Browse files
lyakhgregkh
authored andcommitted
[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: Guennadi Liakhovetski <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent ca85485 commit 73e487f

File tree

3 files changed

+29
-7
lines changed

3 files changed

+29
-7
lines changed

drivers/usb/serial/console.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun
202202
struct usb_serial *serial;
203203
int retval = -ENODEV;
204204

205-
if (!port)
205+
if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
206206
return;
207207
serial = port->serial;
208208

@@ -255,6 +255,14 @@ static struct console usbcons = {
255255
.index = -1,
256256
};
257257

258+
void usb_serial_console_disconnect(struct usb_serial *serial)
259+
{
260+
if (serial && serial->port && serial->port[0] && serial->port[0] == usbcons_info.port) {
261+
usb_serial_console_exit();
262+
usb_serial_put(serial);
263+
}
264+
}
265+
258266
void usb_serial_console_init (int serial_debug, int minor)
259267
{
260268
debug = serial_debug;
@@ -280,6 +288,11 @@ void usb_serial_console_init (int serial_debug, int minor)
280288

281289
void usb_serial_console_exit (void)
282290
{
283-
unregister_console(&usbcons);
291+
if (usbcons_info.port) {
292+
unregister_console(&usbcons);
293+
if (usbcons_info.port->open_count)
294+
usbcons_info.port->open_count--;
295+
usbcons_info.port = NULL;
296+
}
284297
}
285298

drivers/usb/serial/usb-serial.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ static void destroy_serial(struct kref *kref)
168168
kfree (serial);
169169
}
170170

171+
void usb_serial_put(struct usb_serial *serial)
172+
{
173+
kref_put(&serial->kref, destroy_serial);
174+
}
175+
171176
/*****************************************************************************
172177
* Driver tty interface functions
173178
*****************************************************************************/
@@ -232,7 +237,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
232237
port->open_count = 0;
233238
mutex_unlock(&port->mutex);
234239
bailout_kref_put:
235-
kref_put(&serial->kref, destroy_serial);
240+
usb_serial_put(serial);
236241
return retval;
237242
}
238243

@@ -268,15 +273,15 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
268273
}
269274

270275
mutex_unlock(&port->mutex);
271-
kref_put(&port->serial->kref, destroy_serial);
276+
usb_serial_put(port->serial);
272277
}
273278

274279
static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
275280
{
276281
struct usb_serial_port *port = tty->driver_data;
277282
int retval = -EINVAL;
278283

279-
if (!port)
284+
if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
280285
goto exit;
281286

282287
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
473478
begin += length;
474479
length = 0;
475480
}
476-
kref_put(&serial->kref, destroy_serial);
481+
usb_serial_put(serial);
477482
}
478483
*eof = 1;
479484
done:
@@ -985,6 +990,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
985990
struct device *dev = &interface->dev;
986991
struct usb_serial_port *port;
987992

993+
usb_serial_console_disconnect(serial);
988994
dbg ("%s", __FUNCTION__);
989995

990996
usb_set_intfdata (interface, NULL);
@@ -996,7 +1002,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
9961002
}
9971003
/* let the last holder of this object
9981004
* cause it to be cleaned up */
999-
kref_put(&serial->kref, destroy_serial);
1005+
usb_serial_put(serial);
10001006
}
10011007
dev_info(dev, "device disconnected\n");
10021008
}

drivers/usb/serial/usb-serial.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,13 +248,16 @@ extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
248248
#ifdef CONFIG_USB_SERIAL_CONSOLE
249249
extern void usb_serial_console_init (int debug, int minor);
250250
extern void usb_serial_console_exit (void);
251+
extern void usb_serial_console_disconnect(struct usb_serial *serial);
251252
#else
252253
static inline void usb_serial_console_init (int debug, int minor) { }
253254
static inline void usb_serial_console_exit (void) { }
255+
static inline void usb_serial_console_disconnect(struct usb_serial *serial) {}
254256
#endif
255257

256258
/* Functions needed by other parts of the usbserial core */
257259
extern struct usb_serial *usb_serial_get_by_index (unsigned int minor);
260+
extern void usb_serial_put(struct usb_serial *serial);
258261
extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp);
259262
extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count);
260263
extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp);

0 commit comments

Comments
 (0)