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:
Родитель
ae70c6dc3f
Коммит
dcadfaf212
|
@ -448,12 +448,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
|
||||||
|
|
|
@ -14,6 +14,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
|
||||||
|
@ -169,6 +170,51 @@ static ssize_t match_busid_store(struct device_driver *dev, const char *buf,
|
||||||
}
|
}
|
||||||
static DRIVER_ATTR_RW(match_busid);
|
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,
|
static ssize_t rebind_store(struct device_driver *dev, const char *buf,
|
||||||
size_t count)
|
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 */
|
/* 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);
|
||||||
|
@ -323,6 +362,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче