diff options
author | Hans de Goede <hdegoede@redhat.com> | 2013-11-13 03:32:22 -0500 |
---|---|---|
committer | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2014-03-04 18:38:24 -0500 |
commit | 21fc05b680f6fba868b41e2713ade3fdea4049f9 (patch) | |
tree | 88d5fa34ee36c50352df7487926e246a040f5c18 /drivers/usb/storage | |
parent | c6f63207a3ba689025b2120792ea831cf72f9a81 (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.c | 33 |
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: | |||
562 | static struct urb *uas_submit_sense_urb(struct Scsi_Host *shost, | 562 | static 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 | ||
880 | static int uas_slave_alloc(struct scsi_device *sdev) | 880 | static 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); |
1055 | set_alt0: | 1051 | set_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: | |||
1063 | static int uas_pre_reset(struct usb_interface *intf) | 1058 | static 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) | |||
1089 | static int uas_post_reset(struct usb_interface *intf) | 1084 | static 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) | |||
1113 | static int uas_suspend(struct usb_interface *intf, pm_message_t message) | 1108 | static 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) | |||
1133 | static int uas_reset_resume(struct usb_interface *intf) | 1128 | static 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) | |||
1152 | static void uas_disconnect(struct usb_interface *intf) | 1147 | static 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; |