diff --git a/src/servers/registrar/DiskDeviceManager.cpp b/src/servers/registrar/DiskDeviceManager.cpp index 6824a59ef2..6ff8d0408c 100644 --- a/src/servers/registrar/DiskDeviceManager.cpp +++ b/src/servers/registrar/DiskDeviceManager.cpp @@ -9,20 +9,29 @@ #include "DiskDeviceManager.h" #include "Debug.h" #include "EventMaskWatcher.h" +#include "EventQueue.h" +#include "MessageEvent.h" #include "RDiskDevice.h" #include "RDiskDeviceList.h" #include "RPartition.h" #include "RSession.h" +// priorities of the different message kinds enum { REQUEST_PRIORITY = 0, + RESCAN_PRIORITY = 5, NODE_MONITOR_PRIORITY = 10, WATCHING_REQUEST_PRIORITY = 20, }; +// time interval between device rescans +static const bigtime_t kRescanEventInterval = 5000000; + // constructor -DiskDeviceManager::DiskDeviceManager() +DiskDeviceManager::DiskDeviceManager(EventQueue *eventQueue) : BLooper("disk device manager"), + fEventQueue(eventQueue), + fRescanEvent(NULL), fDeviceListLock(), fWatchingService(), fVolumeList(BMessenger(this), fDeviceListLock), @@ -45,11 +54,19 @@ DiskDeviceManager::DiskDeviceManager() if (fWorker >= 0) resume_thread(fWorker); } + // set up the rescan event + fRescanEvent = new MessageEvent(system_time() + kRescanEventInterval, + this, B_REG_ROSTER_DEVICE_RESCAN); + fRescanEvent->SetAutoDelete(false); + fEventQueue->AddEvent(fRescanEvent); } // destructor DiskDeviceManager::~DiskDeviceManager() { + // remove the rescan event from the event queue + fEventQueue->RemoveEvent(fRescanEvent); + // terminate the worker thread fTerminating = true; delete_sem(fMessageCounter); int32 dummy; @@ -74,6 +91,11 @@ DiskDeviceManager::MessageReceived(BMessage *message) if (!_PushMessage(message, WATCHING_REQUEST_PRIORITY)) delete message; break; + case B_REG_ROSTER_DEVICE_RESCAN: + DetachCurrentMessage(); + if (!_PushMessage(message, RESCAN_PRIORITY)) + delete message; + break; case B_NODE_MONITOR: DetachCurrentMessage(); if (!_PushMessage(message, NODE_MONITOR_PRIORITY)) @@ -307,6 +329,12 @@ DiskDeviceManager::_Worker() case B_REG_DEVICE_STOP_WATCHING: _StopWatchingRequest(message); break; + case B_REG_ROSTER_DEVICE_RESCAN: + fDeviceList.Rescan(); + fRescanEvent->SetTime(system_time() + + kRescanEventInterval); + fEventQueue->AddEvent(fRescanEvent); + break; case B_NODE_MONITOR: { fVolumeList.HandleMessage(message); diff --git a/src/servers/registrar/DiskDeviceManager.h b/src/servers/registrar/DiskDeviceManager.h index 732e76dbfa..5a248e4d37 100644 --- a/src/servers/registrar/DiskDeviceManager.h +++ b/src/servers/registrar/DiskDeviceManager.h @@ -15,9 +15,12 @@ #include "RVolumeList.h" #include "WatchingService.h" +class EventQueue; +class MessageEvent; + class DiskDeviceManager : public BLooper { public: - DiskDeviceManager(); + DiskDeviceManager(EventQueue *eventQueue); virtual ~DiskDeviceManager(); virtual void MessageReceived(BMessage *message); @@ -37,6 +40,11 @@ private: int32 _Worker(); private: + class RescanEvent; + +private: + EventQueue *fEventQueue; + MessageEvent *fRescanEvent; BLocker fDeviceListLock; WatchingService fWatchingService; RVolumeList fVolumeList; diff --git a/src/servers/registrar/RDiskDevice.cpp b/src/servers/registrar/RDiskDevice.cpp index 14af023f34..f640a376fe 100644 --- a/src/servers/registrar/RDiskDevice.cpp +++ b/src/servers/registrar/RDiskDevice.cpp @@ -22,7 +22,7 @@ RDiskDevice::RDiskDevice() : fSessions(10, true), fDeviceList(NULL), fID(-1), - fChangeCounter(0), + fChangeCounter(), fTouched(false), fPath(), fFD(-1), @@ -45,7 +45,7 @@ PRINT(("RDiskDevice::SetTo()\n")); Unset(); status_t error = B_OK; fID = _NextID(); - fChangeCounter = 0; + fChangeCounter.Reset(); fTouched = true; fPath.SetTo(path); fFD = fd; @@ -68,28 +68,8 @@ PRINT(("RDiskDevice::SetTo()\n")); error = fMediaStatus; break; } - // scan the device for sessions, if we have a media - if (fMediaStatus == B_OK) { - session_info sessionInfo; - for (int32 i = 0; ; i++) { - // get the session info - status_t status = get_nth_session_info(fFD, i, &sessionInfo); - if (status != B_OK) { - if (status != B_ENTRY_NOT_FOUND) - error = status; - break; - } - // create and add a RSession - if (RSession *session = new(nothrow) RSession) { - error = session->SetTo(fFD, &sessionInfo); - if (error == B_OK) - AddSession(session); - else - delete session; - } else - error = B_NO_MEMORY; - } - } + // scan the device for sessions + error = _RescanSessions(B_DEVICE_CAUSE_UNKNOWN); // cleanup on error if (error != B_OK) Unset(); @@ -102,7 +82,7 @@ void RDiskDevice::Unset() { for (int32 i = CountSessions() - 1; i >= 0; i--) - RemoveSession(i); + RemoveSession(i, B_DEVICE_CAUSE_UNKNOWN); fID = -1; fPath.SetTo(""); if (fFD >= 0) { @@ -111,6 +91,51 @@ RDiskDevice::Unset() } } +// MediaChanged +status_t +RDiskDevice::MediaChanged() +{ +PRINT(("RDiskDevice::MediaChanged()\n")); + status_t error = B_OK; + // get the new media status + status_t mediaStatus; + if (ioctl(fFD, B_GET_MEDIA_STATUS, &mediaStatus) == 0) { + fMediaStatus = mediaStatus; + // analyze the media status + switch (fMediaStatus) { + case B_NO_ERROR: + case B_DEV_NO_MEDIA: + case B_DEV_NOT_READY: + case B_DEV_MEDIA_CHANGE_REQUESTED: + case B_DEV_DOOR_OPEN: + break; + case B_DEV_MEDIA_CHANGED: + // Ignore changes between the our ioctl() and the one before; + // we rescan the sessions anyway. + fMediaStatus = B_OK; + break; + default: + error = fMediaStatus; + break; + } + } + // rescan sessions + error = _RescanSessions(B_DEVICE_CAUSE_PARENT_CHANGED); + // TODO: send notification + // ... + return error; +} + +// SessionLayoutChanged +status_t +RDiskDevice::SessionLayoutChanged() +{ +PRINT(("RDiskDevice::SessionLayoutChanged()\n")); + status_t error = B_OK; + error = _RescanSessions(B_DEVICE_CAUSE_UNKNOWN); + return error; +} + // Size off_t RDiskDevice::Size() const @@ -119,9 +144,25 @@ RDiskDevice::Size() const * fGeometry.cylinder_count * fGeometry.head_count; } +// AddSession +status_t +RDiskDevice::AddSession(const session_info *sessionInfo, uint32 cause) +{ + status_t error = B_OK; + if (RSession *session = new(nothrow) RSession) { + error = session->SetTo(fFD, sessionInfo); + if (error == B_OK) + AddSession(session, cause); + else + delete session; + } else + error = B_NO_MEMORY; + return error; +} + // AddSession bool -RDiskDevice::AddSession(RSession *session) +RDiskDevice::AddSession(RSession *session, uint32 cause) { bool success = false; if (session) { @@ -129,7 +170,7 @@ RDiskDevice::AddSession(RSession *session) if (success) { session->SetDevice(this); if (RDiskDeviceList *deviceList = DeviceList()) - deviceList->SessionAdded(session); + deviceList->SessionAdded(session, cause); } } return success; @@ -137,12 +178,12 @@ RDiskDevice::AddSession(RSession *session) // RemoveSession bool -RDiskDevice::RemoveSession(int32 index) +RDiskDevice::RemoveSession(int32 index, uint32 cause) { RSession *session = SessionAt(index); if (session) { if (RDiskDeviceList *deviceList = DeviceList()) - deviceList->SessionRemoved(session); + deviceList->SessionRemoved(session, cause); session->SetDevice(NULL); fSessions.RemoveItemAt(index); delete session; @@ -152,13 +193,13 @@ RDiskDevice::RemoveSession(int32 index) // RemoveSession bool -RDiskDevice::RemoveSession(RSession *session) +RDiskDevice::RemoveSession(RSession *session, uint32 cause) { bool success = false; if (session) { int32 index = fSessions.IndexOf(session); if (index >= 0) - success = RemoveSession(index); + success = RemoveSession(index, cause); } return success; } @@ -167,7 +208,55 @@ RDiskDevice::RemoveSession(RSession *session) status_t RDiskDevice::Update() { - return B_ERROR; + status_t error = B_OK; + status_t mediaStatus = B_OK; + if (ioctl(fFD, B_GET_MEDIA_STATUS, &mediaStatus) == 0) { + if (mediaStatus == B_DEV_MEDIA_CHANGED + || (mediaStatus == B_NO_ERROR) != (fMediaStatus == B_NO_ERROR)) { + // The media status is B_DEV_MEDIA_CHANGED or it changed from + // B_NO_ERROR to some error code or the other way around. + error = MediaChanged(); + } else { + // TODO: notifications? + fMediaStatus = mediaStatus; + // The media has not been changed. If this is a read-only device, + // then we are safe, since nothing can have changed. Otherwise + // we check the sessions. + if (!IsReadOnly() && fMediaStatus == B_OK) { + session_info sessionInfo; + for (int32 i = 0; error == B_OK; i++) { + // get the session info + status_t status = get_nth_session_info(fFD, i, + &sessionInfo); + if (status != B_OK) { + if (status == B_ENTRY_NOT_FOUND) { + // remove disappeared sessions + for (int32 k = CountSessions() - 1; k >= i; k--) + RemoveSession(k, B_DEVICE_CAUSE_UNKNOWN); + } else + error = status; + break; + } + // check the session + if (RSession *session = SessionAt(i)) { + if (session->Offset() == sessionInfo.offset + && session->Size() == sessionInfo.size) { + session->Update(&sessionInfo); + } else { + // session layout changed + error = SessionLayoutChanged(); + break; + } + } else { + // session added + error = AddSession(&sessionInfo, + B_DEVICE_CAUSE_UNKNOWN); + } + } + } + } + } + return error; } // Archive @@ -179,7 +268,7 @@ RDiskDevice::Archive(BMessage *archive) const if (error == B_OK) error = archive->AddInt32("id", fID); if (error == B_OK) - error = archive->AddInt32("change_counter", fChangeCounter); + error = archive->AddInt32("change_counter", ChangeCounter()); // geometry if (error == B_OK) error = archive->AddInt64("size", Size()); @@ -219,6 +308,32 @@ RDiskDevice::Dump() const session->Dump(); } +// _RescanSessions +status_t +RDiskDevice::_RescanSessions(uint32 cause) +{ + status_t error = B_OK; + // remove the current sessions + for (int32 i = CountSessions() - 1; i >= 0; i--) + RemoveSession(i, cause); + // scan the device for sessions, if we have a media + if (fMediaStatus == B_OK) { + session_info sessionInfo; + for (int32 i = 0; error == B_OK; i++) { + // get the session info + status_t status = get_nth_session_info(fFD, i, &sessionInfo); + if (status != B_OK) { + if (status != B_ENTRY_NOT_FOUND) + error = status; + break; + } + // create and add a RSession + error = AddSession(&sessionInfo, cause); + } + } + RETURN_ERROR(error); +} + // _NextID int32 RDiskDevice::_NextID() diff --git a/src/servers/registrar/RDiskDevice.h b/src/servers/registrar/RDiskDevice.h index 45dfc72f5a..b380d0c541 100644 --- a/src/servers/registrar/RDiskDevice.h +++ b/src/servers/registrar/RDiskDevice.h @@ -10,6 +10,10 @@ #include #include +#include "RChangeCounter.h" + +struct session_info; + class RDiskDeviceList; class RPartition; class RSession; @@ -27,20 +31,31 @@ public: { fDeviceList = deviceList ;} RDiskDeviceList *DeviceList() const { return fDeviceList; } + status_t MediaChanged(); + status_t SessionLayoutChanged(); + int32 ID() const { return fID; } - int32 ChangeCounter() const { return fChangeCounter; } + int32 ChangeCounter() const { return fChangeCounter.Count(); } + void Changed() { fChangeCounter.Increment(); } void SetTouched(bool touched) { fTouched = touched; } bool Touched() const { return fTouched; } + int FD() const { return fFD; } off_t Size() const; int32 BlockSize() const { return fGeometry.bytes_per_sector; } + bool IsReadOnly() { return fGeometry.read_only; } const char *Path() const { return fPath.String(); } - bool AddSession(RSession *session); - bool RemoveSession(int32 index); - bool RemoveSession(RSession *session); + status_t AddSession(const session_info *sessionInfo, + uint32 cause/* = B_DEVICE_CAUSE_UNKNOWN*/); + bool AddSession(RSession *session, + uint32 cause/* = B_DEVICE_CAUSE_UNKNOWN*/); + bool RemoveSession(int32 index, + uint32 cause/* = B_DEVICE_CAUSE_UNKNOWN*/); + bool RemoveSession(RSession *session, + uint32 cause/* = B_DEVICE_CAUSE_UNKNOWN*/); int32 CountSessions() const { return fSessions.CountItems(); } RSession *SessionAt(int32 index) const { return fSessions.ItemAt(index); } int32 IndexOfSession(const RSession *session) const @@ -53,13 +68,15 @@ public: void Dump() const; private: + status_t _RescanSessions(uint32 cause); + static int32 _NextID(); private: BObjectList fSessions; RDiskDeviceList *fDeviceList; int32 fID; - int32 fChangeCounter; + RChangeCounter fChangeCounter; bool fTouched; BString fPath; int fFD; diff --git a/src/servers/registrar/RDiskDeviceList.cpp b/src/servers/registrar/RDiskDeviceList.cpp index ffc3d7adac..5e98ac6821 100644 --- a/src/servers/registrar/RDiskDeviceList.cpp +++ b/src/servers/registrar/RDiskDeviceList.cpp @@ -186,6 +186,52 @@ RDiskDeviceList::MountPointMoved(const RVolume *volume, Unlock(); } +// DeviceAppeared +void +RDiskDeviceList::DeviceAppeared(const char *devicePath) +{ + status_t error = (devicePath ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + int fd = open(devicePath, O_RDONLY); + if (fd >= 0) { + bool closeFile = true; + device_geometry geometry; + status_t mediaStatus = B_OK; + partition_info partitionInfo; + if (ioctl(fd, B_GET_MEDIA_STATUS, &mediaStatus) == 0 + && ioctl(fd, B_GET_GEOMETRY, &geometry) == 0 + && ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo) < 0) { +PRINT(("RDiskDeviceList::DeviceAppeared(`%s')\n", devicePath)); + RDiskDevice *device = new(nothrow) RDiskDevice; + if (device) { + error = device->SetTo(devicePath, fd, &geometry, + mediaStatus); + if (error == B_OK) { + closeFile = false; + device->SetTouched(true); + AddDevice(device); + } else + delete device; + } else + error = B_NO_MEMORY; + } + if (closeFile) + close(fd); + } + } +} + +// DeviceDisappeared +void +RDiskDeviceList::DeviceDisappeared(const char *devicePath) +{ +PRINT(("RDiskDeviceList::DeviceDisappeared(`%s')\n", devicePath)); + if (devicePath) { + if (RDiskDevice *device = DeviceWithPath(devicePath)) + RemoveDevice(device); + } +} + // AddDevice bool RDiskDeviceList::AddDevice(RDiskDevice *device) @@ -280,6 +326,9 @@ status_t RDiskDeviceList::Rescan() { FUNCTION_START(); +// TODO: This method should be reworked, as soon as we react on events only +// and don't need to poll anymore. This method will then do an initial +// scan only. status_t error = B_OK; if (Lock()) { // marked all devices untouched @@ -292,8 +341,9 @@ FUNCTION_START(); } // remove all untouched devices for (int32 i = CountDevices() - 1; i >= 0; i--) { - if (!DeviceAt(i)->Touched()) - RemoveDevice(i); + RDiskDevice *device = DeviceAt(i); + if (!device->Touched()) + DeviceDisappeared(device->Path()); } Unlock(); } else @@ -410,17 +460,11 @@ RDiskDeviceList::Dump() const status_t RDiskDeviceList::_Scan(BDirectory &dir) { -//BEntry dirEntry; -//BPath dirPath; -//dir.GetEntry(&dirEntry); -//dirEntry.GetPath(&dirPath); -//PRINT(("RDiskDeviceList::_Scan(`%s')\n", dirPath.Path())); status_t error = B_OK; BEntry entry; while (dir.GetNextEntry(&entry) == B_OK) { struct stat st; if (entry.GetStat(&st) == B_OK) { -//PRINT(("st.st_mode: 0x%x\n", st.st_mode & S_IFMT)); if (S_ISDIR(st.st_mode)) { BDirectory subdir; if (subdir.SetTo(&entry) == B_OK) @@ -444,37 +488,13 @@ RDiskDeviceList::_ScanDevice(const char *path) // search the list for a device with that path if (RDiskDevice *device = DeviceWithPath(path)) { // found: just update it + device->SetTouched(true); error = device->Update(); } else { // not found: check whether it is really a disk device and add it to // the list - int fd = open(path, O_RDONLY); - if (fd >= 0) { - bool closeFile = true; - device_geometry geometry; - status_t mediaStatus = B_OK; - partition_info partitionInfo; - if (ioctl(fd, B_GET_MEDIA_STATUS, &mediaStatus) == 0 - && ioctl(fd, B_GET_GEOMETRY, &geometry) == 0 - && ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo) < 0) { -// int32 blockSize = geometry.bytes_per_sector; -// off_t deviceSize = (off_t)blockSize -// * geometry.sectors_per_track * geometry.cylinder_count -// * geometry.head_count; - RDiskDevice *device = new(nothrow) RDiskDevice; - if (device) { - error = device->SetTo(path, fd, &geometry, mediaStatus); - if (error == B_OK) { - closeFile = false; - AddDevice(device); - } else - delete device; - } else - error = B_NO_MEMORY; - } - if (closeFile) - close(fd); - } + // The event hook does the work anyway: + DeviceAppeared(path); } return error; } diff --git a/src/servers/registrar/RDiskDeviceList.h b/src/servers/registrar/RDiskDeviceList.h index d044fff395..1bf982f69b 100644 --- a/src/servers/registrar/RDiskDeviceList.h +++ b/src/servers/registrar/RDiskDeviceList.h @@ -43,11 +43,14 @@ public: virtual void HandleMessage(BMessage *message); + // external event hooks virtual void VolumeMounted(const RVolume *volume); virtual void VolumeUnmounted(const RVolume *volume); virtual void MountPointMoved(const RVolume *volume, const entry_ref *oldRoot, const entry_ref *newRoot); + virtual void DeviceAppeared(const char *devicePath); + virtual void DeviceDisappeared(const char *devicePath); bool AddDevice(RDiskDevice *device); bool RemoveDevice(int32 index); @@ -74,6 +77,7 @@ public: bool Lock(); void Unlock(); + // internal event hooks void DeviceAdded(RDiskDevice *device, uint32 cause = B_DEVICE_CAUSE_UNKNOWN); void DeviceRemoved(RDiskDevice *device, diff --git a/src/servers/registrar/RPartition.cpp b/src/servers/registrar/RPartition.cpp index 8b2f1c45e5..d77c64a7be 100644 --- a/src/servers/registrar/RPartition.cpp +++ b/src/servers/registrar/RPartition.cpp @@ -12,7 +12,7 @@ RPartition::RPartition() : fSession(NULL), fID(-1), - fChangeCounter(0), + fChangeCounter(), fVolume(NULL) { } @@ -29,7 +29,7 @@ RPartition::SetTo(int fd, const extended_partition_info *partitionInfo) Unset(); status_t error = B_OK; fID = _NextID(); - fChangeCounter = 0; + fChangeCounter.Reset(); fInfo = *partitionInfo; return error; } @@ -55,6 +55,14 @@ RPartition::Device() const return (fSession ? fSession->Device() : NULL); } +// Changed +void +RPartition::Changed() +{ + if (fChangeCounter.Increment() && fSession) + fSession->Changed(); +} + // Index int32 RPartition::Index() const @@ -76,6 +84,16 @@ RPartition::GetPath(char *path) const } } +// Update +status_t +RPartition::Update(const extended_partition_info *partitionInfo) +{ + status_t error = B_OK; + // TODO: Check the partition info for changes! + fInfo = *partitionInfo; + return error; +} + // Archive status_t RPartition::Archive(BMessage *archive) const @@ -85,7 +103,7 @@ RPartition::Archive(BMessage *archive) const if (error == B_OK) error = archive->AddInt32("id", fID); if (error == B_OK) - error = archive->AddInt32("change_counter", fChangeCounter); + error = archive->AddInt32("change_counter", ChangeCounter()); if (error == B_OK) error = archive->AddInt32("index", Index()); // fInfo.info.* diff --git a/src/servers/registrar/RPartition.h b/src/servers/registrar/RPartition.h index 39d570f58b..71e7b48398 100644 --- a/src/servers/registrar/RPartition.h +++ b/src/servers/registrar/RPartition.h @@ -9,6 +9,8 @@ #include #include +#include "RChangeCounter.h" + class BMessage; class RDiskDevice; @@ -30,18 +32,23 @@ public: RSession *Session() const { return fSession; } int32 ID() const { return fID; } - int32 ChangeCounter() const { return fChangeCounter; } + int32 ChangeCounter() const { return fChangeCounter.Count(); } + void Changed(); int32 Index() const; const extended_partition_info *Info() const { return &fInfo; } void GetPath(char *path) const; + off_t Offset() const { return fInfo.info.offset; } + off_t Size() const { return fInfo.info.size; } void SetVolume(const RVolume *volume) { fVolume = volume; } const RVolume *Volume() const { return fVolume; } status_t Archive(BMessage *archive) const; + status_t Update(const extended_partition_info *partitionInfo); + void Dump() const; private: @@ -50,7 +57,7 @@ private: private: RSession *fSession; int32 fID; - int32 fChangeCounter; + RChangeCounter fChangeCounter; extended_partition_info fInfo; const RVolume *fVolume; diff --git a/src/servers/registrar/RSession.cpp b/src/servers/registrar/RSession.cpp index b652aa6485..16cdf949f1 100644 --- a/src/servers/registrar/RSession.cpp +++ b/src/servers/registrar/RSession.cpp @@ -17,7 +17,7 @@ RSession::RSession() : fPartitions(10, true), fDevice(NULL), fID(-1), - fChangeCounter(0) + fChangeCounter() { } @@ -33,29 +33,10 @@ RSession::SetTo(int fd, const session_info *sessionInfo) Unset(); status_t error = B_OK; fID = _NextID(); - fChangeCounter = 0; + fChangeCounter.Reset(); fInfo = *sessionInfo; - // iterate through the partitions - for (int32 i = 0; ; i++) { - // get the partition info - extended_partition_info partitionInfo; - status_t status = get_nth_partition_info(fd, sessionInfo->index, i, - &partitionInfo, (i == 0 ? fPartitioningSystem : NULL)); - if (status != B_OK) { - if (status != B_ENTRY_NOT_FOUND) - error = status; - break; - } - // create and add a RPartition - if (RPartition *partition = new(nothrow) RPartition) { - error = partition->SetTo(fd, &partitionInfo); - if (error == B_OK) - AddPartition(partition); - else - delete partition; - } else - error = B_NO_MEMORY; - } + // scan for partitions + error = _RescanPartitions(fd, B_DEVICE_CAUSE_UNKNOWN); // cleanup on error if (error != B_OK) Unset(); @@ -67,7 +48,7 @@ void RSession::Unset() { for (int32 i = CountPartitions() - 1; i >= 0; i--) - RemovePartition(i); + RemovePartition(i, B_DEVICE_CAUSE_UNKNOWN); fID = -1; } @@ -78,6 +59,25 @@ RSession::DeviceList() const return (fDevice ? fDevice->DeviceList() : NULL); } +// PartitionLayoutChanged +status_t +RSession::PartitionLayoutChanged() +{ +PRINT(("RSession::PartitionLayoutChanged()\n")); + status_t error = (fDevice ? B_OK : B_ERROR); + if (error == B_OK) + error = _RescanPartitions(fDevice->FD(), B_DEVICE_CAUSE_UNKNOWN); + return error; +} + +// Changed +void +RSession::Changed() +{ + if (fChangeCounter.Increment() && fDevice) + fDevice->Changed(); +} + // Index int32 RSession::Index() const @@ -87,9 +87,26 @@ RSession::Index() const return -1; } +// AddPartition +status_t +RSession::AddPartition(int fd, const extended_partition_info *partitionInfo, + uint32 cause) +{ + status_t error = B_OK; + if (RPartition *partition = new(nothrow) RPartition) { + error = partition->SetTo(fd, partitionInfo); + if (error == B_OK) + AddPartition(partition, cause); + else + delete partition; + } else + error = B_NO_MEMORY; + return error; +} + // AddPartition bool -RSession::AddPartition(RPartition *partition) +RSession::AddPartition(RPartition *partition, uint32 cause) { bool success = false; if (partition) { @@ -97,7 +114,7 @@ RSession::AddPartition(RPartition *partition) if (success) { partition->SetSession(this); if (RDiskDeviceList *deviceList = DeviceList()) - deviceList->PartitionAdded(partition); + deviceList->PartitionAdded(partition, cause); } } return success; @@ -105,12 +122,12 @@ RSession::AddPartition(RPartition *partition) // RemovePartition bool -RSession::RemovePartition(int32 index) +RSession::RemovePartition(int32 index, uint32 cause) { RPartition *partition = PartitionAt(index); if (partition) { if (RDiskDeviceList *deviceList = DeviceList()) - deviceList->PartitionRemoved(partition); + deviceList->PartitionRemoved(partition, cause); partition->SetSession(NULL); fPartitions.RemoveItemAt(index); delete partition; @@ -120,17 +137,66 @@ RSession::RemovePartition(int32 index) // RemovePartition bool -RSession::RemovePartition(RPartition *partition) +RSession::RemovePartition(RPartition *partition, uint32 cause) { bool success = false; if (partition) { int32 index = fPartitions.IndexOf(partition); if (index >= 0) - success = RemovePartition(index); + success = RemovePartition(index, cause); } return success; } +// Update +status_t +RSession::Update(const session_info *sessionInfo) +{ + status_t error = (fDevice ? B_OK : B_ERROR); + // TODO: Check the session info for changes! + fInfo = *sessionInfo; + int fd = (fDevice ? fDevice->FD() : -1); + // check the partitions + for (int32 i = 0; error == B_OK; i++) { + // get the partition info + extended_partition_info partitionInfo; + char partitioningSystem[B_FILE_NAME_LENGTH]; + status_t status = get_nth_partition_info(fd, sessionInfo->index, i, + &partitionInfo, (i == 0 ? partitioningSystem : NULL)); + // check the partitioning system + if ((status == B_OK || status == B_ENTRY_NOT_FOUND) && i == 0 + && strcmp(partitioningSystem, fPartitioningSystem)) { + // partitioning system has changed + error = PartitionLayoutChanged(); + break; + } + if (status != B_OK) { + if (status == B_ENTRY_NOT_FOUND) { + // remove disappeared partitions + for (int32 k = CountPartitions() - 1; k >= i; k--) + RemovePartition(k, B_DEVICE_CAUSE_UNKNOWN); + } else + error = status; + break; + } + // check the partition + if (RPartition *partition = PartitionAt(i)) { + if (partition->Offset() == partitionInfo.info.offset + && partition->Size() == partitionInfo.info.size) { + partition->Update(&partitionInfo); + } else { + // partition layout changed + error = PartitionLayoutChanged(); + break; + } + } else { + // partition added + error = AddPartition(fd, &partitionInfo, B_DEVICE_CAUSE_UNKNOWN); + } + } + return error; +} + // Archive status_t RSession::Archive(BMessage *archive) const @@ -140,7 +206,7 @@ RSession::Archive(BMessage *archive) const if (error == B_OK) error = archive->AddInt32("id", fID); if (error == B_OK) - error = archive->AddInt32("change_counter", fChangeCounter); + error = archive->AddInt32("change_counter", ChangeCounter()); if (error == B_OK) error = archive->AddInt32("index", Index()); // fInfo.* @@ -188,6 +254,31 @@ RSession::Dump() const partition->Dump(); } +// _RescanPartitions +status_t +RSession::_RescanPartitions(int fd, uint32 cause) +{ + status_t error = B_OK; + // remove the current partitions + for (int32 i = CountPartitions() - 1; i >= 0; i--) + RemovePartition(i, cause); + // scan for partitions + for (int32 i = 0; error == B_OK; i++) { + // get the partition info + extended_partition_info partitionInfo; + status_t status = get_nth_partition_info(fd, fInfo.index, i, + &partitionInfo, (i == 0 ? fPartitioningSystem : NULL)); + if (status != B_OK) { + if (status != B_ENTRY_NOT_FOUND) + error = status; + break; + } + // create and add a RPartition + error = AddPartition(fd, &partitionInfo, cause); + } + return error; +} + // _NextID int32 RSession::_NextID() diff --git a/src/servers/registrar/RSession.h b/src/servers/registrar/RSession.h index 3a730706bf..a42a6ff091 100644 --- a/src/servers/registrar/RSession.h +++ b/src/servers/registrar/RSession.h @@ -9,6 +9,8 @@ #include #include +#include "RChangeCounter.h" + class RDiskDevice; class RDiskDeviceList; class RPartition; @@ -25,14 +27,19 @@ public: RDiskDeviceList *DeviceList() const; RDiskDevice *Device() const { return fDevice; } + status_t PartitionLayoutChanged(); + int32 ID() const { return fID; } - int32 ChangeCounter() const { return fChangeCounter; } + int32 ChangeCounter() const { return fChangeCounter.Count(); } + void Changed(); int32 Index() const; - bool AddPartition(RPartition *partition); - bool RemovePartition(int32 index); - bool RemovePartition(RPartition *partition); + status_t AddPartition(int fd, const extended_partition_info *partitionInfo, + uint32 cause); + bool AddPartition(RPartition *partition, uint32 cause); + bool RemovePartition(int32 index, uint32 cause); + bool RemovePartition(RPartition *partition, uint32 cause); int32 CountPartitions() const { return fPartitions.CountItems(); } RPartition *PartitionAt(int32 index) const { return fPartitions.ItemAt(index); } @@ -40,19 +47,25 @@ public: { return fPartitions.IndexOf(partition); } const session_info *Info() const { return &fInfo; } + off_t Offset() const { return fInfo.offset; } + off_t Size() const { return fInfo.size; } + + status_t Update(const session_info *sessionInfo); status_t Archive(BMessage *archive) const; void Dump() const; private: + + status_t _RescanPartitions(int fd, uint32 cause); static int32 _NextID(); private: BObjectList fPartitions; RDiskDevice *fDevice; int32 fID; - int32 fChangeCounter; + RChangeCounter fChangeCounter; session_info fInfo; char fPartitioningSystem[B_FILE_NAME_LENGTH]; diff --git a/src/servers/registrar/Registrar.cpp b/src/servers/registrar/Registrar.cpp index bbfe05e854..c3d4fdee94 100644 --- a/src/servers/registrar/Registrar.cpp +++ b/src/servers/registrar/Registrar.cpp @@ -218,6 +218,8 @@ void Registrar::ReadyToRun() { FUNCTION_START(); + // create event queue + fEventQueue = new EventQueue(kEventQueueName); // create roster fRoster = new TRoster; fRoster->Init(); @@ -228,10 +230,9 @@ Registrar::ReadyToRun() fMIMEManager = new MIMEManager; fMIMEManager->Run(); // create disk device manager - fDiskDeviceManager = new DiskDeviceManager; + fDiskDeviceManager = new DiskDeviceManager(fEventQueue); fDiskDeviceManager->Run(); // create message runner manager - fEventQueue = new EventQueue(kEventQueueName); fMessageRunnerManager = new MessageRunnerManager(fEventQueue); // init the global be_roster BRoster::Private().SetTo(be_app_messenger, BMessenger(NULL, fMIMEManager));