aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/storage
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2013-11-13 03:32:22 -0500
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2014-03-04 18:38:24 -0500
commit21fc05b680f6fba868b41e2713ade3fdea4049f9 (patch)
tree88d5fa34ee36c50352df7487926e246a040f5c18 /drivers/usb/storage
parentc6f63207a3ba689025b2120792ea831cf72f9a81 (diff)
uas: Fix memory management
The scsi-host structure is refcounted, scsi_remove_host tears down the scsi-host but does not decrement the refcount, so we need to call scsi_put_host on disconnect to get the underlying memory to be freed. After calling scsi_remove_host, the scsi-core may still hold a reference to the scsi-host, iow we may still get called after uas_disconnect, but we do our own life cycle management of uas_devinfo, freeing it on disconnect, and thus may end up using devinfo after it has been freed. Switch to letting scsi_host_alloc allocate and manage the memory for us. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r--drivers/usb/storage/uas.c33
1 files changed, 14 insertions, 19 deletions
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 8c685801e267..d81d041842f4 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -315,7 +315,7 @@ static void uas_stat_cmplt(struct urb *urb)
315{ 315{
316 struct iu *iu = urb->transfer_buffer; 316 struct iu *iu = urb->transfer_buffer;
317 struct Scsi_Host *shost = urb->context; 317 struct Scsi_Host *shost = urb->context;
318 struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; 318 struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
319 struct scsi_cmnd *cmnd; 319 struct scsi_cmnd *cmnd;
320 struct uas_cmd_info *cmdinfo; 320 struct uas_cmd_info *cmdinfo;
321 unsigned long flags; 321 unsigned long flags;
@@ -562,7 +562,7 @@ err:
562static struct urb *uas_submit_sense_urb(struct Scsi_Host *shost, 562static struct urb *uas_submit_sense_urb(struct Scsi_Host *shost,
563 gfp_t gfp, unsigned int stream) 563 gfp_t gfp, unsigned int stream)
564{ 564{
565 struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; 565 struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
566 struct urb *urb; 566 struct urb *urb;
567 567
568 urb = uas_alloc_sense_urb(devinfo, gfp, shost, stream); 568 urb = uas_alloc_sense_urb(devinfo, gfp, shost, stream);
@@ -734,7 +734,7 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
734 const char *fname, u8 function) 734 const char *fname, u8 function)
735{ 735{
736 struct Scsi_Host *shost = cmnd->device->host; 736 struct Scsi_Host *shost = cmnd->device->host;
737 struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; 737 struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
738 u16 tag = devinfo->qdepth; 738 u16 tag = devinfo->qdepth;
739 unsigned long flags; 739 unsigned long flags;
740 struct urb *sense_urb; 740 struct urb *sense_urb;
@@ -879,7 +879,7 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
879 879
880static int uas_slave_alloc(struct scsi_device *sdev) 880static int uas_slave_alloc(struct scsi_device *sdev)
881{ 881{
882 sdev->hostdata = (void *)sdev->host->hostdata[0]; 882 sdev->hostdata = (void *)sdev->host->hostdata;
883 return 0; 883 return 0;
884} 884}
885 885
@@ -1005,11 +1005,8 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
1005 if (uas_switch_interface(udev, intf)) 1005 if (uas_switch_interface(udev, intf))
1006 return -ENODEV; 1006 return -ENODEV;
1007 1007
1008 devinfo = kmalloc(sizeof(struct uas_dev_info), GFP_KERNEL); 1008 shost = scsi_host_alloc(&uas_host_template,
1009 if (!devinfo) 1009 sizeof(struct uas_dev_info));
1010 goto set_alt0;
1011
1012 shost = scsi_host_alloc(&uas_host_template, sizeof(void *));
1013 if (!shost) 1010 if (!shost)
1014 goto set_alt0; 1011 goto set_alt0;
1015 1012
@@ -1019,6 +1016,7 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
1019 shost->max_channel = 0; 1016 shost->max_channel = 0;
1020 shost->sg_tablesize = udev->bus->sg_tablesize; 1017 shost->sg_tablesize = udev->bus->sg_tablesize;
1021 1018
1019 devinfo = (struct uas_dev_info *)shost->hostdata;
1022 devinfo->intf = intf; 1020 devinfo->intf = intf;
1023 devinfo->udev = udev; 1021 devinfo->udev = udev;
1024 devinfo->resetting = 0; 1022 devinfo->resetting = 0;
@@ -1044,8 +1042,6 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
1044 if (result) 1042 if (result)
1045 goto free_streams; 1043 goto free_streams;
1046 1044
1047 shost->hostdata[0] = (unsigned long)devinfo;
1048
1049 scsi_scan_host(shost); 1045 scsi_scan_host(shost);
1050 usb_set_intfdata(intf, shost); 1046 usb_set_intfdata(intf, shost);
1051 return result; 1047 return result;
@@ -1054,7 +1050,6 @@ free_streams:
1054 uas_free_streams(devinfo); 1050 uas_free_streams(devinfo);
1055set_alt0: 1051set_alt0:
1056 usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0); 1052 usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
1057 kfree(devinfo);
1058 if (shost) 1053 if (shost)
1059 scsi_host_put(shost); 1054 scsi_host_put(shost);
1060 return result; 1055 return result;
@@ -1063,7 +1058,7 @@ set_alt0:
1063static int uas_pre_reset(struct usb_interface *intf) 1058static int uas_pre_reset(struct usb_interface *intf)
1064{ 1059{
1065 struct Scsi_Host *shost = usb_get_intfdata(intf); 1060 struct Scsi_Host *shost = usb_get_intfdata(intf);
1066 struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; 1061 struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
1067 unsigned long flags; 1062 unsigned long flags;
1068 1063
1069 if (devinfo->shutdown) 1064 if (devinfo->shutdown)
@@ -1089,7 +1084,7 @@ static int uas_pre_reset(struct usb_interface *intf)
1089static int uas_post_reset(struct usb_interface *intf) 1084static int uas_post_reset(struct usb_interface *intf)
1090{ 1085{
1091 struct Scsi_Host *shost = usb_get_intfdata(intf); 1086 struct Scsi_Host *shost = usb_get_intfdata(intf);
1092 struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; 1087 struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
1093 unsigned long flags; 1088 unsigned long flags;
1094 1089
1095 if (devinfo->shutdown) 1090 if (devinfo->shutdown)
@@ -1113,7 +1108,7 @@ static int uas_post_reset(struct usb_interface *intf)
1113static int uas_suspend(struct usb_interface *intf, pm_message_t message) 1108static int uas_suspend(struct usb_interface *intf, pm_message_t message)
1114{ 1109{
1115 struct Scsi_Host *shost = usb_get_intfdata(intf); 1110 struct Scsi_Host *shost = usb_get_intfdata(intf);
1116 struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; 1111 struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
1117 1112
1118 /* Wait for any pending requests to complete */ 1113 /* Wait for any pending requests to complete */
1119 flush_work(&devinfo->work); 1114 flush_work(&devinfo->work);
@@ -1133,7 +1128,7 @@ static int uas_resume(struct usb_interface *intf)
1133static int uas_reset_resume(struct usb_interface *intf) 1128static int uas_reset_resume(struct usb_interface *intf)
1134{ 1129{
1135 struct Scsi_Host *shost = usb_get_intfdata(intf); 1130 struct Scsi_Host *shost = usb_get_intfdata(intf);
1136 struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; 1131 struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
1137 unsigned long flags; 1132 unsigned long flags;
1138 1133
1139 if (uas_configure_endpoints(devinfo) != 0) { 1134 if (uas_configure_endpoints(devinfo) != 0) {
@@ -1152,7 +1147,7 @@ static int uas_reset_resume(struct usb_interface *intf)
1152static void uas_disconnect(struct usb_interface *intf) 1147static void uas_disconnect(struct usb_interface *intf)
1153{ 1148{
1154 struct Scsi_Host *shost = usb_get_intfdata(intf); 1149 struct Scsi_Host *shost = usb_get_intfdata(intf);
1155 struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; 1150 struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
1156 1151
1157 devinfo->resetting = 1; 1152 devinfo->resetting = 1;
1158 cancel_work_sync(&devinfo->work); 1153 cancel_work_sync(&devinfo->work);
@@ -1163,7 +1158,7 @@ static void uas_disconnect(struct usb_interface *intf)
1163 uas_zap_dead(devinfo); 1158 uas_zap_dead(devinfo);
1164 scsi_remove_host(shost); 1159 scsi_remove_host(shost);
1165 uas_free_streams(devinfo); 1160 uas_free_streams(devinfo);
1166 kfree(devinfo); 1161 scsi_host_put(shost);
1167} 1162}
1168 1163
1169/* 1164/*
@@ -1176,7 +1171,7 @@ static void uas_shutdown(struct device *dev)
1176 struct usb_interface *intf = to_usb_interface(dev); 1171 struct usb_interface *intf = to_usb_interface(dev);
1177 struct usb_device *udev = interface_to_usbdev(intf); 1172 struct usb_device *udev = interface_to_usbdev(intf);
1178 struct Scsi_Host *shost = usb_get_intfdata(intf); 1173 struct Scsi_Host *shost = usb_get_intfdata(intf);
1179 struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; 1174 struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
1180 1175
1181 if (system_state != SYSTEM_RESTART) 1176 if (system_state != SYSTEM_RESTART)
1182 return; 1177 return;