Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7510df3f authored by Shuah Khan (Samsung OSG)'s avatar Shuah Khan (Samsung OSG) Committed by Greg Kroah-Hartman
Browse files

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: default avatarShuah Khan (Samsung OSG) <shuah@kernel.org>
Cc: stable <stable@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1e180f16
Loading
Loading
Loading
Loading
+1 −5
Original line number Diff line number Diff line
@@ -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
+51 −9
Original line number Diff line number Diff line
@@ -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);
}