Kernel/FileSystem: Simplify the ProcFS significantly

Since the ProcFS doesn't hold many global objects within it, the need
for a fully-structured design of backing components and a registry like
with the SysFS is no longer true.

To acommodate this, let's remove all backing store and components of the
ProcFS, so now it resembles what we had in the early days of ProcFS in
the project - a mostly-static filesystem, with very small amount of
kmalloc allocations needed.
We still use the inode index mechanism to understand the role of each
inode, but this is done in a much "static"ier way than before.
This commit is contained in:
Liav A 2023-02-20 17:51:18 +02:00 committed by Linus Groh
parent 9216caeec2
commit c56e1c5378
Notes: sideshowbarker 2024-07-17 02:35:27 +09:00
18 changed files with 362 additions and 952 deletions

View File

@ -175,7 +175,6 @@ extern "C" [[noreturn]] void init()
Processor::disable_interrupts();
TimeManagement::initialize(0);
ProcFSComponentRegistry::initialize();
JailManagement::the();
Process::initialize();

View File

@ -47,7 +47,6 @@
#include <Kernel/Panic.h>
#include <Kernel/Prekernel/Prekernel.h>
#include <Kernel/Process.h>
#include <Kernel/ProcessExposed.h>
#include <Kernel/Random.h>
#include <Kernel/Scheduler.h>
#include <Kernel/Sections.h>
@ -232,7 +231,6 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT void init(BootInfo const& boot_info)
__stack_chk_guard = get_fast_random<uintptr_t>();
ProcFSComponentRegistry::initialize();
JailManagement::the();
Process::initialize();

View File

@ -18,7 +18,6 @@
#include <Kernel/Memory/MemoryManager.h>
#include <Kernel/Memory/Region.h>
#include <Kernel/Memory/TypedMapping.h>
#include <Kernel/ProcessExposed.h>
#include <Kernel/Sections.h>
namespace Kernel::PCI {

View File

@ -141,9 +141,9 @@ set(KERNEL_SOURCES
FileSystem/Plan9FS/FileSystem.cpp
FileSystem/Plan9FS/Inode.cpp
FileSystem/Plan9FS/Message.cpp
FileSystem/ProcFS/ComponentRegistry.cpp
FileSystem/ProcFS/FileSystem.cpp
FileSystem/ProcFS/Inode.cpp
FileSystem/ProcFS/ProcessExposed.cpp
FileSystem/RAMFS/FileSystem.cpp
FileSystem/RAMFS/Inode.cpp
FileSystem/SysFS/Component.cpp
@ -255,10 +255,7 @@ set(KERNEL_SOURCES
Net/UDPSocket.cpp
PerformanceEventBuffer.cpp
Process.cpp
ProcessExposed.cpp
ProcessSpecificExposed.cpp
ProcessGroup.cpp
ProcessProcFSTraits.cpp
Random.cpp
Scheduler.cpp
ScopedCritical.cpp

View File

@ -1,33 +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/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())
{
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2023, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/StringView.h>
#include <AK/Types.h>
namespace Kernel {
struct segmented_global_inode_index {
StringView name;
u8 file_type;
u32 primary;
u16 subdirectory;
u32 property;
};
constexpr segmented_global_inode_index global_inode_ids[] = {
{ "."sv, DT_DIR, 0, 0, 1 }, // NOTE: This is here for the root directory
{ "self"sv, DT_DIR, 0, 0, 2 }
};
struct segmented_process_directory_entry {
StringView name;
u8 file_type;
u16 subdirectory;
u32 property;
};
constexpr segmented_process_directory_entry main_process_directory_root_entry = { "."sv, DT_DIR, 0, 0 };
constexpr segmented_process_directory_entry process_fd_subdirectory_root_entry = { "."sv, DT_DIR, 1, 0 };
constexpr segmented_process_directory_entry process_stacks_subdirectory_root_entry = { "."sv, DT_DIR, 2, 0 };
constexpr segmented_process_directory_entry process_children_subdirectory_root_entry = { "."sv, DT_DIR, 3, 0 };
constexpr segmented_process_directory_entry process_fd_directory_entry = { "fd"sv, DT_DIR, 1, 0 };
constexpr segmented_process_directory_entry process_stacks_directory_entry = { "stacks"sv, DT_DIR, 2, 0 };
constexpr segmented_process_directory_entry process_children_directory_entry = { "children"sv, DT_DIR, 3, 0 };
constexpr segmented_process_directory_entry process_unveil_list_entry = { "unveil"sv, DT_REG, 0, 1 };
constexpr segmented_process_directory_entry process_pledge_list_entry = { "pledge"sv, DT_REG, 0, 2 };
constexpr segmented_process_directory_entry process_fds_list_entry = { "fds"sv, DT_REG, 0, 3 };
constexpr segmented_process_directory_entry process_exe_symlink_entry = { "exe"sv, DT_LNK, 0, 4 };
constexpr segmented_process_directory_entry process_cwd_symlink_entry = { "cwd"sv, DT_LNK, 0, 5 };
constexpr segmented_process_directory_entry process_perf_events_entry = { "perf_events"sv, DT_REG, 0, 6 };
constexpr segmented_process_directory_entry process_vm_entry = { "vm"sv, DT_REG, 0, 7 };
constexpr segmented_process_directory_entry process_cmdline_entry = { "cmdline"sv, DT_REG, 0, 8 };
constexpr segmented_process_directory_entry main_process_directory_entries[] = {
process_fd_directory_entry,
process_stacks_directory_entry,
process_children_directory_entry,
process_unveil_list_entry,
process_pledge_list_entry,
process_fds_list_entry,
process_exe_symlink_entry,
process_cwd_symlink_entry,
process_perf_events_entry,
process_vm_entry,
process_cmdline_entry,
};
}

View File

@ -8,7 +8,6 @@
#include <Kernel/FileSystem/ProcFS/FileSystem.h>
#include <Kernel/FileSystem/ProcFS/Inode.h>
#include <Kernel/ProcessExposed.h>
namespace Kernel {
@ -20,9 +19,16 @@ ErrorOr<NonnullLockRefPtr<FileSystem>> ProcFS::try_create()
ProcFS::ProcFS() = default;
ProcFS::~ProcFS() = default;
ErrorOr<NonnullLockRefPtr<Inode>> ProcFS::get_inode(InodeIdentifier inode_id) const
{
if (inode_id.index() == 1)
return *m_root_inode;
return TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSInode(const_cast<ProcFS&>(*this), inode_id.index())));
}
ErrorOr<void> ProcFS::initialize()
{
m_root_inode = TRY(ProcFSComponentRegistry::the().root_directory().to_inode(*this));
m_root_inode = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSInode(const_cast<ProcFS&>(*this), 1)));
return {};
}

View File

@ -16,6 +16,7 @@ namespace Kernel {
class ProcFSInode;
class ProcFS final : public FileSystem {
friend class ProcFSInode;
friend class Process;
public:
virtual ~ProcFS() override;
@ -29,6 +30,8 @@ public:
private:
ProcFS();
ErrorOr<NonnullLockRefPtr<Inode>> get_inode(InodeIdentifier) const;
LockRefPtr<ProcFSInode> m_root_inode;
};

View File

@ -1,189 +1,125 @@
/*
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
* Copyright (c) 2021-2022, Liav A. <liavalb@hotmail.co.il>
* Copyright (c) 2021-2023, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/FileSystem/ProcFS/Inode.h>
#include <Kernel/Process.h>
#include <Kernel/ProcessExposed.h>
#include <Kernel/Time/TimeManagement.h>
namespace Kernel {
ProcFSInode::~ProcFSInode() = default;
ErrorOr<void> ProcFSInode::flush_metadata()
static mode_t determine_procfs_process_inode_mode(u32 subdirectory, u32 property)
{
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<void> ProcFSInode::replace_child(StringView, Inode&)
{
return EROFS;
}
ErrorOr<size_t> ProcFSInode::write_bytes_locked(off_t, size_t, UserOrKernelBuffer const&, OpenFileDescription*)
{
return EROFS;
}
ErrorOr<void> ProcFSInode::truncate(u64)
{
return EROFS;
}
ErrorOr<void> ProcFSInode::update_timestamps(Optional<Time>, Optional<Time>, Optional<Time>)
{
// Note: Silently ignore the update request.
return {};
}
static mode_t determine_procfs_process_inode_mode(SegmentedProcFSIndex::ProcessSubDirectory parent_subdirectory_type, Optional<SegmentedProcFSIndex::MainProcessProperty> main_property)
{
if (parent_subdirectory_type == SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions)
if (subdirectory == process_fd_subdirectory_root_entry.subdirectory)
return S_IFLNK | 0400;
if (parent_subdirectory_type == SegmentedProcFSIndex::ProcessSubDirectory::Stacks)
if (subdirectory == process_stacks_subdirectory_root_entry.subdirectory)
return S_IFREG | 0400;
if (parent_subdirectory_type == SegmentedProcFSIndex::ProcessSubDirectory::Children)
if (subdirectory == process_children_subdirectory_root_entry.subdirectory)
return S_IFLNK | 0400;
VERIFY(parent_subdirectory_type == SegmentedProcFSIndex::ProcessSubDirectory::Reserved);
if (main_property == SegmentedProcFSIndex::MainProcessProperty::BinaryLink)
VERIFY(subdirectory == main_process_directory_root_entry.subdirectory);
if (property == process_exe_symlink_entry.property)
return S_IFLNK | 0777;
if (main_property == SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink)
if (property == process_cwd_symlink_entry.property)
return S_IFLNK | 0777;
return S_IFREG | 0400;
}
ErrorOr<NonnullLockRefPtr<ProcFSInode>> ProcFSInode::try_create_as_file_description_link_inode(ProcFS const& procfs_instance, unsigned fd_number, ProcessID pid)
static u16 extract_subdirectory_index_from_inode_index(InodeIndex inode_index)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSInode(procfs_instance, fd_number, pid));
return (inode_index.value() >> 20) & 0xFFFF;
}
ProcFSInode::ProcFSInode(ProcFS const& procfs_instance, unsigned file_description_index, ProcessID pid)
: Inode(const_cast<ProcFS&>(procfs_instance), SegmentedProcFSIndex::build_segmented_index_for_file_description(pid, file_description_index))
, m_type(Type::FileDescriptionLink)
, m_parent_subdirectory_type(SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions)
, m_associated_pid(pid)
static u32 extract_property_index_from_inode_index(InodeIndex inode_index)
{
m_possible_data.property_index = file_description_index;
return inode_index.value() & 0xFFFFF;
}
ErrorOr<NonnullLockRefPtr<ProcFSInode>> ProcFSInode::try_create_as_thread_stack_inode(ProcFS const& procfs_instance, ThreadID stack_thread_index, ProcessID pid)
InodeIndex ProcFSInode::create_index_from_global_directory_entry(segmented_global_inode_index entry)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSInode(procfs_instance, stack_thread_index, pid));
u64 inode_index = 0;
VERIFY(entry.primary < 0x10000000);
u64 tmp = entry.primary;
inode_index |= tmp << 36;
// NOTE: The sub-directory part is already limited to 0xFFFF, so no need to VERIFY it.
tmp = entry.subdirectory;
inode_index |= tmp << 20;
VERIFY(entry.property < 0x100000);
inode_index |= entry.property;
return inode_index;
}
ProcFSInode::ProcFSInode(ProcFS const& procfs_instance, ThreadID thread_stack_index, ProcessID pid)
: Inode(const_cast<ProcFS&>(procfs_instance), SegmentedProcFSIndex::build_segmented_index_for_thread_stack(pid, thread_stack_index))
, m_type(Type::ThreadStack)
, m_parent_subdirectory_type(SegmentedProcFSIndex::ProcessSubDirectory::Stacks)
, m_associated_pid(pid)
InodeIndex ProcFSInode::create_index_from_process_directory_entry(ProcessID pid, segmented_process_directory_entry entry)
{
m_possible_data.property_index = thread_stack_index.value();
u64 inode_index = 0;
// NOTE: We use 0xFFFFFFF because PID part (bits 64-36) as 0 is reserved for global inodes.
VERIFY(pid.value() < 0xFFFFFFF);
u64 tmp = (pid.value() + 1);
inode_index |= tmp << 36;
// NOTE: The sub-directory part is already limited to 0xFFFF, so no need to VERIFY it.
tmp = entry.subdirectory;
inode_index |= tmp << 20;
VERIFY(entry.property < 0x100000);
inode_index |= entry.property;
return inode_index;
}
ErrorOr<NonnullLockRefPtr<ProcFSInode>> ProcFSInode::try_create_as_pid_property_inode(ProcFS const& procfs_instance, SegmentedProcFSIndex::MainProcessProperty process_property, ProcessID pid)
static Optional<ProcessID> extract_possible_pid_from_inode_index(InodeIndex inode_index)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSInode(procfs_instance, process_property, pid));
auto pid_part = inode_index.value() >> 36;
// NOTE: pid_part is set to 0 for global inodes.
if (pid_part == 0)
return {};
return pid_part - 1;
}
ProcFSInode::ProcFSInode(ProcFS const& procfs_instance, SegmentedProcFSIndex::MainProcessProperty main_property_type, ProcessID pid)
: Inode(const_cast<ProcFS&>(procfs_instance), SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid, main_property_type))
, m_type(Type::ProcessProperty)
, m_parent_subdirectory_type(SegmentedProcFSIndex::ProcessSubDirectory::Reserved)
, m_associated_pid(pid)
ProcFSInode::ProcFSInode(ProcFS const& procfs_instance, InodeIndex inode_index)
: Inode(const_cast<ProcFS&>(procfs_instance), inode_index)
, m_associated_pid(extract_possible_pid_from_inode_index(inode_index))
, m_subdirectory(extract_subdirectory_index_from_inode_index(inode_index))
, m_property(extract_property_index_from_inode_index(inode_index))
{
m_possible_data.property_type = main_property_type;
if (inode_index == 1) {
m_type = Type::RootDirectory;
return;
}
if (inode_index == 2) {
m_type = Type::SelfProcessLink;
return;
}
if (m_property == 0) {
if (m_subdirectory > 0)
m_type = Type::ProcessSubdirectory;
else
m_type = Type::ProcessDirectory;
return;
}
m_type = Type::ProcessProperty;
}
ErrorOr<NonnullLockRefPtr<ProcFSInode>> ProcFSInode::try_create_as_child_process_link_inode(ProcFS const& procfs_instance, ProcessID child_pid, ProcessID pid)
ErrorOr<void> ProcFSInode::traverse_as_root_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSInode(procfs_instance, child_pid, pid));
}
TRY(callback({ "."sv, { fsid(), 1 }, 0 }));
TRY(callback({ ".."sv, { fsid(), 0 }, 0 }));
TRY(callback({ "self"sv, { fsid(), 2 }, 0 }));
ProcFSInode::ProcFSInode(ProcFS const& procfs_instance, ProcessID child_pid, ProcessID pid)
: Inode(const_cast<ProcFS&>(procfs_instance), SegmentedProcFSIndex::build_segmented_index_for_children(pid, child_pid))
, m_type(Type::ChildProcessLink)
, m_parent_subdirectory_type(SegmentedProcFSIndex::ProcessSubDirectory::Children)
, m_associated_pid(pid)
{
m_possible_data.property_index = child_pid.value();
}
ErrorOr<NonnullLockRefPtr<ProcFSInode>> ProcFSInode::try_create_as_process_directory_inode(ProcFS const& procfs_instance, ProcessID pid)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSInode(procfs_instance, pid));
}
ProcFSInode::ProcFSInode(ProcFS const& procfs_instance, ProcessID pid)
: Inode(const_cast<ProcFS&>(procfs_instance), SegmentedProcFSIndex::build_segmented_index_for_pid_directory(pid))
, m_type(Type::ProcessDirectory)
, m_associated_pid(pid)
{
}
ErrorOr<NonnullLockRefPtr<ProcFSInode>> ProcFSInode::try_create_as_process_subdirectory_inode(ProcFS const& procfs_instance, SegmentedProcFSIndex::ProcessSubDirectory subdirectory_type, ProcessID pid)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSInode(procfs_instance, subdirectory_type, pid));
}
ProcFSInode::ProcFSInode(ProcFS const& procfs_instance, SegmentedProcFSIndex::ProcessSubDirectory subdirectory_type, ProcessID pid)
: Inode(const_cast<ProcFS&>(procfs_instance), SegmentedProcFSIndex::build_segmented_index_for_sub_directory(pid, subdirectory_type))
, m_type(Type::ProcessSubdirectory)
, m_subdirectory_type(subdirectory_type)
, m_associated_pid(pid)
{
}
ErrorOr<NonnullLockRefPtr<ProcFSInode>> ProcFSInode::try_create_as_global_link_inode(ProcFS const& procfs_instance, ProcFSExposedLink const& link_component)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSInode(procfs_instance, link_component));
}
ProcFSInode::ProcFSInode(ProcFS const& procfs_instance, ProcFSExposedLink const& link_component)
: Inode(const_cast<ProcFS&>(procfs_instance), link_component.component_index())
, m_type(Type::GlobalLink)
, m_associated_component(link_component)
{
}
ErrorOr<NonnullLockRefPtr<ProcFSInode>> ProcFSInode::try_create_as_directory_inode(ProcFS const& procfs_instance, ProcFSExposedDirectory const& directory_component)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSInode(procfs_instance, directory_component));
}
ProcFSInode::ProcFSInode(ProcFS const& procfs_instance, ProcFSExposedDirectory const& directory_component)
: Inode(const_cast<ProcFS&>(procfs_instance), directory_component.component_index())
, m_type(Type::GlobalDirectory)
, m_associated_component(directory_component)
{
return Process::for_each_in_same_jail([&](Process& process) -> ErrorOr<void> {
VERIFY(!(process.pid() < 0));
u64 process_id = (u64)process.pid().value();
InodeIdentifier identifier = { fsid(), static_cast<InodeIndex>(process_id << 36) };
auto process_id_string = TRY(KString::formatted("{:d}", process_id));
TRY(callback({ process_id_string->view(), identifier, 0 }));
return {};
});
}
ErrorOr<void> ProcFSInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
@ -191,16 +127,15 @@ ErrorOr<void> ProcFSInode::traverse_as_directory(Function<ErrorOr<void>(FileSyst
MutexLocker locker(procfs().m_lock);
if (m_type == Type::ProcessSubdirectory) {
VERIFY(m_associated_pid.has_value());
VERIFY(m_subdirectory_type.has_value());
auto process = Process::from_pid_in_same_jail(m_associated_pid.value());
if (!process)
return EINVAL;
switch (m_subdirectory_type.value()) {
case SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions:
switch (m_subdirectory) {
case process_fd_subdirectory_root_entry.subdirectory:
return process->traverse_file_descriptions_directory(procfs().fsid(), move(callback));
case SegmentedProcFSIndex::ProcessSubDirectory::Stacks:
case process_stacks_subdirectory_root_entry.subdirectory:
return process->traverse_stacks_directory(procfs().fsid(), move(callback));
case SegmentedProcFSIndex::ProcessSubDirectory::Children:
case process_children_subdirectory_root_entry.subdirectory:
return process->traverse_children_directory(procfs().fsid(), move(callback));
default:
VERIFY_NOT_REACHED();
@ -208,16 +143,33 @@ ErrorOr<void> ProcFSInode::traverse_as_directory(Function<ErrorOr<void>(FileSyst
VERIFY_NOT_REACHED();
}
if (m_type == Type::GlobalDirectory) {
VERIFY(m_associated_component);
return m_associated_component->traverse_as_directory(procfs().fsid(), move(callback));
if (m_type == Type::RootDirectory) {
return traverse_as_root_directory(move(callback));
}
VERIFY(m_type == Type::ProcessDirectory);
VERIFY(m_associated_pid.has_value());
auto process = Process::from_pid_in_same_jail(m_associated_pid.value());
if (!process)
return EINVAL;
return process->procfs_traits()->traverse_as_directory(procfs().fsid(), move(callback));
return process->traverse_as_directory(procfs().fsid(), move(callback));
}
ErrorOr<NonnullLockRefPtr<Inode>> ProcFSInode::lookup_as_root_directory(StringView name)
{
if (name == "self"sv)
return procfs().get_inode({ fsid(), 2 });
auto pid = name.to_uint<unsigned>();
if (!pid.has_value())
return ESRCH;
auto actual_pid = pid.value();
if (auto maybe_process = Process::from_pid_in_same_jail(actual_pid)) {
InodeIndex id = (static_cast<u64>(maybe_process->pid().value()) + 1) << 36;
return procfs().get_inode({ fsid(), id });
}
return ENOENT;
}
ErrorOr<NonnullLockRefPtr<Inode>> ProcFSInode::lookup(StringView name)
@ -225,16 +177,15 @@ ErrorOr<NonnullLockRefPtr<Inode>> ProcFSInode::lookup(StringView name)
MutexLocker locker(procfs().m_lock);
if (m_type == Type::ProcessSubdirectory) {
VERIFY(m_associated_pid.has_value());
VERIFY(m_subdirectory_type.has_value());
auto process = Process::from_pid_in_same_jail(m_associated_pid.value());
if (!process)
return ESRCH;
switch (m_subdirectory_type.value()) {
case SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions:
switch (m_subdirectory) {
case process_fd_subdirectory_root_entry.subdirectory:
return process->lookup_file_descriptions_directory(procfs(), name);
case SegmentedProcFSIndex::ProcessSubDirectory::Stacks:
case process_stacks_subdirectory_root_entry.subdirectory:
return process->lookup_stacks_directory(procfs(), name);
case SegmentedProcFSIndex::ProcessSubDirectory::Children:
case process_children_subdirectory_root_entry.subdirectory:
return process->lookup_children_directory(procfs(), name);
default:
VERIFY_NOT_REACHED();
@ -242,10 +193,8 @@ ErrorOr<NonnullLockRefPtr<Inode>> ProcFSInode::lookup(StringView name)
VERIFY_NOT_REACHED();
}
if (m_type == Type::GlobalDirectory) {
VERIFY(m_associated_component);
auto component = TRY(m_associated_component->lookup(name));
return TRY(component->to_inode(procfs()));
if (m_type == Type::RootDirectory) {
return lookup_as_root_directory(name);
}
VERIFY(m_type == Type::ProcessDirectory);
@ -253,53 +202,23 @@ ErrorOr<NonnullLockRefPtr<Inode>> ProcFSInode::lookup(StringView name)
auto process = Process::from_pid_in_same_jail(m_associated_pid.value());
if (!process)
return ESRCH;
if (name == "fd"sv)
return TRY(ProcFSInode::try_create_as_process_subdirectory_inode(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions, m_associated_pid.value()));
if (name == "stacks"sv)
return TRY(ProcFSInode::try_create_as_process_subdirectory_inode(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks, m_associated_pid.value()));
if (name == "children"sv)
return TRY(ProcFSInode::try_create_as_process_subdirectory_inode(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::Children, m_associated_pid.value()));
if (name == "unveil"sv)
return TRY(ProcFSInode::try_create_as_pid_property_inode(procfs(), SegmentedProcFSIndex::MainProcessProperty::Unveil, m_associated_pid.value()));
if (name == "pledge"sv)
return TRY(ProcFSInode::try_create_as_pid_property_inode(procfs(), SegmentedProcFSIndex::MainProcessProperty::Pledge, m_associated_pid.value()));
if (name == "fds"sv)
return TRY(ProcFSInode::try_create_as_pid_property_inode(procfs(), SegmentedProcFSIndex::MainProcessProperty::OpenFileDescriptions, m_associated_pid.value()));
if (name == "exe"sv)
return TRY(ProcFSInode::try_create_as_pid_property_inode(procfs(), SegmentedProcFSIndex::MainProcessProperty::BinaryLink, m_associated_pid.value()));
if (name == "cwd"sv)
return TRY(ProcFSInode::try_create_as_pid_property_inode(procfs(), SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink, m_associated_pid.value()));
if (name == "perf_events"sv)
return TRY(ProcFSInode::try_create_as_pid_property_inode(procfs(), SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents, m_associated_pid.value()));
if (name == "vm"sv)
return TRY(ProcFSInode::try_create_as_pid_property_inode(procfs(), SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats, m_associated_pid.value()));
if (name == "cmdline"sv)
return TRY(ProcFSInode::try_create_as_pid_property_inode(procfs(), SegmentedProcFSIndex::MainProcessProperty::CommandLine, m_associated_pid.value()));
return ENOENT;
return process->lookup_as_directory(procfs(), name);
}
ErrorOr<void> ProcFSInode::attach(OpenFileDescription& description)
{
if (m_type == Type::GlobalDirectory || m_type == Type::ProcessDirectory || m_type == Type::ProcessSubdirectory)
if (m_type == Type::RootDirectory || m_type == Type::SelfProcessLink || m_type == Type::ProcessDirectory || m_type == Type::ProcessSubdirectory)
return {};
if (m_type == Type::GlobalLink)
return m_associated_component->refresh_data(description);
VERIFY(m_type == Type::ProcessProperty || m_type == Type::FileDescriptionLink || m_type == Type::ThreadStack || m_type == Type::ChildProcessLink);
VERIFY(m_type == Type::ProcessProperty);
return refresh_process_property_data(description);
}
void ProcFSInode::did_seek(OpenFileDescription& description, off_t offset)
{
if (m_type == Type::GlobalLink) {
if (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());
}
if (m_type == Type::SelfProcessLink) {
return;
}
VERIFY(m_type == Type::ProcessProperty || m_type == Type::FileDescriptionLink || m_type == Type::ThreadStack || m_type == Type::ChildProcessLink);
VERIFY(m_type == Type::ProcessProperty);
if (offset != 0)
return;
(void)refresh_process_property_data(description);
@ -308,15 +227,24 @@ void ProcFSInode::did_seek(OpenFileDescription& description, off_t offset)
ErrorOr<size_t> ProcFSInode::read_bytes_locked(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription* description) const
{
dbgln_if(PROCFS_DEBUG, "ProcFSInode: read_bytes_locked offset: {} count: {}", offset, count);
if (m_type == Type::GlobalLink) {
VERIFY(m_associated_component);
return m_associated_component->read_bytes(offset, count, buffer, description);
}
VERIFY(m_type == Type::ProcessProperty || m_type == Type::FileDescriptionLink || m_type == Type::ThreadStack || m_type == Type::ChildProcessLink);
VERIFY(offset >= 0);
VERIFY(buffer.user_or_kernel_ptr());
if (m_type == Type::SelfProcessLink) {
auto builder = TRY(KBufferBuilder::try_create());
TRY(builder.appendff("{}", Process::current().pid().value()));
auto data_buffer = builder.build();
if (!data_buffer)
return Error::from_errno(EFAULT);
if ((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;
}
VERIFY(m_type == Type::ProcessProperty);
if (!description) {
auto builder = TRY(KBufferBuilder::try_create());
VERIFY(m_associated_pid.has_value());
@ -327,10 +255,13 @@ ErrorOr<size_t> ProcFSInode::read_bytes_locked(off_t offset, size_t count, UserO
auto data_buffer = builder.build();
if (!data_buffer)
return Error::from_errno(EFAULT);
if ((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;
}
if (!description->data()) {
dbgln("ProcFS Process Information: Do not have cached data!");
return Error::from_errno(EIO);
@ -346,7 +277,6 @@ ErrorOr<size_t> ProcFSInode::read_bytes_locked(off_t offset, size_t count, UserO
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;
}
@ -360,40 +290,43 @@ static ErrorOr<void> build_from_cached_data(KBufferBuilder& builder, ProcFSInode
ErrorOr<void> ProcFSInode::try_fetch_process_property_data(NonnullLockRefPtr<Process> process, KBufferBuilder& builder) const
{
VERIFY(m_type == Type::ProcessProperty || m_type == Type::FileDescriptionLink || m_type == Type::ThreadStack || m_type == Type::ChildProcessLink);
VERIFY(m_parent_subdirectory_type.has_value());
auto parent_subdirectory_type = m_parent_subdirectory_type.value();
if (parent_subdirectory_type == SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions) {
TRY(process->procfs_get_file_description_link(m_possible_data.property_index, builder));
VERIFY(m_type == Type::ProcessProperty);
if (m_subdirectory == process_fd_subdirectory_root_entry.subdirectory) {
// NOTE: All property numbers should start from 1 as 0 is reserved for the directory itself.
// Therefore subtract 1 to get the actual correct fd number.
TRY(process->procfs_get_file_description_link(m_property - 1, builder));
return {};
}
if (parent_subdirectory_type == SegmentedProcFSIndex::ProcessSubDirectory::Stacks) {
TRY(process->procfs_get_thread_stack(m_possible_data.property_index, builder));
if (m_subdirectory == process_stacks_subdirectory_root_entry.subdirectory) {
// NOTE: All property numbers should start from 1 as 0 is reserved for the directory itself.
// Therefore subtract 1 to get the actual correct thread stack number.
TRY(process->procfs_get_thread_stack(m_property - 1, builder));
return {};
}
if (parent_subdirectory_type == SegmentedProcFSIndex::ProcessSubDirectory::Children) {
TRY(process->procfs_get_child_process_link(m_possible_data.property_index, builder));
if (m_subdirectory == process_children_subdirectory_root_entry.subdirectory) {
// NOTE: All property numbers should start from 1 as 0 is reserved for the directory itself.
// Therefore subtract 1 to get the actual correct child process index number for a correct symlink.
TRY(process->procfs_get_child_process_link(m_property - 1, builder));
return {};
}
VERIFY(m_type == Type::ProcessProperty);
VERIFY(parent_subdirectory_type == SegmentedProcFSIndex::ProcessSubDirectory::Reserved);
switch (m_possible_data.property_type) {
case SegmentedProcFSIndex::MainProcessProperty::Unveil:
VERIFY(m_subdirectory == main_process_directory_root_entry.subdirectory);
switch (m_property) {
case process_unveil_list_entry.property:
return process->procfs_get_unveil_stats(builder);
case SegmentedProcFSIndex::MainProcessProperty::Pledge:
case process_pledge_list_entry.property:
return process->procfs_get_pledge_stats(builder);
case SegmentedProcFSIndex::MainProcessProperty::OpenFileDescriptions:
case process_fds_list_entry.property:
return process->procfs_get_fds_stats(builder);
case SegmentedProcFSIndex::MainProcessProperty::BinaryLink:
case process_exe_symlink_entry.property:
return process->procfs_get_binary_link(builder);
case SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink:
case process_cwd_symlink_entry.property:
return process->procfs_get_current_work_directory_link(builder);
case SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents:
case process_perf_events_entry.property:
return process->procfs_get_perf_events(builder);
case SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats:
case process_vm_entry.property:
return process->procfs_get_virtual_memory_stats(builder);
case SegmentedProcFSIndex::MainProcessProperty::CommandLine:
case process_cmdline_entry.property:
return process->procfs_get_command_line(builder);
default:
VERIFY_NOT_REACHED();
@ -405,7 +338,7 @@ ErrorOr<void> ProcFSInode::refresh_process_property_data(OpenFileDescription& de
// 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.
VERIFY(m_type == Type::ProcessProperty || m_type == Type::FileDescriptionLink || m_type == Type::ThreadStack || m_type == Type::ChildProcessLink);
VERIFY(m_type == Type::ProcessProperty);
VERIFY(m_associated_pid.has_value());
auto process = Process::from_pid_in_same_jail(m_associated_pid.value());
if (!process)
@ -434,50 +367,22 @@ InodeMetadata ProcFSInode::metadata() const
{
InodeMetadata metadata;
switch (m_type) {
case Type::GlobalLink: {
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();
case Type::SelfProcessLink: {
metadata.inode = { fsid(), 2 };
metadata.mode = S_IFLNK | 0777;
metadata.uid = 0;
metadata.gid = 0;
metadata.size = 0;
metadata.mtime = m_associated_component->modified_time();
metadata.mtime = TimeManagement::boot_time();
break;
}
case Type::GlobalDirectory: {
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();
case Type::RootDirectory: {
metadata.inode = { fsid(), 1 };
metadata.mode = S_IFDIR | 0555;
metadata.uid = 0;
metadata.gid = 0;
metadata.size = 0;
metadata.mtime = m_associated_component->modified_time();
break;
}
case Type::FileDescriptionLink: {
VERIFY(m_associated_pid.has_value());
auto process = Process::from_pid_in_same_jail(m_associated_pid.value());
if (!process)
return {};
auto traits = process->procfs_traits();
metadata.inode = { fsid(), SegmentedProcFSIndex::build_segmented_index_for_file_description(m_associated_pid.value(), m_possible_data.property_index) };
metadata.mode = determine_procfs_process_inode_mode(m_parent_subdirectory_type.value(), {});
metadata.uid = traits->owner_user();
metadata.gid = traits->owner_group();
metadata.size = 0;
metadata.mtime = traits->modified_time();
break;
}
case Type::ThreadStack: {
VERIFY(m_associated_pid.has_value());
auto process = Process::from_pid_in_same_jail(m_associated_pid.value());
if (!process)
return {};
auto traits = process->procfs_traits();
metadata.inode = { fsid(), SegmentedProcFSIndex::build_segmented_index_for_thread_stack(m_associated_pid.value(), m_possible_data.property_index) };
metadata.mode = determine_procfs_process_inode_mode(m_parent_subdirectory_type.value(), {});
metadata.uid = traits->owner_user();
metadata.gid = traits->owner_group();
metadata.size = 0;
metadata.mtime = traits->modified_time();
metadata.mtime = TimeManagement::boot_time();
break;
}
case Type::ProcessProperty: {
@ -485,27 +390,13 @@ InodeMetadata ProcFSInode::metadata() const
auto process = Process::from_pid_in_same_jail(m_associated_pid.value());
if (!process)
return {};
auto traits = process->procfs_traits();
metadata.inode = { fsid(), SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(m_associated_pid.value(), m_possible_data.property_type) };
metadata.mode = determine_procfs_process_inode_mode(m_parent_subdirectory_type.value(), m_possible_data.property_type);
metadata.uid = traits->owner_user();
metadata.gid = traits->owner_group();
metadata.inode = identifier();
metadata.mode = determine_procfs_process_inode_mode(m_subdirectory, m_property);
auto credentials = process->credentials();
metadata.uid = credentials->uid();
metadata.gid = credentials->gid();
metadata.size = 0;
metadata.mtime = traits->modified_time();
break;
}
case Type::ChildProcessLink: {
VERIFY(m_associated_pid.has_value());
auto process = Process::from_pid_in_same_jail(m_associated_pid.value());
if (!process)
return {};
auto traits = process->procfs_traits();
metadata.inode = { fsid(), SegmentedProcFSIndex::build_segmented_index_for_children(m_associated_pid.value(), m_possible_data.property_index) };
metadata.mode = determine_procfs_process_inode_mode(m_parent_subdirectory_type.value(), {});
metadata.uid = traits->owner_user();
metadata.gid = traits->owner_group();
metadata.size = 0;
metadata.mtime = traits->modified_time();
metadata.mtime = TimeManagement::now();
break;
}
case Type::ProcessDirectory: {
@ -513,28 +404,27 @@ InodeMetadata ProcFSInode::metadata() const
auto process = Process::from_pid_in_same_jail(m_associated_pid.value());
if (!process)
return {};
auto traits = process->procfs_traits();
metadata.inode = { fsid(), traits->component_index() };
metadata.mode = S_IFDIR | traits->required_mode();
metadata.uid = traits->owner_user();
metadata.gid = traits->owner_group();
metadata.inode = identifier();
metadata.mode = S_IFDIR | 0555;
auto credentials = process->credentials();
metadata.uid = credentials->uid();
metadata.gid = credentials->gid();
metadata.size = 0;
metadata.mtime = traits->modified_time();
metadata.mtime = TimeManagement::now();
break;
}
case Type::ProcessSubdirectory: {
VERIFY(m_associated_pid.has_value());
VERIFY(m_subdirectory_type.has_value());
auto process = Process::from_pid_in_same_jail(m_associated_pid.value());
if (!process)
return {};
auto traits = process->procfs_traits();
metadata.inode = { fsid(), SegmentedProcFSIndex::build_segmented_index_for_sub_directory(m_associated_pid.value(), m_subdirectory_type.value()) };
metadata.mode = S_IFDIR | traits->required_mode();
metadata.uid = traits->owner_user();
metadata.gid = traits->owner_group();
metadata.inode = identifier();
metadata.mode = S_IFDIR | 0555;
auto credentials = process->credentials();
metadata.uid = credentials->uid();
metadata.gid = credentials->gid();
metadata.size = 0;
metadata.mtime = traits->modified_time();
metadata.mtime = TimeManagement::now();
break;
}
}

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2022-2023, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -8,95 +9,73 @@
#include <Kernel/FileSystem/Inode.h>
#include <Kernel/FileSystem/OpenFileDescription.h>
#include <Kernel/FileSystem/ProcFS/Definitions.h>
#include <Kernel/FileSystem/ProcFS/FileSystem.h>
#include <Kernel/ProcessExposed.h>
#include <Kernel/KBufferBuilder.h>
#include <Kernel/UnixTypes.h>
namespace Kernel {
struct ProcFSInodeData : public OpenFileDescriptionData {
OwnPtr<KBuffer> buffer;
};
class ProcFSExposedDirectory;
class ProcFSExposedLink;
class ProcFSInode final : public Inode {
friend class ProcFS;
public:
enum class Type {
GlobalLink,
GlobalDirectory,
FileDescriptionLink,
ThreadStack,
RootDirectory,
SelfProcessLink,
ProcessProperty,
ChildProcessLink,
ProcessDirectory,
ProcessSubdirectory,
};
static ErrorOr<NonnullLockRefPtr<ProcFSInode>> try_create_as_file_description_link_inode(ProcFS const&, unsigned, ProcessID);
static ErrorOr<NonnullLockRefPtr<ProcFSInode>> try_create_as_thread_stack_inode(ProcFS const&, ThreadID, ProcessID);
static ErrorOr<NonnullLockRefPtr<ProcFSInode>> try_create_as_pid_property_inode(ProcFS const&, SegmentedProcFSIndex::MainProcessProperty, ProcessID);
static ErrorOr<NonnullLockRefPtr<ProcFSInode>> try_create_as_child_process_link_inode(ProcFS const&, ProcessID, ProcessID);
static ErrorOr<NonnullLockRefPtr<ProcFSInode>> try_create_as_process_directory_inode(ProcFS const&, ProcessID);
static ErrorOr<NonnullLockRefPtr<ProcFSInode>> try_create_as_process_subdirectory_inode(ProcFS const&, SegmentedProcFSIndex::ProcessSubDirectory, ProcessID);
static ErrorOr<NonnullLockRefPtr<ProcFSInode>> try_create_as_directory_inode(ProcFS const&, ProcFSExposedDirectory const&);
static ErrorOr<NonnullLockRefPtr<ProcFSInode>> try_create_as_global_link_inode(ProcFS const&, ProcFSExposedLink const&);
static InodeIndex create_index_from_global_directory_entry(segmented_global_inode_index entry);
static InodeIndex create_index_from_process_directory_entry(ProcessID pid, segmented_process_directory_entry entry);
virtual ~ProcFSInode() override;
private:
// ProcFS PID property inode (/proc/PID/PROPERTY)
ProcFSInode(ProcFS const&, SegmentedProcFSIndex::MainProcessProperty, ProcessID);
// ProcFS Thread stack inode (/proc/PID/stacks/TID)
ProcFSInode(ProcFS const&, ThreadID, ProcessID);
// ProcFS File description link inode (/proc/PID/fd/FD)
ProcFSInode(ProcFS const&, unsigned, ProcessID);
// ProcFS Child process link inode (/proc/PID/children/CHILD_PID)
ProcFSInode(ProcFS const&, ProcessID, ProcessID);
// ProcFS Process directory inode (/proc/PID/)
ProcFSInode(ProcFS const&, ProcessID);
// ProcFS Process sub directory inode (/proc/PID/SUBDIRECTORY)
ProcFSInode(ProcFS const&, SegmentedProcFSIndex::ProcessSubDirectory, ProcessID);
ProcFSInode(ProcFS const&, ProcFSExposedLink const&);
ProcFSInode(ProcFS const&, ProcFSExposedDirectory const&);
ProcFSInode(ProcFS const&, InodeIndex);
ProcFS& procfs() { return static_cast<ProcFS&>(Inode::fs()); }
ProcFS const& procfs() const { return static_cast<ProcFS const&>(Inode::fs()); }
// ^Inode (EROFS handling)
virtual ErrorOr<NonnullLockRefPtr<Inode>> create_child(StringView, mode_t, dev_t, UserID, GroupID) override { return EROFS; }
virtual ErrorOr<void> add_child(Inode&, StringView, mode_t) override { return EROFS; }
virtual ErrorOr<void> remove_child(StringView) override { return EROFS; }
virtual ErrorOr<void> replace_child(StringView, Inode&) override { return EROFS; }
virtual ErrorOr<void> chmod(mode_t) override { return EROFS; }
virtual ErrorOr<void> chown(UserID, GroupID) override { return EROFS; }
virtual ErrorOr<size_t> write_bytes_locked(off_t, size_t, UserOrKernelBuffer const&, OpenFileDescription*) override { return EROFS; }
virtual ErrorOr<void> truncate(u64) override { return EROFS; }
// ^Inode (Silent ignore handling)
virtual ErrorOr<void> flush_metadata() override { return {}; }
virtual ErrorOr<void> update_timestamps(Optional<Time>, Optional<Time>, Optional<Time>) override { return {}; }
// ^Inode
virtual ErrorOr<void> attach(OpenFileDescription& description) override;
virtual void did_seek(OpenFileDescription&, off_t) override;
virtual ErrorOr<void> flush_metadata() override final;
virtual ErrorOr<NonnullLockRefPtr<Inode>> create_child(StringView name, mode_t, dev_t, UserID, GroupID) override;
virtual ErrorOr<void> add_child(Inode&, StringView name, mode_t) override final;
virtual ErrorOr<void> remove_child(StringView name) override final;
virtual ErrorOr<void> replace_child(StringView name, Inode& child) override final;
virtual ErrorOr<void> chmod(mode_t) override final;
virtual ErrorOr<void> chown(UserID, GroupID) override final;
virtual InodeMetadata metadata() const override;
ErrorOr<void> traverse_as_root_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const;
virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
virtual InodeMetadata metadata() const override;
virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override;
virtual ErrorOr<size_t> write_bytes_locked(off_t, size_t, UserOrKernelBuffer const& buffer, OpenFileDescription*) override;
ErrorOr<NonnullLockRefPtr<Inode>> lookup_as_root_directory(StringView name);
virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override final;
virtual ErrorOr<void> truncate(u64) override final;
virtual ErrorOr<void> update_timestamps(Optional<Time> atime, Optional<Time> ctime, Optional<Time> mtime) override;
ErrorOr<void> refresh_process_property_data(OpenFileDescription& description);
ErrorOr<void> try_fetch_process_property_data(NonnullLockRefPtr<Process>, KBufferBuilder& builder) const;
Type m_type;
union {
SegmentedProcFSIndex::MainProcessProperty property_type;
unsigned property_index;
} m_possible_data;
Optional<SegmentedProcFSIndex::ProcessSubDirectory> const m_parent_subdirectory_type {};
Optional<SegmentedProcFSIndex::ProcessSubDirectory> const m_subdirectory_type {};
Optional<ProcessID> const m_associated_pid {};
u16 const m_subdirectory { 0 };
u32 const m_property { 0 };
LockRefPtr<ProcFSExposedComponent> m_associated_component;
mutable Mutex m_refresh_lock;
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
* Copyright (c) 2021-2023, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -14,11 +14,30 @@
#include <Kernel/Memory/AnonymousVMObject.h>
#include <Kernel/Memory/MemoryManager.h>
#include <Kernel/Process.h>
#include <Kernel/ProcessExposed.h>
#include <Kernel/TTY/TTY.h>
namespace Kernel {
ErrorOr<void> Process::traverse_as_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
{
TRY(callback({ main_process_directory_root_entry.name, { fsid, ProcFSInode::create_index_from_process_directory_entry(pid(), main_process_directory_root_entry) }, main_process_directory_root_entry.file_type }));
TRY(callback({ ".."sv, { fsid, ProcFSInode::create_index_from_global_directory_entry(global_inode_ids[0]) }, global_inode_ids[0].file_type }));
for (auto& entry : main_process_directory_entries) {
TRY(callback({ entry.name, { fsid, ProcFSInode::create_index_from_process_directory_entry(pid(), entry) }, entry.file_type }));
}
return {};
}
ErrorOr<NonnullLockRefPtr<Inode>> Process::lookup_as_directory(ProcFS& procfs, StringView name) const
{
for (auto& entry : main_process_directory_entries) {
if (entry.name == name)
return procfs.get_inode({ procfs.fsid(), ProcFSInode::create_index_from_process_directory_entry(pid(), entry) });
}
return ENOENT;
}
ErrorOr<void> Process::procfs_get_thread_stack(ThreadID thread_id, KBufferBuilder& builder) const
{
auto array = TRY(JsonArraySerializer<>::try_create(builder));
@ -44,33 +63,36 @@ ErrorOr<void> Process::procfs_get_thread_stack(ThreadID thread_id, KBufferBuilde
ErrorOr<void> Process::traverse_stacks_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
{
TRY(callback({ "."sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property(pid(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks, SegmentedProcFSIndex::MainProcessProperty::Reserved) }, 0 }));
TRY(callback({ ".."sv, { fsid, m_procfs_traits->component_index() }, 0 }));
TRY(callback({ "."sv, { fsid, ProcFSInode::create_index_from_process_directory_entry(pid(), process_stacks_subdirectory_root_entry) }, DT_DIR }));
TRY(callback({ ".."sv, { fsid, ProcFSInode::create_index_from_process_directory_entry(pid(), main_process_directory_root_entry) }, main_process_directory_root_entry.file_type }));
return thread_list().with([&](auto& list) -> ErrorOr<void> {
for (auto const& thread : list) {
int tid = thread.tid().value();
InodeIdentifier identifier = { fsid, SegmentedProcFSIndex::build_segmented_index_for_thread_stack(pid(), thread.tid()) };
auto name = TRY(KString::number(tid));
// NOTE: All property numbers should start from 1 as 0 is reserved for the directory itself.
auto entry = segmented_process_directory_entry { {}, DT_REG, process_stacks_subdirectory_root_entry.subdirectory, static_cast<u32>(thread.tid().value() + 1) };
InodeIdentifier identifier = { fsid, ProcFSInode::create_index_from_process_directory_entry(pid(), entry) };
auto name = TRY(KString::number(thread.tid().value()));
TRY(callback({ name->view(), identifier, 0 }));
}
return {};
});
}
ErrorOr<NonnullLockRefPtr<Inode>> Process::lookup_stacks_directory(ProcFS const& procfs, StringView name) const
ErrorOr<NonnullLockRefPtr<Inode>> Process::lookup_stacks_directory(ProcFS& procfs, StringView name) const
{
auto maybe_needle = name.to_uint();
if (!maybe_needle.has_value())
return ENOENT;
auto needle = maybe_needle.release_value();
ErrorOr<NonnullLockRefPtr<ProcFSInode>> thread_stack_inode { ENOENT };
ErrorOr<NonnullLockRefPtr<Inode>> thread_stack_inode { ENOENT };
for_each_thread([&](Thread const& thread) {
int tid = thread.tid().value();
VERIFY(!(tid < 0));
if (needle == (unsigned)tid) {
thread_stack_inode = ProcFSInode::try_create_as_thread_stack_inode(procfs, thread.tid(), pid());
// NOTE: All property numbers should start from 1 as 0 is reserved for the directory itself.
auto entry = segmented_process_directory_entry { {}, DT_REG, process_stacks_subdirectory_root_entry.subdirectory, static_cast<u32>(thread.tid().value() + 1) };
thread_stack_inode = procfs.get_inode({ procfs.fsid(), ProcFSInode::create_index_from_process_directory_entry(pid(), entry) });
return IterationDecision::Break;
}
return IterationDecision::Continue;
@ -83,19 +105,21 @@ ErrorOr<NonnullLockRefPtr<Inode>> Process::lookup_stacks_directory(ProcFS const&
ErrorOr<void> Process::traverse_children_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
{
TRY(callback({ "."sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(pid(), SegmentedProcFSIndex::ProcessSubDirectory::Children) }, 0 }));
TRY(callback({ ".."sv, { fsid, m_procfs_traits->component_index() }, 0 }));
TRY(callback({ "."sv, { fsid, ProcFSInode::create_index_from_process_directory_entry(pid(), process_children_subdirectory_root_entry) }, DT_DIR }));
TRY(callback({ ".."sv, { fsid, ProcFSInode::create_index_from_process_directory_entry(pid(), main_process_directory_root_entry) }, main_process_directory_root_entry.file_type }));
return Process::for_each_in_same_jail([&](Process& process) -> ErrorOr<void> {
if (process.ppid() == pid()) {
StringBuilder builder;
builder.appendff("{}", process.pid());
TRY(callback({ builder.string_view(), { fsid, SegmentedProcFSIndex::build_segmented_index_for_children(pid(), process.pid()) }, DT_LNK }));
auto name = TRY(KString::number(process.pid().value()));
// NOTE: All property numbers should start from 1 as 0 is reserved for the directory itself.
auto entry = segmented_process_directory_entry { {}, DT_LNK, process_children_subdirectory_root_entry.subdirectory, static_cast<u32>(process.pid().value() + 1) };
InodeIdentifier identifier = { fsid, ProcFSInode::create_index_from_process_directory_entry(pid(), entry) };
TRY(callback({ name->view(), identifier, DT_LNK }));
}
return {};
});
}
ErrorOr<NonnullLockRefPtr<Inode>> Process::lookup_children_directory(ProcFS const& procfs, StringView name) const
ErrorOr<NonnullLockRefPtr<Inode>> Process::lookup_children_directory(ProcFS& procfs, StringView name) const
{
auto maybe_pid = name.to_uint();
if (!maybe_pid.has_value())
@ -105,7 +129,9 @@ ErrorOr<NonnullLockRefPtr<Inode>> Process::lookup_children_directory(ProcFS cons
if (!child_process || child_process->ppid() != pid())
return ENOENT;
return TRY(ProcFSInode::try_create_as_child_process_link_inode(procfs, *maybe_pid, pid()));
// NOTE: All property numbers should start from 1 as 0 is reserved for the directory itself.
auto entry = segmented_process_directory_entry { {}, DT_LNK, process_children_subdirectory_root_entry.subdirectory, (maybe_pid.value() + 1) };
return procfs.get_inode({ procfs.fsid(), ProcFSInode::create_index_from_process_directory_entry(pid(), entry) });
}
ErrorOr<size_t> Process::procfs_get_child_process_link(ProcessID child_pid, KBufferBuilder& builder) const
@ -125,26 +151,28 @@ ErrorOr<size_t> Process::procfs_get_file_description_link(unsigned fd, KBufferBu
ErrorOr<void> Process::traverse_file_descriptions_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
{
TRY(callback({ "."sv, { fsid, m_procfs_traits->component_index() }, 0 }));
TRY(callback({ ".."sv, { fsid, m_procfs_traits->component_index() }, 0 }));
size_t count = 0;
fds().with_shared([&](auto& fds) {
fds.enumerate([&](auto& file_description_metadata) {
TRY(callback({ "."sv, { fsid, ProcFSInode::create_index_from_process_directory_entry(pid(), process_fd_subdirectory_root_entry) }, DT_DIR }));
TRY(callback({ ".."sv, { fsid, ProcFSInode::create_index_from_process_directory_entry(pid(), main_process_directory_root_entry) }, main_process_directory_root_entry.file_type }));
u32 count = 0;
TRY(fds().with_shared([&](auto& fds) -> ErrorOr<void> {
return fds.try_enumerate([&](auto& file_description_metadata) -> ErrorOr<void> {
if (!file_description_metadata.is_valid()) {
count++;
return;
return {};
}
StringBuilder builder;
builder.appendff("{}", count);
// FIXME: Propagate errors from callback.
(void)callback({ builder.string_view(), { fsid, SegmentedProcFSIndex::build_segmented_index_for_file_description(pid(), count) }, DT_LNK });
auto name = TRY(KString::number(count));
// NOTE: All property numbers should start from 1 as 0 is reserved for the directory itself.
auto entry = segmented_process_directory_entry { {}, DT_LNK, process_fd_subdirectory_root_entry.subdirectory, count + 1 };
InodeIdentifier identifier = { fsid, ProcFSInode::create_index_from_process_directory_entry(pid(), entry) };
TRY(callback({ name->view(), identifier, DT_LNK }));
count++;
return {};
});
});
}));
return {};
}
ErrorOr<NonnullLockRefPtr<Inode>> Process::lookup_file_descriptions_directory(ProcFS const& procfs, StringView name) const
ErrorOr<NonnullLockRefPtr<Inode>> Process::lookup_file_descriptions_directory(ProcFS& procfs, StringView name) const
{
auto maybe_index = name.to_uint();
if (!maybe_index.has_value())
@ -153,7 +181,9 @@ ErrorOr<NonnullLockRefPtr<Inode>> Process::lookup_file_descriptions_directory(Pr
if (!m_fds.with_shared([&](auto& fds) { return fds.get_if_valid(*maybe_index); }))
return ENOENT;
return TRY(ProcFSInode::try_create_as_file_description_link_inode(procfs, *maybe_index, pid()));
// NOTE: All property numbers should start from 1 as 0 is reserved for the directory itself.
auto entry = segmented_process_directory_entry { {}, DT_LNK, process_fd_subdirectory_root_entry.subdirectory, (maybe_index.value() + 1) };
return procfs.get_inode({ procfs.fsid(), ProcFSInode::create_index_from_process_directory_entry(pid(), entry) });
}
ErrorOr<void> Process::procfs_get_pledge_stats(KBufferBuilder& builder) const
@ -328,7 +358,7 @@ mode_t Process::binary_link_required_mode() const
{
if (!executable())
return 0;
return m_procfs_traits->required_mode();
return 0555;
}
ErrorOr<void> Process::procfs_get_binary_link(KBufferBuilder& builder) const

View File

@ -40,13 +40,7 @@ class MasterPTY;
class Mount;
class PerformanceEventBuffer;
class ProcFS;
class ProcFSExposedComponent;
class ProcFSExposedDirectory;
class ProcFSInode;
class ProcFSProcessInformation;
class ProcFSRootDirectory;
class ProcFSSystemBoolean;
class ProcFSSystemDirectory;
class Process;
class ProcessGroup;
class RAMFS;

View File

@ -363,9 +363,6 @@ ErrorOr<void> Process::attach_resources(NonnullOwnPtr<Memory::AddressSpace>&& pr
first_thread->detach();
}
auto weak_ptr = TRY(this->try_make_weak_ptr());
m_procfs_traits = TRY(ProcessProcFSTraits::try_create({}, move(weak_ptr)));
// This is not actually explicitly verified by any official documentation,
// but it's not listed anywhere as being cleared, and rsync expects it to work like this.
if (fork_parent)

View File

@ -32,7 +32,6 @@
#include <Kernel/Locking/MutexProtected.h>
#include <Kernel/Memory/AddressSpace.h>
#include <Kernel/PerformanceEventBuffer.h>
#include <Kernel/ProcessExposed.h>
#include <Kernel/ProcessGroup.h>
#include <Kernel/StdLib.h>
#include <Kernel/Thread.h>
@ -159,8 +158,6 @@ public:
};
public:
class ProcessProcFSTraits;
static Process& current()
{
auto* current_thread = Processor::current_thread();
@ -639,7 +636,8 @@ private:
ErrorOr<FlatPtr> read_impl(int fd, Userspace<u8*> buffer, size_t size);
public:
NonnullLockRefPtr<ProcessProcFSTraits> procfs_traits() const { return *m_procfs_traits; }
ErrorOr<void> traverse_as_directory(FileSystemID, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const;
ErrorOr<NonnullLockRefPtr<Inode>> lookup_as_directory(ProcFS&, StringView name) const;
ErrorOr<void> procfs_get_fds_stats(KBufferBuilder& builder) const;
ErrorOr<void> procfs_get_perf_events(KBufferBuilder& builder) const;
ErrorOr<void> procfs_get_unveil_stats(KBufferBuilder& builder) const;
@ -651,11 +649,11 @@ public:
mode_t binary_link_required_mode() const;
ErrorOr<void> procfs_get_thread_stack(ThreadID thread_id, KBufferBuilder& builder) const;
ErrorOr<void> traverse_stacks_directory(FileSystemID, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const;
ErrorOr<NonnullLockRefPtr<Inode>> lookup_stacks_directory(ProcFS const&, StringView name) const;
ErrorOr<NonnullLockRefPtr<Inode>> lookup_stacks_directory(ProcFS&, StringView name) const;
ErrorOr<size_t> procfs_get_file_description_link(unsigned fd, KBufferBuilder& builder) const;
ErrorOr<void> traverse_file_descriptions_directory(FileSystemID, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const;
ErrorOr<NonnullLockRefPtr<Inode>> lookup_file_descriptions_directory(ProcFS const&, StringView name) const;
ErrorOr<NonnullLockRefPtr<Inode>> lookup_children_directory(ProcFS const&, StringView name) const;
ErrorOr<NonnullLockRefPtr<Inode>> lookup_file_descriptions_directory(ProcFS&, StringView name) const;
ErrorOr<NonnullLockRefPtr<Inode>> lookup_children_directory(ProcFS&, StringView name) const;
ErrorOr<void> traverse_children_directory(FileSystemID, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const;
ErrorOr<size_t> procfs_get_child_process_link(ProcessID child_pid, KBufferBuilder& builder) const;
@ -809,32 +807,6 @@ public:
OpenFileDescriptionAndFlags* m_description { nullptr };
};
class ProcessProcFSTraits : public ProcFSExposedComponent {
public:
static ErrorOr<NonnullLockRefPtr<ProcessProcFSTraits>> try_create(Badge<Process>, LockWeakPtr<Process> process)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcessProcFSTraits(move(process)));
}
virtual InodeIndex component_index() const override;
virtual ErrorOr<NonnullLockRefPtr<ProcFSInode>> to_inode(ProcFS const& procfs_instance) const override;
virtual ErrorOr<void> traverse_as_directory(FileSystemID, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
virtual mode_t required_mode() const override { return 0555; }
virtual UserID owner_user() const override;
virtual GroupID owner_group() const override;
private:
explicit ProcessProcFSTraits(LockWeakPtr<Process> process)
: m_process(move(process))
{
}
// NOTE: We need to weakly hold on to the process, because otherwise
// we would be creating a reference cycle.
LockWeakPtr<Process> m_process;
};
MutexProtected<OpenFileDescriptions>& fds() { return m_fds; }
MutexProtected<OpenFileDescriptions> const& fds() const { return m_fds; }
@ -913,7 +885,6 @@ private:
SpinlockProtected<Array<CoredumpProperty, 4>, LockRank::None> m_coredump_properties {};
NonnullLockRefPtrVector<Thread> m_threads_for_coredump;
mutable LockRefPtr<ProcessProcFSTraits> m_procfs_traits;
struct SignalActionData {
VirtualAddress handler_or_sigaction;
int flags { 0 };

View File

@ -1,245 +0,0 @@
/*
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/FileSystem/ProcFS/Inode.h>
#include <Kernel/KBufferBuilder.h>
#include <Kernel/PerformanceEventBuffer.h>
#include <Kernel/Process.h>
#include <Kernel/ProcessExposed.h>
namespace Kernel {
static Spinlock<LockRank::None> s_index_lock {};
static InodeIndex s_next_inode_index = 0;
namespace SegmentedProcFSIndex {
static InodeIndex __build_raw_segmented_index(u32 primary, u16 sub_directory, u32 property)
{
VERIFY(primary < 0x10000000);
VERIFY(property < 0x100000);
// Note: The sub-directory part is already limited to 0xFFFF, so no need to VERIFY it.
return static_cast<u64>((static_cast<u64>(primary) << 36) | (static_cast<u64>(sub_directory) << 20) | property);
}
static InodeIndex build_segmented_index_with_known_pid(ProcessID pid, u16 sub_directory, u32 property)
{
return __build_raw_segmented_index(pid.value() + 1, sub_directory, property);
}
static InodeIndex build_segmented_index_with_unknown_property(ProcessID pid, ProcessSubDirectory sub_directory, unsigned property)
{
return build_segmented_index_with_known_pid(pid, to_underlying(sub_directory), static_cast<u32>(property));
}
InodeIndex build_segmented_index_for_pid_directory(ProcessID pid)
{
return build_segmented_index_with_unknown_property(pid, ProcessSubDirectory::Reserved, to_underlying(MainProcessProperty::Reserved));
}
InodeIndex build_segmented_index_for_sub_directory(ProcessID pid, ProcessSubDirectory sub_directory)
{
return build_segmented_index_with_unknown_property(pid, sub_directory, to_underlying(MainProcessProperty::Reserved));
}
InodeIndex build_segmented_index_for_main_property(ProcessID pid, ProcessSubDirectory sub_directory, MainProcessProperty property)
{
return build_segmented_index_with_known_pid(pid, to_underlying(sub_directory), to_underlying(property));
}
InodeIndex build_segmented_index_for_main_property_in_pid_directory(ProcessID pid, MainProcessProperty property)
{
return build_segmented_index_with_known_pid(pid, to_underlying(ProcessSubDirectory::Reserved), to_underlying(property));
}
InodeIndex build_segmented_index_for_thread_stack(ProcessID pid, ThreadID thread_id)
{
return build_segmented_index_with_unknown_property(pid, ProcessSubDirectory::Stacks, thread_id.value());
}
InodeIndex build_segmented_index_for_file_description(ProcessID pid, unsigned fd)
{
return build_segmented_index_with_unknown_property(pid, ProcessSubDirectory::OpenFileDescriptions, fd);
}
InodeIndex build_segmented_index_for_children(ProcessID pid, ProcessID child_pid)
{
return build_segmented_index_with_unknown_property(pid, ProcessSubDirectory::Children, child_pid.value());
}
}
static size_t s_allocate_global_inode_index()
{
SpinlockLocker lock(s_index_lock);
s_next_inode_index = s_next_inode_index.value() + 1;
// Note: Global ProcFS indices must be above 0 and up to maximum of what 36 bit (2 ^ 36 - 1) can represent.
VERIFY(s_next_inode_index > 0);
VERIFY(s_next_inode_index < 0x100000000);
return s_next_inode_index.value();
}
ProcFSExposedComponent::ProcFSExposedComponent() = default;
ProcFSExposedComponent::ProcFSExposedComponent(StringView name)
: m_component_index(s_allocate_global_inode_index())
{
auto name_or_error = KString::try_create(name);
if (name_or_error.is_error())
TODO();
m_name = name_or_error.release_value();
}
ProcFSExposedDirectory::ProcFSExposedDirectory(StringView name)
: ProcFSExposedComponent(name)
{
}
ProcFSExposedDirectory::ProcFSExposedDirectory(StringView name, ProcFSExposedDirectory const& parent_directory)
: ProcFSExposedComponent(name)
, m_parent_directory(parent_directory)
{
}
ProcFSExposedLink::ProcFSExposedLink(StringView name)
: ProcFSExposedComponent(name)
{
}
ErrorOr<size_t> ProcFSExposedLink::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription*) const
{
VERIFY(offset == 0);
MutexLocker locker(m_lock);
auto builder = TRY(KBufferBuilder::try_create());
if (!const_cast<ProcFSExposedLink&>(*this).acquire_link(builder))
return Error::from_errno(EFAULT);
auto blob = builder.build();
if (!blob)
return Error::from_errno(EFAULT);
ssize_t nread = min(static_cast<off_t>(blob->size() - offset), static_cast<off_t>(count));
TRY(buffer.write(blob->data() + offset, nread));
return nread;
}
ErrorOr<NonnullLockRefPtr<ProcFSInode>> ProcFSExposedLink::to_inode(ProcFS const& procfs_instance) const
{
return TRY(ProcFSInode::try_create_as_global_link_inode(procfs_instance, *this));
}
ErrorOr<NonnullLockRefPtr<ProcFSInode>> ProcFSExposedDirectory::to_inode(ProcFS const& procfs_instance) const
{
return TRY(ProcFSInode::try_create_as_directory_inode(procfs_instance, *this));
}
void ProcFSExposedDirectory::add_component(ProcFSExposedComponent const&)
{
TODO();
}
ErrorOr<NonnullLockRefPtr<ProcFSExposedComponent>> ProcFSExposedDirectory::lookup(StringView name)
{
for (auto& component : m_components) {
if (component.name() == name) {
return component;
}
}
return ENOENT;
}
ErrorOr<void> ProcFSExposedDirectory::traverse_as_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
{
MutexLocker locker(ProcFSComponentRegistry::the().get_lock());
auto parent_directory = m_parent_directory.strong_ref();
if (parent_directory.is_null())
return Error::from_errno(EINVAL);
TRY(callback({ "."sv, { fsid, component_index() }, DT_DIR }));
TRY(callback({ ".."sv, { fsid, parent_directory->component_index() }, DT_DIR }));
for (auto const& component : m_components) {
InodeIdentifier identifier = { fsid, component.component_index() };
TRY(callback({ component.name(), identifier, 0 }));
}
return {};
}
class ProcFSSelfProcessDirectory final : public ProcFSExposedLink {
public:
static NonnullLockRefPtr<ProcFSSelfProcessDirectory> must_create();
private:
ProcFSSelfProcessDirectory();
virtual bool acquire_link(KBufferBuilder& builder) override
{
return !builder.appendff("{}", Process::current().pid().value()).is_error();
}
};
UNMAP_AFTER_INIT NonnullLockRefPtr<ProcFSSelfProcessDirectory> ProcFSSelfProcessDirectory::must_create()
{
return adopt_lock_ref_if_nonnull(new (nothrow) ProcFSSelfProcessDirectory()).release_nonnull();
}
UNMAP_AFTER_INIT ProcFSSelfProcessDirectory::ProcFSSelfProcessDirectory()
: ProcFSExposedLink("self"sv)
{
}
UNMAP_AFTER_INIT NonnullLockRefPtr<ProcFSRootDirectory> ProcFSRootDirectory::must_create()
{
auto directory = adopt_lock_ref(*new (nothrow) ProcFSRootDirectory);
directory->m_components.append(ProcFSSelfProcessDirectory::must_create());
return directory;
}
ErrorOr<void> ProcFSRootDirectory::traverse_as_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
{
MutexLocker locker(ProcFSComponentRegistry::the().get_lock());
TRY(callback({ "."sv, { fsid, component_index() }, 0 }));
TRY(callback({ ".."sv, { fsid, 0 }, 0 }));
for (auto const& component : m_components) {
InodeIdentifier identifier = { fsid, component.component_index() };
TRY(callback({ component.name(), identifier, 0 }));
}
return Process::for_each_in_same_jail([&](Process& process) -> ErrorOr<void> {
VERIFY(!(process.pid() < 0));
u64 process_id = (u64)process.pid().value();
InodeIdentifier identifier = { fsid, static_cast<InodeIndex>(process_id << 36) };
auto process_id_string = TRY(KString::formatted("{:d}", process_id));
TRY(callback({ process_id_string->view(), identifier, 0 }));
return {};
});
}
ErrorOr<NonnullLockRefPtr<ProcFSExposedComponent>> ProcFSRootDirectory::lookup(StringView name)
{
auto maybe_candidate = ProcFSExposedDirectory::lookup(name);
if (maybe_candidate.is_error()) {
if (maybe_candidate.error().code() != ENOENT) {
return maybe_candidate.release_error();
}
} else {
return maybe_candidate.release_value();
}
auto pid = name.to_uint<unsigned>();
if (!pid.has_value())
return ESRCH;
auto actual_pid = pid.value();
if (auto maybe_process = Process::from_pid_in_same_jail(actual_pid))
return maybe_process->procfs_traits();
return ENOENT;
}
UNMAP_AFTER_INIT ProcFSRootDirectory::~ProcFSRootDirectory() = default;
UNMAP_AFTER_INIT ProcFSRootDirectory::ProcFSRootDirectory()
: ProcFSExposedDirectory("."sv)
{
}
}

View File

@ -1,165 +0,0 @@
/*
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/AtomicRefCounted.h>
#include <AK/Error.h>
#include <AK/Function.h>
#include <AK/Types.h>
#include <Kernel/FileSystem/File.h>
#include <Kernel/FileSystem/FileSystem.h>
#include <Kernel/FileSystem/OpenFileDescription.h>
#include <Kernel/KBufferBuilder.h>
#include <Kernel/Library/LockRefPtr.h>
#include <Kernel/Time/TimeManagement.h>
#include <Kernel/UserOrKernelBuffer.h>
namespace Kernel {
namespace SegmentedProcFSIndex {
enum class MainProcessProperty {
Reserved = 0,
Unveil = 1,
Pledge = 2,
OpenFileDescriptions = 3,
BinaryLink = 4,
CurrentWorkDirectoryLink = 5,
PerformanceEvents = 6,
VirtualMemoryStats = 7,
CommandLine = 8,
};
enum class ProcessSubDirectory {
Reserved = 0,
OpenFileDescriptions = 1,
Stacks = 2,
Children = 3
};
void read_segments(u32& primary, ProcessSubDirectory& sub_directory, MainProcessProperty& property);
InodeIndex build_segmented_index_for_pid_directory(ProcessID);
InodeIndex build_segmented_index_for_sub_directory(ProcessID, ProcessSubDirectory sub_directory);
InodeIndex build_segmented_index_for_main_property(ProcessID, ProcessSubDirectory sub_directory, MainProcessProperty property);
InodeIndex build_segmented_index_for_main_property_in_pid_directory(ProcessID, MainProcessProperty property);
InodeIndex build_segmented_index_for_thread_stack(ProcessID, ThreadID);
InodeIndex build_segmented_index_for_file_description(ProcessID, unsigned);
InodeIndex build_segmented_index_for_children(ProcessID, ProcessID);
}
class ProcFSComponentRegistry {
public:
static ProcFSComponentRegistry& the();
static void initialize();
ProcFSComponentRegistry();
ProcFSRootDirectory& root_directory() { return *m_root_directory; }
Mutex& get_lock() { return m_lock; }
private:
Mutex m_lock;
NonnullLockRefPtr<ProcFSRootDirectory> m_root_directory;
};
class ProcFSExposedComponent : public AtomicRefCounted<ProcFSExposedComponent> {
public:
StringView name() const { return m_name->view(); }
virtual ErrorOr<size_t> read_bytes(off_t, size_t, UserOrKernelBuffer&, OpenFileDescription*) const { VERIFY_NOT_REACHED(); }
virtual ErrorOr<void> traverse_as_directory(FileSystemID, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const { VERIFY_NOT_REACHED(); }
virtual ErrorOr<NonnullLockRefPtr<ProcFSExposedComponent>> lookup(StringView) { VERIFY_NOT_REACHED(); };
virtual ErrorOr<size_t> write_bytes(off_t, size_t, UserOrKernelBuffer const&, OpenFileDescription*) { return EROFS; }
virtual ErrorOr<void> truncate(u64) { return EPERM; }
virtual mode_t required_mode() const { return 0444; }
virtual UserID owner_user() const { return 0; }
virtual GroupID owner_group() const { return 0; }
static Time modified_time() { return TimeManagement::now(); }
virtual void prepare_for_deletion() { }
virtual ErrorOr<void> refresh_data(OpenFileDescription&) const
{
return {};
}
virtual ErrorOr<NonnullLockRefPtr<ProcFSInode>> to_inode(ProcFS const& procfs_instance) const = 0;
virtual InodeIndex component_index() const { return m_component_index; }
virtual ~ProcFSExposedComponent() = default;
protected:
ProcFSExposedComponent();
explicit ProcFSExposedComponent(StringView name);
private:
OwnPtr<KString> m_name;
InodeIndex m_component_index {};
};
class ProcFSExposedDirectory
: public ProcFSExposedComponent
, public LockWeakable<ProcFSExposedDirectory> {
friend class ProcFSComponentRegistry;
public:
virtual ErrorOr<void> traverse_as_directory(FileSystemID, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
virtual ErrorOr<NonnullLockRefPtr<ProcFSExposedComponent>> lookup(StringView name) override;
void add_component(ProcFSExposedComponent const&);
virtual void prepare_for_deletion() override
{
for (auto& component : m_components) {
component.prepare_for_deletion();
}
}
virtual mode_t required_mode() const override { return 0555; }
virtual ErrorOr<NonnullLockRefPtr<ProcFSInode>> to_inode(ProcFS const& procfs_instance) const override final;
protected:
explicit ProcFSExposedDirectory(StringView name);
ProcFSExposedDirectory(StringView name, ProcFSExposedDirectory const& parent_directory);
NonnullLockRefPtrVector<ProcFSExposedComponent> m_components;
LockWeakPtr<ProcFSExposedDirectory> m_parent_directory;
};
class ProcFSExposedLink : public ProcFSExposedComponent {
public:
virtual ErrorOr<NonnullLockRefPtr<ProcFSInode>> to_inode(ProcFS const& procfs_instance) const override final;
virtual ErrorOr<size_t> read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription* description) const override;
protected:
virtual bool acquire_link(KBufferBuilder& builder) = 0;
explicit ProcFSExposedLink(StringView name);
mutable Mutex m_lock { "ProcFSLink"sv };
};
namespace PCI {
class Access;
}
class ProcFSRootDirectory final : public ProcFSExposedDirectory {
friend class ProcFSComponentRegistry;
public:
virtual ErrorOr<NonnullLockRefPtr<ProcFSExposedComponent>> lookup(StringView name) override;
static NonnullLockRefPtr<ProcFSRootDirectory> must_create();
virtual ~ProcFSRootDirectory();
private:
virtual ErrorOr<void> traverse_as_directory(FileSystemID, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
ProcFSRootDirectory();
};
struct ProcFSInodeData : public OpenFileDescriptionData {
OwnPtr<KBuffer> buffer;
};
}

View File

@ -1,73 +0,0 @@
/*
* Copyright (c) 2021, sin-ack <sin-ack@protonmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/FileSystem/ProcFS/Inode.h>
#include <Kernel/Process.h>
#include <Kernel/ProcessExposed.h>
namespace Kernel {
UserID Process::ProcessProcFSTraits::owner_user() const
{
auto process = m_process.strong_ref();
if (!process)
return 0;
auto credentials = process->credentials();
return credentials->uid();
}
GroupID Process::ProcessProcFSTraits::owner_group() const
{
auto process = m_process.strong_ref();
if (!process)
return 0;
auto credentials = process->credentials();
return credentials->gid();
}
InodeIndex Process::ProcessProcFSTraits::component_index() const
{
auto process = m_process.strong_ref();
if (!process)
return {};
return SegmentedProcFSIndex::build_segmented_index_for_pid_directory(process->pid());
}
ErrorOr<NonnullLockRefPtr<ProcFSInode>> Process::ProcessProcFSTraits::to_inode(ProcFS const& procfs_instance) const
{
auto process = m_process.strong_ref();
if (!process)
return ESRCH;
return TRY(ProcFSInode::try_create_as_process_directory_inode(procfs_instance, process->pid()));
}
ErrorOr<void> Process::ProcessProcFSTraits::traverse_as_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
{
auto process = m_process.strong_ref();
if (!process)
return ESRCH;
TRY(callback({ "."sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_pid_directory(process->pid()) }, DT_DIR }));
TRY(callback({ ".."sv, { fsid, ProcFSComponentRegistry::the().root_directory().component_index() }, DT_DIR }));
TRY(callback({ "fd"sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(process->pid(), SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions) }, DT_DIR }));
TRY(callback({ "stacks"sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(process->pid(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks) }, DT_DIR }));
TRY(callback({ "children"sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(process->pid(), SegmentedProcFSIndex::ProcessSubDirectory::Children) }, DT_DIR }));
TRY(callback({ "unveil"sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::Unveil) }, DT_REG }));
TRY(callback({ "pledge"sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::Pledge) }, DT_REG }));
TRY(callback({ "fds"sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::OpenFileDescriptions) }, DT_DIR }));
TRY(callback({ "exe"sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::BinaryLink) }, DT_LNK }));
TRY(callback({ "cwd"sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink) }, DT_LNK }));
TRY(callback({ "perf_events"sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents) }, DT_REG }));
TRY(callback({ "vm"sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats) }, DT_REG }));
TRY(callback({ "cmdline"sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(process->pid(), SegmentedProcFSIndex::MainProcessProperty::CommandLine) }, DT_REG }));
return {};
}
}

View File

@ -23,7 +23,6 @@
#include <Kernel/Panic.h>
#include <Kernel/PerformanceEventBuffer.h>
#include <Kernel/Process.h>
#include <Kernel/ProcessExposed.h>
#include <Kernel/Scheduler.h>
#include <Kernel/Sections.h>
#include <Kernel/Thread.h>