#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Kernel { static DevFileSystem* s_instance = nullptr; void DevFileSystem::initialize() { ASSERT(s_instance == nullptr); s_instance = new DevFileSystem(); ASSERT(s_instance); MUST(s_instance->TmpFileSystem::initialize(0755, 0, 0)); s_instance->add_device(MUST(DebugDevice::create(0666, 0, 0))); s_instance->add_device(MUST(NullDevice::create(0666, 0, 0))); s_instance->add_device(MUST(RandomDevice::create(0666, 0, 0))); s_instance->add_device(MUST(ZeroDevice::create(0666, 0, 0))); s_instance->add_device(MUST(KeyboardDevice::create(0440, 0, 901))); s_instance->add_device(MUST(MouseDevice::create(0440, 0, 901))); // create symlink urandom -> random auto urandom = MUST(TmpSymlinkInode::create_new(DevFileSystem::get(), 0777, 0, 0, "random"_sv)); s_instance->add_inode("urandom"_sv, urandom); } DevFileSystem& DevFileSystem::get() { ASSERT(s_instance); return *s_instance; } void DevFileSystem::initialize_device_updater() { auto* updater_thread = MUST(Thread::create_kernel( [](void* _devfs) { auto* devfs = static_cast(_devfs); uint64_t next_update_ms = SystemTimer::get().ms_since_boot(); while (true) { { LockGuard _(devfs->m_device_lock); for (auto& device : devfs->m_devices) device->update(); } SystemTimer::get().sleep_until_ms(next_update_ms); next_update_ms += 10; } }, s_instance )); MUST(Processor::scheduler().add_thread(updater_thread)); auto* disk_cache_drop_thread = MUST(Thread::create_kernel( [](void* _devfs) { auto* devfs = static_cast(_devfs); while (true) { { SpinLockGuard guard(devfs->m_disk_cache_lock); bool expected = true; if (!devfs->m_should_drop_disk_cache.compare_exchange(expected, false)) { SpinLockGuardAsMutex smutex(guard); devfs->m_disk_cache_thread_blocker.block_indefinite(&smutex); continue; } } LockGuard _(devfs->m_device_lock); size_t pages_dropped = 0; for (auto& device : devfs->m_devices) if (device->is_storage_device()) pages_dropped += static_cast(device.ptr())->drop_disk_cache(); dprintln("Dropped {} pages from disk cache", pages_dropped); } }, s_instance )); MUST(Processor::scheduler().add_thread(disk_cache_drop_thread)); auto* disk_sync_thread = MUST(Thread::create_kernel( [](void* _devfs) { auto* devfs = static_cast(_devfs); constexpr uint64_t sync_interval_ms = 10'000; uint64_t next_sync_ms { sync_interval_ms }; while (true) { devfs->m_device_lock.lock(); while (!devfs->m_should_sync) { const uint64_t current_ms = SystemTimer::get().ms_since_boot(); if (devfs->m_should_sync || current_ms >= next_sync_ms) break; devfs->m_sync_thread_blocker.block_with_timeout_ms(next_sync_ms - current_ms, &devfs->m_device_lock); } BAN::Vector> storage_devices; for (auto& device : devfs->m_devices) if (device->is_storage_device()) MUST(storage_devices.push_back(static_cast(device.ptr()))); devfs->m_device_lock.unlock(); for (auto& device : storage_devices) if (auto ret = device->sync_disk_cache(); ret.is_error()) dwarnln("disk sync: {}", ret.error()); LockGuard _(devfs->m_device_lock); next_sync_ms = SystemTimer::get().ms_since_boot() + sync_interval_ms; devfs->m_should_sync = false; devfs->m_sync_done.unblock(); } }, s_instance )); MUST(Processor::scheduler().add_thread(disk_sync_thread)); } void DevFileSystem::initiate_disk_cache_drop() { SpinLockGuard _(m_disk_cache_lock); m_should_drop_disk_cache = true; m_disk_cache_thread_blocker.unblock(); } void DevFileSystem::initiate_sync(bool should_block) { LockGuard _(m_device_lock); m_should_sync = true; m_sync_thread_blocker.unblock(); while (should_block && m_should_sync) m_sync_done.block_indefinite(&m_device_lock); } void DevFileSystem::add_device(BAN::RefPtr device) { LockGuard _(m_device_lock); ASSERT(!device->name().contains('/')); MUST(static_cast(root_inode().ptr())->link_inode(*device, device->name())); MUST(m_devices.push_back(device)); dprintln_if(DEBUG_DEVFS, "Added device /dev/{}", device->name()); } void DevFileSystem::remove_device(BAN::RefPtr device) { LockGuard _(m_device_lock); ASSERT(!device->name().contains('/')); MUST(static_cast(root_inode().ptr())->unlink(device->name())); for (size_t i = 0; i < m_devices.size(); i++) { if (m_devices[i] == device) { m_devices.remove(i); break; } } dprintln_if(DEBUG_DEVFS, "Removed device /dev/{}", device->name()); } void DevFileSystem::add_inode(BAN::StringView path, BAN::RefPtr inode) { ASSERT(!inode->is_device()); ASSERT(!path.contains('/')); MUST(static_cast(root_inode().ptr())->link_inode(*inode, path)); } }