Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+15 −2
Original line number Diff line number Diff line
@@ -202,7 +202,7 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun
	struct usb_serial *serial;
	int retval = -ENODEV;

	if (!port)
	if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
		return;
	serial = port->serial;

@@ -255,6 +255,14 @@ static struct console usbcons = {
	.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)
{
	debug = serial_debug;
@@ -280,6 +288,11 @@ void usb_serial_console_init (int serial_debug, int minor)

void usb_serial_console_exit (void)
{
	if (usbcons_info.port) {
		unregister_console(&usbcons);
		if (usbcons_info.port->open_count)
			usbcons_info.port->open_count--;
		usbcons_info.port = NULL;
	}
}
+11 −5
Original line number Diff line number Diff line
@@ -168,6 +168,11 @@ static void destroy_serial(struct kref *kref)
	kfree (serial);
}

void usb_serial_put(struct usb_serial *serial)
{
	kref_put(&serial->kref, destroy_serial);
}

/*****************************************************************************
 * Driver tty interface functions
 *****************************************************************************/
@@ -232,7 +237,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
	port->open_count = 0;
	mutex_unlock(&port->mutex);
bailout_kref_put:
	kref_put(&serial->kref, destroy_serial);
	usb_serial_put(serial);
	return retval;
}

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

	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)
@@ -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;
	int retval = -EINVAL;

	if (!port)
	if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
		goto exit;

	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
			begin += length;
			length = 0;
		}
		kref_put(&serial->kref, destroy_serial);
		usb_serial_put(serial);
	}
	*eof = 1;
done:
@@ -985,6 +990,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
	struct device *dev = &interface->dev;
	struct usb_serial_port *port;

	usb_serial_console_disconnect(serial);
	dbg ("%s", __FUNCTION__);

	usb_set_intfdata (interface, NULL);
@@ -996,7 +1002,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
		}
		/* 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");
}
+3 −0
Original line number Diff line number Diff line
@@ -248,13 +248,16 @@ extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
#ifdef CONFIG_USB_SERIAL_CONSOLE
extern void usb_serial_console_init (int debug, int minor);
extern void usb_serial_console_exit (void);
extern void usb_serial_console_disconnect(struct usb_serial *serial);
#else
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_disconnect(struct usb_serial *serial) {}
#endif

/* Functions needed by other parts of the usbserial core */
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_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);