mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 08:38:12 +00:00
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:
parent
9216caeec2
commit
c56e1c5378
18 changed files with 362 additions and 952 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue