usbip: usbip_host: run rebind from exit when module is removed
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) <shuah@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
ae70c6dc3f
commit
dcadfaf212
|
@ -448,12 +448,8 @@ static void stub_disconnect(struct usb_device *udev)
|
|||
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
|
||||
|
|
|
@ -14,6 +14,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
|
||||
|
@ -169,6 +170,51 @@ static ssize_t match_busid_store(struct device_driver *dev, const char *buf,
|
|||
}
|
||||
static DRIVER_ATTR_RW(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,
|
||||
size_t count)
|
||||
{
|
||||
|
@ -189,16 +235,9 @@ static ssize_t rebind_store(struct device_driver *dev, const char *buf,
|
|||
/* 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(&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");
|
||||
ret = do_rebind((char *) buf, bid);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* delete device from busid_table */
|
||||
del_match_busid((char *) buf);
|
||||
|
@ -323,6 +362,9 @@ static void __exit usbip_host_exit(void)
|
|||
*/
|
||||
usb_deregister_device_driver(&stub_driver);
|
||||
|
||||
/* initiate scan to attach devices */
|
||||
stub_device_rebind();
|
||||
|
||||
kmem_cache_destroy(stub_priv_cache);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue