[PATCH 3.16 09/63] usbip: usbip_host: run rebind from exit when module is removed

2018-09-21 Thread Ben Hutchings
3.16.58-rc1 review patch.  If anyone has any objections, please let me know.

--

From: "Shuah Khan (Samsung OSG)" 

commit 7510df3f29d44685bab7b1918b61a8ccd57126a9 upstream.

After removing usbip_host module, devices it releases are left without
a driver. For example, when a keyboard or a mass storage device are
bound to usbip_host when it is removed, these devices are no longer
bound to any driver.

Fix it to run device_attach() from the module exit routine to restore
the devices to their original drivers. This includes cleanup changes
and moving device_attach() code to a common routine to be called from
rebind_store() and usbip_host_exit().

Signed-off-by: Shuah Khan (Samsung OSG) 
Signed-off-by: Greg Kroah-Hartman 
[bwh: Backported to 3.16: adjust filenames]
Signed-off-by: Ben Hutchings 
---
 drivers/staging/usbip/stub_dev.c  |  6 +---
 drivers/staging/usbip/stub_main.c | 60 +--
 2 files changed, 52 insertions(+), 14 deletions(-)

--- a/drivers/staging/usbip/stub_dev.c
+++ b/drivers/staging/usbip/stub_dev.c
@@ -490,12 +490,8 @@ static void stub_disconnect(struct usb_d
busid_priv->sdev = NULL;
stub_device_free(sdev);
 
-   if (busid_priv->status == STUB_BUSID_ALLOC) {
+   if (busid_priv->status == STUB_BUSID_ALLOC)
busid_priv->status = STUB_BUSID_ADDED;
-   } else {
-   busid_priv->status = STUB_BUSID_OTHER;
-   del_match_busid((char *)udev_busid);
-   }
 }
 
 #ifdef CONFIG_PM
--- a/drivers/staging/usbip/stub_main.c
+++ b/drivers/staging/usbip/stub_main.c
@@ -28,6 +28,7 @@
 #define DRIVER_DESC "USB/IP Host Driver"
 
 struct kmem_cache *stub_priv_cache;
+
 /*
  * busid_tables defines matching busids that usbip can grab. A user can change
  * dynamically what device is locally used and what device is exported to a
@@ -188,6 +189,51 @@ static ssize_t store_match_busid(struct
 static DRIVER_ATTR(match_busid, S_IRUSR | S_IWUSR, show_match_busid,
   store_match_busid);
 
+static int do_rebind(char *busid, struct bus_id_priv *busid_priv)
+{
+   int ret;
+
+   /* device_attach() callers should hold parent lock for USB */
+   if (busid_priv->udev->dev.parent)
+   device_lock(busid_priv->udev->dev.parent);
+   ret = device_attach(_priv->udev->dev);
+   if (busid_priv->udev->dev.parent)
+   device_unlock(busid_priv->udev->dev.parent);
+   if (ret < 0) {
+   dev_err(_priv->udev->dev, "rebind failed\n");
+   return ret;
+   }
+   return 0;
+}
+
+static void stub_device_rebind(void)
+{
+#if IS_MODULE(CONFIG_USBIP_HOST)
+   struct bus_id_priv *busid_priv;
+   int i;
+
+   /* update status to STUB_BUSID_OTHER so probe ignores the device */
+   spin_lock(_table_lock);
+   for (i = 0; i < MAX_BUSID; i++) {
+   if (busid_table[i].name[0] &&
+   busid_table[i].shutdown_busid) {
+   busid_priv = &(busid_table[i]);
+   busid_priv->status = STUB_BUSID_OTHER;
+   }
+   }
+   spin_unlock(_table_lock);
+
+   /* now run rebind */
+   for (i = 0; i < MAX_BUSID; i++) {
+   if (busid_table[i].name[0] &&
+   busid_table[i].shutdown_busid) {
+   busid_priv = &(busid_table[i]);
+   do_rebind(busid_table[i].name, busid_priv);
+   }
+   }
+#endif
+}
+
 static ssize_t rebind_store(struct device_driver *dev, const char *buf,
 size_t count)
 {
@@ -208,16 +254,9 @@ static ssize_t rebind_store(struct devic
/* mark the device for deletion so probe ignores it during rescan */
bid->status = STUB_BUSID_OTHER;
 
-   /* device_attach() callers should hold parent lock for USB */
-   if (bid->udev->dev.parent)
-   device_lock(bid->udev->dev.parent);
-   ret = device_attach(>udev->dev);
-   if (bid->udev->dev.parent)
-   device_unlock(bid->udev->dev.parent);
-   if (ret < 0) {
-   dev_err(>udev->dev, "rebind failed\n");
+   ret = do_rebind((char *) buf, bid);
+   if (ret < 0)
return ret;
-   }
 
/* delete device from busid_table */
del_match_busid((char *) buf);
@@ -343,6 +382,9 @@ static void __exit usbip_host_exit(void)
 */
usb_deregister_device_driver(_driver);
 
+   /* initiate scan to attach devices */
+   stub_device_rebind();
+
kmem_cache_destroy(stub_priv_cache);
 }
 



[PATCH 3.16 09/63] usbip: usbip_host: run rebind from exit when module is removed

2018-09-21 Thread Ben Hutchings
3.16.58-rc1 review patch.  If anyone has any objections, please let me know.

--

From: "Shuah Khan (Samsung OSG)" 

commit 7510df3f29d44685bab7b1918b61a8ccd57126a9 upstream.

After removing usbip_host module, devices it releases are left without
a driver. For example, when a keyboard or a mass storage device are
bound to usbip_host when it is removed, these devices are no longer
bound to any driver.

Fix it to run device_attach() from the module exit routine to restore
the devices to their original drivers. This includes cleanup changes
and moving device_attach() code to a common routine to be called from
rebind_store() and usbip_host_exit().

Signed-off-by: Shuah Khan (Samsung OSG) 
Signed-off-by: Greg Kroah-Hartman 
[bwh: Backported to 3.16: adjust filenames]
Signed-off-by: Ben Hutchings 
---
 drivers/staging/usbip/stub_dev.c  |  6 +---
 drivers/staging/usbip/stub_main.c | 60 +--
 2 files changed, 52 insertions(+), 14 deletions(-)

--- a/drivers/staging/usbip/stub_dev.c
+++ b/drivers/staging/usbip/stub_dev.c
@@ -490,12 +490,8 @@ static void stub_disconnect(struct usb_d
busid_priv->sdev = NULL;
stub_device_free(sdev);
 
-   if (busid_priv->status == STUB_BUSID_ALLOC) {
+   if (busid_priv->status == STUB_BUSID_ALLOC)
busid_priv->status = STUB_BUSID_ADDED;
-   } else {
-   busid_priv->status = STUB_BUSID_OTHER;
-   del_match_busid((char *)udev_busid);
-   }
 }
 
 #ifdef CONFIG_PM
--- a/drivers/staging/usbip/stub_main.c
+++ b/drivers/staging/usbip/stub_main.c
@@ -28,6 +28,7 @@
 #define DRIVER_DESC "USB/IP Host Driver"
 
 struct kmem_cache *stub_priv_cache;
+
 /*
  * busid_tables defines matching busids that usbip can grab. A user can change
  * dynamically what device is locally used and what device is exported to a
@@ -188,6 +189,51 @@ static ssize_t store_match_busid(struct
 static DRIVER_ATTR(match_busid, S_IRUSR | S_IWUSR, show_match_busid,
   store_match_busid);
 
+static int do_rebind(char *busid, struct bus_id_priv *busid_priv)
+{
+   int ret;
+
+   /* device_attach() callers should hold parent lock for USB */
+   if (busid_priv->udev->dev.parent)
+   device_lock(busid_priv->udev->dev.parent);
+   ret = device_attach(_priv->udev->dev);
+   if (busid_priv->udev->dev.parent)
+   device_unlock(busid_priv->udev->dev.parent);
+   if (ret < 0) {
+   dev_err(_priv->udev->dev, "rebind failed\n");
+   return ret;
+   }
+   return 0;
+}
+
+static void stub_device_rebind(void)
+{
+#if IS_MODULE(CONFIG_USBIP_HOST)
+   struct bus_id_priv *busid_priv;
+   int i;
+
+   /* update status to STUB_BUSID_OTHER so probe ignores the device */
+   spin_lock(_table_lock);
+   for (i = 0; i < MAX_BUSID; i++) {
+   if (busid_table[i].name[0] &&
+   busid_table[i].shutdown_busid) {
+   busid_priv = &(busid_table[i]);
+   busid_priv->status = STUB_BUSID_OTHER;
+   }
+   }
+   spin_unlock(_table_lock);
+
+   /* now run rebind */
+   for (i = 0; i < MAX_BUSID; i++) {
+   if (busid_table[i].name[0] &&
+   busid_table[i].shutdown_busid) {
+   busid_priv = &(busid_table[i]);
+   do_rebind(busid_table[i].name, busid_priv);
+   }
+   }
+#endif
+}
+
 static ssize_t rebind_store(struct device_driver *dev, const char *buf,
 size_t count)
 {
@@ -208,16 +254,9 @@ static ssize_t rebind_store(struct devic
/* mark the device for deletion so probe ignores it during rescan */
bid->status = STUB_BUSID_OTHER;
 
-   /* device_attach() callers should hold parent lock for USB */
-   if (bid->udev->dev.parent)
-   device_lock(bid->udev->dev.parent);
-   ret = device_attach(>udev->dev);
-   if (bid->udev->dev.parent)
-   device_unlock(bid->udev->dev.parent);
-   if (ret < 0) {
-   dev_err(>udev->dev, "rebind failed\n");
+   ret = do_rebind((char *) buf, bid);
+   if (ret < 0)
return ret;
-   }
 
/* delete device from busid_table */
del_match_busid((char *) buf);
@@ -343,6 +382,9 @@ static void __exit usbip_host_exit(void)
 */
usb_deregister_device_driver(_driver);
 
+   /* initiate scan to attach devices */
+   stub_device_rebind();
+
kmem_cache_destroy(stub_priv_cache);
 }