Skip to content

Commit 0c9e8b3

Browse files
shuahkhgregkh
authored andcommitted
usbip: usbip_host: fix BUG: sleeping function called from invalid context
stub_probe() and stub_disconnect() call functions which could call sleeping function in invalid context whil holding busid_lock. Fix the problem by refining the lock holds to short critical sections to change the busid_priv fields. This fix restructures the code to limit the lock holds in stub_probe() and stub_disconnect(). stub_probe(): [15217.927028] BUG: sleeping function called from invalid context at mm/slab.h:418 [15217.927038] in_atomic(): 1, irqs_disabled(): 0, pid: 29087, name: usbip [15217.927044] 5 locks held by usbip/29087: [15217.927047] #0: 0000000091647f28 (sb_writers#6){....}, at: vfs_write+0x191/0x1c0 [15217.927062] #1: 000000008f9ba75b (&of->mutex){....}, at: kernfs_fop_write+0xf7/0x1b0 [15217.927072] #2: 00000000872e5b4b (&dev->mutex){....}, at: __device_driver_lock+0x3b/0x50 [15217.927082] #3: 00000000e74ececc (&dev->mutex){....}, at: __device_driver_lock+0x46/0x50 [15217.927090] #4: 00000000b20abbe0 (&(&busid_table[i].busid_lock)->rlock){....}, at: get_busid_priv+0x48/0x60 [usbip_host] [15217.927103] CPU: 3 PID: 29087 Comm: usbip Tainted: G W 5.1.0-rc6+ #40 [15217.927106] Hardware name: Dell Inc. OptiPlex 790/0HY9JP, BIOS A18 09/24/2013 [15217.927109] Call Trace: [15217.927118] dump_stack+0x63/0x85 [15217.927127] ___might_sleep+0xff/0x120 [15217.927133] __might_sleep+0x4a/0x80 [15217.927143] kmem_cache_alloc_trace+0x1aa/0x210 [15217.927156] stub_probe+0xe8/0x440 [usbip_host] [15217.927171] usb_probe_device+0x34/0x70 stub_disconnect(): [15279.182478] BUG: sleeping function called from invalid context at kernel/locking/mutex.c:908 [15279.182487] in_atomic(): 1, irqs_disabled(): 0, pid: 29114, name: usbip [15279.182492] 5 locks held by usbip/29114: [15279.182494] #0: 0000000091647f28 (sb_writers#6){....}, at: vfs_write+0x191/0x1c0 [15279.182506] #1: 00000000702cf0f3 (&of->mutex){....}, at: kernfs_fop_write+0xf7/0x1b0 [15279.182514] #2: 00000000872e5b4b (&dev->mutex){....}, at: __device_driver_lock+0x3b/0x50 [15279.182522] #3: 00000000e74ececc (&dev->mutex){....}, at: __device_driver_lock+0x46/0x50 [15279.182529] #4: 00000000b20abbe0 (&(&busid_table[i].busid_lock)->rlock){....}, at: get_busid_priv+0x48/0x60 [usbip_host] [15279.182541] CPU: 0 PID: 29114 Comm: usbip Tainted: G W 5.1.0-rc6+ #40 [15279.182543] Hardware name: Dell Inc. OptiPlex 790/0HY9JP, BIOS A18 09/24/2013 [15279.182546] Call Trace: [15279.182554] dump_stack+0x63/0x85 [15279.182561] ___might_sleep+0xff/0x120 [15279.182566] __might_sleep+0x4a/0x80 [15279.182574] __mutex_lock+0x55/0x950 [15279.182582] ? get_busid_priv+0x48/0x60 [usbip_host] [15279.182587] ? reacquire_held_locks+0xec/0x1a0 [15279.182591] ? get_busid_priv+0x48/0x60 [usbip_host] [15279.182597] ? find_held_lock+0x94/0xa0 [15279.182609] mutex_lock_nested+0x1b/0x20 [15279.182614] ? mutex_lock_nested+0x1b/0x20 [15279.182618] kernfs_remove_by_name_ns+0x2a/0x90 [15279.182625] sysfs_remove_file_ns+0x15/0x20 [15279.182629] device_remove_file+0x19/0x20 [15279.182634] stub_disconnect+0x6d/0x180 [usbip_host] [15279.182643] usb_unbind_device+0x27/0x60 Signed-off-by: Shuah Khan <skhan@linuxfoundation.org> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 9a5729f commit 0c9e8b3

File tree

1 file changed

+43
-22
lines changed

1 file changed

+43
-22
lines changed

drivers/usb/usbip/stub_dev.c

+43-22
Original file line numberDiff line numberDiff line change
@@ -301,9 +301,17 @@ static int stub_probe(struct usb_device *udev)
301301
const char *udev_busid = dev_name(&udev->dev);
302302
struct bus_id_priv *busid_priv;
303303
int rc = 0;
304+
char save_status;
304305

305306
dev_dbg(&udev->dev, "Enter probe\n");
306307

308+
/* Not sure if this is our device. Allocate here to avoid
309+
* calling alloc while holding busid_table lock.
310+
*/
311+
sdev = stub_device_alloc(udev);
312+
if (!sdev)
313+
return -ENOMEM;
314+
307315
/* check we should claim or not by busid_table */
308316
busid_priv = get_busid_priv(udev_busid);
309317
if (!busid_priv || (busid_priv->status == STUB_BUSID_REMOV) ||
@@ -318,14 +326,14 @@ static int stub_probe(struct usb_device *udev)
318326
* See driver_probe_device() in driver/base/dd.c
319327
*/
320328
rc = -ENODEV;
321-
goto call_put_busid_priv;
329+
goto sdev_free;
322330
}
323331

324332
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) {
325333
dev_dbg(&udev->dev, "%s is a usb hub device... skip!\n",
326334
udev_busid);
327335
rc = -ENODEV;
328-
goto call_put_busid_priv;
336+
goto sdev_free;
329337
}
330338

331339
if (!strcmp(udev->bus->bus_name, "vhci_hcd")) {
@@ -334,15 +342,9 @@ static int stub_probe(struct usb_device *udev)
334342
udev_busid);
335343

336344
rc = -ENODEV;
337-
goto call_put_busid_priv;
345+
goto sdev_free;
338346
}
339347

340-
/* ok, this is my device */
341-
sdev = stub_device_alloc(udev);
342-
if (!sdev) {
343-
rc = -ENOMEM;
344-
goto call_put_busid_priv;
345-
}
346348

347349
dev_info(&udev->dev,
348350
"usbip-host: register new device (bus %u dev %u)\n",
@@ -352,9 +354,13 @@ static int stub_probe(struct usb_device *udev)
352354

353355
/* set private data to usb_device */
354356
dev_set_drvdata(&udev->dev, sdev);
357+
355358
busid_priv->sdev = sdev;
356359
busid_priv->udev = udev;
357360

361+
save_status = busid_priv->status;
362+
busid_priv->status = STUB_BUSID_ALLOC;
363+
358364
/*
359365
* Claim this hub port.
360366
* It doesn't matter what value we pass as owner
@@ -367,15 +373,16 @@ static int stub_probe(struct usb_device *udev)
367373
goto err_port;
368374
}
369375

376+
/* release the busid_lock */
377+
put_busid_priv(busid_priv);
378+
370379
rc = stub_add_files(&udev->dev);
371380
if (rc) {
372381
dev_err(&udev->dev, "stub_add_files for %s\n", udev_busid);
373382
goto err_files;
374383
}
375-
busid_priv->status = STUB_BUSID_ALLOC;
376384

377-
rc = 0;
378-
goto call_put_busid_priv;
385+
return 0;
379386

380387
err_files:
381388
usb_hub_release_port(udev->parent, udev->portnum,
@@ -384,23 +391,24 @@ static int stub_probe(struct usb_device *udev)
384391
dev_set_drvdata(&udev->dev, NULL);
385392
usb_put_dev(udev);
386393

394+
/* we already have busid_priv, just lock busid_lock */
395+
spin_lock(&busid_priv->busid_lock);
387396
busid_priv->sdev = NULL;
397+
busid_priv->status = save_status;
398+
sdev_free:
388399
stub_device_free(sdev);
389-
390-
call_put_busid_priv:
400+
/* release the busid_lock */
391401
put_busid_priv(busid_priv);
402+
392403
return rc;
393404
}
394405

395406
static void shutdown_busid(struct bus_id_priv *busid_priv)
396407
{
397-
if (busid_priv->sdev && !busid_priv->shutdown_busid) {
398-
busid_priv->shutdown_busid = 1;
399-
usbip_event_add(&busid_priv->sdev->ud, SDEV_EVENT_REMOVED);
408+
usbip_event_add(&busid_priv->sdev->ud, SDEV_EVENT_REMOVED);
400409

401-
/* wait for the stop of the event handler */
402-
usbip_stop_eh(&busid_priv->sdev->ud);
403-
}
410+
/* wait for the stop of the event handler */
411+
usbip_stop_eh(&busid_priv->sdev->ud);
404412
}
405413

406414
/*
@@ -432,6 +440,9 @@ static void stub_disconnect(struct usb_device *udev)
432440

433441
dev_set_drvdata(&udev->dev, NULL);
434442

443+
/* release busid_lock before call to remove device files */
444+
put_busid_priv(busid_priv);
445+
435446
/*
436447
* NOTE: rx/tx threads are invoked for each usb_device.
437448
*/
@@ -442,18 +453,27 @@ static void stub_disconnect(struct usb_device *udev)
442453
(struct usb_dev_state *) udev);
443454
if (rc) {
444455
dev_dbg(&udev->dev, "unable to release port\n");
445-
goto call_put_busid_priv;
456+
return;
446457
}
447458

448459
/* If usb reset is called from event handler */
449460
if (usbip_in_eh(current))
450-
goto call_put_busid_priv;
461+
return;
462+
463+
/* we already have busid_priv, just lock busid_lock */
464+
spin_lock(&busid_priv->busid_lock);
465+
if (!busid_priv->shutdown_busid)
466+
busid_priv->shutdown_busid = 1;
467+
/* release busid_lock */
468+
put_busid_priv(busid_priv);
451469

452470
/* shutdown the current connection */
453471
shutdown_busid(busid_priv);
454472

455473
usb_put_dev(sdev->udev);
456474

475+
/* we already have busid_priv, just lock busid_lock */
476+
spin_lock(&busid_priv->busid_lock);
457477
/* free sdev */
458478
busid_priv->sdev = NULL;
459479
stub_device_free(sdev);
@@ -462,6 +482,7 @@ static void stub_disconnect(struct usb_device *udev)
462482
busid_priv->status = STUB_BUSID_ADDED;
463483

464484
call_put_busid_priv:
485+
/* release busid_lock */
465486
put_busid_priv(busid_priv);
466487
}
467488

0 commit comments

Comments
 (0)