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

Commit 50dde868 authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman
Browse files

USB: metro-usb: fix port-data memory leak



Fix port-data memory leak by moving port data allocation and
deallocation to port_probe and port_remove.

Since commit 0998d063 (device-core: Ensure drvdata = NULL when no
driver is bound) the port private data is no longer freed at release as
it is no longer accessible.

Note that the call to metrousb_clean (close) in shutdown was redundant.

Compile-only tested.

Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarJohan Hovold <jhovold@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d7870af7
Loading
Loading
Loading
Loading
+13 −37
Original line number Diff line number Diff line
@@ -271,52 +271,28 @@ static int metrousb_set_modem_ctrl(struct usb_serial *serial, unsigned int contr
	return retval;
}

static void metrousb_shutdown(struct usb_serial *serial)
{
	int i = 0;

	dev_dbg(&serial->dev->dev, "%s\n", __func__);

	/* Stop reading and writing on all ports. */
	for (i = 0; i < serial->num_ports; ++i) {
		/* Close any open urbs. */
		metrousb_cleanup(serial->port[i]);

		/* Free memory. */
		kfree(usb_get_serial_port_data(serial->port[i]));
		usb_set_serial_port_data(serial->port[i], NULL);

		dev_dbg(&serial->dev->dev, "%s - freed port number=%d\n",
			__func__, serial->port[i]->number);
	}
}

static int metrousb_startup(struct usb_serial *serial)
static int metrousb_port_probe(struct usb_serial_port *port)
{
	struct metrousb_private *metro_priv;
	struct usb_serial_port *port;
	int i = 0;

	dev_dbg(&serial->dev->dev, "%s\n", __func__);

	/* Loop through the serial ports setting up the private structures.
	 * Currently we only use one port. */
	for (i = 0; i < serial->num_ports; ++i) {
		port = serial->port[i];

		/* Declare memory. */
		metro_priv = kzalloc(sizeof(struct metrousb_private), GFP_KERNEL);
	metro_priv = kzalloc(sizeof(*metro_priv), GFP_KERNEL);
	if (!metro_priv)
		return -ENOMEM;

		/* Initialize memory. */
	spin_lock_init(&metro_priv->lock);

	usb_set_serial_port_data(port, metro_priv);

		dev_dbg(&serial->dev->dev, "%s - port number=%d\n ",
			__func__, port->number);
	return 0;
}

static int metrousb_port_remove(struct usb_serial_port *port)
{
	struct metrousb_private *metro_priv;

	metro_priv = usb_get_serial_port_data(port);
	kfree(metro_priv);

	return 0;
}

@@ -414,8 +390,8 @@ static struct usb_serial_driver metrousb_device = {
	.close			= metrousb_cleanup,
	.read_int_callback	= metrousb_read_int_callback,
	.write_int_callback	= metrousb_write_int_callback,
	.attach			= metrousb_startup,
	.release		= metrousb_shutdown,
	.port_probe		= metrousb_port_probe,
	.port_remove		= metrousb_port_remove,
	.throttle		= metrousb_throttle,
	.unthrottle		= metrousb_unthrottle,
	.tiocmget		= metrousb_tiocmget,