diff options
author | Shaun Ruffell <sruffell@digium.com> | 2012-01-10 22:09:34 +0000 |
---|---|---|
committer | Shaun Ruffell <sruffell@digium.com> | 2012-01-10 22:09:34 +0000 |
commit | b9908040c01908ed27ca21c25e2b46137a294b6e (patch) | |
tree | a5f365dcc886e2c62e2eb165d930280a335f91b7 | |
parent | 90bc4a1a828fb8feeeb3d35e7371ca4f8089f77d (diff) |
xpp: handle failures during dahdi_register_device()
* If dahdi_register_device() failed, not all resources were freed.
When dahdi_unregister_device() was called later (during driver
removal) a panic was caused.
* Add proper error handling for possible failures in
xbus_register_dahdi_device():
- new xbus_free_ddev() safely free an xbus->ddev
- This is called from all failures points.
- It is also called from xbus_unregister_dahdi_device()
Signed-off-by: Oron Peled <oron.peled@xorcom.com>
Acked-By: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=10410
git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/branches/2.6@10419 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r-- | drivers/dahdi/xpp/xbus-core.c | 44 |
1 files changed, 32 insertions, 12 deletions
diff --git a/drivers/dahdi/xpp/xbus-core.c b/drivers/dahdi/xpp/xbus-core.c index 0226b4c..fc9217f 100644 --- a/drivers/dahdi/xpp/xbus-core.c +++ b/drivers/dahdi/xpp/xbus-core.c @@ -900,18 +900,37 @@ int xbus_is_registered(xbus_t *xbus) return xbus->ddev && xbus->ddev->dev.parent; } +static void xbus_free_ddev(xbus_t *xbus) +{ + if (!xbus->ddev) + return; + if (xbus->ddev->devicetype) + kfree(xbus->ddev->devicetype); + xbus->ddev->devicetype = NULL; + xbus->ddev->location = NULL; + xbus->ddev->hardware_id = NULL; + dahdi_free_device(xbus->ddev); + xbus->ddev = NULL; +} + int xbus_register_dahdi_device(xbus_t *xbus) { - int i; - int offset = 0; + int i; + int offset = 0; + int ret; XBUS_DBG(DEVICES, xbus, "Entering %s\n", __func__); if (xbus_is_registered(xbus)) { XBUS_ERR(xbus, "Already registered to DAHDI\n"); WARN_ON(1); - return -EINVAL; + ret = -EINVAL; + goto err; } xbus->ddev = dahdi_create_device(); + if (!xbus->ddev) { + ret = -ENOMEM; + goto err; + } /* * This actually describe the dahdi_spaninfo version 3 * A bunch of unrelated data exported via a modified ioctl() @@ -926,8 +945,10 @@ int xbus_register_dahdi_device(xbus_t *xbus) * OK, let's add to the kernel more useless info. */ xbus->ddev->devicetype = kasprintf(GFP_KERNEL, "Astribank2"); - if (!xbus->ddev->devicetype) - return -ENOMEM; + if (!xbus->ddev->devicetype) { + ret = -ENOMEM; + goto err; + } /* * location is the only usefull new data item. @@ -952,7 +973,8 @@ int xbus_register_dahdi_device(xbus_t *xbus) } if (dahdi_register_device(xbus->ddev, &xbus->astribank)) { XBUS_ERR(xbus, "Failed to dahdi_register_device()\n"); - return -ENODEV; + ret = -ENODEV; + goto err; } for (i = 0; i < MAX_XPDS; i++) { xpd_t *xpd = xpd_of(xbus, i); @@ -962,6 +984,9 @@ int xbus_register_dahdi_device(xbus_t *xbus) } } return 0; +err: + xbus_free_ddev(xbus); + return ret; } void xbus_unregister_dahdi_device(xbus_t *xbus) @@ -976,12 +1001,7 @@ void xbus_unregister_dahdi_device(xbus_t *xbus) if (xbus->ddev) { dahdi_unregister_device(xbus->ddev); XBUS_NOTICE(xbus, "%s: finished dahdi_unregister_device()\n", __func__); - kfree(xbus->ddev->devicetype); - xbus->ddev->devicetype = NULL; - xbus->ddev->location = NULL; - xbus->ddev->hardware_id = NULL; - dahdi_free_device(xbus->ddev); - xbus->ddev = NULL; + xbus_free_ddev(xbus); } for(i = 0; i < MAX_XPDS; i++) { xpd_t *xpd = xpd_of(xbus, i); |