diff --git a/headers/private/kernel/disk_device_manager/KDiskDeviceManager.h b/headers/private/kernel/disk_device_manager/KDiskDeviceManager.h index 4188668e57..465282588e 100644 --- a/headers/private/kernel/disk_device_manager/KDiskDeviceManager.h +++ b/headers/private/kernel/disk_device_manager/KDiskDeviceManager.h @@ -99,8 +99,8 @@ public: status_t RescanDiskSystems(); private: - static void _CheckMediaStatusDaemon(void* self, int iteration); - void _CheckMediaStatus(); + static status_t _CheckMediaStatusDaemon(void* self); + status_t _CheckMediaStatus(); status_t _RescanDiskSystems(bool fileSystems); @@ -127,6 +127,8 @@ private: PartitionMap *fPartitions; DiskSystemMap *fDiskSystems; PartitionSet *fObsoletePartitions; + thread_id fMediaChecker; + volatile bool fTerminating; static KDiskDeviceManager *sDefaultManager; }; diff --git a/headers/private/kernel/disk_device_manager/KPartition.h b/headers/private/kernel/disk_device_manager/KPartition.h index e4e131c42f..40311bf105 100644 --- a/headers/private/kernel/disk_device_manager/KPartition.h +++ b/headers/private/kernel/disk_device_manager/KPartition.h @@ -54,6 +54,7 @@ public: bool IsBusy() const; bool IsBusy(bool includeDescendants); bool CheckAndMarkBusy(bool includeDescendants); + void MarkBusy(bool includeDescendants); void UnmarkBusy(bool includeDescendants); void SetOffset(off_t offset); diff --git a/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp b/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp index f09168ec58..45f8f9dc86 100644 --- a/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp +++ b/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp @@ -103,15 +103,19 @@ KDiskDeviceManager::KDiskDeviceManager() fDevices(new(nothrow) DeviceMap), fPartitions(new(nothrow) PartitionMap), fDiskSystems(new(nothrow) DiskSystemMap), - fObsoletePartitions(new(nothrow) PartitionSet) + fObsoletePartitions(new(nothrow) PartitionSet), + fMediaChecker(-1), + fTerminating(false) { if (InitCheck() != B_OK) return; RescanDiskSystems(); - register_kernel_daemon(&_CheckMediaStatusDaemon, this, 10); - // once every second + fMediaChecker = spawn_kernel_thread(_CheckMediaStatusDaemon, + "media checker", B_NORMAL_PRIORITY, this); + if (fMediaChecker >= 0) + resume_thread(fMediaChecker); DBG(OUT("number of disk systems: %ld\n", CountDiskSystems())); // TODO: Watch the disk systems and the relevant directories. @@ -120,9 +124,11 @@ KDiskDeviceManager::KDiskDeviceManager() KDiskDeviceManager::~KDiskDeviceManager() { - unregister_kernel_daemon(&_CheckMediaStatusDaemon, this); + fTerminating = true; + + status_t result; + wait_for_thread(fMediaChecker, &result); - // TODO: terminate and remove all jobs // remove all devices for (int32 cookie = 0; KDiskDevice *device = NextDevice(&cookie);) { PartitionRegistrar _(device); @@ -1127,35 +1133,45 @@ KDiskDeviceManager::_ScanPartition(KPartition *partition) } -void +status_t KDiskDeviceManager::_CheckMediaStatus() { - if (fLock.LockWithTimeout(0) != B_OK) - return; - - int32 cookie = 0; while (true) { - KDiskDevice* device = NextDevice(&cookie); - if (device == NULL) - break; + int32 cookie = 0; + while (KDiskDevice* device = RegisterNextDevice(&cookie)) { + DeviceWriteLocker locker(device); - bool hadMedia = device->HasMedia(); - device->UpdateMediaStatusIfNeeded(); + if (device->IsBusy(true)) + continue; - // TODO: propagate changes! - if (device->MediaChanged()) { + bool hadMedia = device->HasMedia(); + device->UpdateMediaStatusIfNeeded(); + + if (!device->MediaChanged() && (device->HasMedia() || !hadMedia)) + continue; + + device->MarkBusy(true); + device->UninitializeContents(true); + + if (device->MediaChanged()) { dprintf("Media changed from %s\n", device->Path()); - } else if (!device->HasMedia() && hadMedia) { - dprintf("Media removed from %s\n", device->Path()); + _ScanPartition(device, false); + } else if (!device->HasMedia() && hadMedia) { + dprintf("Media removed from %s\n", device->Path()); + } + + device->UnmarkBusy(true); } + + snooze(1000000); } - fLock.Unlock(); + return 0; } -void -KDiskDeviceManager::_CheckMediaStatusDaemon(void* self, int iteration) +status_t +KDiskDeviceManager::_CheckMediaStatusDaemon(void* self) { - ((KDiskDeviceManager*)self)->_CheckMediaStatus(); + return ((KDiskDeviceManager*)self)->_CheckMediaStatus(); } diff --git a/src/system/kernel/disk_device_manager/KFileDiskDevice.cpp b/src/system/kernel/disk_device_manager/KFileDiskDevice.cpp index 1fb7676233..7bd26f61e7 100644 --- a/src/system/kernel/disk_device_manager/KFileDiskDevice.cpp +++ b/src/system/kernel/disk_device_manager/KFileDiskDevice.cpp @@ -13,7 +13,6 @@ #include #include -#include "virtualdrive.h" // debugging //#define DBG(x) @@ -166,7 +165,6 @@ KFileDiskDevice::GetGeometry(device_geometry *geometry) geometry->write_once = false; return B_OK; - } // _RegisterDevice @@ -175,48 +173,6 @@ KFileDiskDevice::_RegisterDevice(const char *file, const char *device) { return devfs_publish_file_device(device + 5, file); // we need to remove the "/dev/" part from the path - - // TODO: For now we use the virtualdrive driver to register a file - // 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! - // -> Well, we could simply symlink the file there. Doesn't work for R5, - // but we should be able to deal with it properly. -// -// // open the virtualdrive control device -// int fd = open(VIRTUAL_DRIVE_CONTROL_DEVICE, O_RDONLY); -// if (fd < 0) { -// DBG(OUT("Failed to open virtualdrive control device: %s\n", -// strerror(errno))); -// return errno; -// } -// // set up the info -// virtual_drive_info info; -// strcpy(info.file_name, file); -// info.use_geometry = false; -// status_t error = B_OK; -// if (ioctl(fd, VIRTUAL_DRIVE_REGISTER_FILE, &info) != 0) { -// error = errno; -// DBG(OUT("Failed to install file device: %s\n", strerror(error))); -// } -// // close the control device -// close(fd); -// // create a symlink -// if (error == B_OK) { -// if (symlink(info.device_name, device) != 0) { -// DBG(OUT("Failed to create file device symlink: %s\n", -// strerror(error))); -// error = errno; -// // unregister the file device -// // 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 @@ -225,29 +181,6 @@ KFileDiskDevice::_UnregisterDevice(const char *_device) { return devfs_unpublish_file_device(_device + 5); // we need to remove the "/dev/" part from the path - -// // 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; } // _GetDirectoryPath diff --git a/src/system/kernel/disk_device_manager/KPartition.cpp b/src/system/kernel/disk_device_manager/KPartition.cpp index 262d6ccd79..e92d62e5c6 100644 --- a/src/system/kernel/disk_device_manager/KPartition.cpp +++ b/src/system/kernel/disk_device_manager/KPartition.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #include "UserDataWriter.h" @@ -272,6 +274,16 @@ KPartition::CheckAndMarkBusy(bool includeDescendants) if (IsBusy(includeDescendants)) return false; + MarkBusy(includeDescendants); + + return true; +} + + +// MarkBusy +void +KPartition::MarkBusy(bool includeDescendants) +{ if (includeDescendants) { struct MarkBusyVisitor : KPartitionVisitor { virtual bool VisitPre(KPartition* partition) @@ -284,8 +296,6 @@ KPartition::CheckAndMarkBusy(bool includeDescendants) VisitEachDescendant(&markVisitor); } else SetBusy(true); - - return true; } @@ -1039,7 +1049,13 @@ KPartition::UninitializeContents(bool logChanges) // volume if (VolumeID() >= 0) { -// TODO: Unmount? + status_t error = vfs_unmount(VolumeID(), + B_FORCE_UNMOUNT | B_UNMOUNT_BUSY_PARTITION); + if (error != B_OK) { + dprintf("KPartition::UninitializeContents(): Failed to unmount " + "device %ld: %s\n", VolumeID(), strerror(error)); + } + SetVolumeID(-1); flags |= B_PARTITION_CHANGED_VOLUME; } diff --git a/src/system/kernel/disk_device_manager/ddm_userland_interface.cpp b/src/system/kernel/disk_device_manager/ddm_userland_interface.cpp index c27c5ff3c4..3bffd4d0d7 100644 --- a/src/system/kernel/disk_device_manager/ddm_userland_interface.cpp +++ b/src/system/kernel/disk_device_manager/ddm_userland_interface.cpp @@ -1225,7 +1225,7 @@ _user_uninitialize_partition(partition_id partitionID, int32* _changeCounter) return B_BAD_VALUE; // check busy - if (partition->IsBusy(true)) + if (!partition->CheckAndMarkBusy(true)) return B_BUSY; // TODO: We should also check, if any partition is mounted!