aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShuah Khan (Samsung OSG) <shuah@kernel.org>2018-04-30 18:17:20 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-05-15 03:47:52 -0400
commit7510df3f29d44685bab7b1918b61a8ccd57126a9 (patch)
tree77d6090c7237e522a8008830ba34eee0a6e23d59
parent1e180f167d4e413afccbbb4a421b48b2de832549 (diff)
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> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/usbip/stub_dev.c6
-rw-r--r--drivers/usb/usbip/stub_main.c60
2 files changed, 52 insertions, 14 deletions
diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c
index 7813c1862941..9d0425113c4b 100644
--- a/drivers/usb/usbip/stub_dev.c
+++ b/drivers/usb/usbip/stub_dev.c
@@ -448,12 +448,8 @@ static void stub_disconnect(struct usb_device *udev)
448 busid_priv->sdev = NULL; 448 busid_priv->sdev = NULL;
449 stub_device_free(sdev); 449 stub_device_free(sdev);
450 450
451 if (busid_priv->status == STUB_BUSID_ALLOC) { 451 if (busid_priv->status == STUB_BUSID_ALLOC)
452 busid_priv->status = STUB_BUSID_ADDED; 452 busid_priv->status = STUB_BUSID_ADDED;
453 } else {
454 busid_priv->status = STUB_BUSID_OTHER;
455 del_match_busid((char *)udev_busid);
456 }
457} 453}
458 454
459#ifdef CONFIG_PM 455#ifdef CONFIG_PM
diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c
index fb46bd62d538..587b9bc10042 100644
--- a/drivers/usb/usbip/stub_main.c
+++ b/drivers/usb/usbip/stub_main.c
@@ -14,6 +14,7 @@
14#define DRIVER_DESC "USB/IP Host Driver" 14#define DRIVER_DESC "USB/IP Host Driver"
15 15
16struct kmem_cache *stub_priv_cache; 16struct kmem_cache *stub_priv_cache;
17
17/* 18/*
18 * busid_tables defines matching busids that usbip can grab. A user can change 19 * busid_tables defines matching busids that usbip can grab. A user can change
19 * dynamically what device is locally used and what device is exported to a 20 * 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,
169} 170}
170static DRIVER_ATTR_RW(match_busid); 171static DRIVER_ATTR_RW(match_busid);
171 172
173static int do_rebind(char *busid, struct bus_id_priv *busid_priv)
174{
175 int ret;
176
177 /* device_attach() callers should hold parent lock for USB */
178 if (busid_priv->udev->dev.parent)
179 device_lock(busid_priv->udev->dev.parent);
180 ret = device_attach(&busid_priv->udev->dev);
181 if (busid_priv->udev->dev.parent)
182 device_unlock(busid_priv->udev->dev.parent);
183 if (ret < 0) {
184 dev_err(&busid_priv->udev->dev, "rebind failed\n");
185 return ret;
186 }
187 return 0;
188}
189
190static void stub_device_rebind(void)
191{
192#if IS_MODULE(CONFIG_USBIP_HOST)
193 struct bus_id_priv *busid_priv;
194 int i;
195
196 /* update status to STUB_BUSID_OTHER so probe ignores the device */
197 spin_lock(&busid_table_lock);
198 for (i = 0; i < MAX_BUSID; i++) {
199 if (busid_table[i].name[0] &&
200 busid_table[i].shutdown_busid) {
201 busid_priv = &(busid_table[i]);
202 busid_priv->status = STUB_BUSID_OTHER;
203 }
204 }
205 spin_unlock(&busid_table_lock);
206
207 /* now run rebind */
208 for (i = 0; i < MAX_BUSID; i++) {
209 if (busid_table[i].name[0] &&
210 busid_table[i].shutdown_busid) {
211 busid_priv = &(busid_table[i]);
212 do_rebind(busid_table[i].name, busid_priv);
213 }
214 }
215#endif
216}
217
172static ssize_t rebind_store(struct device_driver *dev, const char *buf, 218static ssize_t rebind_store(struct device_driver *dev, const char *buf,
173 size_t count) 219 size_t count)
174{ 220{
@@ -189,16 +235,9 @@ static ssize_t rebind_store(struct device_driver *dev, const char *buf,
189 /* mark the device for deletion so probe ignores it during rescan */ 235 /* mark the device for deletion so probe ignores it during rescan */
190 bid->status = STUB_BUSID_OTHER; 236 bid->status = STUB_BUSID_OTHER;
191 237
192 /* device_attach() callers should hold parent lock for USB */ 238 ret = do_rebind((char *) buf, bid);
193 if (bid->udev->dev.parent) 239 if (ret < 0)
194 device_lock(bid->udev->dev.parent);
195 ret = device_attach(&bid->udev->dev);
196 if (bid->udev->dev.parent)
197 device_unlock(bid->udev->dev.parent);
198 if (ret < 0) {
199 dev_err(&bid->udev->dev, "rebind failed\n");
200 return ret; 240 return ret;
201 }
202 241
203 /* delete device from busid_table */ 242 /* delete device from busid_table */
204 del_match_busid((char *) buf); 243 del_match_busid((char *) buf);
@@ -323,6 +362,9 @@ static void __exit usbip_host_exit(void)
323 */ 362 */
324 usb_deregister_device_driver(&stub_driver); 363 usb_deregister_device_driver(&stub_driver);
325 364
365 /* initiate scan to attach devices */
366 stub_device_rebind();
367
326 kmem_cache_destroy(stub_priv_cache); 368 kmem_cache_destroy(stub_priv_cache);
327} 369}
328 370