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
This commit is contained in:
Oron Peled 2012-01-10 22:09:34 +00:00 committed by Shaun Ruffell
parent 17a2ce9421
commit f06c8d50cf

View File

@ -900,18 +900,37 @@ int xbus_is_registered(xbus_t *xbus)
return xbus->ddev && xbus->ddev->dev.parent; 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 xbus_register_dahdi_device(xbus_t *xbus)
{ {
int i; int i;
int offset = 0; int offset = 0;
int ret;
XBUS_DBG(DEVICES, xbus, "Entering %s\n", __func__); XBUS_DBG(DEVICES, xbus, "Entering %s\n", __func__);
if (xbus_is_registered(xbus)) { if (xbus_is_registered(xbus)) {
XBUS_ERR(xbus, "Already registered to DAHDI\n"); XBUS_ERR(xbus, "Already registered to DAHDI\n");
WARN_ON(1); WARN_ON(1);
return -EINVAL; ret = -EINVAL;
goto err;
} }
xbus->ddev = dahdi_create_device(); xbus->ddev = dahdi_create_device();
if (!xbus->ddev) {
ret = -ENOMEM;
goto err;
}
/* /*
* This actually describe the dahdi_spaninfo version 3 * This actually describe the dahdi_spaninfo version 3
* A bunch of unrelated data exported via a modified ioctl() * 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. * OK, let's add to the kernel more useless info.
*/ */
xbus->ddev->devicetype = kasprintf(GFP_KERNEL, "Astribank2"); xbus->ddev->devicetype = kasprintf(GFP_KERNEL, "Astribank2");
if (!xbus->ddev->devicetype) if (!xbus->ddev->devicetype) {
return -ENOMEM; ret = -ENOMEM;
goto err;
}
/* /*
* location is the only usefull new data item. * 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)) { if (dahdi_register_device(xbus->ddev, &xbus->astribank)) {
XBUS_ERR(xbus, "Failed to dahdi_register_device()\n"); XBUS_ERR(xbus, "Failed to dahdi_register_device()\n");
return -ENODEV; ret = -ENODEV;
goto err;
} }
for (i = 0; i < MAX_XPDS; i++) { for (i = 0; i < MAX_XPDS; i++) {
xpd_t *xpd = xpd_of(xbus, i); xpd_t *xpd = xpd_of(xbus, i);
@ -962,6 +984,9 @@ int xbus_register_dahdi_device(xbus_t *xbus)
} }
} }
return 0; return 0;
err:
xbus_free_ddev(xbus);
return ret;
} }
void xbus_unregister_dahdi_device(xbus_t *xbus) void xbus_unregister_dahdi_device(xbus_t *xbus)
@ -976,12 +1001,7 @@ void xbus_unregister_dahdi_device(xbus_t *xbus)
if (xbus->ddev) { if (xbus->ddev) {
dahdi_unregister_device(xbus->ddev); dahdi_unregister_device(xbus->ddev);
XBUS_NOTICE(xbus, "%s: finished dahdi_unregister_device()\n", __func__); XBUS_NOTICE(xbus, "%s: finished dahdi_unregister_device()\n", __func__);
kfree(xbus->ddev->devicetype); xbus_free_ddev(xbus);
xbus->ddev->devicetype = NULL;
xbus->ddev->location = NULL;
xbus->ddev->hardware_id = NULL;
dahdi_free_device(xbus->ddev);
xbus->ddev = NULL;
} }
for(i = 0; i < MAX_XPDS; i++) { for(i = 0; i < MAX_XPDS; i++) {
xpd_t *xpd = xpd_of(xbus, i); xpd_t *xpd = xpd_of(xbus, i);