* Implemented what was left to do for KDiskDevice and KPartition

management regarding removal and deletion of objects.
* Fixed the file disk system related stuff. KFileDiskSystem now uses the
  virtualdrive driver. The former method was seemed simple and brilliant,
  but the B_SET_PARTITION ioctl wouldn't work.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3650 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2003-06-24 23:56:16 +00:00
parent 7a424c3923
commit b23394f957
8 changed files with 274 additions and 101 deletions

View File

@ -36,8 +36,10 @@ public:
// manager lock owners can be sure, that it won't change. // manager lock owners can be sure, that it won't change.
bool ReadLock(); bool ReadLock();
void ReadUnlock(); void ReadUnlock();
bool IsReadLocked(bool orWriteLocked = true);
bool WriteLock(); bool WriteLock();
void WriteUnlock(); void WriteUnlock();
bool IsWriteLocked();
virtual void SetID(partition_id id); virtual void SetID(partition_id id);

View File

@ -53,7 +53,7 @@ public:
KFileDiskDevice *RegisterFileDevice(const char *filePath, KFileDiskDevice *RegisterFileDevice(const char *filePath,
bool noShadow = true); bool noShadow = true);
status_t CreateFileDevice(const char *filePath, int32 *device = 0); status_t CreateFileDevice(const char *filePath, partition_id *device = 0);
status_t DeleteFileDevice(const char *filePath); status_t DeleteFileDevice(const char *filePath);
// manager must be locked // manager must be locked
@ -62,6 +62,7 @@ public:
bool PartitionAdded(KPartition *partition); // implementation internal bool PartitionAdded(KPartition *partition); // implementation internal
bool PartitionRemoved(KPartition *partition); // bool PartitionRemoved(KPartition *partition); //
bool DeletePartition(KPartition *partition); //
// Jobs // Jobs
@ -106,9 +107,10 @@ private:
status_t _ScanPartition(KPartition *partition); status_t _ScanPartition(KPartition *partition);
BLocker fLock; BLocker fLock;
List<KDiskDevice*> fDevices; // TODO: Optimize! List<KDiskDevice*> fDevices; // TODO: Optimize!
List<KPartition*> fPartitions; // List<KPartition*> fPartitions; //
List<KDiskSystem*> fDiskSystems; // List<KDiskSystem*> fDiskSystems; //
List<KPartition*> fObsoletePartitions; //
static KDiskDeviceManager *fDefaultManager; static KDiskDeviceManager *fDefaultManager;
}; };

View File

@ -26,9 +26,9 @@ public:
// virtual void Dump(bool deep = true, int32 level = 0); // virtual void Dump(bool deep = true, int32 level = 0);
protected: private:
virtual status_t GetMediaStatus(status_t *mediaStatus); static status_t _RegisterDevice(const char *file, const char *device);
virtual status_t GetGeometry(device_geometry *geometry); static status_t _UnregisterDevice(const char *device);
private: private:
char *fFilePath; char *fFilePath;

View File

@ -36,6 +36,13 @@ public:
void Unregister(); void Unregister();
int32 CountReferences() const; int32 CountReferences() const;
void MarkObsolete();
// called by the manager only
bool IsObsolete() const;
virtual bool PrepareForRemoval();
virtual bool PrepareForDeletion();
status_t Open(int flags, int *fd); status_t Open(int flags, int *fd);
virtual status_t PublishDevice(); virtual status_t PublishDevice();
virtual status_t UnpublishDevice(); virtual status_t UnpublishDevice();
@ -122,7 +129,9 @@ public:
status_t AddChild(KPartition *partition, int32 index = -1); status_t AddChild(KPartition *partition, int32 index = -1);
status_t CreateChild(partition_id id, int32 index, status_t CreateChild(partition_id id, int32 index,
KPartition **child = NULL); KPartition **child = NULL);
KPartition *RemoveChild(int32 index); bool RemoveChild(int32 index);
bool RemoveChild(KPartition *child);
bool RemoveAllChildren();
KPartition *ChildAt(int32 index) const; KPartition *ChildAt(int32 index) const;
int32 CountChildren() const; int32 CountChildren() const;
@ -137,7 +146,6 @@ public:
void SetDiskSystem(KDiskSystem *diskSystem); void SetDiskSystem(KDiskSystem *diskSystem);
KDiskSystem *DiskSystem() const; KDiskSystem *DiskSystem() const;
void SetParentDiskSystem(KDiskSystem *diskSystem);
KDiskSystem *ParentDiskSystem() const; KDiskSystem *ParentDiskSystem() const;
// When setting a disk system, it must already be loaded. // When setting a disk system, it must already be loaded.
// The partition will load it too, hence it won't be unloaded before // The partition will load it too, hence it won't be unloaded before
@ -161,8 +169,8 @@ protected:
KDiskDevice *fDevice; KDiskDevice *fDevice;
KPartition *fParent; KPartition *fParent;
KDiskSystem *fDiskSystem; KDiskSystem *fDiskSystem;
KDiskSystem *fParentDiskSystem;
int32 fReferenceCount; int32 fReferenceCount;
bool fObsolete;
static int32 fNextID; static int32 fNextID;
}; };

View File

@ -111,6 +111,13 @@ KDiskDevice::ReadUnlock()
fLocker.ReadUnlock(); fLocker.ReadUnlock();
} }
// IsReadLocked
bool
KDiskDevice::IsReadLocked(bool orWriteLocked)
{
return fLocker.IsReadLocked(orWriteLocked);
}
// WriteLock // WriteLock
bool bool
KDiskDevice::WriteLock() KDiskDevice::WriteLock()
@ -125,6 +132,13 @@ KDiskDevice::WriteUnlock()
fLocker.WriteUnlock(); fLocker.WriteUnlock();
} }
// IsWriteLocked
bool
KDiskDevice::IsWriteLocked()
{
return fLocker.IsWriteLocked();
}
// SetID // SetID
void void
KDiskDevice::SetID(partition_id id) KDiskDevice::SetID(partition_id id)

View File

@ -35,7 +35,8 @@ KDiskDeviceManager::KDiskDeviceManager()
: fLock("disk device manager"), : fLock("disk device manager"),
fDevices(20), fDevices(20),
fPartitions(100), fPartitions(100),
fDiskSystems(20) fDiskSystems(20),
fObsoletePartitions(20)
{ {
// add partitioning systems // add partitioning systems
if (void *list = open_module_list(kPartitioningSystemPrefix)) { if (void *list = open_module_list(kPartitioningSystemPrefix)) {
@ -66,9 +67,35 @@ DBG(OUT("number of disk systems: %ld\n", CountDiskSystems()));
// destructor // destructor
KDiskDeviceManager::~KDiskDeviceManager() KDiskDeviceManager::~KDiskDeviceManager()
{ {
// unpublish all partitions (only needed for testing) // remove all devices
for (int32 i = 0; KPartition *partition = fPartitions.ItemAt(i); i++) int32 count = CountDevices();
partition->UnpublishDevice(); for (int32 i = count - 1; i >= 0; i--) {
if (KDiskDevice *device = DeviceAt(i)) {
PartitionRegistrar _(device);
_RemoveDevice(device);
}
}
// some sanity checks
if (fPartitions.CountItems() > 0) {
DBG(OUT("WARNING: There are still %ld unremoved partitions!\n",
fPartitions.CountItems()));
}
if (fObsoletePartitions.CountItems() > 0) {
DBG(OUT("WARNING: There are still %ld obsolete partitions!\n",
fObsoletePartitions.CountItems()));
}
// remove all disk systems
count = CountDiskSystems();
for (int32 i = count - 1; i >= 0; i--) {
if (KDiskSystem *diskSystem = DiskSystemAt(i)) {
fDiskSystems.RemoveItem(i);
if (diskSystem->IsLoaded()) {
DBG(OUT("WARNING: Disk system `%s' (%ld) is still loaded!\n",
diskSystem->Name(), diskSystem->ID()));
} else
delete diskSystem;
}
}
} }
// InitCheck // InitCheck
@ -280,7 +307,8 @@ KDiskDeviceManager::RegisterFileDevice(const char *filePath, bool noShadow)
// CreateFileDevice // CreateFileDevice
status_t status_t
KDiskDeviceManager::CreateFileDevice(const char *filePath, int32 *deviceID) KDiskDeviceManager::CreateFileDevice(const char *filePath,
partition_id *deviceID)
{ {
if (!filePath) if (!filePath)
return B_BAD_VALUE; return B_BAD_VALUE;
@ -296,7 +324,7 @@ KDiskDeviceManager::CreateFileDevice(const char *filePath, int32 *deviceID)
return B_NO_MEMORY; return B_NO_MEMORY;
// initialize and add the device // initialize and add the device
error = device->SetTo(filePath); error = device->SetTo(filePath);
if (error == B_OK && !fDevices.AddItem(device)) if (error == B_OK && !_AddDevice(device))
error = B_NO_MEMORY; error = B_NO_MEMORY;
// set result / cleanup und failure // set result / cleanup und failure
if (error != B_OK) { if (error != B_OK) {
@ -319,7 +347,13 @@ KDiskDeviceManager::CreateFileDevice(const char *filePath, int32 *deviceID)
status_t status_t
KDiskDeviceManager::DeleteFileDevice(const char *filePath) KDiskDeviceManager::DeleteFileDevice(const char *filePath)
{ {
// not implemented if (KFileDiskDevice *device = RegisterFileDevice(filePath)) {
PartitionRegistrar _(device, true);
if (DeviceWriteLocker locker = device) {
if (_RemoveDevice(device))
return B_OK;
}
}
return B_ERROR; return B_ERROR;
} }
@ -352,7 +386,29 @@ KDiskDeviceManager::PartitionAdded(KPartition *partition)
bool bool
KDiskDeviceManager::PartitionRemoved(KPartition *partition) KDiskDeviceManager::PartitionRemoved(KPartition *partition)
{ {
return (partition && fPartitions.RemoveItem(partition)); if (partition && partition->PrepareForRemoval()
&& fPartitions.RemoveItem(partition)) {
// If adding the partition to the obsolete list fails (due to lack
// of memory), we can't do anything about it. We will leak memory then.
fObsoletePartitions.AddItem(partition);
partition->MarkObsolete();
return true;
}
return false;
}
// DeletePartition
bool
KDiskDeviceManager::DeletePartition(KPartition *partition)
{
if (partition && partition->IsObsolete()
&& partition->CountReferences() == 0
&& partition->PrepareForDeletion()
&& fObsoletePartitions.RemoveItem(partition)) {
delete partition;
return true;
}
return false;
} }
// JobWithID // JobWithID
@ -551,7 +607,7 @@ KDiskDeviceManager::_AddDevice(KDiskDevice *device)
bool bool
KDiskDeviceManager::_RemoveDevice(KDiskDevice *device) KDiskDeviceManager::_RemoveDevice(KDiskDevice *device)
{ {
return (device && PartitionRemoved(device) && fDevices.RemoveItem(device)); return (device && fDevices.RemoveItem(device) && PartitionRemoved(device));
} }
// _Scan // _Scan
@ -667,13 +723,9 @@ DBG(OUT(" returned: %f\n", priority));
DBG(OUT(" scanning with: %s\n", bestDiskSystem->Name())); DBG(OUT(" scanning with: %s\n", bestDiskSystem->Name()));
error = bestDiskSystem->Scan(partition, bestCookie); error = bestDiskSystem->Scan(partition, bestCookie);
if (error == B_OK) { if (error == B_OK) {
// TODO: Maybe better move setting the partition's and children's disk system
// in K{File,Partitioning}System::Scan()?
partition->SetDiskSystem(bestDiskSystem); partition->SetDiskSystem(bestDiskSystem);
for (int32 i = 0; KPartition *child = partition->ChildAt(i); i++) { for (int32 i = 0; KPartition *child = partition->ChildAt(i); i++)
child->SetParentDiskSystem(bestDiskSystem);
_ScanPartition(child); _ScanPartition(child);
}
} else { } else {
// TODO: Handle the error. // TODO: Handle the error.
DBG(OUT(" scanning failed: %s\n", strerror(error))); DBG(OUT(" scanning failed: %s\n", strerror(error)));

View File

@ -10,6 +10,13 @@
#include <KDiskDeviceUtils.h> #include <KDiskDeviceUtils.h>
#include <KFileDiskDevice.h> #include <KFileDiskDevice.h>
#include "virtualdrive.h"
// debugging
//#define DBG(x)
#define DBG(x) x
#define OUT printf
static const char *kFileDevicesDir = "/dev/disk/virtual/files"; static const char *kFileDevicesDir = "/dev/disk/virtual/files";
// constructor // constructor
@ -58,9 +65,6 @@ KFileDiskDevice::SetTo(const char *filePath, const char *devicePath)
char tmpDevicePath[B_PATH_NAME_LENGTH]; char tmpDevicePath[B_PATH_NAME_LENGTH];
if (!devicePath) { if (!devicePath) {
// no device path: we shall create a new device entry // no device path: we shall create a new device entry
// create the device entry
// TODO: Now we simply create a link. Replace that with the
// respective kernel magic!
// make the file devices dir // make the file devices dir
if (mkdir(kFileDevicesDir, 0777) != 0) { if (mkdir(kFileDevicesDir, 0777) != 0) {
if (errno != B_FILE_EXISTS) if (errno != B_FILE_EXISTS)
@ -73,8 +77,10 @@ KFileDiskDevice::SetTo(const char *filePath, const char *devicePath)
// get the device path name // get the device path name
sprintf(tmpDevicePath, "%s/%ld/raw", kFileDevicesDir, ID()); sprintf(tmpDevicePath, "%s/%ld/raw", kFileDevicesDir, ID());
devicePath = tmpDevicePath; devicePath = tmpDevicePath;
if (symlink(filePath, devicePath) != 0) // register the file as virtual drive
return errno; status_t error = _RegisterDevice(filePath, devicePath);
if (error != B_OK)
return error;
} }
status_t error = set_string(fFilePath, filePath); status_t error = set_string(fFilePath, filePath);
if (error != B_OK) if (error != B_OK)
@ -86,6 +92,14 @@ KFileDiskDevice::SetTo(const char *filePath, const char *devicePath)
void void
KFileDiskDevice::Unset() KFileDiskDevice::Unset()
{ {
// remove the device and the directory it resides in
if (Path() && ID() >= 0) {
_UnregisterDevice(Path());
char dirPath[B_PATH_NAME_LENGTH];
sprintf(dirPath, "%s/%ld", kFileDevicesDir, ID());
rmdir(dirPath);
}
// free file path
free(fFilePath); free(fFilePath);
fFilePath = NULL; fFilePath = NULL;
} }
@ -112,41 +126,76 @@ KFileDiskDevice::CreateShadowPartition()
return NULL; return NULL;
} }
// GetMediaStatus // _RegisterDevice
status_t status_t
KFileDiskDevice::GetMediaStatus(status_t *mediaStatus) KFileDiskDevice::_RegisterDevice(const char *file, const char *device)
{ {
*mediaStatus = B_OK; // TODO: For now we use the virtualdrive driver to register a file
return B_OK; // as a device and then simply symlink the assigned device to the
} // desired device location. Replace that with the
// respective kernel magic for the OBOS kernel!
// GetGeometry // open the virtualdrive control device
status_t int fd = open(VIRTUAL_DRIVE_CONTROL_DEVICE, O_RDONLY);
KFileDiskDevice::GetGeometry(device_geometry *geometry) if (fd < 0) {
{ DBG(OUT("Failed to open virtualdrive control device: %s\n",
// get the file size strerror(errno)));
struct stat st;
if (stat(fFilePath, &st) != 0)
return errno; return errno;
// default to 512 bytes block size }
off_t size = st.st_size; // set up the info
uint32 blockSize = 512; virtual_drive_info info;
// Optimally we have only 1 block per sector and only one head. strcpy(info.file_name, file);
// Since we have only a uint32 for the cylinder count, this won't work info.use_geometry = false;
// for files > 2TB. So, we set the head count to the minimally possible status_t error = B_OK;
// value. if (ioctl(fd, VIRTUAL_DRIVE_REGISTER_FILE, &info) != 0) {
off_t blocks = size / blockSize; error = errno;
uint32 heads = (blocks + ULONG_MAX - 1) / ULONG_MAX; DBG(OUT("Failed to install file device: %s\n", strerror(error)));
if (heads == 0) }
heads = 1; // close the control device
geometry->bytes_per_sector = blockSize; close(fd);
geometry->sectors_per_track = 1; // create a symlink
geometry->cylinder_count = blocks / heads; if (error == B_OK) {
geometry->head_count = heads; if (symlink(info.device_name, device) != 0) {
geometry->device_type = B_DISK; // TODO: Add a new constant. DBG(OUT("Failed to create file device symlink: %s\n",
geometry->removable = false; strerror(error)));
geometry->read_only = false; error = errno;
geometry->write_once = false; // unregister the file device
return B_OK; // open the device
int deviceFD = open(info.device_name, O_RDONLY);
if (deviceFD >= 0) {
ioctl(deviceFD, VIRTUAL_DRIVE_UNREGISTER_FILE);
close(deviceFD);
}
}
}
return error;
}
// _UnregisterDevice
status_t
KFileDiskDevice::_UnregisterDevice(const char *_device)
{
// read the symlink to get the path of the virtualdrive device
char device[B_PATH_NAME_LENGTH];
ssize_t bytesRead = readlink(_device, device, sizeof(device) - 1);
if (bytesRead < 0)
return errno;
device[bytesRead] = '\0';
// open the device
int fd = open(device, O_RDONLY);
if (fd < 0)
return errno;
// issue the ioctl
status_t error = B_OK;
if (ioctl(fd, VIRTUAL_DRIVE_UNREGISTER_FILE) != 0)
error = errno;
// close the control device
close(fd);
// remove the symlink
if (error == B_OK) {
if (remove(_device) < 0)
error = errno;
}
return error;
} }

View File

@ -10,11 +10,6 @@
#include <Drivers.h> #include <Drivers.h>
#include <Errors.h> #include <Errors.h>
// debugging
//#define DBG(x)
#define DBG(x) x
#define OUT printf
#include "KDiskDevice.h" #include "KDiskDevice.h"
#include "KDiskDeviceManager.h" #include "KDiskDeviceManager.h"
#include "KDiskDeviceUtils.h" #include "KDiskDeviceUtils.h"
@ -24,14 +19,19 @@
using namespace std; using namespace std;
// constructor // constructor
// debugging
//#define DBG(x)
#define DBG(x) x
#define OUT printf
KPartition::KPartition(partition_id id) KPartition::KPartition(partition_id id)
: fPartitionData(), : fPartitionData(),
fChildren(), fChildren(),
fDevice(NULL), fDevice(NULL),
fParent(NULL), fParent(NULL),
fDiskSystem(NULL), fDiskSystem(NULL),
fParentDiskSystem(NULL), fReferenceCount(0),
fReferenceCount(0) fObsolete(false)
{ {
fPartitionData.id = (id >= 0 ? id : _NextID()); fPartitionData.id = (id >= 0 ? id : _NextID());
fPartitionData.offset = 0; fPartitionData.offset = 0;
@ -55,6 +55,7 @@ KPartition::KPartition(partition_id id)
// destructor // destructor
KPartition::~KPartition() KPartition::~KPartition()
{ {
SetDiskSystem(NULL);
free(fPartitionData.name); free(fPartitionData.name);
free(fPartitionData.content_name); free(fPartitionData.content_name);
free(fPartitionData.type); free(fPartitionData.type);
@ -74,8 +75,13 @@ KPartition::Register()
void void
KPartition::Unregister() KPartition::Unregister()
{ {
ManagerLocker locker(KDiskDeviceManager::Default()); KDiskDeviceManager *manager = KDiskDeviceManager::Default();
ManagerLocker locker(manager);
fReferenceCount--; fReferenceCount--;
if (IsObsolete() && fReferenceCount == 0) {
// let the manager delete object
manager->DeletePartition(this);
}
} }
// CountReferences // CountReferences
@ -85,6 +91,36 @@ KPartition::CountReferences() const
return fReferenceCount; return fReferenceCount;
} }
// MarkObsolete
void
KPartition::MarkObsolete()
{
fObsolete = true;
}
// IsObsolete
bool
KPartition::IsObsolete() const
{
return fObsolete;
}
// PrepareForRemoval
bool
KPartition::PrepareForRemoval()
{
bool result = RemoveAllChildren();
UnpublishDevice();
return result;
}
// PrepareForDeletion
bool
KPartition::PrepareForDeletion()
{
return true;
}
// Open // Open
status_t status_t
KPartition::Open(int flags, int *fd) KPartition::Open(int flags, int *fd)
@ -566,26 +602,51 @@ KPartition::CreateChild(partition_id id, int32 index, KPartition **_child)
} }
// RemoveChild // RemoveChild
KPartition * bool
KPartition::RemoveChild(int32 index) KPartition::RemoveChild(int32 index)
{ {
KPartition *partition = NULL; if (index < 0 || index >= fPartitionData.child_count)
if (index >= 0 && index < fPartitionData.child_count) { return false;
KDiskDeviceManager *manager = KDiskDeviceManager::Default(); KDiskDeviceManager *manager = KDiskDeviceManager::Default();
if (ManagerLocker locker = manager) { if (ManagerLocker locker = manager) {
partition = fChildren.ItemAt(index); KPartition *partition = fChildren.ItemAt(index);
if (!partition || !manager->PartitionRemoved(partition)) PartitionRegistrar _(partition);
return NULL; if (!partition || !manager->PartitionRemoved(partition)
if (fChildren.RemoveItem(index)) { || !fChildren.RemoveItem(index)) {
_UpdateChildIndices(index + 1); return false;
partition->SetIndex(-1);
fPartitionData.child_count--;
partition->SetParent(NULL);
partition->SetDevice(NULL);
}
} }
_UpdateChildIndices(index + 1);
partition->SetIndex(-1);
fPartitionData.child_count--;
partition->SetParent(NULL);
partition->SetDevice(NULL);
return true;
} }
return partition; return false;
}
// RemoveChild
bool
KPartition::RemoveChild(KPartition *child)
{
if (child) {
int32 index = fChildren.IndexOf(child);
if (index >= 0)
return RemoveChild(index);
}
return false;
}
// RemoveAllChildren
bool
KPartition::RemoveAllChildren()
{
int32 count = CountChildren();
for (int32 i = count - 1; i >= 0; i--) {
if (!RemoveChild(i))
return false;
}
return true;
} }
// ChildAt // ChildAt
@ -655,26 +716,11 @@ KPartition::DiskSystem() const
return fDiskSystem; return fDiskSystem;
} }
// SetParentDiskSystem
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 // ParentDiskSystem
KDiskSystem * KDiskSystem *
KPartition::ParentDiskSystem() const KPartition::ParentDiskSystem() const
{ {
return fParentDiskSystem; return (Parent() ? Parent()->DiskSystem() : NULL);
} }
// SetCookie // SetCookie