aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2012-10-25 04:29:19 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-10-25 12:37:13 -0400
commitf525c05babc7938cc1d4236550fd8a659fb05960 (patch)
treebf5923b4ddf04ddd25ee199e4728c9d9c4de1c52
parent084817d79399ab5ccab2f90a148b0369912a8369 (diff)
USB: sierra: 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 0998d0631001288 (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 also that urb-count for multi-port interfaces has not been changed even though the usb-serial port number is now determined from the port and interface minor numbers. Compile-only tested. Cc: <stable@vger.kernel.org> Signed-off-by: Johan Hovold <jhovold@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/serial/sierra.c125
1 files changed, 58 insertions, 67 deletions
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index bb2ecaf3296b..270860f6bb2a 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -878,12 +878,7 @@ static void sierra_dtr_rts(struct usb_serial_port *port, int on)
878 878
879static int sierra_startup(struct usb_serial *serial) 879static int sierra_startup(struct usb_serial *serial)
880{ 880{
881 struct usb_serial_port *port;
882 struct sierra_intf_private *intfdata; 881 struct sierra_intf_private *intfdata;
883 struct sierra_port_private *portdata;
884 struct sierra_iface_info *himemoryp = NULL;
885 int i;
886 u8 ifnum;
887 882
888 intfdata = kzalloc(sizeof(*intfdata), GFP_KERNEL); 883 intfdata = kzalloc(sizeof(*intfdata), GFP_KERNEL);
889 if (!intfdata) 884 if (!intfdata)
@@ -900,77 +895,71 @@ static int sierra_startup(struct usb_serial *serial)
900 if (nmea) 895 if (nmea)
901 sierra_vsc_set_nmea(serial->dev, 1); 896 sierra_vsc_set_nmea(serial->dev, 1);
902 897
903 /* Now setup per port private data */ 898 return 0;
904 for (i = 0; i < serial->num_ports; i++) { 899}
905 port = serial->port[i]; 900
906 portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); 901static void sierra_release(struct usb_serial *serial)
907 if (!portdata) { 902{
908 dev_dbg(&port->dev, "%s: kmalloc for " 903 struct sierra_intf_private *intfdata;
909 "sierra_port_private (%d) failed!\n", 904
910 __func__, i); 905 intfdata = usb_get_serial_data(serial);
911 goto err; 906 kfree(intfdata);
912 } 907}
913 spin_lock_init(&portdata->lock); 908
914 init_usb_anchor(&portdata->active); 909static int sierra_port_probe(struct usb_serial_port *port)
915 init_usb_anchor(&portdata->delayed); 910{
916 ifnum = i; 911 struct usb_serial *serial = port->serial;
917 /* Assume low memory requirements */ 912 struct sierra_port_private *portdata;
918 portdata->num_out_urbs = N_OUT_URB; 913 const struct sierra_iface_info *himemoryp;
919 portdata->num_in_urbs = N_IN_URB; 914 u8 ifnum;
920 915
921 /* Determine actual memory requirements */ 916 portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
922 if (serial->num_ports == 1) { 917 if (!portdata)
923 /* Get interface number for composite device */ 918 return -ENOMEM;
924 ifnum = sierra_calc_interface(serial); 919
925 himemoryp = 920 spin_lock_init(&portdata->lock);
926 (struct sierra_iface_info *)&typeB_interface_list; 921 init_usb_anchor(&portdata->active);
927 if (is_himemory(ifnum, himemoryp)) { 922 init_usb_anchor(&portdata->delayed);
928 portdata->num_out_urbs = N_OUT_URB_HM; 923
929 portdata->num_in_urbs = N_IN_URB_HM; 924 /* Assume low memory requirements */
930 } 925 portdata->num_out_urbs = N_OUT_URB;
931 } 926 portdata->num_in_urbs = N_IN_URB;
932 else { 927
933 himemoryp = 928 /* Determine actual memory requirements */
934 (struct sierra_iface_info *)&typeA_interface_list; 929 if (serial->num_ports == 1) {
935 if (is_himemory(i, himemoryp)) { 930 /* Get interface number for composite device */
936 portdata->num_out_urbs = N_OUT_URB_HM; 931 ifnum = sierra_calc_interface(serial);
937 portdata->num_in_urbs = N_IN_URB_HM; 932 himemoryp = &typeB_interface_list;
938 } 933 } else {
939 } 934 /* This is really the usb-serial port number of the interface
940 dev_dbg(&serial->dev->dev, 935 * rather than the interface number.
941 "Memory usage (urbs) interface #%d, in=%d, out=%d\n", 936 */
942 ifnum,portdata->num_in_urbs, portdata->num_out_urbs ); 937 ifnum = port->number - serial->minor;
943 /* Set the port private data pointer */ 938 himemoryp = &typeA_interface_list;
944 usb_set_serial_port_data(port, portdata);
945 } 939 }
946 940
947 return 0; 941 if (is_himemory(ifnum, himemoryp)) {
948err: 942 portdata->num_out_urbs = N_OUT_URB_HM;
949 for (--i; i >= 0; --i) { 943 portdata->num_in_urbs = N_IN_URB_HM;
950 portdata = usb_get_serial_port_data(serial->port[i]);
951 kfree(portdata);
952 } 944 }
953 kfree(intfdata);
954 945
955 return -ENOMEM; 946 dev_dbg(&port->dev,
947 "Memory usage (urbs) interface #%d, in=%d, out=%d\n",
948 ifnum, portdata->num_in_urbs, portdata->num_out_urbs);
949
950 usb_set_serial_port_data(port, portdata);
951
952 return 0;
956} 953}
957 954
958static void sierra_release(struct usb_serial *serial) 955static int sierra_port_remove(struct usb_serial_port *port)
959{ 956{
960 int i;
961 struct usb_serial_port *port;
962 struct sierra_port_private *portdata; 957 struct sierra_port_private *portdata;
963 958
964 for (i = 0; i < serial->num_ports; ++i) { 959 portdata = usb_get_serial_port_data(port);
965 port = serial->port[i]; 960 kfree(portdata);
966 if (!port) 961
967 continue; 962 return 0;
968 portdata = usb_get_serial_port_data(port);
969 if (!portdata)
970 continue;
971 kfree(portdata);
972 }
973 kfree(serial->private);
974} 963}
975 964
976#ifdef CONFIG_PM 965#ifdef CONFIG_PM
@@ -1074,6 +1063,8 @@ static struct usb_serial_driver sierra_device = {
1074 .tiocmset = sierra_tiocmset, 1063 .tiocmset = sierra_tiocmset,
1075 .attach = sierra_startup, 1064 .attach = sierra_startup,
1076 .release = sierra_release, 1065 .release = sierra_release,
1066 .port_probe = sierra_port_probe,
1067 .port_remove = sierra_port_remove,
1077 .suspend = sierra_suspend, 1068 .suspend = sierra_suspend,
1078 .resume = sierra_resume, 1069 .resume = sierra_resume,
1079 .read_int_callback = sierra_instat_callback, 1070 .read_int_callback = sierra_instat_callback,