Ver código fonte

Kernel: Split the ProcFS core file into smaller components

Liav A 2 anos atrás
pai
commit
3906dd3aa3
30 arquivos alterados com 1080 adições e 822 exclusões
  1. 0 1
      Kernel/Arch/x86/ISABus/IDEController.cpp
  2. 0 1
      Kernel/Arch/x86/PCI/IDELegacyModeController.cpp
  3. 10 1
      Kernel/CMakeLists.txt
  4. 0 610
      Kernel/FileSystem/ProcFS.cpp
  5. 0 201
      Kernel/FileSystem/ProcFS.h
  6. 33 0
      Kernel/FileSystem/ProcFS/ComponentRegistry.cpp
  7. 51 0
      Kernel/FileSystem/ProcFS/DirectoryInode.cpp
  8. 28 0
      Kernel/FileSystem/ProcFS/DirectoryInode.h
  9. 34 0
      Kernel/FileSystem/ProcFS/FileSystem.cpp
  10. 45 0
      Kernel/FileSystem/ProcFS/FileSystem.h
  11. 88 0
      Kernel/FileSystem/ProcFS/GlobalInode.cpp
  12. 40 0
      Kernel/FileSystem/ProcFS/GlobalInode.h
  13. 50 0
      Kernel/FileSystem/ProcFS/Inode.cpp
  14. 40 0
      Kernel/FileSystem/ProcFS/Inode.h
  15. 36 0
      Kernel/FileSystem/ProcFS/LinkInode.cpp
  16. 24 0
      Kernel/FileSystem/ProcFS/LinkInode.h
  17. 24 0
      Kernel/FileSystem/ProcFS/ProcessAssociatedInode.cpp
  18. 28 0
      Kernel/FileSystem/ProcFS/ProcessAssociatedInode.h
  19. 95 0
      Kernel/FileSystem/ProcFS/ProcessDirectoryInode.cpp
  20. 31 0
      Kernel/FileSystem/ProcFS/ProcessDirectoryInode.h
  21. 236 0
      Kernel/FileSystem/ProcFS/ProcessPropertyInode.cpp
  22. 51 0
      Kernel/FileSystem/ProcFS/ProcessPropertyInode.h
  23. 96 0
      Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.cpp
  24. 34 0
      Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.h
  25. 2 3
      Kernel/ProcessExposed.cpp
  26. 2 1
      Kernel/ProcessProcFSTraits.cpp
  27. 1 1
      Kernel/ProcessSpecificExposed.cpp
  28. 0 1
      Kernel/Storage/ATA/GenericIDE/Controller.cpp
  29. 0 1
      Kernel/Storage/NVMe/NVMeController.cpp
  30. 1 1
      Kernel/Syscalls/mount.cpp

+ 0 - 1
Kernel/Arch/x86/ISABus/IDEController.cpp

@@ -8,7 +8,6 @@
 #include <AK/Types.h>
 #include <Kernel/Arch/x86/ISABus/IDEController.h>
 #include <Kernel/Bus/PCI/API.h>
-#include <Kernel/FileSystem/ProcFS.h>
 #include <Kernel/Library/LockRefPtr.h>
 #include <Kernel/Sections.h>
 #include <Kernel/Storage/ATA/ATADiskDevice.h>

+ 0 - 1
Kernel/Arch/x86/PCI/IDELegacyModeController.cpp

@@ -8,7 +8,6 @@
 #include <AK/Types.h>
 #include <Kernel/Arch/x86/PCI/IDELegacyModeController.h>
 #include <Kernel/Bus/PCI/API.h>
-#include <Kernel/FileSystem/ProcFS.h>
 #include <Kernel/Library/LockRefPtr.h>
 #include <Kernel/Sections.h>
 #include <Kernel/Storage/ATA/ATADiskDevice.h>

+ 10 - 1
Kernel/CMakeLists.txt

@@ -125,7 +125,16 @@ set(KERNEL_SOURCES
     FileSystem/Mount.cpp
     FileSystem/OpenFileDescription.cpp
     FileSystem/Plan9FileSystem.cpp
-    FileSystem/ProcFS.cpp
+    FileSystem/ProcFS/ComponentRegistry.cpp
+    FileSystem/ProcFS/DirectoryInode.cpp
+    FileSystem/ProcFS/FileSystem.cpp
+    FileSystem/ProcFS/GlobalInode.cpp
+    FileSystem/ProcFS/Inode.cpp
+    FileSystem/ProcFS/LinkInode.cpp
+    FileSystem/ProcFS/ProcessAssociatedInode.cpp
+    FileSystem/ProcFS/ProcessDirectoryInode.cpp
+    FileSystem/ProcFS/ProcessPropertyInode.cpp
+    FileSystem/ProcFS/ProcessSubDirectoryInode.cpp
     FileSystem/SysFS/Component.cpp
     FileSystem/SysFS/DirectoryInode.cpp
     FileSystem/SysFS/FileSystem.cpp

+ 0 - 610
Kernel/FileSystem/ProcFS.cpp

@@ -1,610 +0,0 @@
-/*
- * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
- * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#include <AK/Singleton.h>
-#include <Kernel/API/POSIX/errno.h>
-#include <Kernel/Debug.h>
-#include <Kernel/FileSystem/Custody.h>
-#include <Kernel/FileSystem/OpenFileDescription.h>
-#include <Kernel/FileSystem/ProcFS.h>
-#include <Kernel/FileSystem/VirtualFileSystem.h>
-#include <Kernel/Heap/kmalloc.h>
-#include <Kernel/Process.h>
-#include <Kernel/Sections.h>
-
-namespace Kernel {
-
-static Singleton<ProcFSComponentRegistry> s_the;
-
-ProcFSComponentRegistry& ProcFSComponentRegistry::the()
-{
-    return *s_the;
-}
-
-UNMAP_AFTER_INIT void ProcFSComponentRegistry::initialize()
-{
-    VERIFY(!s_the.is_initialized());
-    s_the.ensure_instance();
-}
-
-UNMAP_AFTER_INIT ProcFSComponentRegistry::ProcFSComponentRegistry()
-    : m_root_directory(ProcFSRootDirectory::must_create())
-{
-}
-
-ErrorOr<NonnullLockRefPtr<FileSystem>> ProcFS::try_create()
-{
-    return TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFS));
-}
-
-ProcFS::ProcFS() = default;
-ProcFS::~ProcFS() = default;
-
-ErrorOr<void> ProcFS::initialize()
-{
-    m_root_inode = static_ptr_cast<ProcFSDirectoryInode>(TRY(ProcFSComponentRegistry::the().root_directory().to_inode(*this)));
-    return {};
-}
-
-Inode& ProcFS::root_inode()
-{
-    return *m_root_inode;
-}
-
-ProcFSInode::ProcFSInode(ProcFS const& fs, InodeIndex index)
-    : Inode(const_cast<ProcFS&>(fs), index)
-{
-}
-
-ProcFSInode::~ProcFSInode() = default;
-
-ErrorOr<void> ProcFSInode::flush_metadata()
-{
-    return {};
-}
-
-ErrorOr<void> ProcFSInode::add_child(Inode&, StringView, mode_t)
-{
-    return EROFS;
-}
-
-ErrorOr<NonnullLockRefPtr<Inode>> ProcFSInode::create_child(StringView, mode_t, dev_t, UserID, GroupID)
-{
-    return EROFS;
-}
-
-ErrorOr<void> ProcFSInode::remove_child(StringView)
-{
-    return EROFS;
-}
-
-ErrorOr<void> ProcFSInode::chmod(mode_t)
-{
-    return EPERM;
-}
-
-ErrorOr<void> ProcFSInode::chown(UserID, GroupID)
-{
-    return EPERM;
-}
-
-ErrorOr<NonnullLockRefPtr<ProcFSGlobalInode>> ProcFSGlobalInode::try_create(ProcFS const& fs, ProcFSExposedComponent const& component)
-{
-    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSGlobalInode(fs, component));
-}
-
-ProcFSGlobalInode::ProcFSGlobalInode(ProcFS const& fs, ProcFSExposedComponent const& component)
-    : ProcFSInode(fs, component.component_index())
-    , m_associated_component(component)
-{
-}
-
-void ProcFSGlobalInode::did_seek(OpenFileDescription& description, off_t new_offset)
-{
-    if (new_offset != 0)
-        return;
-    auto result = m_associated_component->refresh_data(description);
-    if (result.is_error()) {
-        // Subsequent calls to read will return EIO!
-        dbgln("ProcFS: Could not refresh contents: {}", result.error());
-    }
-}
-
-ErrorOr<void> ProcFSGlobalInode::attach(OpenFileDescription& description)
-{
-    return m_associated_component->refresh_data(description);
-}
-
-ErrorOr<size_t> ProcFSGlobalInode::read_bytes_locked(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription* fd) const
-{
-    return m_associated_component->read_bytes(offset, count, buffer, fd);
-}
-
-StringView ProcFSGlobalInode::name() const
-{
-    return m_associated_component->name();
-}
-
-ErrorOr<void> ProcFSGlobalInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const
-{
-    VERIFY_NOT_REACHED();
-}
-
-ErrorOr<NonnullLockRefPtr<Inode>> ProcFSGlobalInode::lookup(StringView)
-{
-    VERIFY_NOT_REACHED();
-}
-
-ErrorOr<void> ProcFSGlobalInode::truncate(u64 size)
-{
-    return m_associated_component->truncate(size);
-}
-
-ErrorOr<void> ProcFSGlobalInode::update_timestamps(Optional<time_t>, Optional<time_t>, Optional<time_t>)
-{
-    return {};
-}
-
-InodeMetadata ProcFSGlobalInode::metadata() const
-{
-    MutexLocker locker(m_inode_lock);
-    InodeMetadata metadata;
-    metadata.inode = { fsid(), m_associated_component->component_index() };
-    metadata.mode = S_IFREG | m_associated_component->required_mode();
-    metadata.uid = m_associated_component->owner_user();
-    metadata.gid = m_associated_component->owner_group();
-    metadata.size = 0;
-    metadata.mtime = m_associated_component->modified_time();
-    return metadata;
-}
-
-ErrorOr<size_t> ProcFSGlobalInode::write_bytes_locked(off_t offset, size_t count, UserOrKernelBuffer const& buffer, OpenFileDescription* fd)
-{
-    return m_associated_component->write_bytes(offset, count, buffer, fd);
-}
-
-ErrorOr<NonnullLockRefPtr<ProcFSDirectoryInode>> ProcFSDirectoryInode::try_create(ProcFS const& procfs, ProcFSExposedComponent const& component)
-{
-    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSDirectoryInode(procfs, component));
-}
-
-ProcFSDirectoryInode::ProcFSDirectoryInode(ProcFS const& fs, ProcFSExposedComponent const& component)
-    : ProcFSGlobalInode(fs, component)
-{
-}
-
-ProcFSDirectoryInode::~ProcFSDirectoryInode() = default;
-InodeMetadata ProcFSDirectoryInode::metadata() const
-{
-    MutexLocker locker(m_inode_lock);
-    InodeMetadata metadata;
-    metadata.inode = { fsid(), m_associated_component->component_index() };
-    metadata.mode = S_IFDIR | m_associated_component->required_mode();
-    metadata.uid = m_associated_component->owner_user();
-    metadata.gid = m_associated_component->owner_group();
-    metadata.size = 0;
-    metadata.mtime = m_associated_component->modified_time();
-    return metadata;
-}
-ErrorOr<void> ProcFSDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
-{
-    MutexLocker locker(procfs().m_lock);
-    return m_associated_component->traverse_as_directory(procfs().fsid(), move(callback));
-}
-
-ErrorOr<NonnullLockRefPtr<Inode>> ProcFSDirectoryInode::lookup(StringView name)
-{
-    MutexLocker locker(procfs().m_lock);
-    auto component = TRY(m_associated_component->lookup(name));
-    return component->to_inode(procfs());
-}
-
-ErrorOr<NonnullLockRefPtr<ProcFSLinkInode>> ProcFSLinkInode::try_create(ProcFS const& procfs, ProcFSExposedComponent const& component)
-{
-    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSLinkInode(procfs, component));
-}
-
-ProcFSLinkInode::ProcFSLinkInode(ProcFS const& fs, ProcFSExposedComponent const& component)
-    : ProcFSGlobalInode(fs, component)
-{
-}
-
-InodeMetadata ProcFSLinkInode::metadata() const
-{
-    MutexLocker locker(m_inode_lock);
-    InodeMetadata metadata;
-    metadata.inode = { fsid(), m_associated_component->component_index() };
-    metadata.mode = S_IFLNK | m_associated_component->required_mode();
-    metadata.uid = m_associated_component->owner_user();
-    metadata.gid = m_associated_component->owner_group();
-    metadata.size = 0;
-    metadata.mtime = m_associated_component->modified_time();
-    return metadata;
-}
-
-ProcFSProcessAssociatedInode::ProcFSProcessAssociatedInode(ProcFS const& fs, ProcessID associated_pid, InodeIndex determined_index)
-    : ProcFSInode(fs, determined_index)
-    , m_pid(associated_pid)
-{
-}
-
-ErrorOr<size_t> ProcFSProcessAssociatedInode::write_bytes_locked(off_t, size_t, UserOrKernelBuffer const&, OpenFileDescription*)
-{
-    return ENOTSUP;
-}
-
-ErrorOr<NonnullLockRefPtr<ProcFSProcessDirectoryInode>> ProcFSProcessDirectoryInode::try_create(ProcFS const& procfs, ProcessID pid)
-{
-    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessDirectoryInode(procfs, pid));
-}
-
-ProcFSProcessDirectoryInode::ProcFSProcessDirectoryInode(ProcFS const& procfs, ProcessID pid)
-    : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_pid_directory(pid))
-{
-}
-
-ErrorOr<void> ProcFSProcessDirectoryInode::attach(OpenFileDescription&)
-{
-    return {};
-}
-
-InodeMetadata ProcFSProcessDirectoryInode::metadata() const
-{
-    MutexLocker locker(m_inode_lock);
-    auto process = Process::from_pid_in_same_jail(associated_pid());
-    if (!process)
-        return {};
-
-    auto traits = process->procfs_traits();
-    InodeMetadata metadata;
-    metadata.inode = { fsid(), traits->component_index() };
-    metadata.mode = S_IFDIR | traits->required_mode();
-    metadata.uid = traits->owner_user();
-    metadata.gid = traits->owner_group();
-    metadata.size = 0;
-    metadata.mtime = traits->modified_time();
-    return metadata;
-}
-
-ErrorOr<size_t> ProcFSProcessDirectoryInode::read_bytes_locked(off_t, size_t, UserOrKernelBuffer&, OpenFileDescription*) const
-{
-    VERIFY_NOT_REACHED();
-}
-
-ErrorOr<void> ProcFSProcessDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
-{
-    MutexLocker locker(procfs().m_lock);
-    auto process = Process::from_pid_in_same_jail(associated_pid());
-    if (!process)
-        return EINVAL;
-    return process->procfs_traits()->traverse_as_directory(procfs().fsid(), move(callback));
-}
-
-ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessDirectoryInode::lookup(StringView name)
-{
-    MutexLocker locker(procfs().m_lock);
-    auto process = Process::from_pid_in_same_jail(associated_pid());
-    if (!process)
-        return ESRCH;
-    if (name == "fd"sv)
-        return TRY(ProcFSProcessSubDirectoryInode::try_create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions, associated_pid()));
-    if (name == "stacks"sv)
-        return TRY(ProcFSProcessSubDirectoryInode::try_create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks, associated_pid()));
-    if (name == "children"sv)
-        return TRY(ProcFSProcessSubDirectoryInode::try_create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::Children, associated_pid()));
-    if (name == "unveil"sv)
-        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::Unveil, associated_pid()));
-    if (name == "pledge"sv)
-        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::Pledge, associated_pid()));
-    if (name == "fds"sv)
-        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::OpenFileDescriptions, associated_pid()));
-    if (name == "exe"sv)
-        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::BinaryLink, associated_pid()));
-    if (name == "cwd"sv)
-        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink, associated_pid()));
-    if (name == "perf_events"sv)
-        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents, associated_pid()));
-    if (name == "vm"sv)
-        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats, associated_pid()));
-    if (name == "cmdline"sv)
-        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::CommandLine, associated_pid()));
-    return ENOENT;
-}
-
-ErrorOr<NonnullLockRefPtr<ProcFSProcessSubDirectoryInode>> ProcFSProcessSubDirectoryInode::try_create(ProcFS const& procfs, SegmentedProcFSIndex::ProcessSubDirectory sub_directory_type, ProcessID pid)
-{
-    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessSubDirectoryInode(procfs, sub_directory_type, pid));
-}
-
-ProcFSProcessSubDirectoryInode::ProcFSProcessSubDirectoryInode(ProcFS const& procfs, SegmentedProcFSIndex::ProcessSubDirectory sub_directory_type, ProcessID pid)
-    : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(pid, sub_directory_type))
-    , m_sub_directory_type(sub_directory_type)
-{
-}
-
-ErrorOr<size_t> ProcFSProcessSubDirectoryInode::read_bytes_locked(off_t, size_t, UserOrKernelBuffer&, OpenFileDescription*) const
-{
-    VERIFY_NOT_REACHED();
-}
-
-ErrorOr<void> ProcFSProcessSubDirectoryInode::attach(OpenFileDescription&)
-{
-    return {};
-}
-
-void ProcFSProcessSubDirectoryInode::did_seek(OpenFileDescription&, off_t)
-{
-    VERIFY_NOT_REACHED();
-}
-
-InodeMetadata ProcFSProcessSubDirectoryInode::metadata() const
-{
-    MutexLocker locker(m_inode_lock);
-    auto process = Process::from_pid_in_same_jail(associated_pid());
-    if (!process)
-        return {};
-
-    auto traits = process->procfs_traits();
-    InodeMetadata metadata;
-    metadata.inode = { fsid(), traits->component_index() };
-    metadata.mode = S_IFDIR | traits->required_mode();
-    metadata.uid = traits->owner_user();
-    metadata.gid = traits->owner_group();
-    metadata.size = 0;
-    metadata.mtime = traits->modified_time();
-    return metadata;
-}
-
-ErrorOr<void> ProcFSProcessSubDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
-{
-    MutexLocker locker(procfs().m_lock);
-    auto process = Process::from_pid_in_same_jail(associated_pid());
-    if (!process)
-        return EINVAL;
-    switch (m_sub_directory_type) {
-    case SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions:
-        return process->traverse_file_descriptions_directory(procfs().fsid(), move(callback));
-    case SegmentedProcFSIndex::ProcessSubDirectory::Stacks:
-        return process->traverse_stacks_directory(procfs().fsid(), move(callback));
-    case SegmentedProcFSIndex::ProcessSubDirectory::Children:
-        return process->traverse_children_directory(procfs().fsid(), move(callback));
-    default:
-        VERIFY_NOT_REACHED();
-    }
-    VERIFY_NOT_REACHED();
-}
-
-ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessSubDirectoryInode::lookup(StringView name)
-{
-    MutexLocker locker(procfs().m_lock);
-    auto process = Process::from_pid_in_same_jail(associated_pid());
-    if (!process)
-        return ESRCH;
-    switch (m_sub_directory_type) {
-    case SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions:
-        return process->lookup_file_descriptions_directory(procfs(), name);
-    case SegmentedProcFSIndex::ProcessSubDirectory::Stacks:
-        return process->lookup_stacks_directory(procfs(), name);
-    case SegmentedProcFSIndex::ProcessSubDirectory::Children:
-        return process->lookup_children_directory(procfs(), name);
-    default:
-        VERIFY_NOT_REACHED();
-    }
-}
-
-ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_file_description_link(ProcFS const& procfs, unsigned file_description_index, ProcessID pid)
-{
-    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, file_description_index, pid));
-}
-ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_thread_stack(ProcFS const& procfs, ThreadID stack_thread_index, ProcessID pid)
-{
-    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, stack_thread_index, pid));
-}
-ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_pid_property(ProcFS const& procfs, SegmentedProcFSIndex::MainProcessProperty main_property_type, ProcessID pid)
-{
-    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, main_property_type, pid));
-}
-ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_child_process_link(ProcFS const& procfs, ProcessID child_pid, ProcessID pid)
-{
-    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, child_pid, pid));
-}
-
-ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, SegmentedProcFSIndex::MainProcessProperty main_property_type, ProcessID pid)
-    : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid, main_property_type))
-    , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Reserved)
-{
-    m_possible_data.property_type = main_property_type;
-}
-
-ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, unsigned file_description_index, ProcessID pid)
-    : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_file_description(pid, file_description_index))
-    , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions)
-{
-    m_possible_data.property_index = file_description_index;
-}
-
-ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, ThreadID thread_stack_index, ProcessID pid)
-    : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_thread_stack(pid, thread_stack_index))
-    , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Stacks)
-{
-    m_possible_data.property_index = thread_stack_index.value();
-}
-
-ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, ProcessID child_pid, ProcessID pid)
-    : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_children(pid, child_pid))
-    , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Children)
-{
-    m_possible_data.property_index = child_pid.value();
-}
-
-ErrorOr<void> ProcFSProcessPropertyInode::attach(OpenFileDescription& description)
-{
-    return refresh_data(description);
-}
-void ProcFSProcessPropertyInode::did_seek(OpenFileDescription& description, off_t offset)
-{
-    if (offset != 0)
-        return;
-    (void)refresh_data(description);
-}
-
-static mode_t determine_procfs_process_inode_mode(SegmentedProcFSIndex::ProcessSubDirectory parent_sub_directory_type, SegmentedProcFSIndex::MainProcessProperty main_property)
-{
-    if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions)
-        return S_IFLNK | 0400;
-    if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Stacks)
-        return S_IFREG | 0400;
-    if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Children)
-        return S_IFLNK | 0400;
-    VERIFY(parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Reserved);
-    if (main_property == SegmentedProcFSIndex::MainProcessProperty::BinaryLink)
-        return S_IFLNK | 0777;
-    if (main_property == SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink)
-        return S_IFLNK | 0777;
-    return S_IFREG | 0400;
-}
-
-InodeMetadata ProcFSProcessPropertyInode::metadata() const
-{
-    MutexLocker locker(m_inode_lock);
-    auto process = Process::from_pid_in_same_jail(associated_pid());
-    if (!process)
-        return {};
-
-    auto traits = process->procfs_traits();
-    InodeMetadata metadata;
-    metadata.inode = { fsid(), traits->component_index() };
-    metadata.mode = determine_procfs_process_inode_mode(m_parent_sub_directory_type, m_possible_data.property_type);
-    metadata.uid = traits->owner_user();
-    metadata.gid = traits->owner_group();
-    metadata.size = 0;
-    metadata.mtime = traits->modified_time();
-    return metadata;
-}
-ErrorOr<void> ProcFSProcessPropertyInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const
-{
-    VERIFY_NOT_REACHED();
-}
-ErrorOr<size_t> ProcFSProcessPropertyInode::read_bytes_locked(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription* description) const
-{
-    dbgln_if(PROCFS_DEBUG, "ProcFS ProcessInformation: read_bytes_locked offset: {} count: {}", offset, count);
-
-    VERIFY(offset >= 0);
-    VERIFY(buffer.user_or_kernel_ptr());
-
-    if (!description) {
-        auto builder = TRY(KBufferBuilder::try_create());
-        auto process = Process::from_pid_in_same_jail(associated_pid());
-        if (!process)
-            return Error::from_errno(ESRCH);
-        TRY(try_to_acquire_data(*process, builder));
-        auto data_buffer = builder.build();
-        if (!data_buffer)
-            return Error::from_errno(EFAULT);
-        ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
-        TRY(buffer.write(data_buffer->data() + offset, nread));
-        return nread;
-    }
-    if (!description->data()) {
-        dbgln("ProcFS Process Information: Do not have cached data!");
-        return Error::from_errno(EIO);
-    }
-
-    MutexLocker locker(m_refresh_lock);
-
-    auto& typed_cached_data = static_cast<ProcFSInodeData&>(*description->data());
-    auto& data_buffer = typed_cached_data.buffer;
-
-    if (!data_buffer || (size_t)offset >= data_buffer->size())
-        return 0;
-
-    ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
-    TRY(buffer.write(data_buffer->data() + offset, nread));
-
-    return nread;
-}
-ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessPropertyInode::lookup(StringView)
-{
-    return EINVAL;
-}
-
-static ErrorOr<void> build_from_cached_data(KBufferBuilder& builder, ProcFSInodeData& cached_data)
-{
-    cached_data.buffer = builder.build();
-    if (!cached_data.buffer)
-        return ENOMEM;
-    return {};
-}
-
-ErrorOr<void> ProcFSProcessPropertyInode::try_to_acquire_data(Process& process, KBufferBuilder& builder) const
-{
-    // FIXME: Verify process is already ref-counted
-    if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions) {
-        TRY(process.procfs_get_file_description_link(m_possible_data.property_index, builder));
-        return {};
-    }
-    if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Stacks) {
-        TRY(process.procfs_get_thread_stack(m_possible_data.property_index, builder));
-        return {};
-    }
-    if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Children) {
-        TRY(process.procfs_get_child_proccess_link(m_possible_data.property_index, builder));
-        return {};
-    }
-
-    VERIFY(m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Reserved);
-    switch (m_possible_data.property_type) {
-    case SegmentedProcFSIndex::MainProcessProperty::Unveil:
-        return process.procfs_get_unveil_stats(builder);
-    case SegmentedProcFSIndex::MainProcessProperty::Pledge:
-        return process.procfs_get_pledge_stats(builder);
-    case SegmentedProcFSIndex::MainProcessProperty::OpenFileDescriptions:
-        return process.procfs_get_fds_stats(builder);
-    case SegmentedProcFSIndex::MainProcessProperty::BinaryLink:
-        return process.procfs_get_binary_link(builder);
-    case SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink:
-        return process.procfs_get_current_work_directory_link(builder);
-    case SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents:
-        return process.procfs_get_perf_events(builder);
-    case SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats:
-        return process.procfs_get_virtual_memory_stats(builder);
-    case SegmentedProcFSIndex::MainProcessProperty::CommandLine:
-        return process.procfs_get_command_line(builder);
-    default:
-        VERIFY_NOT_REACHED();
-    }
-}
-
-ErrorOr<void> ProcFSProcessPropertyInode::refresh_data(OpenFileDescription& description)
-{
-    // For process-specific inodes, hold the process's ptrace lock across refresh
-    // and refuse to load data if the process is not dumpable.
-    // Without this, files opened before a process went non-dumpable could still be used for dumping.
-    auto process = Process::from_pid_in_same_jail(associated_pid());
-    if (!process)
-        return Error::from_errno(ESRCH);
-    process->ptrace_lock().lock();
-    if (!process->is_dumpable()) {
-        process->ptrace_lock().unlock();
-        return EPERM;
-    }
-    ScopeGuard guard = [&] {
-        process->ptrace_lock().unlock();
-    };
-    MutexLocker locker(m_refresh_lock);
-    auto& cached_data = description.data();
-    if (!cached_data) {
-        cached_data = adopt_own_if_nonnull(new (nothrow) ProcFSInodeData);
-        if (!cached_data)
-            return ENOMEM;
-    }
-    auto builder = TRY(KBufferBuilder::try_create());
-    TRY(try_to_acquire_data(*process, builder));
-    return build_from_cached_data(builder, static_cast<ProcFSInodeData&>(*cached_data));
-}
-}

+ 0 - 201
Kernel/FileSystem/ProcFS.h

@@ -1,201 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#pragma once
-
-#include <AK/HashMap.h>
-#include <AK/Types.h>
-#include <Kernel/FileSystem/FileSystem.h>
-#include <Kernel/FileSystem/Inode.h>
-#include <Kernel/Forward.h>
-#include <Kernel/KBufferBuilder.h>
-#include <Kernel/Locking/Mutex.h>
-#include <Kernel/ProcessExposed.h>
-#include <Kernel/UnixTypes.h>
-
-namespace Kernel {
-
-class ProcFS final : public FileSystem {
-    friend class ProcFSInode;
-    friend class ProcFSDirectoryInode;
-    friend class ProcFSProcessDirectoryInode;
-    friend class ProcFSGlobalInode;
-    friend class ProcFSAssociatedProcessInode;
-    friend class ProcFSProcessSubDirectoryInode;
-
-public:
-    virtual ~ProcFS() override;
-    static ErrorOr<NonnullLockRefPtr<FileSystem>> try_create();
-
-    virtual ErrorOr<void> initialize() override;
-    virtual StringView class_name() const override { return "ProcFS"sv; }
-
-    virtual Inode& root_inode() override;
-
-private:
-    ProcFS();
-
-    LockRefPtr<ProcFSDirectoryInode> m_root_inode;
-};
-
-class ProcFSInode : public Inode {
-    friend class ProcFS;
-
-public:
-    virtual ~ProcFSInode() override;
-
-protected:
-    ProcFSInode(ProcFS const&, InodeIndex);
-
-    ProcFS& procfs() { return static_cast<ProcFS&>(Inode::fs()); }
-    ProcFS const& procfs() const { return static_cast<ProcFS const&>(Inode::fs()); }
-
-    // ^Inode
-    virtual ErrorOr<void> attach(OpenFileDescription& description) override = 0;
-    virtual void did_seek(OpenFileDescription&, off_t) override = 0;
-    virtual ErrorOr<void> flush_metadata() override final;
-    virtual ErrorOr<NonnullLockRefPtr<Inode>> create_child(StringView name, mode_t, dev_t, UserID, GroupID) override final;
-    virtual ErrorOr<void> add_child(Inode&, StringView name, mode_t) override final;
-    virtual ErrorOr<void> remove_child(StringView name) override final;
-    virtual ErrorOr<void> chmod(mode_t) override final;
-    virtual ErrorOr<void> chown(UserID, GroupID) override final;
-};
-
-class ProcFSGlobalInode : public ProcFSInode {
-    friend class ProcFS;
-
-public:
-    static ErrorOr<NonnullLockRefPtr<ProcFSGlobalInode>> try_create(ProcFS const&, ProcFSExposedComponent const&);
-    virtual ~ProcFSGlobalInode() override {};
-    StringView name() const;
-
-protected:
-    ProcFSGlobalInode(ProcFS const&, ProcFSExposedComponent const&);
-
-    // ^Inode
-    virtual ErrorOr<void> attach(OpenFileDescription& description) override final;
-    virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
-    virtual ErrorOr<size_t> write_bytes_locked(off_t, size_t, UserOrKernelBuffer const& buffer, OpenFileDescription*) override final;
-    virtual void did_seek(OpenFileDescription&, off_t) override final;
-    virtual InodeMetadata metadata() const override;
-    virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
-    virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView) override;
-    virtual ErrorOr<void> truncate(u64) override final;
-    virtual ErrorOr<void> update_timestamps(Optional<time_t> atime, Optional<time_t> ctime, Optional<time_t> mtime) override;
-
-    NonnullLockRefPtr<ProcFSExposedComponent> m_associated_component;
-};
-
-class ProcFSLinkInode : public ProcFSGlobalInode {
-    friend class ProcFS;
-
-public:
-    static ErrorOr<NonnullLockRefPtr<ProcFSLinkInode>> try_create(ProcFS const&, ProcFSExposedComponent const&);
-
-protected:
-    ProcFSLinkInode(ProcFS const&, ProcFSExposedComponent const&);
-    virtual InodeMetadata metadata() const override;
-};
-
-class ProcFSDirectoryInode final : public ProcFSGlobalInode {
-    friend class ProcFS;
-
-public:
-    static ErrorOr<NonnullLockRefPtr<ProcFSDirectoryInode>> try_create(ProcFS const&, ProcFSExposedComponent const&);
-    virtual ~ProcFSDirectoryInode() override;
-
-protected:
-    ProcFSDirectoryInode(ProcFS const&, ProcFSExposedComponent const&);
-    // ^Inode
-    virtual InodeMetadata metadata() const override;
-    virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
-    virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override;
-};
-
-class ProcFSProcessAssociatedInode : public ProcFSInode {
-    friend class ProcFS;
-
-protected:
-    ProcFSProcessAssociatedInode(ProcFS const&, ProcessID, InodeIndex);
-    ProcessID associated_pid() const { return m_pid; }
-
-    // ^Inode
-    virtual ErrorOr<size_t> write_bytes_locked(off_t, size_t, UserOrKernelBuffer const& buffer, OpenFileDescription*) override final;
-
-private:
-    const ProcessID m_pid;
-};
-
-class ProcFSProcessDirectoryInode final : public ProcFSProcessAssociatedInode {
-    friend class ProcFS;
-
-public:
-    static ErrorOr<NonnullLockRefPtr<ProcFSProcessDirectoryInode>> try_create(ProcFS const&, ProcessID);
-
-private:
-    ProcFSProcessDirectoryInode(ProcFS const&, ProcessID);
-    // ^Inode
-    virtual ErrorOr<void> attach(OpenFileDescription& description) override;
-    virtual void did_seek(OpenFileDescription&, off_t) override { }
-    virtual InodeMetadata metadata() const override;
-    virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
-    virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
-    virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override;
-};
-
-class ProcFSProcessSubDirectoryInode final : public ProcFSProcessAssociatedInode {
-    friend class ProcFS;
-
-public:
-    static ErrorOr<NonnullLockRefPtr<ProcFSProcessSubDirectoryInode>> try_create(ProcFS const&, SegmentedProcFSIndex::ProcessSubDirectory, ProcessID);
-
-private:
-    ProcFSProcessSubDirectoryInode(ProcFS const&, SegmentedProcFSIndex::ProcessSubDirectory, ProcessID);
-    // ^Inode
-    virtual ErrorOr<void> attach(OpenFileDescription& description) override;
-    virtual void did_seek(OpenFileDescription&, off_t) override;
-    virtual InodeMetadata metadata() const override;
-    virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
-    virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
-    virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override;
-
-    const SegmentedProcFSIndex::ProcessSubDirectory m_sub_directory_type;
-};
-
-class ProcFSProcessPropertyInode final : public ProcFSProcessAssociatedInode {
-    friend class ProcFS;
-
-public:
-    static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_file_description_link(ProcFS const&, unsigned, ProcessID);
-    static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_thread_stack(ProcFS const&, ThreadID, ProcessID);
-    static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_pid_property(ProcFS const&, SegmentedProcFSIndex::MainProcessProperty, ProcessID);
-    static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_child_process_link(ProcFS const&, ProcessID, ProcessID);
-
-private:
-    ProcFSProcessPropertyInode(ProcFS const&, SegmentedProcFSIndex::MainProcessProperty, ProcessID);
-    ProcFSProcessPropertyInode(ProcFS const&, ThreadID, ProcessID);
-    ProcFSProcessPropertyInode(ProcFS const&, unsigned, ProcessID);
-    ProcFSProcessPropertyInode(ProcFS const&, ProcessID, ProcessID);
-
-    // ^Inode
-    virtual ErrorOr<void> attach(OpenFileDescription& description) override;
-    virtual void did_seek(OpenFileDescription&, off_t) override;
-    virtual InodeMetadata metadata() const override;
-    virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
-    virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
-    virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override final;
-
-    ErrorOr<void> refresh_data(OpenFileDescription& description);
-    ErrorOr<void> try_to_acquire_data(Process& process, KBufferBuilder& builder) const;
-
-    const SegmentedProcFSIndex::ProcessSubDirectory m_parent_sub_directory_type;
-    union {
-        SegmentedProcFSIndex::MainProcessProperty property_type;
-        unsigned property_index;
-    } m_possible_data;
-    mutable Mutex m_refresh_lock;
-};
-}

+ 33 - 0
Kernel/FileSystem/ProcFS/ComponentRegistry.cpp

@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/Singleton.h>
+#include <Kernel/ProcessExposed.h>
+#include <Kernel/Sections.h>
+
+namespace Kernel {
+
+static Singleton<ProcFSComponentRegistry> s_the;
+
+ProcFSComponentRegistry& ProcFSComponentRegistry::the()
+{
+    return *s_the;
+}
+
+UNMAP_AFTER_INIT void ProcFSComponentRegistry::initialize()
+{
+    VERIFY(!s_the.is_initialized());
+    s_the.ensure_instance();
+}
+
+UNMAP_AFTER_INIT ProcFSComponentRegistry::ProcFSComponentRegistry()
+    : m_root_directory(ProcFSRootDirectory::must_create())
+{
+}
+
+}

+ 51 - 0
Kernel/FileSystem/ProcFS/DirectoryInode.cpp

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/DirectoryInode.h>
+
+namespace Kernel {
+
+ErrorOr<NonnullLockRefPtr<ProcFSDirectoryInode>> ProcFSDirectoryInode::try_create(ProcFS const& procfs, ProcFSExposedComponent const& component)
+{
+    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSDirectoryInode(procfs, component));
+}
+
+ProcFSDirectoryInode::ProcFSDirectoryInode(ProcFS const& fs, ProcFSExposedComponent const& component)
+    : ProcFSGlobalInode(fs, component)
+{
+}
+
+ProcFSDirectoryInode::~ProcFSDirectoryInode() = default;
+
+InodeMetadata ProcFSDirectoryInode::metadata() const
+{
+    MutexLocker locker(m_inode_lock);
+    InodeMetadata metadata;
+    metadata.inode = { fsid(), m_associated_component->component_index() };
+    metadata.mode = S_IFDIR | m_associated_component->required_mode();
+    metadata.uid = m_associated_component->owner_user();
+    metadata.gid = m_associated_component->owner_group();
+    metadata.size = 0;
+    metadata.mtime = m_associated_component->modified_time();
+    return metadata;
+}
+
+ErrorOr<void> ProcFSDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
+{
+    MutexLocker locker(procfs().m_lock);
+    return m_associated_component->traverse_as_directory(procfs().fsid(), move(callback));
+}
+
+ErrorOr<NonnullLockRefPtr<Inode>> ProcFSDirectoryInode::lookup(StringView name)
+{
+    MutexLocker locker(procfs().m_lock);
+    auto component = TRY(m_associated_component->lookup(name));
+    return component->to_inode(procfs());
+}
+
+}

+ 28 - 0
Kernel/FileSystem/ProcFS/DirectoryInode.h

@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/ProcFS/GlobalInode.h>
+
+namespace Kernel {
+
+class ProcFSDirectoryInode final : public ProcFSGlobalInode {
+    friend class ProcFS;
+
+public:
+    static ErrorOr<NonnullLockRefPtr<ProcFSDirectoryInode>> try_create(ProcFS const&, ProcFSExposedComponent const&);
+    virtual ~ProcFSDirectoryInode() override;
+
+protected:
+    ProcFSDirectoryInode(ProcFS const&, ProcFSExposedComponent const&);
+    // ^Inode
+    virtual InodeMetadata metadata() const override;
+    virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
+    virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override;
+};
+
+}

+ 34 - 0
Kernel/FileSystem/ProcFS/FileSystem.cpp

@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/DirectoryInode.h>
+#include <Kernel/FileSystem/ProcFS/FileSystem.h>
+#include <Kernel/ProcessExposed.h>
+
+namespace Kernel {
+
+ErrorOr<NonnullLockRefPtr<FileSystem>> ProcFS::try_create()
+{
+    return TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFS));
+}
+
+ProcFS::ProcFS() = default;
+ProcFS::~ProcFS() = default;
+
+ErrorOr<void> ProcFS::initialize()
+{
+    m_root_inode = static_ptr_cast<ProcFSDirectoryInode>(TRY(ProcFSComponentRegistry::the().root_directory().to_inode(*this)));
+    return {};
+}
+
+Inode& ProcFS::root_inode()
+{
+    return *m_root_inode;
+}
+
+}

+ 45 - 0
Kernel/FileSystem/ProcFS/FileSystem.h

@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Types.h>
+#include <Kernel/FileSystem/FileSystem.h>
+#include <Kernel/FileSystem/Inode.h>
+#include <Kernel/Forward.h>
+
+namespace Kernel {
+
+class ProcFSInode;
+class ProcFSProcessDirectoryInode;
+class ProcFSGlobalInode;
+class ProcFSAssociatedProcessInode;
+class ProcFSProcessSubDirectoryInode;
+
+class ProcFS final : public FileSystem {
+    friend class ProcFSInode;
+    friend class ProcFSDirectoryInode;
+    friend class ProcFSProcessDirectoryInode;
+    friend class ProcFSGlobalInode;
+    friend class ProcFSAssociatedProcessInode;
+    friend class ProcFSProcessSubDirectoryInode;
+
+public:
+    virtual ~ProcFS() override;
+    static ErrorOr<NonnullLockRefPtr<FileSystem>> try_create();
+
+    virtual ErrorOr<void> initialize() override;
+    virtual StringView class_name() const override { return "ProcFS"sv; }
+
+    virtual Inode& root_inode() override;
+
+private:
+    ProcFS();
+
+    LockRefPtr<ProcFSDirectoryInode> m_root_inode;
+};
+
+}

+ 88 - 0
Kernel/FileSystem/ProcFS/GlobalInode.cpp

@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/GlobalInode.h>
+
+namespace Kernel {
+
+ErrorOr<NonnullLockRefPtr<ProcFSGlobalInode>> ProcFSGlobalInode::try_create(ProcFS const& fs, ProcFSExposedComponent const& component)
+{
+    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSGlobalInode(fs, component));
+}
+
+ProcFSGlobalInode::ProcFSGlobalInode(ProcFS const& fs, ProcFSExposedComponent const& component)
+    : ProcFSInode(fs, component.component_index())
+    , m_associated_component(component)
+{
+}
+
+void ProcFSGlobalInode::did_seek(OpenFileDescription& description, off_t new_offset)
+{
+    if (new_offset != 0)
+        return;
+    auto result = m_associated_component->refresh_data(description);
+    if (result.is_error()) {
+        // Subsequent calls to read will return EIO!
+        dbgln("ProcFS: Could not refresh contents: {}", result.error());
+    }
+}
+
+ErrorOr<void> ProcFSGlobalInode::attach(OpenFileDescription& description)
+{
+    return m_associated_component->refresh_data(description);
+}
+
+ErrorOr<size_t> ProcFSGlobalInode::read_bytes_locked(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription* fd) const
+{
+    return m_associated_component->read_bytes(offset, count, buffer, fd);
+}
+
+StringView ProcFSGlobalInode::name() const
+{
+    return m_associated_component->name();
+}
+
+ErrorOr<void> ProcFSGlobalInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const
+{
+    VERIFY_NOT_REACHED();
+}
+
+ErrorOr<NonnullLockRefPtr<Inode>> ProcFSGlobalInode::lookup(StringView)
+{
+    VERIFY_NOT_REACHED();
+}
+
+ErrorOr<void> ProcFSGlobalInode::truncate(u64 size)
+{
+    return m_associated_component->truncate(size);
+}
+
+ErrorOr<void> ProcFSGlobalInode::update_timestamps(Optional<time_t>, Optional<time_t>, Optional<time_t>)
+{
+    return {};
+}
+
+InodeMetadata ProcFSGlobalInode::metadata() const
+{
+    MutexLocker locker(m_inode_lock);
+    InodeMetadata metadata;
+    metadata.inode = { fsid(), m_associated_component->component_index() };
+    metadata.mode = S_IFREG | m_associated_component->required_mode();
+    metadata.uid = m_associated_component->owner_user();
+    metadata.gid = m_associated_component->owner_group();
+    metadata.size = 0;
+    metadata.mtime = m_associated_component->modified_time();
+    return metadata;
+}
+
+ErrorOr<size_t> ProcFSGlobalInode::write_bytes_locked(off_t offset, size_t count, UserOrKernelBuffer const& buffer, OpenFileDescription* fd)
+{
+    return m_associated_component->write_bytes(offset, count, buffer, fd);
+}
+
+}

+ 40 - 0
Kernel/FileSystem/ProcFS/GlobalInode.h

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/ProcFS/FileSystem.h>
+#include <Kernel/FileSystem/ProcFS/Inode.h>
+#include <Kernel/ProcessExposed.h>
+
+namespace Kernel {
+
+class ProcFSGlobalInode : public ProcFSInode {
+    friend class ProcFS;
+
+public:
+    static ErrorOr<NonnullLockRefPtr<ProcFSGlobalInode>> try_create(ProcFS const&, ProcFSExposedComponent const&);
+    virtual ~ProcFSGlobalInode() override {};
+    StringView name() const;
+
+protected:
+    ProcFSGlobalInode(ProcFS const&, ProcFSExposedComponent const&);
+
+    // ^Inode
+    virtual ErrorOr<void> attach(OpenFileDescription& description) override final;
+    virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
+    virtual ErrorOr<size_t> write_bytes_locked(off_t, size_t, UserOrKernelBuffer const& buffer, OpenFileDescription*) override final;
+    virtual void did_seek(OpenFileDescription&, off_t) override final;
+    virtual InodeMetadata metadata() const override;
+    virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
+    virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView) override;
+    virtual ErrorOr<void> truncate(u64) override final;
+    virtual ErrorOr<void> update_timestamps(Optional<time_t> atime, Optional<time_t> ctime, Optional<time_t> mtime) override;
+
+    NonnullLockRefPtr<ProcFSExposedComponent> m_associated_component;
+};
+
+}

+ 50 - 0
Kernel/FileSystem/ProcFS/Inode.cpp

@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/Inode.h>
+
+namespace Kernel {
+
+ProcFSInode::ProcFSInode(ProcFS const& fs, InodeIndex index)
+    : Inode(const_cast<ProcFS&>(fs), index)
+{
+}
+
+ProcFSInode::~ProcFSInode() = default;
+
+ErrorOr<void> ProcFSInode::flush_metadata()
+{
+    return {};
+}
+
+ErrorOr<void> ProcFSInode::add_child(Inode&, StringView, mode_t)
+{
+    return EROFS;
+}
+
+ErrorOr<NonnullLockRefPtr<Inode>> ProcFSInode::create_child(StringView, mode_t, dev_t, UserID, GroupID)
+{
+    return EROFS;
+}
+
+ErrorOr<void> ProcFSInode::remove_child(StringView)
+{
+    return EROFS;
+}
+
+ErrorOr<void> ProcFSInode::chmod(mode_t)
+{
+    return EPERM;
+}
+
+ErrorOr<void> ProcFSInode::chown(UserID, GroupID)
+{
+    return EPERM;
+}
+
+}

+ 40 - 0
Kernel/FileSystem/ProcFS/Inode.h

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/Inode.h>
+#include <Kernel/FileSystem/OpenFileDescription.h>
+#include <Kernel/FileSystem/ProcFS/FileSystem.h>
+#include <Kernel/ProcessExposed.h>
+#include <Kernel/UnixTypes.h>
+
+namespace Kernel {
+
+class ProcFSInode : public Inode {
+    friend class ProcFS;
+
+public:
+    virtual ~ProcFSInode() override;
+
+protected:
+    ProcFSInode(ProcFS const&, InodeIndex);
+
+    ProcFS& procfs() { return static_cast<ProcFS&>(Inode::fs()); }
+    ProcFS const& procfs() const { return static_cast<ProcFS const&>(Inode::fs()); }
+
+    // ^Inode
+    virtual ErrorOr<void> attach(OpenFileDescription& description) override = 0;
+    virtual void did_seek(OpenFileDescription&, off_t) override = 0;
+    virtual ErrorOr<void> flush_metadata() override final;
+    virtual ErrorOr<NonnullLockRefPtr<Inode>> create_child(StringView name, mode_t, dev_t, UserID, GroupID) override final;
+    virtual ErrorOr<void> add_child(Inode&, StringView name, mode_t) override final;
+    virtual ErrorOr<void> remove_child(StringView name) override final;
+    virtual ErrorOr<void> chmod(mode_t) override final;
+    virtual ErrorOr<void> chown(UserID, GroupID) override final;
+};
+
+}

+ 36 - 0
Kernel/FileSystem/ProcFS/LinkInode.cpp

@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/LinkInode.h>
+
+namespace Kernel {
+
+ErrorOr<NonnullLockRefPtr<ProcFSLinkInode>> ProcFSLinkInode::try_create(ProcFS const& procfs, ProcFSExposedComponent const& component)
+{
+    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSLinkInode(procfs, component));
+}
+
+ProcFSLinkInode::ProcFSLinkInode(ProcFS const& fs, ProcFSExposedComponent const& component)
+    : ProcFSGlobalInode(fs, component)
+{
+}
+
+InodeMetadata ProcFSLinkInode::metadata() const
+{
+    MutexLocker locker(m_inode_lock);
+    InodeMetadata metadata;
+    metadata.inode = { fsid(), m_associated_component->component_index() };
+    metadata.mode = S_IFLNK | m_associated_component->required_mode();
+    metadata.uid = m_associated_component->owner_user();
+    metadata.gid = m_associated_component->owner_group();
+    metadata.size = 0;
+    metadata.mtime = m_associated_component->modified_time();
+    return metadata;
+}
+
+}

+ 24 - 0
Kernel/FileSystem/ProcFS/LinkInode.h

@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/ProcFS/GlobalInode.h>
+
+namespace Kernel {
+
+class ProcFSLinkInode : public ProcFSGlobalInode {
+    friend class ProcFS;
+
+public:
+    static ErrorOr<NonnullLockRefPtr<ProcFSLinkInode>> try_create(ProcFS const&, ProcFSExposedComponent const&);
+
+protected:
+    ProcFSLinkInode(ProcFS const&, ProcFSExposedComponent const&);
+    virtual InodeMetadata metadata() const override;
+};
+
+}

+ 24 - 0
Kernel/FileSystem/ProcFS/ProcessAssociatedInode.cpp

@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/ProcessAssociatedInode.h>
+
+namespace Kernel {
+
+ProcFSProcessAssociatedInode::ProcFSProcessAssociatedInode(ProcFS const& fs, ProcessID associated_pid, InodeIndex determined_index)
+    : ProcFSInode(fs, determined_index)
+    , m_pid(associated_pid)
+{
+}
+
+ErrorOr<size_t> ProcFSProcessAssociatedInode::write_bytes_locked(off_t, size_t, UserOrKernelBuffer const&, OpenFileDescription*)
+{
+    return ENOTSUP;
+}
+
+}

+ 28 - 0
Kernel/FileSystem/ProcFS/ProcessAssociatedInode.h

@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/ProcFS/Inode.h>
+#include <Kernel/Forward.h>
+
+namespace Kernel {
+
+class ProcFSProcessAssociatedInode : public ProcFSInode {
+    friend class ProcFS;
+
+protected:
+    ProcFSProcessAssociatedInode(ProcFS const&, ProcessID, InodeIndex);
+    ProcessID associated_pid() const { return m_pid; }
+
+    // ^Inode
+    virtual ErrorOr<size_t> write_bytes_locked(off_t, size_t, UserOrKernelBuffer const& buffer, OpenFileDescription*) override final;
+
+private:
+    const ProcessID m_pid;
+};
+
+}

+ 95 - 0
Kernel/FileSystem/ProcFS/ProcessDirectoryInode.cpp

@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/ProcessDirectoryInode.h>
+#include <Kernel/FileSystem/ProcFS/ProcessPropertyInode.h>
+#include <Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.h>
+#include <Kernel/Process.h>
+#include <Kernel/ProcessExposed.h>
+
+namespace Kernel {
+
+ErrorOr<NonnullLockRefPtr<ProcFSProcessDirectoryInode>> ProcFSProcessDirectoryInode::try_create(ProcFS const& procfs, ProcessID pid)
+{
+    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessDirectoryInode(procfs, pid));
+}
+
+ProcFSProcessDirectoryInode::ProcFSProcessDirectoryInode(ProcFS const& procfs, ProcessID pid)
+    : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_pid_directory(pid))
+{
+}
+
+ErrorOr<void> ProcFSProcessDirectoryInode::attach(OpenFileDescription&)
+{
+    return {};
+}
+
+InodeMetadata ProcFSProcessDirectoryInode::metadata() const
+{
+    MutexLocker locker(m_inode_lock);
+    auto process = Process::from_pid_in_same_jail(associated_pid());
+    if (!process)
+        return {};
+
+    auto traits = process->procfs_traits();
+    InodeMetadata metadata;
+    metadata.inode = { fsid(), traits->component_index() };
+    metadata.mode = S_IFDIR | traits->required_mode();
+    metadata.uid = traits->owner_user();
+    metadata.gid = traits->owner_group();
+    metadata.size = 0;
+    metadata.mtime = traits->modified_time();
+    return metadata;
+}
+
+ErrorOr<size_t> ProcFSProcessDirectoryInode::read_bytes_locked(off_t, size_t, UserOrKernelBuffer&, OpenFileDescription*) const
+{
+    VERIFY_NOT_REACHED();
+}
+
+ErrorOr<void> ProcFSProcessDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
+{
+    MutexLocker locker(procfs().m_lock);
+    auto process = Process::from_pid_in_same_jail(associated_pid());
+    if (!process)
+        return EINVAL;
+    return process->procfs_traits()->traverse_as_directory(procfs().fsid(), move(callback));
+}
+
+ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessDirectoryInode::lookup(StringView name)
+{
+    MutexLocker locker(procfs().m_lock);
+    auto process = Process::from_pid_in_same_jail(associated_pid());
+    if (!process)
+        return ESRCH;
+    if (name == "fd"sv)
+        return TRY(ProcFSProcessSubDirectoryInode::try_create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions, associated_pid()));
+    if (name == "stacks"sv)
+        return TRY(ProcFSProcessSubDirectoryInode::try_create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks, associated_pid()));
+    if (name == "children"sv)
+        return TRY(ProcFSProcessSubDirectoryInode::try_create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::Children, associated_pid()));
+    if (name == "unveil"sv)
+        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::Unveil, associated_pid()));
+    if (name == "pledge"sv)
+        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::Pledge, associated_pid()));
+    if (name == "fds"sv)
+        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::OpenFileDescriptions, associated_pid()));
+    if (name == "exe"sv)
+        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::BinaryLink, associated_pid()));
+    if (name == "cwd"sv)
+        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink, associated_pid()));
+    if (name == "perf_events"sv)
+        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents, associated_pid()));
+    if (name == "vm"sv)
+        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats, associated_pid()));
+    if (name == "cmdline"sv)
+        return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::CommandLine, associated_pid()));
+    return ENOENT;
+}
+
+}

+ 31 - 0
Kernel/FileSystem/ProcFS/ProcessDirectoryInode.h

@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/ProcFS/ProcessAssociatedInode.h>
+#include <Kernel/Forward.h>
+
+namespace Kernel {
+
+class ProcFSProcessDirectoryInode final : public ProcFSProcessAssociatedInode {
+    friend class ProcFS;
+
+public:
+    static ErrorOr<NonnullLockRefPtr<ProcFSProcessDirectoryInode>> try_create(ProcFS const&, ProcessID);
+
+private:
+    ProcFSProcessDirectoryInode(ProcFS const&, ProcessID);
+    // ^Inode
+    virtual ErrorOr<void> attach(OpenFileDescription& description) override;
+    virtual void did_seek(OpenFileDescription&, off_t) override { }
+    virtual InodeMetadata metadata() const override;
+    virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
+    virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
+    virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override;
+};
+
+}

+ 236 - 0
Kernel/FileSystem/ProcFS/ProcessPropertyInode.cpp

@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/API/POSIX/errno.h>
+#include <Kernel/Debug.h>
+#include <Kernel/FileSystem/OpenFileDescription.h>
+#include <Kernel/FileSystem/ProcFS/ProcessPropertyInode.h>
+#include <Kernel/Process.h>
+#include <Kernel/ProcessExposed.h>
+
+namespace Kernel {
+
+ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_file_description_link(ProcFS const& procfs, unsigned file_description_index, ProcessID pid)
+{
+    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, file_description_index, pid));
+}
+
+ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_thread_stack(ProcFS const& procfs, ThreadID stack_thread_index, ProcessID pid)
+{
+    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, stack_thread_index, pid));
+}
+
+ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_pid_property(ProcFS const& procfs, SegmentedProcFSIndex::MainProcessProperty main_property_type, ProcessID pid)
+{
+    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, main_property_type, pid));
+}
+
+ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_child_process_link(ProcFS const& procfs, ProcessID child_pid, ProcessID pid)
+{
+    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, child_pid, pid));
+}
+
+ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, SegmentedProcFSIndex::MainProcessProperty main_property_type, ProcessID pid)
+    : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid, main_property_type))
+    , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Reserved)
+{
+    m_possible_data.property_type = main_property_type;
+}
+
+ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, unsigned file_description_index, ProcessID pid)
+    : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_file_description(pid, file_description_index))
+    , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions)
+{
+    m_possible_data.property_index = file_description_index;
+}
+
+ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, ThreadID thread_stack_index, ProcessID pid)
+    : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_thread_stack(pid, thread_stack_index))
+    , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Stacks)
+{
+    m_possible_data.property_index = thread_stack_index.value();
+}
+
+ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, ProcessID child_pid, ProcessID pid)
+    : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_children(pid, child_pid))
+    , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Children)
+{
+    m_possible_data.property_index = child_pid.value();
+}
+
+ErrorOr<void> ProcFSProcessPropertyInode::attach(OpenFileDescription& description)
+{
+    return refresh_data(description);
+}
+
+void ProcFSProcessPropertyInode::did_seek(OpenFileDescription& description, off_t offset)
+{
+    if (offset != 0)
+        return;
+    (void)refresh_data(description);
+}
+
+static mode_t determine_procfs_process_inode_mode(SegmentedProcFSIndex::ProcessSubDirectory parent_sub_directory_type, SegmentedProcFSIndex::MainProcessProperty main_property)
+{
+    if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions)
+        return S_IFLNK | 0400;
+    if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Stacks)
+        return S_IFREG | 0400;
+    if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Children)
+        return S_IFLNK | 0400;
+    VERIFY(parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Reserved);
+    if (main_property == SegmentedProcFSIndex::MainProcessProperty::BinaryLink)
+        return S_IFLNK | 0777;
+    if (main_property == SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink)
+        return S_IFLNK | 0777;
+    return S_IFREG | 0400;
+}
+
+InodeMetadata ProcFSProcessPropertyInode::metadata() const
+{
+    MutexLocker locker(m_inode_lock);
+    auto process = Process::from_pid_in_same_jail(associated_pid());
+    if (!process)
+        return {};
+
+    auto traits = process->procfs_traits();
+    InodeMetadata metadata;
+    metadata.inode = { fsid(), traits->component_index() };
+    metadata.mode = determine_procfs_process_inode_mode(m_parent_sub_directory_type, m_possible_data.property_type);
+    metadata.uid = traits->owner_user();
+    metadata.gid = traits->owner_group();
+    metadata.size = 0;
+    metadata.mtime = traits->modified_time();
+    return metadata;
+}
+
+ErrorOr<void> ProcFSProcessPropertyInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const
+{
+    VERIFY_NOT_REACHED();
+}
+
+ErrorOr<size_t> ProcFSProcessPropertyInode::read_bytes_locked(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription* description) const
+{
+    dbgln_if(PROCFS_DEBUG, "ProcFS ProcessInformation: read_bytes_locked offset: {} count: {}", offset, count);
+
+    VERIFY(offset >= 0);
+    VERIFY(buffer.user_or_kernel_ptr());
+
+    if (!description) {
+        auto builder = TRY(KBufferBuilder::try_create());
+        auto process = Process::from_pid_in_same_jail(associated_pid());
+        if (!process)
+            return Error::from_errno(ESRCH);
+        TRY(try_to_acquire_data(*process, builder));
+        auto data_buffer = builder.build();
+        if (!data_buffer)
+            return Error::from_errno(EFAULT);
+        ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
+        TRY(buffer.write(data_buffer->data() + offset, nread));
+        return nread;
+    }
+    if (!description->data()) {
+        dbgln("ProcFS Process Information: Do not have cached data!");
+        return Error::from_errno(EIO);
+    }
+
+    MutexLocker locker(m_refresh_lock);
+
+    auto& typed_cached_data = static_cast<ProcFSInodeData&>(*description->data());
+    auto& data_buffer = typed_cached_data.buffer;
+
+    if (!data_buffer || (size_t)offset >= data_buffer->size())
+        return 0;
+
+    ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
+    TRY(buffer.write(data_buffer->data() + offset, nread));
+
+    return nread;
+}
+
+ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessPropertyInode::lookup(StringView)
+{
+    return EINVAL;
+}
+
+static ErrorOr<void> build_from_cached_data(KBufferBuilder& builder, ProcFSInodeData& cached_data)
+{
+    cached_data.buffer = builder.build();
+    if (!cached_data.buffer)
+        return ENOMEM;
+    return {};
+}
+
+ErrorOr<void> ProcFSProcessPropertyInode::try_to_acquire_data(Process& process, KBufferBuilder& builder) const
+{
+    // FIXME: Verify process is already ref-counted
+    if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions) {
+        TRY(process.procfs_get_file_description_link(m_possible_data.property_index, builder));
+        return {};
+    }
+    if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Stacks) {
+        TRY(process.procfs_get_thread_stack(m_possible_data.property_index, builder));
+        return {};
+    }
+    if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Children) {
+        TRY(process.procfs_get_child_proccess_link(m_possible_data.property_index, builder));
+        return {};
+    }
+
+    VERIFY(m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Reserved);
+    switch (m_possible_data.property_type) {
+    case SegmentedProcFSIndex::MainProcessProperty::Unveil:
+        return process.procfs_get_unveil_stats(builder);
+    case SegmentedProcFSIndex::MainProcessProperty::Pledge:
+        return process.procfs_get_pledge_stats(builder);
+    case SegmentedProcFSIndex::MainProcessProperty::OpenFileDescriptions:
+        return process.procfs_get_fds_stats(builder);
+    case SegmentedProcFSIndex::MainProcessProperty::BinaryLink:
+        return process.procfs_get_binary_link(builder);
+    case SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink:
+        return process.procfs_get_current_work_directory_link(builder);
+    case SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents:
+        return process.procfs_get_perf_events(builder);
+    case SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats:
+        return process.procfs_get_virtual_memory_stats(builder);
+    case SegmentedProcFSIndex::MainProcessProperty::CommandLine:
+        return process.procfs_get_command_line(builder);
+    default:
+        VERIFY_NOT_REACHED();
+    }
+}
+
+ErrorOr<void> ProcFSProcessPropertyInode::refresh_data(OpenFileDescription& description)
+{
+    // For process-specific inodes, hold the process's ptrace lock across refresh
+    // and refuse to load data if the process is not dumpable.
+    // Without this, files opened before a process went non-dumpable could still be used for dumping.
+    auto process = Process::from_pid_in_same_jail(associated_pid());
+    if (!process)
+        return Error::from_errno(ESRCH);
+    process->ptrace_lock().lock();
+    if (!process->is_dumpable()) {
+        process->ptrace_lock().unlock();
+        return EPERM;
+    }
+    ScopeGuard guard = [&] {
+        process->ptrace_lock().unlock();
+    };
+    MutexLocker locker(m_refresh_lock);
+    auto& cached_data = description.data();
+    if (!cached_data) {
+        cached_data = adopt_own_if_nonnull(new (nothrow) ProcFSInodeData);
+        if (!cached_data)
+            return ENOMEM;
+    }
+    auto builder = TRY(KBufferBuilder::try_create());
+    TRY(try_to_acquire_data(*process, builder));
+    return build_from_cached_data(builder, static_cast<ProcFSInodeData&>(*cached_data));
+}
+
+}

+ 51 - 0
Kernel/FileSystem/ProcFS/ProcessPropertyInode.h

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/ProcFS/ProcessAssociatedInode.h>
+#include <Kernel/Forward.h>
+#include <Kernel/KBufferBuilder.h>
+#include <Kernel/Locking/Mutex.h>
+#include <Kernel/ProcessExposed.h>
+#include <Kernel/UnixTypes.h>
+
+namespace Kernel {
+
+class ProcFSProcessPropertyInode final : public ProcFSProcessAssociatedInode {
+    friend class ProcFS;
+
+public:
+    static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_file_description_link(ProcFS const&, unsigned, ProcessID);
+    static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_thread_stack(ProcFS const&, ThreadID, ProcessID);
+    static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_pid_property(ProcFS const&, SegmentedProcFSIndex::MainProcessProperty, ProcessID);
+    static ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> try_create_for_child_process_link(ProcFS const&, ProcessID, ProcessID);
+
+private:
+    ProcFSProcessPropertyInode(ProcFS const&, SegmentedProcFSIndex::MainProcessProperty, ProcessID);
+    ProcFSProcessPropertyInode(ProcFS const&, ThreadID, ProcessID);
+    ProcFSProcessPropertyInode(ProcFS const&, unsigned, ProcessID);
+    ProcFSProcessPropertyInode(ProcFS const&, ProcessID, ProcessID);
+
+    // ^Inode
+    virtual ErrorOr<void> attach(OpenFileDescription& description) override;
+    virtual void did_seek(OpenFileDescription&, off_t) override;
+    virtual InodeMetadata metadata() const override;
+    virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
+    virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
+    virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override final;
+
+    ErrorOr<void> refresh_data(OpenFileDescription& description);
+    ErrorOr<void> try_to_acquire_data(Process& process, KBufferBuilder& builder) const;
+
+    const SegmentedProcFSIndex::ProcessSubDirectory m_parent_sub_directory_type;
+    union {
+        SegmentedProcFSIndex::MainProcessProperty property_type;
+        unsigned property_index;
+    } m_possible_data;
+    mutable Mutex m_refresh_lock;
+};
+}

+ 96 - 0
Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.cpp

@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.h>
+#include <Kernel/Process.h>
+#include <Kernel/ProcessExposed.h>
+
+namespace Kernel {
+
+ErrorOr<NonnullLockRefPtr<ProcFSProcessSubDirectoryInode>> ProcFSProcessSubDirectoryInode::try_create(ProcFS const& procfs, SegmentedProcFSIndex::ProcessSubDirectory sub_directory_type, ProcessID pid)
+{
+    return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessSubDirectoryInode(procfs, sub_directory_type, pid));
+}
+
+ProcFSProcessSubDirectoryInode::ProcFSProcessSubDirectoryInode(ProcFS const& procfs, SegmentedProcFSIndex::ProcessSubDirectory sub_directory_type, ProcessID pid)
+    : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(pid, sub_directory_type))
+    , m_sub_directory_type(sub_directory_type)
+{
+}
+
+ErrorOr<size_t> ProcFSProcessSubDirectoryInode::read_bytes_locked(off_t, size_t, UserOrKernelBuffer&, OpenFileDescription*) const
+{
+    VERIFY_NOT_REACHED();
+}
+
+ErrorOr<void> ProcFSProcessSubDirectoryInode::attach(OpenFileDescription&)
+{
+    return {};
+}
+
+void ProcFSProcessSubDirectoryInode::did_seek(OpenFileDescription&, off_t)
+{
+    VERIFY_NOT_REACHED();
+}
+
+InodeMetadata ProcFSProcessSubDirectoryInode::metadata() const
+{
+    MutexLocker locker(m_inode_lock);
+    auto process = Process::from_pid_in_same_jail(associated_pid());
+    if (!process)
+        return {};
+
+    auto traits = process->procfs_traits();
+    InodeMetadata metadata;
+    metadata.inode = { fsid(), traits->component_index() };
+    metadata.mode = S_IFDIR | traits->required_mode();
+    metadata.uid = traits->owner_user();
+    metadata.gid = traits->owner_group();
+    metadata.size = 0;
+    metadata.mtime = traits->modified_time();
+    return metadata;
+}
+
+ErrorOr<void> ProcFSProcessSubDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
+{
+    MutexLocker locker(procfs().m_lock);
+    auto process = Process::from_pid_in_same_jail(associated_pid());
+    if (!process)
+        return EINVAL;
+    switch (m_sub_directory_type) {
+    case SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions:
+        return process->traverse_file_descriptions_directory(procfs().fsid(), move(callback));
+    case SegmentedProcFSIndex::ProcessSubDirectory::Stacks:
+        return process->traverse_stacks_directory(procfs().fsid(), move(callback));
+    case SegmentedProcFSIndex::ProcessSubDirectory::Children:
+        return process->traverse_children_directory(procfs().fsid(), move(callback));
+    default:
+        VERIFY_NOT_REACHED();
+    }
+    VERIFY_NOT_REACHED();
+}
+
+ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessSubDirectoryInode::lookup(StringView name)
+{
+    MutexLocker locker(procfs().m_lock);
+    auto process = Process::from_pid_in_same_jail(associated_pid());
+    if (!process)
+        return ESRCH;
+    switch (m_sub_directory_type) {
+    case SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions:
+        return process->lookup_file_descriptions_directory(procfs(), name);
+    case SegmentedProcFSIndex::ProcessSubDirectory::Stacks:
+        return process->lookup_stacks_directory(procfs(), name);
+    case SegmentedProcFSIndex::ProcessSubDirectory::Children:
+        return process->lookup_children_directory(procfs(), name);
+    default:
+        VERIFY_NOT_REACHED();
+    }
+}
+
+}

+ 34 - 0
Kernel/FileSystem/ProcFS/ProcessSubDirectoryInode.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/FileSystem/ProcFS/ProcessAssociatedInode.h>
+#include <Kernel/Forward.h>
+#include <Kernel/ProcessExposed.h>
+
+namespace Kernel {
+
+class ProcFSProcessSubDirectoryInode final : public ProcFSProcessAssociatedInode {
+    friend class ProcFS;
+
+public:
+    static ErrorOr<NonnullLockRefPtr<ProcFSProcessSubDirectoryInode>> try_create(ProcFS const&, SegmentedProcFSIndex::ProcessSubDirectory, ProcessID);
+
+private:
+    ProcFSProcessSubDirectoryInode(ProcFS const&, SegmentedProcFSIndex::ProcessSubDirectory, ProcessID);
+    // ^Inode
+    virtual ErrorOr<void> attach(OpenFileDescription& description) override;
+    virtual void did_seek(OpenFileDescription&, off_t) override;
+    virtual InodeMetadata metadata() const override;
+    virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
+    virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override final;
+    virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override;
+
+    const SegmentedProcFSIndex::ProcessSubDirectory m_sub_directory_type;
+};
+
+}

+ 2 - 3
Kernel/ProcessExposed.cpp

@@ -5,9 +5,8 @@
  */
 
 #include <Kernel/Debug.h>
-#include <Kernel/Devices/BlockDevice.h>
-#include <Kernel/FileSystem/ProcFS.h>
-#include <Kernel/FileSystem/VirtualFileSystem.h>
+#include <Kernel/FileSystem/ProcFS/DirectoryInode.h>
+#include <Kernel/FileSystem/ProcFS/LinkInode.h>
 #include <Kernel/KBufferBuilder.h>
 #include <Kernel/PerformanceEventBuffer.h>
 #include <Kernel/Process.h>

+ 2 - 1
Kernel/ProcessProcFSTraits.cpp

@@ -4,8 +4,9 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
-#include <Kernel/FileSystem/ProcFS.h>
+#include <Kernel/FileSystem/ProcFS/ProcessDirectoryInode.h>
 #include <Kernel/Process.h>
+#include <Kernel/ProcessExposed.h>
 
 namespace Kernel {
 

+ 1 - 1
Kernel/ProcessSpecificExposed.cpp

@@ -8,7 +8,7 @@
 #include <AK/JsonObjectSerializer.h>
 #include <AK/JsonValue.h>
 #include <Kernel/FileSystem/Custody.h>
-#include <Kernel/FileSystem/ProcFS.h>
+#include <Kernel/FileSystem/ProcFS/ProcessPropertyInode.h>
 #include <Kernel/InterruptDisabler.h>
 #include <Kernel/KBufferBuilder.h>
 #include <Kernel/Memory/AnonymousVMObject.h>

+ 0 - 1
Kernel/Storage/ATA/GenericIDE/Controller.cpp

@@ -7,7 +7,6 @@
 #include <AK/OwnPtr.h>
 #include <AK/Types.h>
 #include <Kernel/Bus/PCI/API.h>
-#include <Kernel/FileSystem/ProcFS.h>
 #include <Kernel/Library/LockRefPtr.h>
 #include <Kernel/Sections.h>
 #include <Kernel/Storage/ATA/ATADiskDevice.h>

+ 0 - 1
Kernel/Storage/NVMe/NVMeController.cpp

@@ -12,7 +12,6 @@
 #include <Kernel/Bus/PCI/API.h>
 #include <Kernel/CommandLine.h>
 #include <Kernel/Devices/Device.h>
-#include <Kernel/FileSystem/ProcFS.h>
 #include <Kernel/Library/LockRefPtr.h>
 #include <Kernel/Sections.h>
 #include <Kernel/Storage/NVMe/NVMeController.h>

+ 1 - 1
Kernel/Syscalls/mount.cpp

@@ -10,7 +10,7 @@
 #include <Kernel/FileSystem/FATFS/FileSystem.h>
 #include <Kernel/FileSystem/ISO9660FileSystem.h>
 #include <Kernel/FileSystem/Plan9FileSystem.h>
-#include <Kernel/FileSystem/ProcFS.h>
+#include <Kernel/FileSystem/ProcFS/FileSystem.h>
 #include <Kernel/FileSystem/SysFS/FileSystem.h>
 #include <Kernel/FileSystem/TmpFS/FileSystem.h>
 #include <Kernel/FileSystem/VirtualFileSystem.h>