diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2012-12-23 15:09:55 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-01-21 13:52:37 -0500 |
commit | 779d516ca91d796cb37bd0760282d08f90661ee2 (patch) | |
tree | 8e5157be9c343294f4270e2b1d9fe1aa0d69bd1f /drivers/usb/gadget/composite.c | |
parent | afd2e186bd7e58dc9d298ff5fb5a2fc30578867e (diff) |
usb: gadget: composite: don't call driver's unbind() if bind() failed
Lets assume nokia_bind() starts with "return -EINVAL". After loading the
gadget we end up with:
|udc dummy_udc.0: registering UDC driver [g_nokia]
|BUG: unable to handle kernel NULL pointer dereference at 00000040
|IP: [<c11f9555>] __list_add+0x25/0xf0
|Call Trace:
| [<c12d4e21>] rollback_registered+0x21/0x40
| [<c12d513f>] unregister_netdevice_queue+0x4f/0xa0
| [<c12d5259>] unregister_netdev+0x19/0x30
| [<f81335b2>] gphonet_cleanup+0x32/0x50 [g_nokia]
| [<f8133f1c>] nokia_unbind+0x1c/0x2a [g_nokia]
| [<f802509f>] __composite_unbind.constprop.10+0x4f/0xb0 [libcomposite]
| [<f80255be>] composite_bind+0x1ae/0x230 [libcomposite]
| [<c129e576>] usb_gadget_probe_driver+0xc6/0x1b0
| [<f8024aba>] usb_composite_probe+0x7a/0xa0 [libcomposite]
That is crash from nokia_unbind() invoked via nokia_bind(). This crash
will look different we if make it until usb_string_ids_tab() before we
enter an error condition in the probe function.
nokia_bind_config() tries to clean up which is IMHO the right thing to
do. Leaving things as-is and hoping that its unbind() will clean it up
is kinda backwards. Especially since the bind function never succeeded so
it can't know how much it needs to clean up.
This fixes the behaviour by not calling the driver's unbind function if
its bind function failed.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget/composite.c')
-rw-r--r-- | drivers/usb/gadget/composite.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 71475b6d8568..9db000013f5d 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c | |||
@@ -1349,8 +1349,7 @@ static ssize_t composite_show_suspended(struct device *dev, | |||
1349 | 1349 | ||
1350 | static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL); | 1350 | static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL); |
1351 | 1351 | ||
1352 | static void | 1352 | static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver) |
1353 | composite_unbind(struct usb_gadget *gadget) | ||
1354 | { | 1353 | { |
1355 | struct usb_composite_dev *cdev = get_gadget_data(gadget); | 1354 | struct usb_composite_dev *cdev = get_gadget_data(gadget); |
1356 | 1355 | ||
@@ -1367,7 +1366,7 @@ composite_unbind(struct usb_gadget *gadget) | |||
1367 | struct usb_configuration, list); | 1366 | struct usb_configuration, list); |
1368 | remove_config(cdev, c); | 1367 | remove_config(cdev, c); |
1369 | } | 1368 | } |
1370 | if (cdev->driver->unbind) | 1369 | if (cdev->driver->unbind && unbind_driver) |
1371 | cdev->driver->unbind(cdev); | 1370 | cdev->driver->unbind(cdev); |
1372 | 1371 | ||
1373 | if (cdev->req) { | 1372 | if (cdev->req) { |
@@ -1380,6 +1379,11 @@ composite_unbind(struct usb_gadget *gadget) | |||
1380 | set_gadget_data(gadget, NULL); | 1379 | set_gadget_data(gadget, NULL); |
1381 | } | 1380 | } |
1382 | 1381 | ||
1382 | static void composite_unbind(struct usb_gadget *gadget) | ||
1383 | { | ||
1384 | __composite_unbind(gadget, true); | ||
1385 | } | ||
1386 | |||
1383 | static void update_unchanged_dev_desc(struct usb_device_descriptor *new, | 1387 | static void update_unchanged_dev_desc(struct usb_device_descriptor *new, |
1384 | const struct usb_device_descriptor *old) | 1388 | const struct usb_device_descriptor *old) |
1385 | { | 1389 | { |
@@ -1488,7 +1492,7 @@ static int composite_bind(struct usb_gadget *gadget, | |||
1488 | return 0; | 1492 | return 0; |
1489 | 1493 | ||
1490 | fail: | 1494 | fail: |
1491 | composite_unbind(gadget); | 1495 | __composite_unbind(gadget, false); |
1492 | return status; | 1496 | return status; |
1493 | } | 1497 | } |
1494 | 1498 | ||