From 6015793f57d08929e6e27b7bdc690835ac98eedc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 12 May 2009 20:03:58 +0000 Subject: [PATCH] * Instead of deleting the device directly, we now only remove it from its parent. * Additionally, when a vnode is deleted, the new BaseDevice::Removed() method is called that will remove the device from its parent if needed, and delete it then. * This should fix #3856. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30726 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/device_manager/BaseDevice.cpp | 8 ++++- src/system/kernel/device_manager/BaseDevice.h | 4 ++- src/system/kernel/device_manager/devfs.cpp | 5 +++- .../kernel/device_manager/device_manager.cpp | 24 +++++++++++++-- .../kernel/device_manager/legacy_drivers.cpp | 30 +++++++++++++++---- 5 files changed, 61 insertions(+), 10 deletions(-) diff --git a/src/system/kernel/device_manager/BaseDevice.cpp b/src/system/kernel/device_manager/BaseDevice.cpp index 1e462f4bca..780ce2f72f 100644 --- a/src/system/kernel/device_manager/BaseDevice.cpp +++ b/src/system/kernel/device_manager/BaseDevice.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2008-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ @@ -33,3 +33,9 @@ void BaseDevice::UninitDevice() { } + + +void +BaseDevice::Removed() +{ +} diff --git a/src/system/kernel/device_manager/BaseDevice.h b/src/system/kernel/device_manager/BaseDevice.h index 8b0bfa8346..cf8b18ec76 100644 --- a/src/system/kernel/device_manager/BaseDevice.h +++ b/src/system/kernel/device_manager/BaseDevice.h @@ -1,5 +1,5 @@ /* - * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2008-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #ifndef BASE_DEVICE_H @@ -22,6 +22,8 @@ public: virtual status_t InitDevice(); virtual void UninitDevice(); + virtual void Removed(); + device_module_info* Module() const { return fDeviceModule; } void* Data() const { return fDeviceData; } diff --git a/src/system/kernel/device_manager/devfs.cpp b/src/system/kernel/device_manager/devfs.cpp index 8190eb2402..8e5390af8e 100644 --- a/src/system/kernel/device_manager/devfs.cpp +++ b/src/system/kernel/device_manager/devfs.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. @@ -252,6 +252,9 @@ devfs_delete_vnode(struct devfs* fs, struct devfs_vnode* vnode, hash_remove(fs->vnode_hash, vnode); if (S_ISCHR(vnode->stream.type)) { + // pass the call through to the underlying device + vnode->stream.u.dev.device->Removed(); + // for partitions, we have to release the raw device but must // not free the device info as it was inherited from the raw // device and is still in use there diff --git a/src/system/kernel/device_manager/device_manager.cpp b/src/system/kernel/device_manager/device_manager.cpp index 01791cacaf..1adf81ee35 100644 --- a/src/system/kernel/device_manager/device_manager.cpp +++ b/src/system/kernel/device_manager/device_manager.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2008-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ @@ -84,8 +84,14 @@ public: virtual status_t InitDevice(); virtual void UninitDevice(); + virtual void Removed(); + + void SetRemovedFromParent(bool removed) + { fRemovedFromParent = removed; } + private: const char* fModuleName; + bool fRemovedFromParent; }; typedef DoublyLinkedList DeviceList; @@ -1057,6 +1063,8 @@ device_attr_private::Compare(const device_attr* attrA, const device_attr *attrB) Device::Device(device_node* node, const char* moduleName) + : + fRemovedFromParent(false) { fNode = node; fModuleName = strdup(moduleName); @@ -1144,6 +1152,18 @@ Device::UninitDevice() } +void +Device::Removed() +{ + RecursiveLocker _(sLock); + + if (!fRemovedFromParent) + fNode->RemoveDevice(this); + + delete this; +} + + // #pragma mark - device_node @@ -1201,8 +1221,8 @@ device_node::~device_node() // Delete devices while (Device* device = fDevices.RemoveHead()) { + device->SetRemovedFromParent(true); devfs_unpublish_device(device, true); - delete device; } // Delete attributes diff --git a/src/system/kernel/device_manager/legacy_drivers.cpp b/src/system/kernel/device_manager/legacy_drivers.cpp index 053fb1480c..2047143ec2 100644 --- a/src/system/kernel/device_manager/legacy_drivers.cpp +++ b/src/system/kernel/device_manager/legacy_drivers.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ @@ -54,6 +54,8 @@ public: virtual status_t InitDevice(); virtual void UninitDevice(); + virtual void Removed(); + void SetHooks(device_hooks* hooks); legacy_driver* Driver() const { return fDriver; } @@ -67,11 +69,16 @@ public: bool Republished() const { return fRepublished; } void SetRepublished(bool republished) { fRepublished = republished; } + + void SetRemovedFromParent(bool removed) + { fRemovedFromParent = removed; } + private: legacy_driver* fDriver; const char* fPath; device_hooks* fHooks; bool fRepublished; + bool fRemovedFromParent; }; typedef DoublyLinkedList DeviceList; @@ -284,9 +291,9 @@ republish_driver(legacy_driver* driver) TRACE(("devfs: unpublishing no more present \"%s\"\n", device->Path())); iterator.Remove(); + device->SetRemovedFromParent(true); devfs_unpublish_device(device, true); - delete device; } if (exported == 0) { @@ -430,8 +437,8 @@ static void unpublish_driver(legacy_driver *driver) { while (LegacyDevice* device = driver->devices.RemoveHead()) { - if (devfs_unpublish_device(device, true) == B_OK) - delete device; + device->SetRemovedFromParent(true); + devfs_unpublish_device(device, true); } } @@ -1109,7 +1116,8 @@ LegacyDevice::LegacyDevice(legacy_driver* driver, const char* path, device_hooks* hooks) : fDriver(driver), - fRepublished(true) + fRepublished(true), + fRemovedFromParent(false) { fDeviceModule = (device_module_info*)malloc(sizeof(device_module_info)); if (fDeviceModule != NULL) @@ -1171,6 +1179,18 @@ LegacyDevice::UninitDevice() } +void +LegacyDevice::Removed() +{ + RecursiveLocker _(sLock); + + if (!fRemovedFromParent) + fDriver->devices.Remove(this); + + delete this; +} + + void LegacyDevice::SetHooks(device_hooks* hooks) {