summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
authorLiav A <liavalb@gmail.com>2021-08-10 20:51:28 +0300
committerAndreas Kling <kling@serenityos.org>2021-08-12 20:57:32 +0200
commit7ba991dc371ecd055829699852f7cb821472667f (patch)
tree1c53f16ae0de005e8f539a15f12329453b5d4f4a /Kernel
parentbf1adc2d5d383c0421f19ccb36a0358ff2ee0ce5 (diff)
downloadserenity-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')
-rw-r--r--Kernel/FileSystem/ProcFS.cpp493
-rw-r--r--Kernel/FileSystem/ProcFS.h139
-rw-r--r--Kernel/GlobalProcessExposed.cpp34
-rw-r--r--Kernel/Process.cpp15
-rw-r--r--Kernel/Process.h37
-rw-r--r--Kernel/ProcessExposed.cpp147
-rw-r--r--Kernel/ProcessExposed.h128
-rw-r--r--Kernel/ProcessSpecificExposed.cpp717
-rw-r--r--Kernel/Thread.cpp1
-rw-r--r--Kernel/Thread.h6
10 files changed, 879 insertions, 838 deletions
diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp
index bda413bdf7..0f4f098f17 100644
--- a/Kernel/FileSystem/ProcFS.cpp
+++ b/Kernel/FileSystem/ProcFS.cpp
@@ -13,6 +13,7 @@
#include <Kernel/FileSystem/ProcFS.h>
#include <Kernel/FileSystem/VirtualFileSystem.h>
#include <Kernel/Heap/kmalloc.h>
+#include <Kernel/Process.h>
#include <Kernel/Sections.h>
#include <LibC/errno_numbers.h>
@@ -36,23 +37,14 @@ UNMAP_AFTER_INIT ProcFSComponentRegistry::ProcFSComponentRegistry()
{
}
-void ProcFSComponentRegistry::register_new_process(Process& new_process)
-{
- MutexLocker locker(m_lock);
- m_root_directory->m_process_directories.append(ProcFSProcessDirectory::create(new_process));
-}
-
-void ProcFSComponentRegistry::unregister_process(Process& deleted_process)
+RefPtr<ProcFS> ProcFS::create()
{
- auto process_directory = m_root_directory->process_directory_for(deleted_process).release_nonnull();
- process_directory->prepare_for_deletion();
- process_directory->m_list_node.remove();
- dbgln_if(PROCFS_DEBUG, "ProcFSExposedDirectory ref_count now: {}", process_directory->ref_count());
+ return adopt_ref_if_nonnull(new (nothrow) ProcFS);
}
-RefPtr<ProcFS> ProcFS::create()
+ProcFS::ProcFS()
+ : m_root_inode(ProcFSComponentRegistry::the().root_directory().to_inode(*this))
{
- return adopt_ref_if_nonnull(new (nothrow) ProcFS);
}
ProcFS::~ProcFS()
@@ -69,112 +61,112 @@ Inode& ProcFS::root_inode()
return *m_root_inode;
}
-NonnullRefPtr<ProcFSInode> ProcFSInode::create(const ProcFS& fs, const ProcFSExposedComponent& component)
+ProcFSInode::ProcFSInode(const ProcFS& fs, InodeIndex index)
+ : Inode(const_cast<ProcFS&>(fs), index)
{
- return adopt_ref(*new (nothrow) ProcFSInode(fs, component));
}
-ProcFSInode::ProcFSInode(const ProcFS& fs, const ProcFSExposedComponent& component)
- : Inode(const_cast<ProcFS&>(fs), component.component_index())
- , m_associated_component(component)
+ProcFSInode::~ProcFSInode()
{
}
-KResult ProcFSInode::attach(FileDescription& description)
+void ProcFSInode::flush_metadata()
{
- return m_associated_component->refresh_data(description);
}
-void ProcFSInode::did_seek(FileDescription& description, off_t new_offset)
+KResult ProcFSInode::add_child(Inode&, const StringView&, mode_t)
{
- if (new_offset != 0)
- return;
- auto result = m_associated_component->refresh_data(description);
- if (result.is_error()) {
- // Subsequent calls to read will return EIO!
- dbgln("ProcFS: Could not refresh contents: {}", result.error());
- }
+ return EROFS;
}
-ProcFSInode::~ProcFSInode()
+KResultOr<NonnullRefPtr<Inode>> ProcFSInode::create_child(StringView, mode_t, dev_t, uid_t, gid_t)
{
+ return EROFS;
}
-ProcFS::ProcFS()
- : m_root_inode(ProcFSComponentRegistry::the().root_directory().to_inode(*this))
+KResult ProcFSInode::remove_child(const StringView&)
{
+ return EROFS;
}
-KResultOr<size_t> ProcFSInode::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription* fd) const
+KResult ProcFSInode::chmod(mode_t)
{
- return m_associated_component->read_bytes(offset, count, buffer, fd);
+ return EPERM;
}
-StringView ProcFSInode::name() const
+KResult ProcFSInode::chown(uid_t, gid_t)
{
- return m_associated_component->name();
+ return EPERM;
}
-KResult ProcFSInode::traverse_as_directory(Function<bool(FileSystem::DirectoryEntryView const&)>) const
+KResult ProcFSInode::truncate(u64)
{
- VERIFY_NOT_REACHED();
+ return EPERM;
}
-RefPtr<Inode> ProcFSInode::lookup(StringView)
+NonnullRefPtr<ProcFSGlobalInode> ProcFSGlobalInode::create(const ProcFS& fs, const ProcFSExposedComponent& component)
{
- VERIFY_NOT_REACHED();
+ return adopt_ref(*new (nothrow) ProcFSGlobalInode(fs, component));
}
-InodeMetadata ProcFSInode::metadata() const
+ProcFSGlobalInode::ProcFSGlobalInode(const ProcFS& fs, const ProcFSExposedComponent& component)
+ : ProcFSInode(fs, component.component_index())
+ , m_associated_component(component)
{
- MutexLocker locker(m_inode_lock);
- InodeMetadata metadata;
- metadata.inode = { fsid(), m_associated_component->component_index() };
- metadata.mode = S_IFREG | m_associated_component->required_mode();
- metadata.uid = m_associated_component->owner_user();
- metadata.gid = m_associated_component->owner_group();
- metadata.size = m_associated_component->size();
- metadata.mtime = m_associated_component->modified_time();
- return metadata;
}
-void ProcFSInode::flush_metadata()
+void ProcFSGlobalInode::did_seek(FileDescription& description, off_t new_offset)
{
+ if (new_offset != 0)
+ return;
+ auto result = m_associated_component->refresh_data(description);
+ if (result.is_error()) {
+ // Subsequent calls to read will return EIO!
+ dbgln("ProcFS: Could not refresh contents: {}", result.error());
+ }
}
-KResultOr<size_t> ProcFSInode::write_bytes(off_t offset, size_t count, const UserOrKernelBuffer& buffer, FileDescription* fd)
+KResult ProcFSGlobalInode::attach(FileDescription& description)
{
- return m_associated_component->write_bytes(offset, count, buffer, fd);
+ return m_associated_component->refresh_data(description);
}
-KResultOr<NonnullRefPtr<Inode>> ProcFSInode::create_child(StringView, mode_t, dev_t, uid_t, gid_t)
+KResultOr<size_t> ProcFSGlobalInode::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription* fd) const
{
- return EROFS;
+ return m_associated_component->read_bytes(offset, count, buffer, fd);
}
-KResult ProcFSInode::add_child(Inode&, const StringView&, mode_t)
+StringView ProcFSGlobalInode::name() const
{
- return EROFS;
+ return m_associated_component->name();
}
-KResult ProcFSInode::remove_child(const StringView&)
+KResult ProcFSGlobalInode::traverse_as_directory(Function<bool(FileSystem::DirectoryEntryView const&)>) const
{
- return EROFS;
+ VERIFY_NOT_REACHED();
}
-KResult ProcFSInode::chmod(mode_t)
+RefPtr<Inode> ProcFSGlobalInode::lookup(StringView)
{
- return EPERM;
+ VERIFY_NOT_REACHED();
}
-KResult ProcFSInode::chown(uid_t, gid_t)
+InodeMetadata ProcFSGlobalInode::metadata() const
{
- return EPERM;
+ MutexLocker locker(m_inode_lock);
+ InodeMetadata metadata;
+ metadata.inode = { fsid(), m_associated_component->component_index() };
+ metadata.mode = S_IFREG | m_associated_component->required_mode();
+ metadata.uid = m_associated_component->owner_user();
+ metadata.gid = m_associated_component->owner_group();
+ metadata.size = m_associated_component->size();
+ metadata.mtime = m_associated_component->modified_time();
+ return metadata;
}
-KResult ProcFSInode::truncate(u64)
+KResultOr<size_t> ProcFSGlobalInode::write_bytes(off_t offset, size_t count, const UserOrKernelBuffer& buffer, FileDescription* fd)
{
- return EPERM;
+ return m_associated_component->write_bytes(offset, count, buffer, fd);
}
NonnullRefPtr<ProcFSDirectoryInode> ProcFSDirectoryInode::create(const ProcFS& procfs, const ProcFSExposedComponent& component)
@@ -183,7 +175,7 @@ NonnullRefPtr<ProcFSDirectoryInode> ProcFSDirectoryInode::create(const ProcFS& p
}
ProcFSDirectoryInode::ProcFSDirectoryInode(const ProcFS& fs, const ProcFSExposedComponent& component)
- : ProcFSInode(fs, component)
+ : ProcFSGlobalInode(fs, component)
{
}
@@ -204,17 +196,17 @@ InodeMetadata ProcFSDirectoryInode::metadata() const
}
KResult ProcFSDirectoryInode::traverse_as_directory(Function<bool(FileSystem::DirectoryEntryView const&)> callback) const
{
- MutexLocker locker(fs().m_lock);
- return m_associated_component->traverse_as_directory(fs().fsid(), move(callback));
+ MutexLocker locker(procfs().m_lock);
+ return m_associated_component->traverse_as_directory(procfs().fsid(), move(callback));
}
RefPtr<Inode> ProcFSDirectoryInode::lookup(StringView name)
{
- MutexLocker locker(fs().m_lock);
+ MutexLocker locker(procfs().m_lock);
auto component = m_associated_component->lookup(name);
if (!component)
return {};
- return component->to_inode(fs());
+ return component->to_inode(procfs());
}
NonnullRefPtr<ProcFSLinkInode> ProcFSLinkInode::create(const ProcFS& procfs, const ProcFSExposedComponent& component)
@@ -223,9 +215,10 @@ NonnullRefPtr<ProcFSLinkInode> ProcFSLinkInode::create(const ProcFS& procfs, con
}
ProcFSLinkInode::ProcFSLinkInode(const ProcFS& fs, const ProcFSExposedComponent& component)
- : ProcFSInode(fs, component)
+ : ProcFSGlobalInode(fs, component)
{
}
+
InodeMetadata ProcFSLinkInode::metadata() const
{
MutexLocker locker(m_inode_lock);
@@ -239,4 +232,364 @@ InodeMetadata ProcFSLinkInode::metadata() const
return metadata;
}
+ProcFSProcessAssociatedInode::ProcFSProcessAssociatedInode(const ProcFS& fs, ProcessID associated_pid, InodeIndex determined_index)
+ : ProcFSInode(fs, determined_index)
+ , m_pid(associated_pid)
+{
+}
+
+KResultOr<size_t> ProcFSProcessAssociatedInode::write_bytes(off_t, size_t, const UserOrKernelBuffer&, FileDescription*)
+{
+ VERIFY_NOT_REACHED();
+}
+
+NonnullRefPtr<ProcFSProcessDirectoryInode> ProcFSProcessDirectoryInode::create(const ProcFS& procfs, ProcessID pid)
+{
+ return adopt_ref_if_nonnull(new (nothrow) ProcFSProcessDirectoryInode(procfs, pid)).release_nonnull();
+}
+
+ProcFSProcessDirectoryInode::ProcFSProcessDirectoryInode(const ProcFS& procfs, ProcessID pid)
+ : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_pid_directory(pid))
+{
+}
+
+KResult ProcFSProcessDirectoryInode::attach(FileDescription&)
+{
+ return KSuccess;
+}
+
+InodeMetadata ProcFSProcessDirectoryInode::metadata() const
+{
+ MutexLocker locker(m_inode_lock);
+ auto process = Process::from_pid(associated_pid());
+ if (!process)
+ return {};
+ InodeMetadata metadata;
+ metadata.inode = { fsid(), process->component_index() };
+ metadata.mode = S_IFDIR | process->required_mode();
+ metadata.uid = process->owner_user();
+ metadata.gid = process->owner_group();
+ metadata.size = 0;
+ metadata.mtime = process->modified_time();
+ return metadata;
+}
+
+KResultOr<size_t> ProcFSProcessDirectoryInode::read_bytes(off_t, size_t, UserOrKernelBuffer&, FileDescription*) const
+{
+ VERIFY_NOT_REACHED();
+}
+
+KResult ProcFSProcessDirectoryInode::traverse_as_directory(Function<bool(FileSystem::DirectoryEntryView const&)> callback) const
+{
+ MutexLocker locker(procfs().m_lock);
+ auto process = Process::from_pid(associated_pid());
+ if (!process)
+ return EINVAL;
+ return process->traverse_as_directory(procfs().fsid(), move(callback));
+}
+
+RefPtr<Inode> ProcFSProcessDirectoryInode::lookup(StringView name)
+{
+ MutexLocker locker(procfs().m_lock);
+ auto process = Process::from_pid(associated_pid());
+ if (!process)
+ return nullptr;
+ if (name == "fd")
+ return ProcFSProcessSubDirectoryInode::create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::FileDescriptions, associated_pid());
+ if (name == "stacks")
+ return ProcFSProcessSubDirectoryInode::create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks, associated_pid());
+ if (name == "unveil")
+ return ProcFSProcessPropertyInode::create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::Unveil, associated_pid());
+ if (name == "pledge")
+ return ProcFSProcessPropertyInode::create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::Pledge, associated_pid());
+ if (name == "fds")
+ return ProcFSProcessPropertyInode::create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::FileDescriptions, associated_pid());
+ if (name == "exe")
+ return ProcFSProcessPropertyInode::create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::BinaryLink, associated_pid());
+ if (name == "cwd")
+ return ProcFSProcessPropertyInode::create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink, associated_pid());
+ if (name == "perf_events")
+ return ProcFSProcessPropertyInode::create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents, associated_pid());
+ if (name == "vm")
+ return ProcFSProcessPropertyInode::create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats, associated_pid());
+ if (name == "root")
+ return ProcFSProcessPropertyInode::create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::RootLink, associated_pid());
+ return nullptr;
+}
+
+NonnullRefPtr<ProcFSProcessSubDirectoryInode> ProcFSProcessSubDirectoryInode::create(const ProcFS& procfs, SegmentedProcFSIndex::ProcessSubDirectory sub_directory_type, ProcessID pid)
+{
+ return adopt_ref_if_nonnull(new (nothrow) ProcFSProcessSubDirectoryInode(procfs, sub_directory_type, pid)).release_nonnull();
+}
+
+ProcFSProcessSubDirectoryInode::ProcFSProcessSubDirectoryInode(const ProcFS& procfs, SegmentedProcFSIndex::ProcessSubDirectory sub_directory_type, ProcessID pid)
+ : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(pid, sub_directory_type))
+ , m_sub_directory_type(sub_directory_type)
+{
+}
+
+KResultOr<size_t> ProcFSProcessSubDirectoryInode::read_bytes(off_t, size_t, UserOrKernelBuffer&, FileDescription*) const
+{
+ VERIFY_NOT_REACHED();
+}
+
+KResult ProcFSProcessSubDirectoryInode::attach(FileDescription&)
+{
+ return KSuccess;
+}
+
+void ProcFSProcessSubDirectoryInode::did_seek(FileDescription&, off_t)
+{
+ VERIFY_NOT_REACHED();
+}
+
+InodeMetadata ProcFSProcessSubDirectoryInode::metadata() const
+{
+ MutexLocker locker(m_inode_lock);
+ auto process = Process::from_pid(associated_pid());
+ if (!process)
+ return {};
+ InodeMetadata metadata;
+ metadata.inode = { fsid(), process->component_index() };
+ metadata.mode = S_IFDIR | process->required_mode();
+ metadata.uid = process->owner_user();
+ metadata.gid = process->owner_group();
+ metadata.size = 0;
+ metadata.mtime = process->modified_time();
+ return metadata;
+}
+
+KResult ProcFSProcessSubDirectoryInode::traverse_as_directory(Function<bool(FileSystem::DirectoryEntryView const&)> callback) const
+{
+ MutexLocker locker(procfs().m_lock);
+ auto process = Process::from_pid(associated_pid());
+ if (!process)
+ return EINVAL;
+ switch (m_sub_directory_type) {
+ case SegmentedProcFSIndex::ProcessSubDirectory::FileDescriptions:
+ return process->traverse_file_descriptions_directory(procfs().fsid(), move(callback));
+ case SegmentedProcFSIndex::ProcessSubDirectory::Stacks:
+ return process->traverse_stacks_directory(procfs().fsid(), move(callback));
+ default:
+ VERIFY_NOT_REACHED();
+ }
+ VERIFY_NOT_REACHED();
+}
+
+RefPtr<Inode> ProcFSProcessSubDirectoryInode::lookup(StringView name)
+{
+ MutexLocker locker(procfs().m_lock);
+ auto process = Process::from_pid(associated_pid());
+ if (!process)
+ return {};
+ switch (m_sub_directory_type) {
+ case SegmentedProcFSIndex::ProcessSubDirectory::FileDescriptions:
+ return process->lookup_file_descriptions_directory(procfs(), name);
+ case SegmentedProcFSIndex::ProcessSubDirectory::Stacks:
+ return process->lookup_stacks_directory(procfs(), name);
+ default:
+ VERIFY_NOT_REACHED();
+ }
+ VERIFY_NOT_REACHED();
+}
+
+NonnullRefPtr<ProcFSProcessPropertyInode> ProcFSProcessPropertyInode::create_for_file_description_link(const ProcFS& procfs, unsigned file_description_index, ProcessID pid)
+{
+ return adopt_ref_if_nonnull(new (nothrow) ProcFSProcessPropertyInode(procfs, file_description_index, pid)).release_nonnull();
+}
+NonnullRefPtr<ProcFSProcessPropertyInode> ProcFSProcessPropertyInode::create_for_thread_stack(const ProcFS& procfs, ThreadID stack_thread_index, ProcessID pid)
+{
+ return adopt_ref_if_nonnull(new (nothrow) ProcFSProcessPropertyInode(procfs, stack_thread_index, pid)).release_nonnull();
+}
+NonnullRefPtr<ProcFSProcessPropertyInode> ProcFSProcessPropertyInode::create_for_pid_property(const ProcFS& procfs, SegmentedProcFSIndex::MainProcessProperty main_property_type, ProcessID pid)
+{
+ return adopt_ref_if_nonnull(new (nothrow) ProcFSProcessPropertyInode(procfs, main_property_type, pid)).release_nonnull();
+}
+
+ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(const ProcFS& procfs, SegmentedProcFSIndex::MainProcessProperty main_property_type, ProcessID pid)
+ : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid, main_property_type))
+ , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Reserved)
+{
+ m_possible_data.property_type = main_property_type;
+}
+
+ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(const ProcFS& procfs, unsigned file_description_index, ProcessID pid)
+ : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_file_description(pid, file_description_index))
+ , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::FileDescriptions)
+{
+ m_possible_data.property_index = file_description_index;
+}
+
+ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(const ProcFS& procfs, ThreadID thread_stack_index, ProcessID pid)
+ : ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_thread_stack(pid, thread_stack_index))
+ , m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Stacks)
+{
+ m_possible_data.property_index = thread_stack_index.value();
+}
+
+KResult ProcFSProcessPropertyInode::attach(FileDescription& description)
+{
+ return refresh_data(description);
+}
+void ProcFSProcessPropertyInode::did_seek(FileDescription& description, off_t offset)
+{
+ if (offset != 0)
+ return;
+ (void)refresh_data(description);
+}
+
+static mode_t determine_procfs_process_inode_mode(SegmentedProcFSIndex::ProcessSubDirectory parent_sub_directory_type, SegmentedProcFSIndex::MainProcessProperty main_property)
+{
+ if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::FileDescriptions)
+ return S_IFLNK | 0400;
+ if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Stacks)
+ return S_IFREG | 0400;
+ VERIFY(parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Reserved);
+ if (main_property == SegmentedProcFSIndex::MainProcessProperty::BinaryLink)
+ return S_IFLNK | 0777;
+ if (main_property == SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink)
+ return S_IFLNK | 0777;
+ if (main_property == SegmentedProcFSIndex::MainProcessProperty::RootLink)
+ return S_IFLNK | 0777;
+ return S_IFREG | 0400;
+}
+
+InodeMetadata ProcFSProcessPropertyInode::metadata() const
+{
+ MutexLocker locker(m_inode_lock);
+ auto process = Process::from_pid(associated_pid());
+ if (!process)
+ return {};
+ InodeMetadata metadata;
+ metadata.inode = { fsid(), process->component_index() };
+ metadata.mode = determine_procfs_process_inode_mode(m_parent_sub_directory_type, m_possible_data.property_type);
+ metadata.uid = process->owner_user();
+ metadata.gid = process->owner_group();
+ metadata.size = 0;
+ metadata.mtime = process->modified_time();
+ return metadata;
+}
+KResult ProcFSProcessPropertyInode::traverse_as_directory(Function<bool(FileSystem::DirectoryEntryView const&)>) const
+{
+ VERIFY_NOT_REACHED();
+}
+KResultOr<size_t> ProcFSProcessPropertyInode::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription* description) const
+{
+ dbgln_if(PROCFS_DEBUG, "ProcFS ProcessInformation: read_bytes offset: {} count: {}", offset, count);
+
+ VERIFY(offset >= 0);
+ VERIFY(buffer.user_or_kernel_ptr());
+
+ if (!description) {
+ KBufferBuilder builder;
+ auto process = Process::from_pid(associated_pid());
+ if (!process)
+ return KResult(ESRCH);
+ if (auto result = try_to_acquire_data(*process, builder); result.is_error())
+ return result.error();
+ auto data_buffer = builder.build();
+ if (!data_buffer)
+ return KResult(EFAULT);
+ ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
+ if (!buffer.write(data_buffer->data() + offset, nread))
+ return KResult(EFAULT);
+ return nread;
+ }
+ if (!description->data()) {
+ dbgln("ProcFS Process Information: Do not have cached data!");
+ return KResult(EIO);
+ }
+
+ MutexLocker locker(m_refresh_lock);
+
+ auto& typed_cached_data = static_cast<ProcFSInodeData&>(*description->data());
+ auto& data_buffer = typed_cached_data.buffer;
+
+ if (!data_buffer || (size_t)offset >= data_buffer->size())
+ return 0;
+
+ ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
+ if (!buffer.write(data_buffer->data() + offset, nread))
+ return KResult(EFAULT);
+
+ return nread;
+}
+RefPtr<Inode> ProcFSProcessPropertyInode::lookup(StringView)
+{
+ VERIFY_NOT_REACHED();
+}
+
+static KResult build_from_cached_data(KBufferBuilder& builder, ProcFSInodeData& cached_data)
+{
+ cached_data.buffer = builder.build();
+ if (!cached_data.buffer)
+ return ENOMEM;
+ return KSuccess;
+}
+
+KResult ProcFSProcessPropertyInode::try_to_acquire_data(Process& process, KBufferBuilder& builder) const
+{
+ // FIXME: Verify process is already ref-counted
+ if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::FileDescriptions) {
+ if (auto result = process.procfs_get_file_description_link(m_possible_data.property_index, builder); result.is_error())
+ return result.error();
+ return KSuccess;
+ }
+ if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Stacks) {
+ if (auto result = process.procfs_get_thread_stack(m_possible_data.property_index, builder); result.is_error())
+ return result.error();
+ return KSuccess;
+ }
+
+ VERIFY(m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Reserved);
+ switch (m_possible_data.property_type) {
+ case SegmentedProcFSIndex::MainProcessProperty::Unveil:
+ return process.procfs_get_fds_stats(builder);
+ case SegmentedProcFSIndex::MainProcessProperty::Pledge:
+ return process.procfs_get_pledge_stats(builder);
+ case SegmentedProcFSIndex::MainProcessProperty::FileDescriptions:
+ return process.procfs_get_fds_stats(builder);
+ case SegmentedProcFSIndex::MainProcessProperty::BinaryLink:
+ return process.procfs_get_binary_link(builder);
+ case SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink:
+ return process.procfs_get_current_work_directory_link(builder);
+ case SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents:
+ return process.procfs_get_perf_events(builder);
+ case SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats:
+ return process.procfs_get_virtual_memory_stats(builder);
+ case SegmentedProcFSIndex::MainProcessProperty::RootLink:
+ return process.procfs_get_root_link(builder);
+ default:
+ VERIFY_NOT_REACHED();
+ }
+}
+
+KResult ProcFSProcessPropertyInode::refresh_data(FileDescription& description)
+{
+ // For process-specific inodes, hold the process's ptrace lock across refresh
+ // and refuse to load data if the process is not dumpable.
+ // Without this, files opened before a process went non-dumpable could still be used for dumping.
+ auto process = Process::from_pid(associated_pid());
+ if (!process)
+ return KResult(ESRCH);
+ process->ptrace_lock().lock();
+ if (!process->is_dumpable()) {
+ process->ptrace_lock().unlock();
+ return EPERM;
+ }
+ ScopeGuard guard = [&] {
+ process->ptrace_lock().unlock();
+ };
+ MutexLocker locker(m_refresh_lock);
+ auto& cached_data = description.data();
+ if (!cached_data) {
+ cached_data = adopt_own_if_nonnull(new (nothrow) ProcFSInodeData);
+ if (!cached_data)
+ return ENOMEM;
+ }
+ KBufferBuilder builder;
+ if (auto result = try_to_acquire_data(*process, builder); result.is_error())
+ return result;
+ return build_from_cached_data(builder, static_cast<ProcFSInodeData&>(*cached_data));
+}
}
diff --git a/Kernel/FileSystem/ProcFS.h b/Kernel/FileSystem/ProcFS.h
index 9ffecfedf8..49b4d89b44 100644
--- a/Kernel/FileSystem/ProcFS.h
+++ b/Kernel/FileSystem/ProcFS.h
@@ -14,12 +14,17 @@
#include <Kernel/KBufferBuilder.h>
#include <Kernel/Locking/Mutex.h>
#include <Kernel/ProcessExposed.h>
+#include <Kernel/UnixTypes.h>
namespace Kernel {
class ProcFS final : public FileSystem {
friend class ProcFSInode;
friend class ProcFSDirectoryInode;
+ friend class ProcFSProcessDirectoryInode;
+ friend class ProcFSGlobalInode;
+ friend class ProcFSAssociatedProcessInode;
+ friend class ProcFSProcessSubDirectoryInode;
public:
virtual ~ProcFS() override;
@@ -40,33 +45,50 @@ class ProcFSInode : public Inode {
friend class ProcFS;
public:
- static NonnullRefPtr<ProcFSInode> create(const ProcFS&, const ProcFSExposedComponent&);
virtual ~ProcFSInode() override;
+
+protected:
+ ProcFSInode(const ProcFS&, InodeIndex);
+
+ ProcFS& procfs() { return static_cast<ProcFS&>(Inode::fs()); }
+ ProcFS const& procfs() const { return static_cast<ProcFS const&>(Inode::fs()); }
+
+ // ^Inode
+ virtual KResult attach(FileDescription& description) = 0;
+ virtual void did_seek(FileDescription&, off_t) = 0;
+ virtual void flush_metadata() override final;
+ virtual KResultOr<NonnullRefPtr<Inode>> create_child(StringView name, mode_t, dev_t, uid_t, gid_t) override final;
+ virtual KResult add_child(Inode&, const StringView& name, mode_t) override final;
+ virtual KResult remove_child(const StringView& name) override final;
+ virtual KResult chmod(mode_t) override final;
+ virtual KResult chown(uid_t, gid_t) override final;
+ virtual KResult truncate(u64) override final;
+};
+
+class ProcFSGlobalInode : public ProcFSInode {
+ friend class ProcFS;
+
+public:
+ static NonnullRefPtr<ProcFSGlobalInode> create(const ProcFS&, const ProcFSExposedComponent&);
+ virtual ~ProcFSGlobalInode() override {};
StringView name() const;
protected:
- ProcFSInode(const ProcFS&, const ProcFSExposedComponent&);
+ ProcFSGlobalInode(const ProcFS&, const ProcFSExposedComponent&);
// ^Inode
- virtual KResult attach(FileDescription& description) override;
- virtual KResultOr<size_t> read_bytes(off_t, size_t, UserOrKernelBuffer& buffer, FileDescription*) const override;
- virtual KResult traverse_as_directory(Function<bool(FileSystem::DirectoryEntryView const&)>) const override;
- virtual RefPtr<Inode> lookup(StringView name) override;
- virtual void flush_metadata() override;
+ virtual KResult attach(FileDescription& description) override final;
+ virtual KResultOr<size_t> read_bytes(off_t, size_t, UserOrKernelBuffer& buffer, FileDescription*) const override final;
+ virtual KResultOr<size_t> write_bytes(off_t, size_t, const UserOrKernelBuffer& buffer, FileDescription*) override final;
+ virtual void did_seek(FileDescription&, off_t) override final;
virtual InodeMetadata metadata() const override;
- virtual KResultOr<size_t> write_bytes(off_t, size_t, const UserOrKernelBuffer& buffer, FileDescription*) override;
- virtual KResultOr<NonnullRefPtr<Inode>> create_child(StringView name, mode_t, dev_t, uid_t, gid_t) override;
- virtual KResult add_child(Inode&, const StringView& name, mode_t) override;
- virtual KResult remove_child(const StringView& name) override;
- virtual void did_seek(FileDescription&, off_t) override;
- virtual KResult chmod(mode_t) override;
- virtual KResult chown(uid_t, gid_t) override;
- virtual KResult truncate(u64) override;
+ virtual KResult traverse_as_directory(Function<bool(FileSystem::DirectoryEntryView const&)>) const override;
+ virtual RefPtr<Inode> lookup(StringView) override;
NonnullRefPtr<ProcFSExposedComponent> m_associated_component;
};
-class ProcFSLinkInode : public ProcFSInode {
+class ProcFSLinkInode : public ProcFSGlobalInode {
friend class ProcFS;
public:
@@ -77,16 +99,13 @@ protected:
virtual InodeMetadata metadata() const override;
};
-class ProcFSDirectoryInode : public ProcFSInode {
+class ProcFSDirectoryInode final : public ProcFSGlobalInode {
friend class ProcFS;
public:
static NonnullRefPtr<ProcFSDirectoryInode> create(const ProcFS&, const ProcFSExposedComponent&);
virtual ~ProcFSDirectoryInode() override;
- ProcFS& fs() { return static_cast<ProcFS&>(Inode::fs()); }
- ProcFS const& fs() const { return static_cast<ProcFS const&>(Inode::fs()); }
-
protected:
ProcFSDirectoryInode(const ProcFS&, const ProcFSExposedComponent&);
// ^Inode
@@ -95,4 +114,84 @@ protected:
virtual RefPtr<Inode> lookup(StringView name) override;
};
+class ProcFSProcessAssociatedInode : public ProcFSInode {
+ friend class ProcFS;
+
+protected:
+ ProcFSProcessAssociatedInode(const ProcFS&, ProcessID, InodeIndex);
+ ProcessID associated_pid() const { return m_pid; }
+
+ // ^Inode
+ virtual KResultOr<size_t> write_bytes(off_t, size_t, const UserOrKernelBuffer& buffer, FileDescription*) override final;
+
+private:
+ const ProcessID m_pid;
+};
+
+class ProcFSProcessDirectoryInode final : public ProcFSProcessAssociatedInode {
+ friend class ProcFS;
+
+public:
+ static NonnullRefPtr<ProcFSProcessDirectoryInode> create(const ProcFS&, ProcessID);
+
+private:
+ ProcFSProcessDirectoryInode(const ProcFS&, ProcessID);
+ // ^Inode
+ virtual KResult attach(FileDescription& description) override;
+ virtual void did_seek(FileDescription&, off_t) override { }
+ virtual InodeMetadata metadata() const override;
+ virtual KResult traverse_as_directory(Function<bool(FileSystem::DirectoryEntryView const&)>) const override;
+ virtual KResultOr<size_t> read_bytes(off_t, size_t, UserOrKernelBuffer& buffer, FileDescription*) const override final;
+ virtual RefPtr<Inode> lookup(StringView name) override;
+};
+
+class ProcFSProcessSubDirectoryInode final : public ProcFSProcessAssociatedInode {
+ friend class ProcFS;
+
+public:
+ static NonnullRefPtr<ProcFSProcessSubDirectoryInode> create(const ProcFS&, SegmentedProcFSIndex::ProcessSubDirectory, ProcessID);
+
+private:
+ ProcFSProcessSubDirectoryInode(const ProcFS&, SegmentedProcFSIndex::ProcessSubDirectory, ProcessID);
+ // ^Inode
+ virtual KResult attach(FileDescription& description) override;
+ virtual void did_seek(FileDescription&, off_t) override;
+ virtual InodeMetadata metadata() const override;
+ virtual KResult traverse_as_directory(Function<bool(FileSystem::DirectoryEntryView const&)>) const override;
+ virtual KResultOr<size_t> read_bytes(off_t, size_t, UserOrKernelBuffer& buffer, FileDescription*) const override final;
+ virtual RefPtr<Inode> lookup(StringView name) override;
+
+ const SegmentedProcFSIndex::ProcessSubDirectory m_sub_directory_type;
+};
+
+class ProcFSProcessPropertyInode final : public ProcFSProcessAssociatedInode {
+ friend class ProcFS;
+
+public:
+ static NonnullRefPtr<ProcFSProcessPropertyInode> create_for_file_description_link(const ProcFS&, unsigned, ProcessID);
+ static NonnullRefPtr<ProcFSProcessPropertyInode> create_for_thread_stack(const ProcFS&, ThreadID, ProcessID);
+ static NonnullRefPtr<ProcFSProcessPropertyInode> create_for_pid_property(const ProcFS&, SegmentedProcFSIndex::MainProcessProperty, ProcessID);
+
+private:
+ ProcFSProcessPropertyInode(const ProcFS&, SegmentedProcFSIndex::MainProcessProperty, ProcessID);
+ ProcFSProcessPropertyInode(const ProcFS&, ThreadID, ProcessID);
+ ProcFSProcessPropertyInode(const ProcFS&, unsigned, ProcessID);
+ // ^Inode
+ virtual KResult attach(FileDescription& description) override;
+ virtual void did_seek(FileDescription&, off_t) override;
+ virtual InodeMetadata metadata() const override;
+ virtual KResult traverse_as_directory(Function<bool(FileSystem::DirectoryEntryView const&)>) const override;
+ virtual KResultOr<size_t> read_bytes(off_t, size_t, UserOrKernelBuffer& buffer, FileDescription*) const override final;
+ virtual RefPtr<Inode> lookup(StringView name) override final;
+
+ KResult refresh_data(FileDescription& description);
+ KResult try_to_acquire_data(Process& process, KBufferBuilder& builder) const;
+
+ const SegmentedProcFSIndex::ProcessSubDirectory m_parent_sub_directory_type;
+ union {
+ SegmentedProcFSIndex::MainProcessProperty property_type;
+ unsigned property_index;
+ } m_possible_data;
+ mutable Mutex m_refresh_lock;
+};
}
diff --git a/Kernel/GlobalProcessExposed.cpp b/Kernel/GlobalProcessExposed.cpp
index c4c6516c41..8ce519b424 100644
--- a/Kernel/GlobalProcessExposed.cpp
+++ b/Kernel/GlobalProcessExposed.cpp
@@ -27,6 +27,7 @@
#include <Kernel/Net/Routing.h>
#include <Kernel/Net/TCPSocket.h>
#include <Kernel/Net/UDPSocket.h>
+#include <Kernel/Process.h>
#include <Kernel/ProcessExposed.h>
#include <Kernel/Sections.h>
#include <Kernel/TTY/TTY.h>
@@ -905,10 +906,13 @@ KResult ProcFSRootDirectory::traverse_as_directory(unsigned fsid, Function<bool(
InodeIdentifier identifier = { fsid, component.component_index() };
callback({ component.name(), identifier, 0 });
}
- for (auto& component : m_process_directories) {
- InodeIdentifier identifier = { fsid, component.component_index() };
- callback({ component.name(), identifier, 0 });
- }
+ processes().for_each_shared([&](Process& process) {
+ VERIFY(!(process.pid() < 0));
+ u64 process_id = (u64)process.pid().value();
+ InodeIdentifier identifier = { fsid, static_cast<InodeIndex>(process_id << 36) };
+ callback({ String::formatted("{:d}", process.pid().value()), identifier, 0 });
+ return IterationDecision::Continue;
+ });
return KSuccess;
}
@@ -917,12 +921,12 @@ RefPtr<ProcFSExposedComponent> ProcFSRootDirectory::lookup(StringView name)
if (auto candidate = ProcFSExposedDirectory::lookup(name); !candidate.is_null())
return candidate;
- for (auto& component : m_process_directories) {
- if (component.name() == name) {
- return component;
- }
- }
- return {};
+ String process_directory_name = name;
+ auto pid = process_directory_name.to_uint<unsigned>();
+ if (!pid.has_value())
+ return {};
+ auto actual_pid = pid.value();
+ return Process::from_pid(actual_pid);
}
UNMAP_AFTER_INIT ProcFSRootDirectory::ProcFSRootDirectory()
@@ -934,14 +938,4 @@ UNMAP_AFTER_INIT ProcFSRootDirectory::~ProcFSRootDirectory()
{
}
-RefPtr<ProcFSProcessDirectory> ProcFSRootDirectory::process_directory_for(Process& process)
-{
- RefPtr<Process> checked_process = process;
- for (auto& directory : m_process_directories) {
- if (directory.associated_process().ptr() == checked_process.ptr())
- return directory;
- }
- return {};
-}
-
}
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp
index 359b277a35..e3ec84c56c 100644
--- a/Kernel/Process.cpp
+++ b/Kernel/Process.cpp
@@ -141,7 +141,6 @@ void Process::register_new(Process& process)
processes().with_exclusive([&](auto& list) {
list.prepend(process);
});
- ProcFSComponentRegistry::the().register_new_process(process);
}
RefPtr<Process> Process::create_user_process(RefPtr<Thread>& first_thread, const String& path, uid_t uid, gid_t gid, ProcessID parent_pid, int& error, Vector<String>&& arguments, Vector<String>&& environment, TTY* tty)
@@ -594,12 +593,6 @@ void Process::finalize()
m_arguments.clear();
m_environment.clear();
- // Note: We need to remove the references from the ProcFS registrar
- // If we don't do it here, we can't drop the object later, and we can't
- // do this from the destructor because the state of the object doesn't
- // allow us to take references anymore.
- ProcFSComponentRegistry::the().unregister_process(*this);
-
m_state.store(State::Dead, AK::MemoryOrder::memory_order_release);
{
@@ -752,13 +745,6 @@ void Process::FileDescriptionAndFlags::clear()
// FIXME: Verify Process::m_fds_lock is locked!
m_description = nullptr;
m_flags = 0;
- m_global_procfs_inode_index = 0;
-}
-
-void Process::FileDescriptionAndFlags::refresh_inode_index()
-{
- // FIXME: Verify Process::m_fds_lock is locked!
- m_global_procfs_inode_index = ProcFSComponentRegistry::the().allocate_inode_index();
}
void Process::FileDescriptionAndFlags::set(NonnullRefPtr<FileDescription>&& description, u32 flags)
@@ -766,7 +752,6 @@ void Process::FileDescriptionAndFlags::set(NonnullRefPtr<FileDescription>&& desc
// FIXME: Verify Process::m_fds_lock is locked!
m_description = move(description);
m_flags = flags;
- m_global_procfs_inode_index = ProcFSComponentRegistry::the().allocate_inode_index();
}
Custody& Process::root_directory()
diff --git a/Kernel/Process.h b/Kernel/Process.h
index c8152fd7b0..fce09313ba 100644
--- a/Kernel/Process.h
+++ b/Kernel/Process.h
@@ -27,6 +27,7 @@
#include <Kernel/Locking/ProtectedValue.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>
@@ -84,7 +85,7 @@ typedef HashMap<FlatPtr, RefPtr<FutexQueue>> FutexQueues;
struct LoadResult;
class Process
- : public RefCounted<Process>
+ : public ProcFSExposedComponent
, public Weakable<Process> {
private:
@@ -551,6 +552,31 @@ private:
void setup_socket_fd(int fd, NonnullRefPtr<FileDescription> description, int type);
+public:
+ // ^ProcFSExposedComponent stats
+ virtual InodeIndex component_index() const override;
+ virtual NonnullRefPtr<Inode> to_inode(const ProcFS& procfs_instance) const override;
+ virtual KResult traverse_as_directory(unsigned, Function<bool(FileSystem::DirectoryEntryView const&)>) const override;
+ virtual mode_t required_mode() const override { return 0555; }
+ virtual uid_t owner_user() const override { return uid(); }
+ virtual gid_t owner_group() const override { return gid(); }
+ KResult procfs_get_fds_stats(KBufferBuilder& builder) const;
+ KResult procfs_get_perf_events(KBufferBuilder& builder) const;
+ KResult procfs_get_unveil_stats(KBufferBuilder& builder) const;
+ KResult procfs_get_pledge_stats(KBufferBuilder& builder) const;
+ KResult procfs_get_virtual_memory_stats(KBufferBuilder& builder) const;
+ KResult procfs_get_binary_link(KBufferBuilder& builder) const;
+ KResult procfs_get_root_link(KBufferBuilder& builder) const;
+ KResult procfs_get_current_work_directory_link(KBufferBuilder& builder) const;
+ mode_t binary_link_required_mode() const;
+ KResultOr<size_t> procfs_get_thread_stack(ThreadID thread_id, KBufferBuilder& builder) const;
+ KResult traverse_stacks_directory(unsigned fsid, Function<bool(FileSystem::DirectoryEntryView const&)> callback) const;
+ RefPtr<Inode> lookup_stacks_directory(const ProcFS&, StringView name) const;
+ KResultOr<size_t> procfs_get_file_description_link(unsigned fd, KBufferBuilder& builder) const;
+ KResult traverse_file_descriptions_directory(unsigned fsid, Function<bool(FileSystem::DirectoryEntryView const&)> callback) const;
+ RefPtr<Inode> lookup_file_descriptions_directory(const ProcFS&, StringView name) const;
+
+private:
inline PerformanceEventBuffer* current_perf_events_buffer()
{
if (g_profiling_all_threads)
@@ -595,22 +621,16 @@ public:
FileDescription* description() { return m_description; }
const FileDescription* description() const { return m_description; }
- InodeIndex global_procfs_inode_index() const { return m_global_procfs_inode_index; }
u32 flags() const { return m_flags; }
void set_flags(u32 flags) { m_flags = flags; }
void clear();
void set(NonnullRefPtr<FileDescription>&&, u32 flags = 0);
- void refresh_inode_index();
private:
RefPtr<FileDescription> m_description;
bool m_is_allocated { false };
u32 m_flags { 0 };
-
- // Note: This is needed so when we generate inodes for ProcFS, we know that
- // we assigned a global Inode index to it so we can use it later
- InodeIndex m_global_procfs_inode_index;
};
class ScopedDescriptionAllocation;
@@ -626,9 +646,6 @@ public:
ScopedSpinLock lock(m_fds_lock);
ScopedSpinLock lock_other(other.m_fds_lock);
m_fds_metadatas = other.m_fds_metadatas;
- for (auto& file_description_metadata : m_fds_metadatas) {
- file_description_metadata.refresh_inode_index();
- }
return *this;
}
diff --git a/Kernel/ProcessExposed.cpp b/Kernel/ProcessExposed.cpp
index c286476805..ecf85dbc8a 100644
--- a/Kernel/ProcessExposed.cpp
+++ b/Kernel/ProcessExposed.cpp
@@ -18,32 +18,74 @@ namespace Kernel {
static SpinLock<u8> s_index_lock;
static InodeIndex s_next_inode_index = 0;
-static size_t s_allocate_inode_index()
+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::FileDescriptions, fd);
+}
+
+}
+
+static size_t s_allocate_global_inode_index()
{
ScopedSpinLock 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();
}
-InodeIndex ProcFSComponentRegistry::allocate_inode_index() const
+ProcFSExposedComponent::ProcFSExposedComponent()
{
- return s_allocate_inode_index();
}
ProcFSExposedComponent::ProcFSExposedComponent(StringView name)
- : m_component_index(s_allocate_inode_index())
-{
- m_name = KString::try_create(name);
-}
-
-// Note: This constructor is intended to be used in /proc/pid/fd/* symlinks
-// so we preallocated inode index for them so we just need to set it here.
-ProcFSExposedComponent::ProcFSExposedComponent(StringView name, InodeIndex preallocated_index)
- : m_component_index(preallocated_index.value())
+ : m_component_index(s_allocate_global_inode_index())
{
- VERIFY(preallocated_index.value() != 0);
- VERIFY(preallocated_index <= s_next_inode_index);
m_name = KString::try_create(name);
}
@@ -62,16 +104,6 @@ ProcFSExposedLink::ProcFSExposedLink(StringView name)
: ProcFSExposedComponent(name)
{
}
-
-ProcFSExposedLink::ProcFSExposedLink(StringView name, InodeIndex preallocated_index)
- : ProcFSExposedComponent(name, preallocated_index)
-{
-}
-
-struct ProcFSInodeData : public FileDescriptionData {
- OwnPtr<KBuffer> buffer;
-};
-
KResultOr<size_t> ProcFSGlobalInformation::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription* description) const
{
dbgln_if(PROCFS_DEBUG, "ProcFSGlobalInformation @ {}: read_bytes offset: {} count: {}", name(), offset, count);
@@ -121,71 +153,6 @@ KResult ProcFSGlobalInformation::refresh_data(FileDescription& description) cons
return KSuccess;
}
-KResultOr<size_t> ProcFSProcessInformation::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription* description) const
-{
- dbgln_if(PROCFS_DEBUG, "ProcFSProcessInformation @ {}: read_bytes offset: {} count: {}", name(), offset, count);
-
- VERIFY(offset >= 0);
- VERIFY(buffer.user_or_kernel_ptr());
-
- if (!description)
- return KResult(EIO);
- if (!description->data()) {
- dbgln("ProcFSGlobalInformation: Do not have cached data!");
- return KResult(EIO);
- }
-
- MutexLocker locker(m_refresh_lock);
-
- auto& typed_cached_data = static_cast<ProcFSInodeData&>(*description->data());
- auto& data_buffer = typed_cached_data.buffer;
-
- if (!data_buffer || (size_t)offset >= data_buffer->size())
- return 0;
-
- ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
- if (!buffer.write(data_buffer->data() + offset, nread))
- return KResult(EFAULT);
-
- return nread;
-}
-
-KResult ProcFSProcessInformation::refresh_data(FileDescription& description) const
-{
- // For process-specific inodes, hold the process's ptrace lock across refresh
- // and refuse to load data if the process is not dumpable.
- // Without this, files opened before a process went non-dumpable could still be used for dumping.
- auto parent_directory = const_cast<ProcFSProcessInformation&>(*this).m_parent_directory.strong_ref();
- if (parent_directory.is_null())
- return KResult(EINVAL);
- auto process = parent_directory->associated_process();
- if (!process)
- return KResult(ESRCH);
- process->ptrace_lock().lock();
- if (!process->is_dumpable()) {
- process->ptrace_lock().unlock();
- return EPERM;
- }
- ScopeGuard guard = [&] {
- process->ptrace_lock().unlock();
- };
- MutexLocker locker(m_refresh_lock);
- auto& cached_data = description.data();
- if (!cached_data) {
- cached_data = adopt_own_if_nonnull(new (nothrow) ProcFSInodeData);
- if (!cached_data)
- return ENOMEM;
- }
- KBufferBuilder builder;
- if (!const_cast<ProcFSProcessInformation&>(*this).output(builder))
- return ENOENT;
- auto& typed_cached_data = static_cast<ProcFSInodeData&>(*cached_data);
- typed_cached_data.buffer = builder.build();
- if (!typed_cached_data.buffer)
- return ENOMEM;
- return KSuccess;
-}
-
KResultOr<size_t> ProcFSExposedLink::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription*) const
{
VERIFY(offset == 0);
@@ -210,7 +177,7 @@ NonnullRefPtr<Inode> ProcFSExposedLink::to_inode(const ProcFS& procfs_instance)
NonnullRefPtr<Inode> ProcFSExposedComponent::to_inode(const ProcFS& procfs_instance) const
{
- return ProcFSInode::create(procfs_instance, *this);
+ return ProcFSGlobalInode::create(procfs_instance, *this);
}
NonnullRefPtr<Inode> ProcFSExposedDirectory::to_inode(const ProcFS& procfs_instance) const
diff --git a/Kernel/ProcessExposed.h b/Kernel/ProcessExposed.h
index 527898d72b..85afd01425 100644
--- a/Kernel/ProcessExposed.h
+++ b/Kernel/ProcessExposed.h
@@ -13,27 +13,49 @@
#include <AK/Types.h>
#include <Kernel/Arch/x86/CPU.h>
#include <Kernel/FileSystem/File.h>
+#include <Kernel/FileSystem/FileDescription.h>
#include <Kernel/FileSystem/FileSystem.h>
#include <Kernel/KBufferBuilder.h>
#include <Kernel/KResult.h>
-#include <Kernel/Process.h>
#include <Kernel/UserOrKernelBuffer.h>
namespace Kernel {
+namespace SegmentedProcFSIndex {
+enum class MainProcessProperty {
+ Reserved = 0,
+ Unveil = 1,
+ Pledge = 2,
+ FileDescriptions = 3,
+ BinaryLink = 4,
+ CurrentWorkDirectoryLink = 5,
+ PerformanceEvents = 6,
+ VirtualMemoryStats = 7,
+ RootLink = 8,
+};
+
+enum class ProcessSubDirectory {
+ Reserved = 0,
+ FileDescriptions = 1,
+ Stacks = 2,
+};
+
+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);
+}
+
class ProcFSComponentRegistry {
public:
static ProcFSComponentRegistry& the();
static void initialize();
-
- InodeIndex allocate_inode_index() const;
-
ProcFSComponentRegistry();
- void register_new_process(Process&);
- void unregister_process(Process&);
-
ProcFSRootDirectory& root_directory() { return *m_root_directory; }
Mutex& get_lock() { return m_lock; }
@@ -64,13 +86,13 @@ public:
virtual NonnullRefPtr<Inode> to_inode(const ProcFS& procfs_instance) const;
- InodeIndex component_index() const { return m_component_index; };
+ virtual InodeIndex component_index() const { return m_component_index; }
virtual ~ProcFSExposedComponent() = default;
protected:
+ ProcFSExposedComponent();
explicit ProcFSExposedComponent(StringView name);
- ProcFSExposedComponent(StringView name, InodeIndex preallocated_index);
private:
OwnPtr<KString> m_name;
@@ -80,7 +102,6 @@ private:
class ProcFSExposedDirectory
: public ProcFSExposedComponent
, public Weakable<ProcFSExposedDirectory> {
- friend class ProcFSProcessDirectory;
friend class ProcFSComponentRegistry;
public:
@@ -114,62 +135,24 @@ public:
protected:
virtual bool acquire_link(KBufferBuilder& builder) = 0;
explicit ProcFSExposedLink(StringView name);
- ProcFSExposedLink(StringView name, InodeIndex preallocated_index);
mutable Mutex m_lock { "ProcFSLink" };
};
-class ProcFSProcessDirectory final
- : public ProcFSExposedDirectory {
- friend class ProcFSComponentRegistry;
- friend class ProcFSRootDirectory;
- friend class ProcFSProcessInformation;
- friend class ProcFSProcessPledge;
- friend class ProcFSProcessUnveil;
- friend class ProcFSProcessPerformanceEvents;
- friend class ProcFSProcessFileDescription;
- friend class ProcFSProcessFileDescriptions;
- friend class ProcFSProcessOverallFileDescriptions;
- friend class ProcFSProcessRoot;
- friend class ProcFSProcessVirtualMemory;
- friend class ProcFSProcessCurrentWorkDirectory;
- friend class ProcFSProcessBinary;
- friend class ProcFSProcessStacks;
-
-public:
- static NonnullRefPtr<ProcFSProcessDirectory> create(const Process&);
- RefPtr<Process> associated_process() { return m_associated_process; }
-
- virtual uid_t owner_user() const override { return m_associated_process ? m_associated_process->uid() : 0; }
- virtual gid_t owner_group() const override { return m_associated_process ? m_associated_process->gid() : 0; }
- virtual KResult refresh_data(FileDescription&) const override;
- virtual RefPtr<ProcFSExposedComponent> lookup(StringView name) override;
- virtual mode_t required_mode() const override { return 0500; }
-
- virtual void prepare_for_deletion() override;
-
-private:
- void on_attach();
- IntrusiveListNode<ProcFSProcessDirectory, RefPtr<ProcFSProcessDirectory>> m_list_node;
-
- explicit ProcFSProcessDirectory(const Process&);
- RefPtr<Process> m_associated_process;
-};
-
class ProcFSRootDirectory final : public ProcFSExposedDirectory {
friend class ProcFSComponentRegistry;
public:
virtual RefPtr<ProcFSExposedComponent> lookup(StringView name) override;
-
- RefPtr<ProcFSProcessDirectory> process_directory_for(Process&);
static NonnullRefPtr<ProcFSRootDirectory> must_create();
virtual ~ProcFSRootDirectory();
private:
virtual KResult traverse_as_directory(unsigned, Function<bool(FileSystem::DirectoryEntryView const&)>) const override;
ProcFSRootDirectory();
+};
- IntrusiveList<ProcFSProcessDirectory, RefPtr<ProcFSProcessDirectory>, &ProcFSProcessDirectory::m_list_node> m_process_directories;
+struct ProcFSInodeData : public FileDescriptionData {
+ OwnPtr<KBuffer> buffer;
};
class ProcFSGlobalInformation : public ProcFSExposedComponent {
@@ -208,47 +191,4 @@ protected:
}
};
-class ProcFSProcessInformation : public ProcFSExposedComponent {
-public:
- virtual ~ProcFSProcessInformation() override {};
-
- virtual KResultOr<size_t> read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription* description) const override;
-
- virtual uid_t owner_user() const override
- {
- auto parent_directory = m_parent_directory.strong_ref();
- if (!parent_directory)
- return false;
- auto process = parent_directory->associated_process();
- if (!process)
- return false;
- return process->uid();
- }
- virtual gid_t owner_group() const override
- {
- auto parent_directory = m_parent_directory.strong_ref();
- if (!parent_directory)
- return false;
- auto process = parent_directory->associated_process();
- if (!process)
- return false;
- return process->gid();
- }
-
- virtual mode_t required_mode() const override { return 0400; }
-
-protected:
- ProcFSProcessInformation(StringView name, const ProcFSProcessDirectory& process_directory)
- : ProcFSExposedComponent(name)
- , m_parent_directory(process_directory)
- {
- }
-
- virtual KResult refresh_data(FileDescription&) const override;
- virtual bool output(KBufferBuilder& builder) = 0;
-
- WeakPtr<ProcFSProcessDirectory> m_parent_directory;
- mutable Mutex m_refresh_lock;
-};
-
}
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;
}
}
diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp
index b580e6445e..f4f6c88fac 100644
--- a/Kernel/Thread.cpp
+++ b/Kernel/Thread.cpp
@@ -62,7 +62,6 @@ Thread::Thread(NonnullRefPtr<Process> process, NonnullOwnPtr<Memory::Region> ker
, m_kernel_stack_region(move(kernel_stack_region))
, m_name(move(name))
, m_block_timer(block_timer)
- , m_global_procfs_inode_index(ProcFSComponentRegistry::the().allocate_inode_index())
{
bool is_first_thread = m_process->add_thread(*this);
if (is_first_thread) {
diff --git a/Kernel/Thread.h b/Kernel/Thread.h
index b7431d0b40..24441292ac 100644
--- a/Kernel/Thread.h
+++ b/Kernel/Thread.h
@@ -1213,8 +1213,6 @@ public:
bool is_profiling_suppressed() const { return m_is_profiling_suppressed; }
void set_profiling_suppressed() { m_is_profiling_suppressed = true; }
- InodeIndex global_procfs_inode_index() const { return m_global_procfs_inode_index; }
-
String backtrace();
private:
@@ -1364,10 +1362,6 @@ private:
RefPtr<Timer> m_block_timer;
- // Note: This is needed so when we generate thread stack inodes for ProcFS, we know that
- // we assigned a global Inode index to it so we can use it later
- InodeIndex m_global_procfs_inode_index;
-
bool m_is_profiling_suppressed { false };
void yield_and_release_relock_big_lock();