diff options
author | Liav A <liavalb@gmail.com> | 2021-08-10 20:51:28 +0300 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-08-12 20:57:32 +0200 |
commit | 7ba991dc371ecd055829699852f7cb821472667f (patch) | |
tree | 1c53f16ae0de005e8f539a15f12329453b5d4f4a /Kernel/ProcessSpecificExposed.cpp | |
parent | bf1adc2d5d383c0421f19ccb36a0358ff2ee0ce5 (diff) | |
download | serenity-7ba991dc371ecd055829699852f7cb821472667f.zip |
Kernel: Steer away from heap allocations for ProcFS process data
Instead, use more static patterns to acquire that sort of data.
Diffstat (limited to 'Kernel/ProcessSpecificExposed.cpp')
-rw-r--r-- | Kernel/ProcessSpecificExposed.cpp | 717 |
1 files changed, 205 insertions, 512 deletions
diff --git a/Kernel/ProcessSpecificExposed.cpp b/Kernel/ProcessSpecificExposed.cpp index 3cf220cd7c..6e53a85f1c 100644 --- a/Kernel/ProcessSpecificExposed.cpp +++ b/Kernel/ProcessSpecificExposed.cpp @@ -9,601 +9,294 @@ #include <AK/JsonValue.h> #include <Kernel/Arch/x86/InterruptDisabler.h> #include <Kernel/FileSystem/Custody.h> +#include <Kernel/FileSystem/ProcFS.h> #include <Kernel/KBufferBuilder.h> #include <Kernel/Memory/AnonymousVMObject.h> #include <Kernel/Memory/MemoryManager.h> +#include <Kernel/Process.h> #include <Kernel/ProcessExposed.h> namespace Kernel { -class ProcFSProcessStacks; -class ProcFSThreadStack final : public ProcFSProcessInformation { -public: - // Note: We pass const ProcFSProcessStacks& to enforce creation with this type of directory - static NonnullRefPtr<ProcFSThreadStack> create(const ProcFSProcessDirectory& process_directory, const ProcFSProcessStacks&, const Thread& thread) - { - return adopt_ref(*new (nothrow) ProcFSThreadStack(process_directory, thread)); - } - -private: - explicit ProcFSThreadStack(const ProcFSProcessDirectory& process_directory, const Thread& thread) - : ProcFSProcessInformation(String::formatted("{}", thread.tid()), process_directory) - , m_associated_thread(thread) - { - } - virtual bool output(KBufferBuilder& builder) override - { - JsonArraySerializer array { builder }; - bool show_kernel_addresses = Process::current()->is_superuser(); - bool kernel_address_added = false; - for (auto address : Processor::capture_stack_trace(*m_associated_thread, 1024)) { - if (!show_kernel_addresses && !Memory::is_user_address(VirtualAddress { address })) { - if (kernel_address_added) - continue; - address = 0xdeadc0de; - kernel_address_added = true; - } - array.add(address); +KResultOr<size_t> Process::procfs_get_thread_stack(ThreadID thread_id, KBufferBuilder& builder) const +{ + JsonArraySerializer array { builder }; + auto thread = Thread::from_tid(thread_id); + if (!thread) + return KResult(ESRCH); + bool show_kernel_addresses = Process::current()->is_superuser(); + bool kernel_address_added = false; + for (auto address : Processor::capture_stack_trace(*thread, 1024)) { + if (!show_kernel_addresses && !Memory::is_user_address(VirtualAddress { address })) { + if (kernel_address_added) + continue; + address = 0xdeadc0de; + kernel_address_added = true; } - - array.finish(); - return true; + array.add(address); } - NonnullRefPtr<Thread> m_associated_thread; -}; - -class ProcFSProcessStacks final : public ProcFSExposedDirectory { - // Note: This directory is special, because everything that is created here is dynamic! - // This means we don't register anything in the m_components Vector, and every inode - // is created in runtime when called to get it - // Every ProcFSThreadStack (that represents a thread stack) is created only as a temporary object - // therefore, we don't use m_components so when we are done with the ProcFSThreadStack object, - // It should be deleted (as soon as possible) -public: - virtual KResult traverse_as_directory(unsigned, Function<bool(FileSystem::DirectoryEntryView const&)>) const override; - virtual RefPtr<ProcFSExposedComponent> lookup(StringView name) override; + array.finish(); + return KSuccess; +} - static NonnullRefPtr<ProcFSProcessStacks> create(const ProcFSProcessDirectory& parent_directory) - { - auto directory = adopt_ref(*new (nothrow) ProcFSProcessStacks(parent_directory)); - return directory; - } +InodeIndex Process::component_index() const +{ + return SegmentedProcFSIndex::build_segmented_index_for_pid_directory(pid()); +} - virtual void prepare_for_deletion() override - { - ProcFSExposedDirectory::prepare_for_deletion(); - m_process_directory.clear(); - } +NonnullRefPtr<Inode> Process::to_inode(const ProcFS& procfs_instance) const +{ + return ProcFSProcessDirectoryInode::create(procfs_instance, m_protected_values.pid); +} -private: - ProcFSProcessStacks(const ProcFSProcessDirectory& parent_directory) - : ProcFSExposedDirectory("stacks"sv, parent_directory) - , m_process_directory(parent_directory) - { - } - WeakPtr<ProcFSProcessDirectory> m_process_directory; - mutable Mutex m_lock; -}; +KResult Process::traverse_as_directory(unsigned fsid, Function<bool(FileSystem::DirectoryEntryView const&)> callback) const +{ + callback({ ".", { fsid, SegmentedProcFSIndex::build_segmented_index_for_pid_directory(pid()) }, 0 }); + callback({ "..", { fsid, ProcFSComponentRegistry::the().root_directory().component_index() }, 0 }); + callback({ "fd", { fsid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(pid(), SegmentedProcFSIndex::ProcessSubDirectory::FileDescriptions) }, 0 }); + callback({ "stacks", { fsid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(pid(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks) }, 0 }); + callback({ "unveil", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::Unveil) }, 0 }); + callback({ "pledge", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::Pledge) }, 0 }); + callback({ "fds", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::FileDescriptions) }, 0 }); + callback({ "exe", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::BinaryLink) }, 0 }); + callback({ "cwd", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink) }, 0 }); + callback({ "perf_events", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents) }, 0 }); + callback({ "vm", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats) }, 0 }); + callback({ "root", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid(), SegmentedProcFSIndex::MainProcessProperty::RootLink) }, 0 }); + return KSuccess; +} -KResult ProcFSProcessStacks::traverse_as_directory(unsigned fsid, Function<bool(FileSystem::DirectoryEntryView const&)> callback) const +KResult Process::traverse_stacks_directory(unsigned fsid, Function<bool(FileSystem::DirectoryEntryView const&)> callback) const { - MutexLocker locker(m_lock); - auto parent_directory = m_process_directory.strong_ref(); - if (parent_directory.is_null()) - return KResult(EINVAL); - callback({ ".", { fsid, component_index() }, 0 }); - callback({ "..", { fsid, parent_directory->component_index() }, 0 }); + callback({ ".", { fsid, SegmentedProcFSIndex::build_segmented_index_for_main_property(pid(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks, SegmentedProcFSIndex::MainProcessProperty::Reserved) }, 0 }); + callback({ "..", { fsid, component_index() }, 0 }); - auto process = parent_directory->associated_process(); - if (process.is_null()) - return KResult(ESRCH); - process->for_each_thread([&](const Thread& thread) { + for_each_thread([&](const Thread& thread) { int tid = thread.tid().value(); - InodeIdentifier identifier = { fsid, thread.global_procfs_inode_index() }; + InodeIdentifier identifier = { fsid, SegmentedProcFSIndex::build_segmented_index_for_thread_stack(pid(), thread.tid()) }; callback({ String::number(tid), identifier, 0 }); }); return KSuccess; } -RefPtr<ProcFSExposedComponent> ProcFSProcessStacks::lookup(StringView name) +RefPtr<Inode> Process::lookup_stacks_directory(const ProcFS& procfs, StringView name) const { - MutexLocker locker(m_lock); - auto parent_directory = m_process_directory.strong_ref(); - if (parent_directory.is_null()) - return nullptr; - auto process = parent_directory->associated_process(); - if (process.is_null()) - return nullptr; - RefPtr<ProcFSThreadStack> procfd_stack; + RefPtr<ProcFSProcessPropertyInode> thread_stack_inode; // FIXME: Try to exit the loop earlier - process->for_each_thread([&](const Thread& thread) { + for_each_thread([&](const Thread& thread) { int tid = thread.tid().value(); + VERIFY(!(tid < 0)); if (name == String::number(tid)) { - procfd_stack = ProcFSThreadStack::create(*parent_directory, *this, thread); + thread_stack_inode = ProcFSProcessPropertyInode::create_for_thread_stack(procfs, thread.tid(), pid()); } }); - return procfd_stack; + return thread_stack_inode; } -class ProcFSProcessFileDescriptions; -class ProcFSProcessFileDescription final : public ProcFSExposedLink { -public: - // Note: we pass const ProcFSProcessFileDescriptions& just to enforce creation of this in the correct directory. - static NonnullRefPtr<ProcFSProcessFileDescription> create(unsigned fd_number, const FileDescription& fd, InodeIndex preallocated_index, const ProcFSProcessFileDescriptions&) - { - return adopt_ref(*new (nothrow) ProcFSProcessFileDescription(fd_number, fd, preallocated_index)); - } - -private: - explicit ProcFSProcessFileDescription(unsigned fd_number, const FileDescription& fd, InodeIndex preallocated_index) - : ProcFSExposedLink(String::formatted("{}", fd_number), preallocated_index) - , m_associated_file_description(fd) - { - } - virtual bool acquire_link(KBufferBuilder& builder) override - { - builder.append_bytes(m_associated_file_description->absolute_path().bytes()); - return true; - } - - NonnullRefPtr<FileDescription> m_associated_file_description; -}; - -class ProcFSProcessFileDescriptions final : public ProcFSExposedDirectory { - // Note: This directory is special, because everything that is created here is dynamic! - // This means we don't register anything in the m_components Vector, and every inode - // is created in runtime when called to get it - // Every ProcFSProcessFileDescription (that represents a file descriptor) is created only as a temporary object - // therefore, we don't use m_components so when we are done with the ProcFSProcessFileDescription object, - // It should be deleted (as soon as possible) -public: - virtual KResult traverse_as_directory(unsigned, Function<bool(FileSystem::DirectoryEntryView const&)>) const override; - virtual RefPtr<ProcFSExposedComponent> lookup(StringView name) override; - - static NonnullRefPtr<ProcFSProcessFileDescriptions> create(const ProcFSProcessDirectory& parent_directory) - { - return adopt_ref(*new (nothrow) ProcFSProcessFileDescriptions(parent_directory)); - } - - virtual void prepare_for_deletion() override - { - ProcFSExposedDirectory::prepare_for_deletion(); - m_process_directory.clear(); - } - -private: - explicit ProcFSProcessFileDescriptions(const ProcFSProcessDirectory& parent_directory) - : ProcFSExposedDirectory("fd"sv, parent_directory) - , m_process_directory(parent_directory) - { - } - WeakPtr<ProcFSProcessDirectory> m_process_directory; - mutable Mutex m_lock; -}; +KResultOr<size_t> Process::procfs_get_file_description_link(unsigned fd, KBufferBuilder& builder) const +{ + auto file_description = m_fds.file_description(fd); + if (!file_description) + return EBADF; + auto data = file_description->absolute_path(); + builder.append(data); + return data.length(); +} -KResult ProcFSProcessFileDescriptions::traverse_as_directory(unsigned fsid, Function<bool(FileSystem::DirectoryEntryView const&)> callback) const +KResult Process::traverse_file_descriptions_directory(unsigned fsid, Function<bool(FileSystem::DirectoryEntryView const&)> callback) const { - MutexLocker locker(m_lock); - auto parent_directory = m_process_directory.strong_ref(); - if (parent_directory.is_null()) - return KResult(EINVAL); callback({ ".", { fsid, component_index() }, 0 }); - callback({ "..", { fsid, parent_directory->component_index() }, 0 }); - - auto process = parent_directory->associated_process(); - if (process.is_null()) - return KResult(ESRCH); + callback({ "..", { fsid, component_index() }, 0 }); size_t count = 0; - process->fds().enumerate([&](auto& file_description_metadata) { + fds().enumerate([&](auto& file_description_metadata) { if (!file_description_metadata.is_valid()) { count++; return; } - InodeIdentifier identifier = { fsid, file_description_metadata.global_procfs_inode_index() }; + InodeIdentifier identifier = { fsid, SegmentedProcFSIndex::build_segmented_index_for_file_description(pid(), count) }; callback({ String::number(count), identifier, 0 }); count++; }); return KSuccess; } -RefPtr<ProcFSExposedComponent> ProcFSProcessFileDescriptions::lookup(StringView name) + +RefPtr<Inode> Process::lookup_file_descriptions_directory(const ProcFS& procfs, StringView name) const { - MutexLocker locker(m_lock); - auto parent_directory = m_process_directory.strong_ref(); - if (parent_directory.is_null()) - return nullptr; - auto process = parent_directory->associated_process(); - if (process.is_null()) - return nullptr; - RefPtr<ProcFSProcessFileDescription> procfd_fd; + RefPtr<ProcFSProcessPropertyInode> file_description_link; // FIXME: Try to exit the loop earlier size_t count = 0; - process->fds().enumerate([&](auto& file_description_metadata) { + fds().enumerate([&](auto& file_description_metadata) { if (!file_description_metadata.is_valid()) { count++; return; } if (name == String::number(count)) { - procfd_fd = ProcFSProcessFileDescription::create(count, *file_description_metadata.description(), file_description_metadata.global_procfs_inode_index(), *this); + file_description_link = ProcFSProcessPropertyInode::create_for_file_description_link(procfs, static_cast<unsigned>(count), pid()); } count++; }); - return procfd_fd; + return file_description_link; } -class ProcFSProcessPledge final : public ProcFSProcessInformation { -public: - static NonnullRefPtr<ProcFSProcessPledge> create(const ProcFSProcessDirectory& parent_directory) - { - return adopt_ref(*new (nothrow) ProcFSProcessPledge(parent_directory)); - } - -private: - explicit ProcFSProcessPledge(const ProcFSProcessDirectory& parent_directory) - : ProcFSProcessInformation("pledge"sv, parent_directory) - { - } - virtual bool output(KBufferBuilder& builder) override - { - auto parent_directory = m_parent_directory.strong_ref(); - if (parent_directory.is_null()) - return false; - auto process = parent_directory->associated_process(); - if (process.is_null()) - return false; - JsonObjectSerializer obj { builder }; -#define __ENUMERATE_PLEDGE_PROMISE(x) \ - if (process->has_promised(Pledge::x)) { \ - if (!builder.is_empty()) \ - builder.append(' '); \ - builder.append(#x); \ +KResult Process::procfs_get_pledge_stats(KBufferBuilder& builder) const +{ + JsonObjectSerializer obj { builder }; +#define __ENUMERATE_PLEDGE_PROMISE(x) \ + if (has_promised(Pledge::x)) { \ + if (!builder.is_empty()) \ + builder.append(' '); \ + builder.append(#x); \ + } + if (has_promises()) { + StringBuilder builder; + ENUMERATE_PLEDGE_PROMISES + obj.add("promises", builder.build()); } - if (process->has_promises()) { - StringBuilder builder; - ENUMERATE_PLEDGE_PROMISES - obj.add("promises", builder.build()); - } #undef __ENUMERATE_PLEDGE_PROMISE - obj.finish(); - return true; - } -}; - -class ProcFSProcessUnveil final : public ProcFSProcessInformation { -public: - static NonnullRefPtr<ProcFSProcessUnveil> create(const ProcFSProcessDirectory& parent_directory) - { - return adopt_ref(*new (nothrow) ProcFSProcessUnveil(parent_directory)); - } - -private: - explicit ProcFSProcessUnveil(const ProcFSProcessDirectory& parent_directory) - : ProcFSProcessInformation("unveil"sv, parent_directory) - { - } - virtual bool output(KBufferBuilder& builder) override - { - auto parent_directory = m_parent_directory.strong_ref(); - if (parent_directory.is_null()) - return false; - auto process = parent_directory->associated_process(); - if (process.is_null()) - return false; - JsonArraySerializer array { builder }; - for (auto& unveiled_path : process->unveiled_paths()) { - if (!unveiled_path.was_explicitly_unveiled()) - continue; - auto obj = array.add_object(); - obj.add("path", unveiled_path.path()); - StringBuilder permissions_builder; - if (unveiled_path.permissions() & UnveilAccess::Read) - permissions_builder.append('r'); - if (unveiled_path.permissions() & UnveilAccess::Write) - permissions_builder.append('w'); - if (unveiled_path.permissions() & UnveilAccess::Execute) - permissions_builder.append('x'); - if (unveiled_path.permissions() & UnveilAccess::CreateOrRemove) - permissions_builder.append('c'); - if (unveiled_path.permissions() & UnveilAccess::Browse) - permissions_builder.append('b'); - obj.add("permissions", permissions_builder.to_string()); - } - array.finish(); - return true; - } -}; - -class ProcFSProcessPerformanceEvents final : public ProcFSProcessInformation { -public: - static NonnullRefPtr<ProcFSProcessPerformanceEvents> create(const ProcFSProcessDirectory& parent_directory) - { - return adopt_ref(*new (nothrow) ProcFSProcessPerformanceEvents(parent_directory)); - } - -private: - explicit ProcFSProcessPerformanceEvents(const ProcFSProcessDirectory& parent_directory) - : ProcFSProcessInformation("perf_events"sv, parent_directory) - { - } - virtual bool output(KBufferBuilder& builder) override - { - InterruptDisabler disabler; - auto parent_directory = m_parent_directory.strong_ref(); - if (parent_directory.is_null()) - return false; - auto process = parent_directory->associated_process(); - if (process.is_null()) - return false; - if (!process->perf_events()) { - dbgln("ProcFS: No perf events for {}", process->pid()); - return false; - } - return process->perf_events()->to_json(builder); - } -}; + obj.finish(); + return KSuccess; +} -class ProcFSProcessOverallFileDescriptions final : public ProcFSProcessInformation { -public: - static NonnullRefPtr<ProcFSProcessOverallFileDescriptions> create(const ProcFSProcessDirectory& parent_directory) - { - return adopt_ref(*new (nothrow) ProcFSProcessOverallFileDescriptions(parent_directory)); - } +KResult Process::procfs_get_unveil_stats(KBufferBuilder& builder) const +{ + JsonArraySerializer array { builder }; + for (auto& unveiled_path : unveiled_paths()) { + if (!unveiled_path.was_explicitly_unveiled()) + continue; + auto obj = array.add_object(); + obj.add("path", unveiled_path.path()); + StringBuilder permissions_builder; + if (unveiled_path.permissions() & UnveilAccess::Read) + permissions_builder.append('r'); + if (unveiled_path.permissions() & UnveilAccess::Write) + permissions_builder.append('w'); + if (unveiled_path.permissions() & UnveilAccess::Execute) + permissions_builder.append('x'); + if (unveiled_path.permissions() & UnveilAccess::CreateOrRemove) + permissions_builder.append('c'); + if (unveiled_path.permissions() & UnveilAccess::Browse) + permissions_builder.append('b'); + obj.add("permissions", permissions_builder.to_string()); + } + array.finish(); + return KSuccess; +} -private: - explicit ProcFSProcessOverallFileDescriptions(const ProcFSProcessDirectory& parent_directory) - : ProcFSProcessInformation("fds"sv, parent_directory) - { +KResult Process::procfs_get_perf_events(KBufferBuilder& builder) const +{ + InterruptDisabler disabler; + if (!const_cast<Process&>(*this).perf_events()) { + dbgln("ProcFS: No perf events for {}", pid()); + return KResult(ENOBUFS); } - virtual bool output(KBufferBuilder& builder) override - { - auto parent_directory = m_parent_directory.strong_ref(); - if (parent_directory.is_null()) - return false; - JsonArraySerializer array { builder }; - auto process = parent_directory->associated_process(); - if (process.is_null()) - return false; - if (process->fds().open_count() == 0) { - array.finish(); - return true; - } - - size_t count = 0; - process->fds().enumerate([&](auto& file_description_metadata) { - if (!file_description_metadata.is_valid()) { - count++; - return; - } - bool cloexec = file_description_metadata.flags() & FD_CLOEXEC; - RefPtr<FileDescription> description = file_description_metadata.description(); - auto description_object = array.add_object(); - description_object.add("fd", count); - description_object.add("absolute_path", description->absolute_path()); - description_object.add("seekable", description->file().is_seekable()); - description_object.add("class", description->file().class_name()); - description_object.add("offset", description->offset()); - description_object.add("cloexec", cloexec); - description_object.add("blocking", description->is_blocking()); - description_object.add("can_read", description->can_read()); - description_object.add("can_write", description->can_write()); - count++; - }); + return const_cast<Process&>(*this).perf_events()->to_json(builder) ? KSuccess : KResult(EINVAL); +} +KResult Process::procfs_get_fds_stats(KBufferBuilder& builder) const +{ + JsonArraySerializer array { builder }; + if (fds().open_count() == 0) { array.finish(); - return true; - } -}; - -class ProcFSProcessRoot final : public ProcFSExposedLink { -public: - static NonnullRefPtr<ProcFSProcessRoot> create(const ProcFSProcessDirectory& parent_directory) - { - return adopt_ref(*new (nothrow) ProcFSProcessRoot(parent_directory)); - } - -private: - explicit ProcFSProcessRoot(const ProcFSProcessDirectory& parent_directory) - : ProcFSExposedLink("root"sv) - , m_parent_process_directory(parent_directory) - { - } - virtual bool acquire_link(KBufferBuilder& builder) override - { - auto parent_directory = m_parent_process_directory.strong_ref(); - if (parent_directory.is_null()) - return false; - auto process = parent_directory->associated_process(); - if (process.is_null()) - return false; - builder.append_bytes(process->root_directory_relative_to_global_root().absolute_path().to_byte_buffer()); - return true; - } - WeakPtr<ProcFSProcessDirectory> m_parent_process_directory; -}; - -class ProcFSProcessVirtualMemory final : public ProcFSProcessInformation { -public: - static NonnullRefPtr<ProcFSProcessRoot> create(const ProcFSProcessDirectory& parent_directory) - { - return adopt_ref(*new (nothrow) ProcFSProcessVirtualMemory(parent_directory)); + return KSuccess; } -private: - explicit ProcFSProcessVirtualMemory(const ProcFSProcessDirectory& parent_directory) - : ProcFSProcessInformation("vm"sv, parent_directory) - { - } - virtual bool output(KBufferBuilder& builder) override - { - auto parent_directory = m_parent_directory.strong_ref(); - if (parent_directory.is_null()) - return false; - auto process = parent_directory->associated_process(); - if (process.is_null()) - return false; - JsonArraySerializer array { builder }; - { - ScopedSpinLock lock(process->address_space().get_lock()); - for (auto& region : process->address_space().regions()) { - if (!region->is_user() && !Process::current()->is_superuser()) - continue; - auto region_object = array.add_object(); - region_object.add("readable", region->is_readable()); - region_object.add("writable", region->is_writable()); - region_object.add("executable", region->is_executable()); - region_object.add("stack", region->is_stack()); - region_object.add("shared", region->is_shared()); - region_object.add("syscall", region->is_syscall_region()); - region_object.add("purgeable", region->vmobject().is_anonymous()); - if (region->vmobject().is_anonymous()) { - region_object.add("volatile", static_cast<Memory::AnonymousVMObject const&>(region->vmobject()).is_volatile()); - } - region_object.add("cacheable", region->is_cacheable()); - region_object.add("address", region->vaddr().get()); - region_object.add("size", region->size()); - region_object.add("amount_resident", region->amount_resident()); - region_object.add("amount_dirty", region->amount_dirty()); - region_object.add("cow_pages", region->cow_pages()); - region_object.add("name", region->name()); - region_object.add("vmobject", region->vmobject().class_name()); - - StringBuilder pagemap_builder; - for (size_t i = 0; i < region->page_count(); ++i) { - auto* page = region->physical_page(i); - if (!page) - pagemap_builder.append('N'); - else if (page->is_shared_zero_page() || page->is_lazy_committed_page()) - pagemap_builder.append('Z'); - else - pagemap_builder.append('P'); - } - region_object.add("pagemap", pagemap_builder.to_string()); - } + size_t count = 0; + fds().enumerate([&](auto& file_description_metadata) { + if (!file_description_metadata.is_valid()) { + count++; + return; } - array.finish(); - return true; - } -}; - -class ProcFSProcessCurrentWorkDirectory final : public ProcFSExposedLink { -public: - static NonnullRefPtr<ProcFSProcessCurrentWorkDirectory> create(const ProcFSProcessDirectory& parent_directory) - { - return adopt_ref(*new (nothrow) ProcFSProcessCurrentWorkDirectory(parent_directory)); - } - -private: - explicit ProcFSProcessCurrentWorkDirectory(const ProcFSProcessDirectory& parent_directory) - : ProcFSExposedLink("cwd"sv) - , m_parent_process_directory(parent_directory) - { - } - virtual bool acquire_link(KBufferBuilder& builder) override - { - auto parent_directory = m_parent_process_directory.strong_ref(); - if (parent_directory.is_null()) - return false; - auto process = parent_directory->associated_process(); - if (process.is_null()) - return false; - builder.append_bytes(process->current_directory().absolute_path().bytes()); - return true; - } - - WeakPtr<ProcFSProcessDirectory> m_parent_process_directory; -}; - -class ProcFSProcessBinary final : public ProcFSExposedLink { -public: - static NonnullRefPtr<ProcFSProcessBinary> create(const ProcFSProcessDirectory& parent_directory) - { - return adopt_ref(*new (nothrow) ProcFSProcessBinary(parent_directory)); - } - - virtual mode_t required_mode() const override - { - auto parent_directory = m_parent_process_directory.strong_ref(); - if (parent_directory.is_null()) - return false; - auto process = parent_directory->associated_process(); - if (process.is_null()) - return false; - if (!process->executable()) - return 0; - return ProcFSExposedComponent::required_mode(); - } - -private: - explicit ProcFSProcessBinary(const ProcFSProcessDirectory& parent_directory) - : ProcFSExposedLink("exe"sv) - , m_parent_process_directory(parent_directory) - { - } - virtual bool acquire_link(KBufferBuilder& builder) override - { - auto parent_directory = m_parent_process_directory.strong_ref(); - if (parent_directory.is_null()) - return false; - auto process = parent_directory->associated_process(); - if (process.is_null()) - return false; - auto* custody = process->executable(); - if (!custody) - return false; - builder.append(custody->absolute_path().bytes()); - return true; - } - - WeakPtr<ProcFSProcessDirectory> m_parent_process_directory; -}; + bool cloexec = file_description_metadata.flags() & FD_CLOEXEC; + RefPtr<FileDescription> description = file_description_metadata.description(); + auto description_object = array.add_object(); + description_object.add("fd", count); + description_object.add("absolute_path", description->absolute_path()); + description_object.add("seekable", description->file().is_seekable()); + description_object.add("class", description->file().class_name()); + description_object.add("offset", description->offset()); + description_object.add("cloexec", cloexec); + description_object.add("blocking", description->is_blocking()); + description_object.add("can_read", description->can_read()); + description_object.add("can_write", description->can_write()); + count++; + }); -void ProcFSProcessDirectory::on_attach() -{ - VERIFY(m_components.size() == 0); - m_components.append(ProcFSProcessPledge::create(*this)); - m_components.append(ProcFSProcessUnveil::create(*this)); - m_components.append(ProcFSProcessPerformanceEvents::create(*this)); - m_components.append(ProcFSProcessFileDescriptions::create(*this)); - m_components.append(ProcFSProcessOverallFileDescriptions::create(*this)); - m_components.append(ProcFSProcessRoot::create(*this)); - m_components.append(ProcFSProcessVirtualMemory::create(*this)); - m_components.append(ProcFSProcessCurrentWorkDirectory::create(*this)); - m_components.append(ProcFSProcessBinary::create(*this)); - m_components.append(ProcFSProcessStacks::create(*this)); + array.finish(); + return KSuccess; } -RefPtr<ProcFSExposedComponent> ProcFSProcessDirectory::lookup(StringView name) +KResult Process::procfs_get_root_link(KBufferBuilder& builder) const { - // Note: we need to allocate all sub components when doing a lookup, because - // for some reason, the caller may not call ProcFSInode::attach method before calling this. - if (m_components.size() == 0) - on_attach(); - return ProcFSExposedDirectory::lookup(name); + builder.append_bytes(const_cast<Process&>(*this).root_directory_relative_to_global_root().absolute_path().to_byte_buffer()); + return KSuccess; } -KResult ProcFSProcessDirectory::refresh_data(FileDescription&) const +KResult Process::procfs_get_virtual_memory_stats(KBufferBuilder& builder) const { - if (m_components.size() != 0) - return KSuccess; - const_cast<ProcFSProcessDirectory&>(*this).on_attach(); + JsonArraySerializer array { builder }; + { + ScopedSpinLock lock(address_space().get_lock()); + for (auto& region : address_space().regions()) { + if (!region->is_user() && !Process::current()->is_superuser()) + continue; + auto region_object = array.add_object(); + region_object.add("readable", region->is_readable()); + region_object.add("writable", region->is_writable()); + region_object.add("executable", region->is_executable()); + region_object.add("stack", region->is_stack()); + region_object.add("shared", region->is_shared()); + region_object.add("syscall", region->is_syscall_region()); + region_object.add("purgeable", region->vmobject().is_anonymous()); + if (region->vmobject().is_anonymous()) { + region_object.add("volatile", static_cast<Memory::AnonymousVMObject const&>(region->vmobject()).is_volatile()); + } + region_object.add("cacheable", region->is_cacheable()); + region_object.add("address", region->vaddr().get()); + region_object.add("size", region->size()); + region_object.add("amount_resident", region->amount_resident()); + region_object.add("amount_dirty", region->amount_dirty()); + region_object.add("cow_pages", region->cow_pages()); + region_object.add("name", region->name()); + region_object.add("vmobject", region->vmobject().class_name()); + + StringBuilder pagemap_builder; + for (size_t i = 0; i < region->page_count(); ++i) { + auto* page = region->physical_page(i); + if (!page) + pagemap_builder.append('N'); + else if (page->is_shared_zero_page() || page->is_lazy_committed_page()) + pagemap_builder.append('Z'); + else + pagemap_builder.append('P'); + } + region_object.add("pagemap", pagemap_builder.to_string()); + } + } + array.finish(); return KSuccess; } -NonnullRefPtr<ProcFSProcessDirectory> ProcFSProcessDirectory::create(const Process& process) +KResult Process::procfs_get_current_work_directory_link(KBufferBuilder& builder) const { - return adopt_ref_if_nonnull(new (nothrow) ProcFSProcessDirectory(process)).release_nonnull(); + builder.append_bytes(const_cast<Process&>(*this).current_directory().absolute_path().bytes()); + return KSuccess; } -void ProcFSProcessDirectory::prepare_for_deletion() +mode_t Process::binary_link_required_mode() const { - ProcFSExposedDirectory::prepare_for_deletion(); - m_associated_process.clear(); + if (!executable()) + return 0; + return ProcFSExposedComponent::required_mode(); } -ProcFSProcessDirectory::ProcFSProcessDirectory(const Process& process) - : ProcFSExposedDirectory(String::formatted("{:d}", process.pid().value()), ProcFSComponentRegistry::the().root_directory()) - , m_associated_process(process) +KResult Process::procfs_get_binary_link(KBufferBuilder& builder) const { + auto* custody = executable(); + if (!custody) + return KResult(ENOEXEC); + builder.append(custody->absolute_path().bytes()); + return KSuccess; } } |