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 <hdego...@redhat.com>
---
 drivers/usb/storage/uas.c | 33 ++++++++++++++-------------------
 1 file changed, 14 insertions(+), 19 deletions(-)

diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 5b31fbf..c9d1fbe 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)
 {
        struct iu *iu = urb->transfer_buffer;
        struct Scsi_Host *shost = urb->context;
-       struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+       struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
        struct scsi_cmnd *cmnd;
        struct uas_cmd_info *cmdinfo;
        unsigned long flags;
@@ -563,7 +563,7 @@ err:
 static struct urb *uas_submit_sense_urb(struct Scsi_Host *shost, int size,
                                        gfp_t gfp, unsigned int stream)
 {
-       struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+       struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
        struct urb *urb;
 
        urb = uas_alloc_sense_urb(devinfo, size, gfp, shost, stream);
@@ -736,7 +736,7 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
                            const char *fname, u8 function)
 {
        struct Scsi_Host *shost = cmnd->device->host;
-       struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+       struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
        u16 tag = devinfo->qdepth;
        unsigned long flags;
        struct urb *sense_urb;
@@ -882,7 +882,7 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
 
 static int uas_slave_alloc(struct scsi_device *sdev)
 {
-       sdev->hostdata = (void *)sdev->host->hostdata[0];
+       sdev->hostdata = (void *)sdev->host->hostdata;
        return 0;
 }
 
@@ -1022,11 +1022,8 @@ static int uas_probe(struct usb_interface *intf, const 
struct usb_device_id *id)
        if (uas_switch_interface(udev, intf))
                return -ENODEV;
 
-       devinfo = kmalloc(sizeof(struct uas_dev_info), GFP_KERNEL);
-       if (!devinfo)
-               goto set_alt0;
-
-       shost = scsi_host_alloc(&uas_host_template, sizeof(void *));
+       shost = scsi_host_alloc(&uas_host_template,
+                               sizeof(struct uas_dev_info));
        if (!shost)
                goto set_alt0;
 
@@ -1036,6 +1033,7 @@ static int uas_probe(struct usb_interface *intf, const 
struct usb_device_id *id)
        shost->max_channel = 0;
        shost->sg_tablesize = udev->bus->sg_tablesize;
 
+       devinfo = (struct uas_dev_info *)shost->hostdata;
        devinfo->intf = intf;
        devinfo->udev = udev;
        devinfo->resetting = 0;
@@ -1061,8 +1059,6 @@ static int uas_probe(struct usb_interface *intf, const 
struct usb_device_id *id)
        if (result)
                goto free_streams;
 
-       shost->hostdata[0] = (unsigned long)devinfo;
-
        scsi_scan_host(shost);
        usb_set_intfdata(intf, shost);
        return result;
@@ -1071,7 +1067,6 @@ free_streams:
        uas_free_streams(devinfo);
 set_alt0:
        usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
-       kfree(devinfo);
        if (shost)
                scsi_host_put(shost);
        return result;
@@ -1080,7 +1075,7 @@ set_alt0:
 static int uas_pre_reset(struct usb_interface *intf)
 {
        struct Scsi_Host *shost = usb_get_intfdata(intf);
-       struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+       struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
        unsigned long flags;
 
        if (devinfo->shutdown)
@@ -1106,7 +1101,7 @@ static int uas_pre_reset(struct usb_interface *intf)
 static int uas_post_reset(struct usb_interface *intf)
 {
        struct Scsi_Host *shost = usb_get_intfdata(intf);
-       struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+       struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
        unsigned long flags;
 
        if (devinfo->shutdown)
@@ -1130,7 +1125,7 @@ static int uas_post_reset(struct usb_interface *intf)
 static int uas_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct Scsi_Host *shost = usb_get_intfdata(intf);
-       struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+       struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
 
        /* Wait for any pending requests to complete */
        flush_work(&devinfo->work);
@@ -1150,7 +1145,7 @@ static int uas_resume(struct usb_interface *intf)
 static int uas_reset_resume(struct usb_interface *intf)
 {
        struct Scsi_Host *shost = usb_get_intfdata(intf);
-       struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+       struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
        unsigned long flags;
 
        if (uas_configure_endpoints(devinfo) != 0) {
@@ -1169,7 +1164,7 @@ static int uas_reset_resume(struct usb_interface *intf)
 static void uas_disconnect(struct usb_interface *intf)
 {
        struct Scsi_Host *shost = usb_get_intfdata(intf);
-       struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+       struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
 
        devinfo->resetting = 1;
        cancel_work_sync(&devinfo->work);
@@ -1180,7 +1175,7 @@ static void uas_disconnect(struct usb_interface *intf)
        uas_zap_dead(devinfo);
        scsi_remove_host(shost);
        uas_free_streams(devinfo);
-       kfree(devinfo);
+       scsi_host_put(shost);
 }
 
 /*
@@ -1193,7 +1188,7 @@ static void uas_shutdown(struct device *dev)
        struct usb_interface *intf = to_usb_interface(dev);
        struct usb_device *udev = interface_to_usbdev(intf);
        struct Scsi_Host *shost = usb_get_intfdata(intf);
-       struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+       struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
 
        if (system_state != SYSTEM_RESTART)
                return;
-- 
1.8.4.2

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to