From 1f89a3766aabc54e84a0bdebcac66d85c3202727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sat, 1 Dec 2007 11:09:58 +0000 Subject: [PATCH] * device_delete_child() now works differently from FreeBSD: in FreeBSD you can't just call this function if you don't know if a device has a direct reference to one of its children. Since we want to be able to delete the root without having any knowledge about its children, we now detach everything first, and then delete the entries. This fixes a possible crashing bug when a preloaded driver (used for network boot) tried to acquire its resources again at a later point. * device_detach() and device_attach() now check if the device has an attach or detach method at all. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23036 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/libs/compat/freebsd_network/compat.c | 37 +++++++++++++++++------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/src/libs/compat/freebsd_network/compat.c b/src/libs/compat/freebsd_network/compat.c index 80c660e652..d89c3d8e2b 100644 --- a/src/libs/compat/freebsd_network/compat.c +++ b/src/libs/compat/freebsd_network/compat.c @@ -314,27 +314,40 @@ device_add_child(device_t parent, const char *name, int unit) int device_delete_child(device_t parent, device_t child) { + int status; + if (child == NULL) return 0; if (parent != NULL) list_remove_item(&parent->children, child); + // We differentiate from the FreeBSD logic here - it will first delete + // the children, and will then detach the device. + // This has the problem that you cannot safely call device_delete_child() + // as you don't know if one of the children deletes its own children this + // way when it is detached. + // Therefore, we'll detach first, and then delete whatever is left. + parent = child; + child = NULL; - while ((child = list_remove_head_item(&parent->children)) != NULL) { - device_delete_child(NULL, child); + // detach children + while ((child = list_get_next_item(&parent->children, child)) != NULL) { + device_detach(child); } - if ((atomic_and(&parent->flags, ~DEVICE_ATTACHED) & DEVICE_ATTACHED) != 0 - && parent->methods.detach != NULL) { - int status = parent->methods.detach(parent); - if (status != 0) { - atomic_or(&parent->flags, DEVICE_ATTACHED); - return status; - } + // detach device + status = device_detach(parent); + if (status != 0) + return status; + + // delete children + while ((child = list_get_first_item(&parent->children)) != NULL) { + device_delete_child(parent, child); } + // delete device if (parent->flags & DEVICE_DESC_ALLOCED) free((char *)parent->description); @@ -356,7 +369,8 @@ device_attach(device_t device) { int result; - if (device->driver == NULL) + if (device->driver == NULL + || device->methods.attach == NULL) return B_ERROR; result = device->methods.attach(device); @@ -373,7 +387,8 @@ device_detach(device_t device) if (device->driver == NULL) return B_ERROR; - if ((atomic_and(&device->flags, ~DEVICE_ATTACHED) & DEVICE_ATTACHED) != 0) { + if ((atomic_and(&device->flags, ~DEVICE_ATTACHED) & DEVICE_ATTACHED) != 0 + && device->methods.detach != NULL) { int result = device->methods.detach(device); if (result != 0) { atomic_or(&device->flags, DEVICE_ATTACHED);