Commit 59ad4f53 authored by Shuah Khan (Samsung OSG)'s avatar Shuah Khan (Samsung OSG) Committed by Greg Kroah-Hartman

usbip: usbip_host: run rebind from exit when module is removed

commit 7510df3f 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: default avatarShuah Khan (Samsung OSG) <shuah@kernel.org>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 58c9c70c
...@@ -462,12 +462,8 @@ static void stub_disconnect(struct usb_device *udev) ...@@ -462,12 +462,8 @@ static void stub_disconnect(struct usb_device *udev)
busid_priv->sdev = NULL; busid_priv->sdev = NULL;
stub_device_free(sdev); stub_device_free(sdev);
if (busid_priv->status == STUB_BUSID_ALLOC) { if (busid_priv->status == STUB_BUSID_ALLOC)
busid_priv->status = STUB_BUSID_ADDED; busid_priv->status = STUB_BUSID_ADDED;
} else {
busid_priv->status = STUB_BUSID_OTHER;
del_match_busid((char *)udev_busid);
}
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#define DRIVER_DESC "USB/IP Host Driver" #define DRIVER_DESC "USB/IP Host Driver"
struct kmem_cache *stub_priv_cache; struct kmem_cache *stub_priv_cache;
/* /*
* busid_tables defines matching busids that usbip can grab. A user can change * 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 * dynamically what device is locally used and what device is exported to a
...@@ -184,6 +185,51 @@ static ssize_t store_match_busid(struct device_driver *dev, const char *buf, ...@@ -184,6 +185,51 @@ static ssize_t store_match_busid(struct device_driver *dev, const char *buf,
static DRIVER_ATTR(match_busid, S_IRUSR | S_IWUSR, show_match_busid, static DRIVER_ATTR(match_busid, S_IRUSR | S_IWUSR, show_match_busid,
store_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(&busid_priv->udev->dev);
if (busid_priv->udev->dev.parent)
device_unlock(busid_priv->udev->dev.parent);
if (ret < 0) {
dev_err(&busid_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(&busid_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(&busid_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, static ssize_t rebind_store(struct device_driver *dev, const char *buf,
size_t count) size_t count)
{ {
...@@ -204,16 +250,9 @@ static ssize_t rebind_store(struct device_driver *dev, const char *buf, ...@@ -204,16 +250,9 @@ static ssize_t rebind_store(struct device_driver *dev, const char *buf,
/* mark the device for deletion so probe ignores it during rescan */ /* mark the device for deletion so probe ignores it during rescan */
bid->status = STUB_BUSID_OTHER; bid->status = STUB_BUSID_OTHER;
/* device_attach() callers should hold parent lock for USB */ ret = do_rebind((char *) buf, bid);
if (bid->udev->dev.parent) if (ret < 0)
device_lock(bid->udev->dev.parent);
ret = device_attach(&bid->udev->dev);
if (bid->udev->dev.parent)
device_unlock(bid->udev->dev.parent);
if (ret < 0) {
dev_err(&bid->udev->dev, "rebind failed\n");
return ret; return ret;
}
/* delete device from busid_table */ /* delete device from busid_table */
del_match_busid((char *) buf); del_match_busid((char *) buf);
...@@ -339,6 +378,9 @@ static void __exit usbip_host_exit(void) ...@@ -339,6 +378,9 @@ static void __exit usbip_host_exit(void)
*/ */
usb_deregister_device_driver(&stub_driver); usb_deregister_device_driver(&stub_driver);
/* initiate scan to attach devices */
stub_device_rebind();
kmem_cache_destroy(stub_priv_cache); kmem_cache_destroy(stub_priv_cache);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment