From ef9b1b52eeb1a76daf914efb01cb847fdbb48211 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 12 Jun 2003 22:21:10 +0000 Subject: [PATCH] Implemented a preliminary disk device scanning in KDiskDeviceManager. Some changes to KPartition, KDiskDevice, KDiskSystem on this way. Still missing is KPartition::Publish() and its invocation in KDiskDeviceManager. Then everything should be in place to start with porting the scanning parts of our disk system modules. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3486 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/disk_device_manager/KDiskDevice.h | 5 + .../disk_device_manager/KDiskDeviceManager.h | 13 +- .../kernel/disk_device_manager/KDiskSystem.h | 1 + .../kernel/disk_device_manager/KPartition.h | 5 + .../core/disk_device_manager/KDiskDevice.cpp | 77 ++++++- .../KDiskDeviceManager.cpp | 195 +++++++++++++++++- .../core/disk_device_manager/KDiskSystem.cpp | 4 + .../core/disk_device_manager/KPartition.cpp | 31 ++- 8 files changed, 316 insertions(+), 15 deletions(-) diff --git a/headers/private/kernel/disk_device_manager/KDiskDevice.h b/headers/private/kernel/disk_device_manager/KDiskDevice.h index f5973db469..50b8c21a37 100644 --- a/headers/private/kernel/disk_device_manager/KDiskDevice.h +++ b/headers/private/kernel/disk_device_manager/KDiskDevice.h @@ -23,7 +23,10 @@ public: KDiskDevice(partition_id id = -1); virtual ~KDiskDevice(); + status_t SetTo(const char *path); + void Unset(); status_t InitCheck() const; + // TODO: probably superfluous // A read lock owner can be sure that the device (incl. all of its // partitions won't be changed). @@ -64,6 +67,8 @@ public: team_id ShadowOwner() const; private: + void _InitPartitionData(); + disk_device_data fDeviceData; RWLocker fLocker; int fFD; diff --git a/headers/private/kernel/disk_device_manager/KDiskDeviceManager.h b/headers/private/kernel/disk_device_manager/KDiskDeviceManager.h index 81010d4463..d203596727 100644 --- a/headers/private/kernel/disk_device_manager/KDiskDeviceManager.h +++ b/headers/private/kernel/disk_device_manager/KDiskDeviceManager.h @@ -44,12 +44,13 @@ public: KDiskDevice *RegisterDevice(const char *path, bool noShadow = true); KDiskDevice *RegisterDevice(partition_id id, bool noShadow = true); + KDiskDevice *RegisterNextDevice(int32 *cookie); KPartition *RegisterPartition(const char *path, bool noShadow = true); KPartition *RegisterPartition(partition_id id, bool noShadow = true); // manager must be locked - int32 CountDiskDevices(); - KDiskDevice *DiskDeviceAt(int32 index); + int32 CountDevices(); + KDiskDevice *DeviceAt(int32 index); bool PartitionAdded(KPartition *partition); // implementation internal bool PartitionRemoved(KPartition *partition); // @@ -74,16 +75,24 @@ public: int32 CountDiskSystems(); KDiskSystem *DiskSystemAt(int32 index); + KDiskSystem *LoadDiskSystem(disk_system_id id); + KDiskSystem *LoadNextDiskSystem(int32 *cookie); + // Watching // TODO: Watching service for the kernel. The userland watching is handled // by the registrar. + status_t InitialDeviceScan(); + private: status_t _AddPartitioningSystem(const char *name); status_t _AddFileSystem(const char *name); status_t _AddDiskSystem(KDiskSystem *diskSystem); + status_t _Scan(const char *path); + status_t _ScanPartition(KPartition *partition); + BLocker fLock; List fDevices; // TODO: Optimize! List fPartitions; // diff --git a/headers/private/kernel/disk_device_manager/KDiskSystem.h b/headers/private/kernel/disk_device_manager/KDiskSystem.h index 62ab750769..f58af9fc1f 100644 --- a/headers/private/kernel/disk_device_manager/KDiskSystem.h +++ b/headers/private/kernel/disk_device_manager/KDiskSystem.h @@ -26,6 +26,7 @@ public: virtual bool IsFileSystem() const; bool IsPartitioningSystem() const; + // manager will be locked status_t Load(); // load/unload -- can be nested void Unload(); // bool IsLoaded() const; diff --git a/headers/private/kernel/disk_device_manager/KPartition.h b/headers/private/kernel/disk_device_manager/KPartition.h index 182c321c3e..ef56bc8c97 100644 --- a/headers/private/kernel/disk_device_manager/KPartition.h +++ b/headers/private/kernel/disk_device_manager/KPartition.h @@ -139,6 +139,9 @@ public: KDiskSystem *DiskSystem() const; void SetParentDiskSystem(KDiskSystem *diskSystem); KDiskSystem *ParentDiskSystem() const; + // When setting a disk system, it must already be loaded. + // The partition will load it too, hence it won't be unloaded before + // it is unset here. void SetCookie(void *cookie); void *Cookie() const; @@ -148,6 +151,7 @@ public: private: void _UpdateChildIndices(int32 index); + static int32 _NextID(); protected: partition_data fPartitionData; @@ -157,6 +161,7 @@ protected: KDiskSystem *fDiskSystem; KDiskSystem *fParentDiskSystem; int32 fReferenceCount; + static int32 fNextID; }; } // namespace DiskDevice diff --git a/src/kernel/core/disk_device_manager/KDiskDevice.cpp b/src/kernel/core/disk_device_manager/KDiskDevice.cpp index 4508127419..8fe80b4404 100644 --- a/src/kernel/core/disk_device_manager/KDiskDevice.cpp +++ b/src/kernel/core/disk_device_manager/KDiskDevice.cpp @@ -1,5 +1,11 @@ // KDiskDevice.cpp +#include +#include +#include + +#include + #include "KDiskDevice.h" #include "KDiskDeviceUtils.h" @@ -12,9 +18,59 @@ KDiskDevice::KDiskDevice(partition_id id) fMediaStatus(B_ERROR), fShadowOwner(-1) { + Unset(); +} + +// destructor +KDiskDevice::~KDiskDevice() +{ + Unset(); +} + +// SetTo +status_t +KDiskDevice::SetTo(const char *path) +{ + // check initialization and parameter + status_t error = InitCheck(); + if (error != B_OK) + return error; + if (!path) + return B_BAD_VALUE; + Unset(); + // set the path + error = set_string(fDeviceData.path, path); + if (error != B_OK) + return error; + // open the device + fFD = open(path, O_RDONLY); + if (fFD < 0) + return errno; + // get device geometry and media status + // TODO: files need to be handled differently + if (ioctl(fFD, B_GET_MEDIA_STATUS, &fMediaStatus) == 0 + && ioctl(fFD, B_GET_GEOMETRY, &fDeviceData.geometry) == 0) { + _InitPartitionData(); + } + return B_OK; +} + +// Unset +void +KDiskDevice::Unset() +{ + if (fFD >= 0) { + close(fFD); + fFD = -1; + } + fMediaStatus = B_ERROR; + fShadowOwner = -1; fDeviceData.id = -1; fDeviceData.flags = 0; - fDeviceData.path = NULL; + if (fDeviceData.path) { + free(fDeviceData.path); + fDeviceData.path = NULL; + } fDeviceData.geometry.bytes_per_sector = 0; fDeviceData.geometry.sectors_per_track = 0; fDeviceData.geometry.cylinder_count = 0; @@ -25,12 +81,6 @@ KDiskDevice::KDiskDevice(partition_id id) fDeviceData.geometry.write_once = false; } -// destructor -KDiskDevice::~KDiskDevice() -{ - free(fDeviceData.path); -} - // InitCheck status_t KDiskDevice::InitCheck() const @@ -178,3 +228,16 @@ KDiskDevice::ShadowOwner() const return fShadowOwner; } +// _InitPartitionData +void +KDiskDevice::_InitPartitionData() +{ + fDeviceData.id = fPartitionData.id; + fPartitionData.block_size = fDeviceData.geometry.bytes_per_sector; + fPartitionData.offset = 0; + fPartitionData.size = (off_t)fPartitionData.block_size + * fDeviceData.geometry.sectors_per_track + * fDeviceData.geometry.cylinder_count + * fDeviceData.geometry.head_count; +} + diff --git a/src/kernel/core/disk_device_manager/KDiskDeviceManager.cpp b/src/kernel/core/disk_device_manager/KDiskDeviceManager.cpp index 9debe67ef7..4901b78613 100644 --- a/src/kernel/core/disk_device_manager/KDiskDeviceManager.cpp +++ b/src/kernel/core/disk_device_manager/KDiskDeviceManager.cpp @@ -1,8 +1,12 @@ // KDiskDeviceManager.cpp +#include +#include #include +#include #include #include +#include #include "KDiskDevice.h" #include "KDiskDeviceManager.h" @@ -188,6 +192,26 @@ KDiskDeviceManager::RegisterDevice(partition_id id, bool noShadow) return NULL; } +// RegisterNextDevice +KDiskDevice * +KDiskDeviceManager::RegisterNextDevice(int32 *cookie) +{ + if (!cookie) + return NULL; + if (ManagerLocker locker = this) { + // TODO: This loop assumes that the device list is ordered. Make sure + // that this is really the case. + for (int32 i = 0; KDiskDevice *device = fDevices.ItemAt(i); i++) { + if (device->ID() >= *cookie) { + device->Register(); + *cookie = device->ID() + 1; + return device; + } + } + } + return NULL; +} + // RegisterPartition KPartition * KDiskDeviceManager::RegisterPartition(const char *path, bool noShadow) @@ -214,18 +238,18 @@ KDiskDeviceManager::RegisterPartition(partition_id id, bool noShadow) return NULL; } -// CountDiskDevices +// CountDevices int32 -KDiskDeviceManager::CountDiskDevices() +KDiskDeviceManager::CountDevices() { if (ManagerLocker locker = this) return fDevices.CountItems(); return 0; } -// DiskDeviceAt +// DiskAt KDiskDevice * -KDiskDeviceManager::DiskDeviceAt(int32 index) +KDiskDeviceManager::DeviceAt(int32 index) { if (ManagerLocker locker = this) return fDevices.ItemAt(index); @@ -330,6 +354,68 @@ KDiskDeviceManager::DiskSystemAt(int32 index) return fDiskSystems.ItemAt(index); } +// LoadDiskSystem +KDiskSystem * +KDiskDeviceManager::LoadDiskSystem(disk_system_id id) +{ + KDiskSystem *diskSystem = NULL; + if (ManagerLocker locker = this) { + diskSystem = DiskSystemWithID(id); + if (diskSystem && diskSystem->Load() != B_OK) + diskSystem = NULL; + } + return diskSystem; +} + +// LoadNextDiskSystem +KDiskSystem * +KDiskDeviceManager::LoadNextDiskSystem(int32 *cookie) +{ + if (!cookie) + return NULL; + if (ManagerLocker locker = this) { + // TODO: This loop assumes that the disk system list is ordered. + // Make sure that this is really the case. + for (int32 i = 0; KDiskSystem *diskSystem = DiskSystemAt(i); i++) { + if (diskSystem->ID() >= *cookie) { + if (diskSystem->Load() == B_OK) { + *cookie = diskSystem->ID() + 1; + return diskSystem; + } + } + } + } + return NULL; +} + +// InitialDeviceScan +status_t +KDiskDeviceManager::InitialDeviceScan() +{ + status_t error = B_ERROR; + // scan for devices + if (ManagerLocker locker = this) + error = _Scan("/dev/disk"); + // scan the devices for partitions + // TODO: This is only provisional. + if (error == B_OK) { + int32 cookie = 0; + while (KDiskDevice *device = RegisterNextDevice(&cookie)) { + if (device->WriteLock()) { + // scan the device + error = _ScanPartition(device); + if (error != B_OK) { + // ... + error = B_OK; + } + device->WriteUnlock(); + } + device->Unregister(); + } + } + return error; +} + // _AddPartitioningSystem status_t KDiskDeviceManager::_AddPartitioningSystem(const char *name) @@ -372,6 +458,107 @@ KDiskDeviceManager::_AddDiskSystem(KDiskSystem *diskSystem) return error; } +// _Scan +status_t +KDiskDeviceManager::_Scan(const char *path) +{ + status_t error = B_OK; + struct stat st; + if (lstat(path, &st) < 0) + return errno; + if (S_ISDIR(st.st_mode)) { + // a directory: iterate through its contents + DIR *dir = opendir(path); + if (!dir) + return errno; + while (dirent *entry = readdir(dir)) { + // skip "." and ".." + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) + continue; + if (strlen(path) + strlen(entry->d_name) + 1 >= B_PATH_NAME_LENGTH) + continue; + char entryPath[B_PATH_NAME_LENGTH]; + sprintf(entryPath, "%s/%s", path, entry->d_name); + _Scan(entryPath); + } + closedir(dir); + } else { + // not a directory + // check, if it is named "raw" + int32 len = strlen(path); + int32 leafLen = strlen("/raw"); + if (len <= leafLen || strcmp(path + len - leafLen, "/raw")) + return B_ERROR; + // create a KDiskDevice for it + KDiskDevice *device = new(nothrow) KDiskDevice; + if (!device) + return B_NO_MEMORY; + // init the KDiskDevice + status_t error = device->SetTo(path); + // add the device + if (error == B_OK && !fDevices.AddItem(device)) + error = B_NO_MEMORY; + // cleanup on error + if (error != B_OK) + delete device; + } + return error; +} + +// _ScanPartition +status_t +KDiskDeviceManager::_ScanPartition(KPartition *partition) +{ + // the partition's device must be write-locked + if (!partition) + return B_BAD_VALUE; + // find the disk system that returns the best priority for this partition + float bestPriority = -1; + KDiskSystem *bestDiskSystem = NULL; + void *bestCookie = NULL; + int32 itCookie; + while (KDiskSystem *diskSystem = LoadNextDiskSystem(&itCookie)) { + void *cookie = NULL; + float priority = diskSystem->Identify(partition, &cookie); + if (priority >= 0 && priority > bestPriority) { + // new best disk system + if (bestDiskSystem) { + bestDiskSystem->FreeIdentifyCookie(partition, bestCookie); + bestDiskSystem->Unload(); + } + bestPriority = priority; + bestDiskSystem = diskSystem; + bestCookie = cookie; + } else { + // disk system doesn't identify the partition or worse than our + // current favorite + diskSystem->FreeIdentifyCookie(partition, cookie); + diskSystem->Unload(); + } + } + // now, if we have found a disk system, let it scan the partition + status_t error = B_OK; + if (bestDiskSystem) { + error = bestDiskSystem->Scan(partition, bestCookie); + if (error == B_OK) { + partition->SetDiskSystem(bestDiskSystem); + for (int32 i = 0; KPartition *child = partition->ChildAt(i); i++) { + child->SetParentDiskSystem(bestDiskSystem); + _ScanPartition(child); + } + } else { + // TODO: Handle the error. + } + // now we can safely unload the disk system -- it has been loaded by + // the partition(s) and thus will not really be unloaded + bestDiskSystem->Unload(); + } else { + // contents not recognized + // nothing to be done -- partitions are created as unrecognized + } + return error; +} + // singleton instance KDiskDeviceManager *KDiskDeviceManager::fDefaultManager = NULL; diff --git a/src/kernel/core/disk_device_manager/KDiskSystem.cpp b/src/kernel/core/disk_device_manager/KDiskSystem.cpp index daef43a860..2ddaeb8908 100644 --- a/src/kernel/core/disk_device_manager/KDiskSystem.cpp +++ b/src/kernel/core/disk_device_manager/KDiskSystem.cpp @@ -2,6 +2,7 @@ #include +#include "KDiskDeviceManager.h" #include "KDiskDeviceUtils.h" #include "KDiskSystem.h" @@ -75,6 +76,7 @@ KDiskSystem::IsPartitioningSystem() const status_t KDiskSystem::Load() { + ManagerLocker locker(KDiskDeviceManager::Default()); status_t error = B_OK; if (fLoadCounter == 0) error = LoadModule(); @@ -87,6 +89,7 @@ KDiskSystem::Load() void KDiskSystem::Unload() { + ManagerLocker locker(KDiskDeviceManager::Default()); if (fLoadCounter > 0 && --fLoadCounter == 0) UnloadModule(); } @@ -95,6 +98,7 @@ KDiskSystem::Unload() bool KDiskSystem::IsLoaded() const { + ManagerLocker locker(KDiskDeviceManager::Default()); return (fLoadCounter > 0); } diff --git a/src/kernel/core/disk_device_manager/KPartition.cpp b/src/kernel/core/disk_device_manager/KPartition.cpp index fe97dea8dd..077efa6e34 100644 --- a/src/kernel/core/disk_device_manager/KPartition.cpp +++ b/src/kernel/core/disk_device_manager/KPartition.cpp @@ -14,10 +14,10 @@ #include "KDiskDevice.h" #include "KDiskDeviceManager.h" #include "KDiskDeviceUtils.h" +#include "KDiskSystem.h" #include "KPartition.h" using namespace std; -using BPrivate::DiskDevice::KDiskSystem; // constructor KPartition::KPartition(partition_id id) @@ -29,7 +29,7 @@ KPartition::KPartition(partition_id id) fParentDiskSystem(NULL), fReferenceCount(0) { - fPartitionData.id = id; + fPartitionData.id = (id >= 0 ? id : _NextID()); fPartitionData.offset = 0; fPartitionData.size = 0; fPartitionData.block_size = 0; @@ -600,7 +600,15 @@ KPartition::IsShadowPartition() const void KPartition::SetDiskSystem(KDiskSystem *diskSystem) { + // unload former disk system + if (fDiskSystem) { + fDiskSystem->Unload(); + fDiskSystem = NULL; + } + // set and load new one fDiskSystem = diskSystem; + if (fDiskSystem) + fDiskSystem->Load(); } // DiskSystem @@ -614,7 +622,15 @@ KPartition::DiskSystem() const void KPartition::SetParentDiskSystem(KDiskSystem *diskSystem) { + // unload former disk system + if (fParentDiskSystem) { + fParentDiskSystem->Unload(); + fParentDiskSystem = NULL; + } + // set and load new one fParentDiskSystem = diskSystem; + if (fParentDiskSystem) + fParentDiskSystem->Load(); } // ParentDiskSystem @@ -660,3 +676,14 @@ KPartition::_UpdateChildIndices(int32 index) child->SetIndex(index); } +// _NextID +int32 +KPartition::_NextID() +{ + return atomic_add(&fNextID, 1); +} + + +// fNextID +int32 KPartition::fNextID = 0; +