From zaitcev@redhat.com Wed Jun 21 15:03:55 2006 Date: Wed, 21 Jun 2006 15:03:40 -0700 From: Pete Zaitcev To: greg@kroah.com Cc: zaitcev@redhat.com Subject: USB: fix visor leaks Message-Id: <20060621150340.df69ec81.zaitcev@redhat.com> This patch fixes blatant leaks in visor driver and makes it report mode sensible things in ->write_room (this is only needed if your visor is a terminal though). It is made to fit into 80 columns with a temporary variable. Might even save a few instructions... Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/visor.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) --- gregkh-2.6.orig/drivers/usb/serial/visor.c +++ gregkh-2.6/drivers/usb/serial/visor.c @@ -435,13 +435,25 @@ static int visor_write (struct usb_seria static int visor_write_room (struct usb_serial_port *port) { + struct visor_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + dbg("%s - port %d", __FUNCTION__, port->number); /* * We really can take anything the user throws at us * but let's pick a nice big number to tell the tty - * layer that we have lots of free space + * layer that we have lots of free space, unless we don't. */ + + spin_lock_irqsave(&priv->lock, flags); + if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) { + spin_unlock_irqrestore(&priv->lock, flags); + dbg("%s - write limit hit\n", __FUNCTION__); + return 0; + } + spin_unlock_irqrestore(&priv->lock, flags); + return 2048; } @@ -758,15 +770,22 @@ static int visor_calc_num_ports (struct static int generic_startup(struct usb_serial *serial) { + struct usb_serial_port **ports = serial->port; struct visor_private *priv; int i; for (i = 0; i < serial->num_ports; ++i) { priv = kzalloc (sizeof(*priv), GFP_KERNEL); - if (!priv) + if (!priv) { + while (i-- != 0) { + priv = usb_get_serial_port_data(ports[i]); + usb_set_serial_port_data(ports[i], NULL); + kfree(priv); + } return -ENOMEM; + } spin_lock_init(&priv->lock); - usb_set_serial_port_data(serial->port[i], priv); + usb_set_serial_port_data(ports[i], priv); } return 0; } @@ -876,7 +895,18 @@ static int clie_5_attach (struct usb_ser static void visor_shutdown (struct usb_serial *serial) { + struct visor_private *priv; + int i; + dbg("%s", __FUNCTION__); + + for (i = 0; i < serial->num_ports; i++) { + priv = usb_get_serial_port_data(serial->port[i]); + if (priv) { + usb_set_serial_port_data(serial->port[i], NULL); + kfree(priv); + } + } } static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)