aboutsummaryrefslogtreecommitdiffstats
path: root/usb/usb-fix-visor-leaks.patch
blob: e427526603284d516b6248df9eebea01dfdf72f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
From zaitcev@redhat.com Wed Jun 21 15:03:55 2006
Date: Wed, 21 Jun 2006 15:03:40 -0700
From: Pete Zaitcev <zaitcev@redhat.com>
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 <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
 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)