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
This commit is contained in:
Ingo Weinhold 2003-06-12 22:21:10 +00:00
parent f3df767f76
commit ef9b1b52ee
8 changed files with 316 additions and 15 deletions

View File

@ -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;

View File

@ -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<KDiskDevice*> fDevices; // TODO: Optimize!
List<KPartition*> fPartitions; //

View File

@ -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;

View File

@ -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

View File

@ -1,5 +1,11 @@
// KDiskDevice.cpp
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <Drivers.h>
#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;
}

View File

@ -1,8 +1,12 @@
// KDiskDeviceManager.cpp
#include <dirent.h>
#include <errno.h>
#include <module.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#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;

View File

@ -2,6 +2,7 @@
#include <stdlib.h>
#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);
}

View File

@ -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;