ladybird/Kernel/FileSystem/ProcFS.cpp

611 lines
24 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
Kernel: Introduce the new ProcFS design The new ProcFS design consists of two main parts: 1. The representative ProcFS class, which is derived from the FS class. The ProcFS and its inodes are much more lean - merely 3 classes to represent the common type of inodes - regular files, symbolic links and directories. They're backed by a ProcFSExposedComponent object, which is responsible for the functional operation behind the scenes. 2. The backend of the ProcFS - the ProcFSComponentsRegistrar class and all derived classes from the ProcFSExposedComponent class. These together form the entire backend and handle all the functions you can expect from the ProcFS. The ProcFSExposedComponent derived classes split to 3 types in the manner of lifetime in the kernel: 1. Persistent objects - this category includes all basic objects, like the root folder, /proc/bus folder, main blob files in the root folders, etc. These objects are persistent and cannot die ever. 2. Semi-persistent objects - this category includes all PID folders, and subdirectories to the PID folders. It also includes exposed objects like the unveil JSON'ed blob. These object are persistent as long as the the responsible process they represent is still alive. 3. Dynamic objects - this category includes files in the subdirectories of a PID folder, like /proc/PID/fd/* or /proc/PID/stacks/*. Essentially, these objects are always created dynamically and when no longer in need after being used, they're deallocated. Nevertheless, the new allocated backend objects and inodes try to use the same InodeIndex if possible - this might change only when a thread dies and a new thread is born with a new thread stack, or when a file descriptor is closed and a new one within the same file descriptor number is opened. This is needed to actually be able to do something useful with these objects. The new design assures that many ProcFS instances can be used at once, with one backend for usage for all instances.
2021-06-12 04:23:58 +03:00
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
Kernel: Introduce the new ProcFS design The new ProcFS design consists of two main parts: 1. The representative ProcFS class, which is derived from the FS class. The ProcFS and its inodes are much more lean - merely 3 classes to represent the common type of inodes - regular files, symbolic links and directories. They're backed by a ProcFSExposedComponent object, which is responsible for the functional operation behind the scenes. 2. The backend of the ProcFS - the ProcFSComponentsRegistrar class and all derived classes from the ProcFSExposedComponent class. These together form the entire backend and handle all the functions you can expect from the ProcFS. The ProcFSExposedComponent derived classes split to 3 types in the manner of lifetime in the kernel: 1. Persistent objects - this category includes all basic objects, like the root folder, /proc/bus folder, main blob files in the root folders, etc. These objects are persistent and cannot die ever. 2. Semi-persistent objects - this category includes all PID folders, and subdirectories to the PID folders. It also includes exposed objects like the unveil JSON'ed blob. These object are persistent as long as the the responsible process they represent is still alive. 3. Dynamic objects - this category includes files in the subdirectories of a PID folder, like /proc/PID/fd/* or /proc/PID/stacks/*. Essentially, these objects are always created dynamically and when no longer in need after being used, they're deallocated. Nevertheless, the new allocated backend objects and inodes try to use the same InodeIndex if possible - this might change only when a thread dies and a new thread is born with a new thread stack, or when a file descriptor is closed and a new one within the same file descriptor number is opened. This is needed to actually be able to do something useful with these objects. The new design assures that many ProcFS instances can be used at once, with one backend for usage for all instances.
2021-06-12 04:23:58 +03:00
#include <AK/Singleton.h>
#include <Kernel/API/POSIX/errno.h>
Meta: Split debug defines into multiple headers. The following script was used to make these changes: #!/bin/bash set -e tmp=$(mktemp -d) echo "tmp=$tmp" find Kernel \( -name '*.cpp' -o -name '*.h' \) | sort > $tmp/Kernel.files find . \( -path ./Toolchain -prune -o -path ./Build -prune -o -path ./Kernel -prune \) -o \( -name '*.cpp' -o -name '*.h' \) -print | sort > $tmp/EverythingExceptKernel.files cat $tmp/Kernel.files | xargs grep -Eho '[A-Z0-9_]+_DEBUG' | sort | uniq > $tmp/Kernel.macros cat $tmp/EverythingExceptKernel.files | xargs grep -Eho '[A-Z0-9_]+_DEBUG' | sort | uniq > $tmp/EverythingExceptKernel.macros comm -23 $tmp/Kernel.macros $tmp/EverythingExceptKernel.macros > $tmp/Kernel.unique comm -1 $tmp/Kernel.macros $tmp/EverythingExceptKernel.macros > $tmp/EverythingExceptKernel.unique cat $tmp/Kernel.unique | awk '{ print "#cmakedefine01 "$1 }' > $tmp/Kernel.header cat $tmp/EverythingExceptKernel.unique | awk '{ print "#cmakedefine01 "$1 }' > $tmp/EverythingExceptKernel.header for macro in $(cat $tmp/Kernel.unique) do cat $tmp/Kernel.files | xargs grep -l $macro >> $tmp/Kernel.new-includes ||: done cat $tmp/Kernel.new-includes | sort > $tmp/Kernel.new-includes.sorted for macro in $(cat $tmp/EverythingExceptKernel.unique) do cat $tmp/Kernel.files | xargs grep -l $macro >> $tmp/Kernel.old-includes ||: done cat $tmp/Kernel.old-includes | sort > $tmp/Kernel.old-includes.sorted comm -23 $tmp/Kernel.new-includes.sorted $tmp/Kernel.old-includes.sorted > $tmp/Kernel.includes.new comm -13 $tmp/Kernel.new-includes.sorted $tmp/Kernel.old-includes.sorted > $tmp/Kernel.includes.old comm -12 $tmp/Kernel.new-includes.sorted $tmp/Kernel.old-includes.sorted > $tmp/Kernel.includes.mixed for file in $(cat $tmp/Kernel.includes.new) do sed -i -E 's/#include <AK\/Debug\.h>/#include <Kernel\/Debug\.h>/' $file done for file in $(cat $tmp/Kernel.includes.mixed) do echo "mixed include in $file, requires manual editing." done
2021-01-25 18:07:10 +03:00
#include <Kernel/Debug.h>
#include <Kernel/FileSystem/Custody.h>
#include <Kernel/FileSystem/OpenFileDescription.h>
#include <Kernel/FileSystem/ProcFS.h>
#include <Kernel/FileSystem/VirtualFileSystem.h>
#include <Kernel/Heap/kmalloc.h>
#include <Kernel/Process.h>
Kernel: Introduce the new ProcFS design The new ProcFS design consists of two main parts: 1. The representative ProcFS class, which is derived from the FS class. The ProcFS and its inodes are much more lean - merely 3 classes to represent the common type of inodes - regular files, symbolic links and directories. They're backed by a ProcFSExposedComponent object, which is responsible for the functional operation behind the scenes. 2. The backend of the ProcFS - the ProcFSComponentsRegistrar class and all derived classes from the ProcFSExposedComponent class. These together form the entire backend and handle all the functions you can expect from the ProcFS. The ProcFSExposedComponent derived classes split to 3 types in the manner of lifetime in the kernel: 1. Persistent objects - this category includes all basic objects, like the root folder, /proc/bus folder, main blob files in the root folders, etc. These objects are persistent and cannot die ever. 2. Semi-persistent objects - this category includes all PID folders, and subdirectories to the PID folders. It also includes exposed objects like the unveil JSON'ed blob. These object are persistent as long as the the responsible process they represent is still alive. 3. Dynamic objects - this category includes files in the subdirectories of a PID folder, like /proc/PID/fd/* or /proc/PID/stacks/*. Essentially, these objects are always created dynamically and when no longer in need after being used, they're deallocated. Nevertheless, the new allocated backend objects and inodes try to use the same InodeIndex if possible - this might change only when a thread dies and a new thread is born with a new thread stack, or when a file descriptor is closed and a new one within the same file descriptor number is opened. This is needed to actually be able to do something useful with these objects. The new design assures that many ProcFS instances can be used at once, with one backend for usage for all instances.
2021-06-12 04:23:58 +03:00
#include <Kernel/Sections.h>
namespace Kernel {
static Singleton<ProcFSComponentRegistry> s_the;
ProcFSComponentRegistry& ProcFSComponentRegistry::the()
{
Kernel: Introduce the new ProcFS design The new ProcFS design consists of two main parts: 1. The representative ProcFS class, which is derived from the FS class. The ProcFS and its inodes are much more lean - merely 3 classes to represent the common type of inodes - regular files, symbolic links and directories. They're backed by a ProcFSExposedComponent object, which is responsible for the functional operation behind the scenes. 2. The backend of the ProcFS - the ProcFSComponentsRegistrar class and all derived classes from the ProcFSExposedComponent class. These together form the entire backend and handle all the functions you can expect from the ProcFS. The ProcFSExposedComponent derived classes split to 3 types in the manner of lifetime in the kernel: 1. Persistent objects - this category includes all basic objects, like the root folder, /proc/bus folder, main blob files in the root folders, etc. These objects are persistent and cannot die ever. 2. Semi-persistent objects - this category includes all PID folders, and subdirectories to the PID folders. It also includes exposed objects like the unveil JSON'ed blob. These object are persistent as long as the the responsible process they represent is still alive. 3. Dynamic objects - this category includes files in the subdirectories of a PID folder, like /proc/PID/fd/* or /proc/PID/stacks/*. Essentially, these objects are always created dynamically and when no longer in need after being used, they're deallocated. Nevertheless, the new allocated backend objects and inodes try to use the same InodeIndex if possible - this might change only when a thread dies and a new thread is born with a new thread stack, or when a file descriptor is closed and a new one within the same file descriptor number is opened. This is needed to actually be able to do something useful with these objects. The new design assures that many ProcFS instances can be used at once, with one backend for usage for all instances.
2021-06-12 04:23:58 +03:00
return *s_the;
}
UNMAP_AFTER_INIT void ProcFSComponentRegistry::initialize()
{
Kernel: Introduce the new ProcFS design The new ProcFS design consists of two main parts: 1. The representative ProcFS class, which is derived from the FS class. The ProcFS and its inodes are much more lean - merely 3 classes to represent the common type of inodes - regular files, symbolic links and directories. They're backed by a ProcFSExposedComponent object, which is responsible for the functional operation behind the scenes. 2. The backend of the ProcFS - the ProcFSComponentsRegistrar class and all derived classes from the ProcFSExposedComponent class. These together form the entire backend and handle all the functions you can expect from the ProcFS. The ProcFSExposedComponent derived classes split to 3 types in the manner of lifetime in the kernel: 1. Persistent objects - this category includes all basic objects, like the root folder, /proc/bus folder, main blob files in the root folders, etc. These objects are persistent and cannot die ever. 2. Semi-persistent objects - this category includes all PID folders, and subdirectories to the PID folders. It also includes exposed objects like the unveil JSON'ed blob. These object are persistent as long as the the responsible process they represent is still alive. 3. Dynamic objects - this category includes files in the subdirectories of a PID folder, like /proc/PID/fd/* or /proc/PID/stacks/*. Essentially, these objects are always created dynamically and when no longer in need after being used, they're deallocated. Nevertheless, the new allocated backend objects and inodes try to use the same InodeIndex if possible - this might change only when a thread dies and a new thread is born with a new thread stack, or when a file descriptor is closed and a new one within the same file descriptor number is opened. This is needed to actually be able to do something useful with these objects. The new design assures that many ProcFS instances can be used at once, with one backend for usage for all instances.
2021-06-12 04:23:58 +03:00
VERIFY(!s_the.is_initialized());
s_the.ensure_instance();
}
UNMAP_AFTER_INIT ProcFSComponentRegistry::ProcFSComponentRegistry()
: m_root_directory(ProcFSRootDirectory::must_create())
{
}
ErrorOr<NonnullLockRefPtr<FileSystem>> ProcFS::try_create()
{
return TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFS));
}
ProcFS::ProcFS() = default;
ProcFS::~ProcFS() = default;
ErrorOr<void> ProcFS::initialize()
{
2021-09-05 20:01:38 +03:00
m_root_inode = static_ptr_cast<ProcFSDirectoryInode>(TRY(ProcFSComponentRegistry::the().root_directory().to_inode(*this)));
return {};
}
Inode& ProcFS::root_inode()
{
return *m_root_inode;
}
2022-04-01 20:58:27 +03:00
ProcFSInode::ProcFSInode(ProcFS const& fs, InodeIndex index)
: Inode(const_cast<ProcFS&>(fs), index)
{
}
ProcFSInode::~ProcFSInode() = default;
ErrorOr<void> ProcFSInode::flush_metadata()
{
return {};
}
ErrorOr<void> ProcFSInode::add_child(Inode&, StringView, mode_t)
{
return EROFS;
}
ErrorOr<NonnullLockRefPtr<Inode>> ProcFSInode::create_child(StringView, mode_t, dev_t, UserID, GroupID)
{
return EROFS;
}
ErrorOr<void> ProcFSInode::remove_child(StringView)
{
return EROFS;
}
ErrorOr<void> ProcFSInode::chmod(mode_t)
{
return EPERM;
}
ErrorOr<void> ProcFSInode::chown(UserID, GroupID)
{
return EPERM;
}
ErrorOr<NonnullLockRefPtr<ProcFSGlobalInode>> ProcFSGlobalInode::try_create(ProcFS const& fs, ProcFSExposedComponent const& component)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSGlobalInode(fs, component));
}
2022-04-01 20:58:27 +03:00
ProcFSGlobalInode::ProcFSGlobalInode(ProcFS const& fs, ProcFSExposedComponent const& component)
: ProcFSInode(fs, component.component_index())
, m_associated_component(component)
{
}
void ProcFSGlobalInode::did_seek(OpenFileDescription& description, off_t new_offset)
2020-01-15 14:05:02 +03:00
{
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());
}
2020-01-15 14:05:02 +03:00
}
ErrorOr<void> ProcFSGlobalInode::attach(OpenFileDescription& description)
{
return m_associated_component->refresh_data(description);
}
ErrorOr<size_t> ProcFSGlobalInode::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription* fd) const
2020-01-15 14:05:02 +03:00
{
return m_associated_component->read_bytes(offset, count, buffer, fd);
2020-01-15 14:05:02 +03:00
}
StringView ProcFSGlobalInode::name() const
2020-01-15 14:05:02 +03:00
{
return m_associated_component->name();
2020-01-15 14:05:02 +03:00
}
ErrorOr<void> ProcFSGlobalInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const
{
VERIFY_NOT_REACHED();
}
ErrorOr<NonnullLockRefPtr<Inode>> ProcFSGlobalInode::lookup(StringView)
2020-01-15 14:05:02 +03:00
{
VERIFY_NOT_REACHED();
2020-01-15 14:05:02 +03:00
}
ErrorOr<void> ProcFSGlobalInode::truncate(u64 size)
{
return m_associated_component->truncate(size);
}
ErrorOr<void> ProcFSGlobalInode::update_timestamps(Optional<time_t>, Optional<time_t>, Optional<time_t>)
{
return {};
}
InodeMetadata ProcFSGlobalInode::metadata() const
{
MutexLocker locker(m_inode_lock);
InodeMetadata metadata;
metadata.inode = { fsid(), m_associated_component->component_index() };
metadata.mode = S_IFREG | m_associated_component->required_mode();
metadata.uid = m_associated_component->owner_user();
metadata.gid = m_associated_component->owner_group();
metadata.size = 0;
metadata.mtime = m_associated_component->modified_time();
return metadata;
}
2022-04-01 20:58:27 +03:00
ErrorOr<size_t> ProcFSGlobalInode::write_bytes(off_t offset, size_t count, UserOrKernelBuffer const& buffer, OpenFileDescription* fd)
2020-01-15 14:05:02 +03:00
{
return m_associated_component->write_bytes(offset, count, buffer, fd);
2020-01-15 14:05:02 +03:00
}
ErrorOr<NonnullLockRefPtr<ProcFSDirectoryInode>> ProcFSDirectoryInode::try_create(ProcFS const& procfs, ProcFSExposedComponent const& component)
2020-01-15 14:05:02 +03:00
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSDirectoryInode(procfs, component));
2020-01-15 14:05:02 +03:00
}
2022-04-01 20:58:27 +03:00
ProcFSDirectoryInode::ProcFSDirectoryInode(ProcFS const& fs, ProcFSExposedComponent const& component)
: ProcFSGlobalInode(fs, component)
2020-01-15 14:05:02 +03:00
{
}
ProcFSDirectoryInode::~ProcFSDirectoryInode() = default;
Kernel: Introduce the new ProcFS design The new ProcFS design consists of two main parts: 1. The representative ProcFS class, which is derived from the FS class. The ProcFS and its inodes are much more lean - merely 3 classes to represent the common type of inodes - regular files, symbolic links and directories. They're backed by a ProcFSExposedComponent object, which is responsible for the functional operation behind the scenes. 2. The backend of the ProcFS - the ProcFSComponentsRegistrar class and all derived classes from the ProcFSExposedComponent class. These together form the entire backend and handle all the functions you can expect from the ProcFS. The ProcFSExposedComponent derived classes split to 3 types in the manner of lifetime in the kernel: 1. Persistent objects - this category includes all basic objects, like the root folder, /proc/bus folder, main blob files in the root folders, etc. These objects are persistent and cannot die ever. 2. Semi-persistent objects - this category includes all PID folders, and subdirectories to the PID folders. It also includes exposed objects like the unveil JSON'ed blob. These object are persistent as long as the the responsible process they represent is still alive. 3. Dynamic objects - this category includes files in the subdirectories of a PID folder, like /proc/PID/fd/* or /proc/PID/stacks/*. Essentially, these objects are always created dynamically and when no longer in need after being used, they're deallocated. Nevertheless, the new allocated backend objects and inodes try to use the same InodeIndex if possible - this might change only when a thread dies and a new thread is born with a new thread stack, or when a file descriptor is closed and a new one within the same file descriptor number is opened. This is needed to actually be able to do something useful with these objects. The new design assures that many ProcFS instances can be used at once, with one backend for usage for all instances.
2021-06-12 04:23:58 +03:00
InodeMetadata ProcFSDirectoryInode::metadata() const
{
2021-07-18 02:13:34 +03:00
MutexLocker locker(m_inode_lock);
Kernel: Introduce the new ProcFS design The new ProcFS design consists of two main parts: 1. The representative ProcFS class, which is derived from the FS class. The ProcFS and its inodes are much more lean - merely 3 classes to represent the common type of inodes - regular files, symbolic links and directories. They're backed by a ProcFSExposedComponent object, which is responsible for the functional operation behind the scenes. 2. The backend of the ProcFS - the ProcFSComponentsRegistrar class and all derived classes from the ProcFSExposedComponent class. These together form the entire backend and handle all the functions you can expect from the ProcFS. The ProcFSExposedComponent derived classes split to 3 types in the manner of lifetime in the kernel: 1. Persistent objects - this category includes all basic objects, like the root folder, /proc/bus folder, main blob files in the root folders, etc. These objects are persistent and cannot die ever. 2. Semi-persistent objects - this category includes all PID folders, and subdirectories to the PID folders. It also includes exposed objects like the unveil JSON'ed blob. These object are persistent as long as the the responsible process they represent is still alive. 3. Dynamic objects - this category includes files in the subdirectories of a PID folder, like /proc/PID/fd/* or /proc/PID/stacks/*. Essentially, these objects are always created dynamically and when no longer in need after being used, they're deallocated. Nevertheless, the new allocated backend objects and inodes try to use the same InodeIndex if possible - this might change only when a thread dies and a new thread is born with a new thread stack, or when a file descriptor is closed and a new one within the same file descriptor number is opened. This is needed to actually be able to do something useful with these objects. The new design assures that many ProcFS instances can be used at once, with one backend for usage for all instances.
2021-06-12 04:23:58 +03:00
InodeMetadata metadata;
metadata.inode = { fsid(), m_associated_component->component_index() };
metadata.mode = S_IFDIR | m_associated_component->required_mode();
metadata.uid = m_associated_component->owner_user();
metadata.gid = m_associated_component->owner_group();
Kernel: Introduce the new ProcFS design The new ProcFS design consists of two main parts: 1. The representative ProcFS class, which is derived from the FS class. The ProcFS and its inodes are much more lean - merely 3 classes to represent the common type of inodes - regular files, symbolic links and directories. They're backed by a ProcFSExposedComponent object, which is responsible for the functional operation behind the scenes. 2. The backend of the ProcFS - the ProcFSComponentsRegistrar class and all derived classes from the ProcFSExposedComponent class. These together form the entire backend and handle all the functions you can expect from the ProcFS. The ProcFSExposedComponent derived classes split to 3 types in the manner of lifetime in the kernel: 1. Persistent objects - this category includes all basic objects, like the root folder, /proc/bus folder, main blob files in the root folders, etc. These objects are persistent and cannot die ever. 2. Semi-persistent objects - this category includes all PID folders, and subdirectories to the PID folders. It also includes exposed objects like the unveil JSON'ed blob. These object are persistent as long as the the responsible process they represent is still alive. 3. Dynamic objects - this category includes files in the subdirectories of a PID folder, like /proc/PID/fd/* or /proc/PID/stacks/*. Essentially, these objects are always created dynamically and when no longer in need after being used, they're deallocated. Nevertheless, the new allocated backend objects and inodes try to use the same InodeIndex if possible - this might change only when a thread dies and a new thread is born with a new thread stack, or when a file descriptor is closed and a new one within the same file descriptor number is opened. This is needed to actually be able to do something useful with these objects. The new design assures that many ProcFS instances can be used at once, with one backend for usage for all instances.
2021-06-12 04:23:58 +03:00
metadata.size = 0;
metadata.mtime = m_associated_component->modified_time();
Kernel: Introduce the new ProcFS design The new ProcFS design consists of two main parts: 1. The representative ProcFS class, which is derived from the FS class. The ProcFS and its inodes are much more lean - merely 3 classes to represent the common type of inodes - regular files, symbolic links and directories. They're backed by a ProcFSExposedComponent object, which is responsible for the functional operation behind the scenes. 2. The backend of the ProcFS - the ProcFSComponentsRegistrar class and all derived classes from the ProcFSExposedComponent class. These together form the entire backend and handle all the functions you can expect from the ProcFS. The ProcFSExposedComponent derived classes split to 3 types in the manner of lifetime in the kernel: 1. Persistent objects - this category includes all basic objects, like the root folder, /proc/bus folder, main blob files in the root folders, etc. These objects are persistent and cannot die ever. 2. Semi-persistent objects - this category includes all PID folders, and subdirectories to the PID folders. It also includes exposed objects like the unveil JSON'ed blob. These object are persistent as long as the the responsible process they represent is still alive. 3. Dynamic objects - this category includes files in the subdirectories of a PID folder, like /proc/PID/fd/* or /proc/PID/stacks/*. Essentially, these objects are always created dynamically and when no longer in need after being used, they're deallocated. Nevertheless, the new allocated backend objects and inodes try to use the same InodeIndex if possible - this might change only when a thread dies and a new thread is born with a new thread stack, or when a file descriptor is closed and a new one within the same file descriptor number is opened. This is needed to actually be able to do something useful with these objects. The new design assures that many ProcFS instances can be used at once, with one backend for usage for all instances.
2021-06-12 04:23:58 +03:00
return metadata;
}
ErrorOr<void> ProcFSDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
{
MutexLocker locker(procfs().m_lock);
return m_associated_component->traverse_as_directory(procfs().fsid(), move(callback));
}
ErrorOr<NonnullLockRefPtr<Inode>> ProcFSDirectoryInode::lookup(StringView name)
{
MutexLocker locker(procfs().m_lock);
2021-09-05 20:01:38 +03:00
auto component = TRY(m_associated_component->lookup(name));
return component->to_inode(procfs());
}
ErrorOr<NonnullLockRefPtr<ProcFSLinkInode>> ProcFSLinkInode::try_create(ProcFS const& procfs, ProcFSExposedComponent const& component)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSLinkInode(procfs, component));
}
2022-04-01 20:58:27 +03:00
ProcFSLinkInode::ProcFSLinkInode(ProcFS const& fs, ProcFSExposedComponent const& component)
: ProcFSGlobalInode(fs, component)
{
}
Kernel: Introduce the new ProcFS design The new ProcFS design consists of two main parts: 1. The representative ProcFS class, which is derived from the FS class. The ProcFS and its inodes are much more lean - merely 3 classes to represent the common type of inodes - regular files, symbolic links and directories. They're backed by a ProcFSExposedComponent object, which is responsible for the functional operation behind the scenes. 2. The backend of the ProcFS - the ProcFSComponentsRegistrar class and all derived classes from the ProcFSExposedComponent class. These together form the entire backend and handle all the functions you can expect from the ProcFS. The ProcFSExposedComponent derived classes split to 3 types in the manner of lifetime in the kernel: 1. Persistent objects - this category includes all basic objects, like the root folder, /proc/bus folder, main blob files in the root folders, etc. These objects are persistent and cannot die ever. 2. Semi-persistent objects - this category includes all PID folders, and subdirectories to the PID folders. It also includes exposed objects like the unveil JSON'ed blob. These object are persistent as long as the the responsible process they represent is still alive. 3. Dynamic objects - this category includes files in the subdirectories of a PID folder, like /proc/PID/fd/* or /proc/PID/stacks/*. Essentially, these objects are always created dynamically and when no longer in need after being used, they're deallocated. Nevertheless, the new allocated backend objects and inodes try to use the same InodeIndex if possible - this might change only when a thread dies and a new thread is born with a new thread stack, or when a file descriptor is closed and a new one within the same file descriptor number is opened. This is needed to actually be able to do something useful with these objects. The new design assures that many ProcFS instances can be used at once, with one backend for usage for all instances.
2021-06-12 04:23:58 +03:00
InodeMetadata ProcFSLinkInode::metadata() const
{
2021-07-18 02:13:34 +03:00
MutexLocker locker(m_inode_lock);
Kernel: Introduce the new ProcFS design The new ProcFS design consists of two main parts: 1. The representative ProcFS class, which is derived from the FS class. The ProcFS and its inodes are much more lean - merely 3 classes to represent the common type of inodes - regular files, symbolic links and directories. They're backed by a ProcFSExposedComponent object, which is responsible for the functional operation behind the scenes. 2. The backend of the ProcFS - the ProcFSComponentsRegistrar class and all derived classes from the ProcFSExposedComponent class. These together form the entire backend and handle all the functions you can expect from the ProcFS. The ProcFSExposedComponent derived classes split to 3 types in the manner of lifetime in the kernel: 1. Persistent objects - this category includes all basic objects, like the root folder, /proc/bus folder, main blob files in the root folders, etc. These objects are persistent and cannot die ever. 2. Semi-persistent objects - this category includes all PID folders, and subdirectories to the PID folders. It also includes exposed objects like the unveil JSON'ed blob. These object are persistent as long as the the responsible process they represent is still alive. 3. Dynamic objects - this category includes files in the subdirectories of a PID folder, like /proc/PID/fd/* or /proc/PID/stacks/*. Essentially, these objects are always created dynamically and when no longer in need after being used, they're deallocated. Nevertheless, the new allocated backend objects and inodes try to use the same InodeIndex if possible - this might change only when a thread dies and a new thread is born with a new thread stack, or when a file descriptor is closed and a new one within the same file descriptor number is opened. This is needed to actually be able to do something useful with these objects. The new design assures that many ProcFS instances can be used at once, with one backend for usage for all instances.
2021-06-12 04:23:58 +03:00
InodeMetadata metadata;
metadata.inode = { fsid(), m_associated_component->component_index() };
metadata.mode = S_IFLNK | m_associated_component->required_mode();
metadata.uid = m_associated_component->owner_user();
metadata.gid = m_associated_component->owner_group();
Kernel: Introduce the new ProcFS design The new ProcFS design consists of two main parts: 1. The representative ProcFS class, which is derived from the FS class. The ProcFS and its inodes are much more lean - merely 3 classes to represent the common type of inodes - regular files, symbolic links and directories. They're backed by a ProcFSExposedComponent object, which is responsible for the functional operation behind the scenes. 2. The backend of the ProcFS - the ProcFSComponentsRegistrar class and all derived classes from the ProcFSExposedComponent class. These together form the entire backend and handle all the functions you can expect from the ProcFS. The ProcFSExposedComponent derived classes split to 3 types in the manner of lifetime in the kernel: 1. Persistent objects - this category includes all basic objects, like the root folder, /proc/bus folder, main blob files in the root folders, etc. These objects are persistent and cannot die ever. 2. Semi-persistent objects - this category includes all PID folders, and subdirectories to the PID folders. It also includes exposed objects like the unveil JSON'ed blob. These object are persistent as long as the the responsible process they represent is still alive. 3. Dynamic objects - this category includes files in the subdirectories of a PID folder, like /proc/PID/fd/* or /proc/PID/stacks/*. Essentially, these objects are always created dynamically and when no longer in need after being used, they're deallocated. Nevertheless, the new allocated backend objects and inodes try to use the same InodeIndex if possible - this might change only when a thread dies and a new thread is born with a new thread stack, or when a file descriptor is closed and a new one within the same file descriptor number is opened. This is needed to actually be able to do something useful with these objects. The new design assures that many ProcFS instances can be used at once, with one backend for usage for all instances.
2021-06-12 04:23:58 +03:00
metadata.size = 0;
metadata.mtime = m_associated_component->modified_time();
Kernel: Introduce the new ProcFS design The new ProcFS design consists of two main parts: 1. The representative ProcFS class, which is derived from the FS class. The ProcFS and its inodes are much more lean - merely 3 classes to represent the common type of inodes - regular files, symbolic links and directories. They're backed by a ProcFSExposedComponent object, which is responsible for the functional operation behind the scenes. 2. The backend of the ProcFS - the ProcFSComponentsRegistrar class and all derived classes from the ProcFSExposedComponent class. These together form the entire backend and handle all the functions you can expect from the ProcFS. The ProcFSExposedComponent derived classes split to 3 types in the manner of lifetime in the kernel: 1. Persistent objects - this category includes all basic objects, like the root folder, /proc/bus folder, main blob files in the root folders, etc. These objects are persistent and cannot die ever. 2. Semi-persistent objects - this category includes all PID folders, and subdirectories to the PID folders. It also includes exposed objects like the unveil JSON'ed blob. These object are persistent as long as the the responsible process they represent is still alive. 3. Dynamic objects - this category includes files in the subdirectories of a PID folder, like /proc/PID/fd/* or /proc/PID/stacks/*. Essentially, these objects are always created dynamically and when no longer in need after being used, they're deallocated. Nevertheless, the new allocated backend objects and inodes try to use the same InodeIndex if possible - this might change only when a thread dies and a new thread is born with a new thread stack, or when a file descriptor is closed and a new one within the same file descriptor number is opened. This is needed to actually be able to do something useful with these objects. The new design assures that many ProcFS instances can be used at once, with one backend for usage for all instances.
2021-06-12 04:23:58 +03:00
return metadata;
}
2022-04-01 20:58:27 +03:00
ProcFSProcessAssociatedInode::ProcFSProcessAssociatedInode(ProcFS const& fs, ProcessID associated_pid, InodeIndex determined_index)
: ProcFSInode(fs, determined_index)
, m_pid(associated_pid)
{
}
2022-04-01 20:58:27 +03:00
ErrorOr<size_t> ProcFSProcessAssociatedInode::write_bytes(off_t, size_t, UserOrKernelBuffer const&, OpenFileDescription*)
{
return ENOTSUP;
}
ErrorOr<NonnullLockRefPtr<ProcFSProcessDirectoryInode>> ProcFSProcessDirectoryInode::try_create(ProcFS const& procfs, ProcessID pid)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessDirectoryInode(procfs, pid));
}
2022-04-01 20:58:27 +03:00
ProcFSProcessDirectoryInode::ProcFSProcessDirectoryInode(ProcFS const& procfs, ProcessID pid)
: ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_pid_directory(pid))
{
}
ErrorOr<void> ProcFSProcessDirectoryInode::attach(OpenFileDescription&)
{
return {};
}
InodeMetadata ProcFSProcessDirectoryInode::metadata() const
{
MutexLocker locker(m_inode_lock);
auto process = Process::from_pid(associated_pid());
if (!process)
return {};
auto traits = process->procfs_traits();
InodeMetadata metadata;
metadata.inode = { fsid(), traits->component_index() };
metadata.mode = S_IFDIR | traits->required_mode();
metadata.uid = traits->owner_user();
metadata.gid = traits->owner_group();
metadata.size = 0;
metadata.mtime = traits->modified_time();
return metadata;
}
ErrorOr<size_t> ProcFSProcessDirectoryInode::read_bytes(off_t, size_t, UserOrKernelBuffer&, OpenFileDescription*) const
{
VERIFY_NOT_REACHED();
}
ErrorOr<void> ProcFSProcessDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
{
MutexLocker locker(procfs().m_lock);
auto process = Process::from_pid(associated_pid());
if (!process)
return EINVAL;
return process->procfs_traits()->traverse_as_directory(procfs().fsid(), move(callback));
}
ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessDirectoryInode::lookup(StringView name)
{
MutexLocker locker(procfs().m_lock);
auto process = Process::from_pid(associated_pid());
if (!process)
return ESRCH;
2021-09-05 20:01:38 +03:00
if (name == "fd"sv)
return TRY(ProcFSProcessSubDirectoryInode::try_create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions, associated_pid()));
2021-09-05 20:01:38 +03:00
if (name == "stacks"sv)
return TRY(ProcFSProcessSubDirectoryInode::try_create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::Stacks, associated_pid()));
if (name == "children"sv)
return TRY(ProcFSProcessSubDirectoryInode::try_create(procfs(), SegmentedProcFSIndex::ProcessSubDirectory::Children, associated_pid()));
2021-09-05 20:01:38 +03:00
if (name == "unveil"sv)
return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::Unveil, associated_pid()));
if (name == "pledge"sv)
return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::Pledge, associated_pid()));
if (name == "fds"sv)
return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::OpenFileDescriptions, associated_pid()));
2021-09-05 20:01:38 +03:00
if (name == "exe"sv)
return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::BinaryLink, associated_pid()));
if (name == "cwd"sv)
return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink, associated_pid()));
if (name == "perf_events"sv)
return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents, associated_pid()));
if (name == "vm"sv)
return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats, associated_pid()));
if (name == "cmdline"sv)
return TRY(ProcFSProcessPropertyInode::try_create_for_pid_property(procfs(), SegmentedProcFSIndex::MainProcessProperty::CommandLine, associated_pid()));
return ENOENT;
}
ErrorOr<NonnullLockRefPtr<ProcFSProcessSubDirectoryInode>> ProcFSProcessSubDirectoryInode::try_create(ProcFS const& procfs, SegmentedProcFSIndex::ProcessSubDirectory sub_directory_type, ProcessID pid)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessSubDirectoryInode(procfs, sub_directory_type, pid));
}
2022-04-01 20:58:27 +03:00
ProcFSProcessSubDirectoryInode::ProcFSProcessSubDirectoryInode(ProcFS const& procfs, SegmentedProcFSIndex::ProcessSubDirectory sub_directory_type, ProcessID pid)
: ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(pid, sub_directory_type))
, m_sub_directory_type(sub_directory_type)
{
}
ErrorOr<size_t> ProcFSProcessSubDirectoryInode::read_bytes(off_t, size_t, UserOrKernelBuffer&, OpenFileDescription*) const
{
VERIFY_NOT_REACHED();
}
ErrorOr<void> ProcFSProcessSubDirectoryInode::attach(OpenFileDescription&)
{
return {};
}
void ProcFSProcessSubDirectoryInode::did_seek(OpenFileDescription&, off_t)
{
VERIFY_NOT_REACHED();
}
InodeMetadata ProcFSProcessSubDirectoryInode::metadata() const
{
MutexLocker locker(m_inode_lock);
auto process = Process::from_pid(associated_pid());
if (!process)
return {};
auto traits = process->procfs_traits();
InodeMetadata metadata;
metadata.inode = { fsid(), traits->component_index() };
metadata.mode = S_IFDIR | traits->required_mode();
metadata.uid = traits->owner_user();
metadata.gid = traits->owner_group();
metadata.size = 0;
metadata.mtime = traits->modified_time();
return metadata;
}
ErrorOr<void> ProcFSProcessSubDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
{
MutexLocker locker(procfs().m_lock);
auto process = Process::from_pid(associated_pid());
if (!process)
return EINVAL;
switch (m_sub_directory_type) {
case SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions:
return process->traverse_file_descriptions_directory(procfs().fsid(), move(callback));
case SegmentedProcFSIndex::ProcessSubDirectory::Stacks:
return process->traverse_stacks_directory(procfs().fsid(), move(callback));
case SegmentedProcFSIndex::ProcessSubDirectory::Children:
return process->traverse_children_directory(procfs().fsid(), move(callback));
default:
VERIFY_NOT_REACHED();
}
VERIFY_NOT_REACHED();
}
ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessSubDirectoryInode::lookup(StringView name)
{
MutexLocker locker(procfs().m_lock);
auto process = Process::from_pid(associated_pid());
if (!process)
return ESRCH;
switch (m_sub_directory_type) {
case SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions:
2021-09-05 20:01:38 +03:00
return process->lookup_file_descriptions_directory(procfs(), name);
case SegmentedProcFSIndex::ProcessSubDirectory::Stacks:
return process->lookup_stacks_directory(procfs(), name);
case SegmentedProcFSIndex::ProcessSubDirectory::Children:
return process->lookup_children_directory(procfs(), name);
default:
VERIFY_NOT_REACHED();
}
}
ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_file_description_link(ProcFS const& procfs, unsigned file_description_index, ProcessID pid)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, file_description_index, pid));
}
ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_thread_stack(ProcFS const& procfs, ThreadID stack_thread_index, ProcessID pid)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, stack_thread_index, pid));
}
ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_pid_property(ProcFS const& procfs, SegmentedProcFSIndex::MainProcessProperty main_property_type, ProcessID pid)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, main_property_type, pid));
}
ErrorOr<NonnullLockRefPtr<ProcFSProcessPropertyInode>> ProcFSProcessPropertyInode::try_create_for_child_process_link(ProcFS const& procfs, ProcessID child_pid, ProcessID pid)
{
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) ProcFSProcessPropertyInode(procfs, child_pid, pid));
}
2022-04-01 20:58:27 +03:00
ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, SegmentedProcFSIndex::MainProcessProperty main_property_type, ProcessID pid)
: ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_main_property_in_pid_directory(pid, main_property_type))
, m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Reserved)
{
m_possible_data.property_type = main_property_type;
}
2022-04-01 20:58:27 +03:00
ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, unsigned file_description_index, ProcessID pid)
: ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_file_description(pid, file_description_index))
, m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions)
{
m_possible_data.property_index = file_description_index;
}
2022-04-01 20:58:27 +03:00
ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, ThreadID thread_stack_index, ProcessID pid)
: ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_thread_stack(pid, thread_stack_index))
, m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Stacks)
{
m_possible_data.property_index = thread_stack_index.value();
}
ProcFSProcessPropertyInode::ProcFSProcessPropertyInode(ProcFS const& procfs, ProcessID child_pid, ProcessID pid)
: ProcFSProcessAssociatedInode(procfs, pid, SegmentedProcFSIndex::build_segmented_index_for_children(pid, child_pid))
, m_parent_sub_directory_type(SegmentedProcFSIndex::ProcessSubDirectory::Children)
{
m_possible_data.property_index = child_pid.value();
}
ErrorOr<void> ProcFSProcessPropertyInode::attach(OpenFileDescription& description)
{
return refresh_data(description);
}
void ProcFSProcessPropertyInode::did_seek(OpenFileDescription& description, off_t offset)
{
if (offset != 0)
return;
(void)refresh_data(description);
}
static mode_t determine_procfs_process_inode_mode(SegmentedProcFSIndex::ProcessSubDirectory parent_sub_directory_type, SegmentedProcFSIndex::MainProcessProperty main_property)
{
if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions)
return S_IFLNK | 0400;
if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Stacks)
return S_IFREG | 0400;
if (parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Children)
return S_IFLNK | 0400;
VERIFY(parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Reserved);
if (main_property == SegmentedProcFSIndex::MainProcessProperty::BinaryLink)
return S_IFLNK | 0777;
if (main_property == SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink)
return S_IFLNK | 0777;
return S_IFREG | 0400;
}
InodeMetadata ProcFSProcessPropertyInode::metadata() const
{
MutexLocker locker(m_inode_lock);
auto process = Process::from_pid(associated_pid());
if (!process)
return {};
auto traits = process->procfs_traits();
InodeMetadata metadata;
metadata.inode = { fsid(), traits->component_index() };
metadata.mode = determine_procfs_process_inode_mode(m_parent_sub_directory_type, m_possible_data.property_type);
metadata.uid = traits->owner_user();
metadata.gid = traits->owner_group();
metadata.size = 0;
metadata.mtime = traits->modified_time();
return metadata;
}
ErrorOr<void> ProcFSProcessPropertyInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const
{
VERIFY_NOT_REACHED();
}
ErrorOr<size_t> ProcFSProcessPropertyInode::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription* 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) {
auto builder = TRY(KBufferBuilder::try_create());
auto process = Process::from_pid(associated_pid());
if (!process)
return Error::from_errno(ESRCH);
2021-09-05 20:01:38 +03:00
TRY(try_to_acquire_data(*process, builder));
auto data_buffer = builder.build();
if (!data_buffer)
return Error::from_errno(EFAULT);
ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
TRY(buffer.write(data_buffer->data() + offset, nread));
return nread;
}
if (!description->data()) {
dbgln("ProcFS Process Information: Do not have cached data!");
return Error::from_errno(EIO);
}
MutexLocker locker(m_refresh_lock);
auto& typed_cached_data = static_cast<ProcFSInodeData&>(*description->data());
auto& data_buffer = typed_cached_data.buffer;
if (!data_buffer || (size_t)offset >= data_buffer->size())
return 0;
ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
TRY(buffer.write(data_buffer->data() + offset, nread));
return nread;
}
ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessPropertyInode::lookup(StringView)
{
return EINVAL;
}
static ErrorOr<void> build_from_cached_data(KBufferBuilder& builder, ProcFSInodeData& cached_data)
{
cached_data.buffer = builder.build();
if (!cached_data.buffer)
return ENOMEM;
return {};
}
ErrorOr<void> ProcFSProcessPropertyInode::try_to_acquire_data(Process& process, KBufferBuilder& builder) const
{
// FIXME: Verify process is already ref-counted
if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::OpenFileDescriptions) {
2021-09-05 20:01:38 +03:00
TRY(process.procfs_get_file_description_link(m_possible_data.property_index, builder));
return {};
}
if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Stacks) {
2021-09-05 20:01:38 +03:00
TRY(process.procfs_get_thread_stack(m_possible_data.property_index, builder));
return {};
}
if (m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Children) {
TRY(process.procfs_get_child_proccess_link(m_possible_data.property_index, builder));
return {};
}
VERIFY(m_parent_sub_directory_type == SegmentedProcFSIndex::ProcessSubDirectory::Reserved);
switch (m_possible_data.property_type) {
case SegmentedProcFSIndex::MainProcessProperty::Unveil:
return process.procfs_get_unveil_stats(builder);
case SegmentedProcFSIndex::MainProcessProperty::Pledge:
return process.procfs_get_pledge_stats(builder);
case SegmentedProcFSIndex::MainProcessProperty::OpenFileDescriptions:
return process.procfs_get_fds_stats(builder);
case SegmentedProcFSIndex::MainProcessProperty::BinaryLink:
return process.procfs_get_binary_link(builder);
case SegmentedProcFSIndex::MainProcessProperty::CurrentWorkDirectoryLink:
return process.procfs_get_current_work_directory_link(builder);
case SegmentedProcFSIndex::MainProcessProperty::PerformanceEvents:
return process.procfs_get_perf_events(builder);
case SegmentedProcFSIndex::MainProcessProperty::VirtualMemoryStats:
return process.procfs_get_virtual_memory_stats(builder);
case SegmentedProcFSIndex::MainProcessProperty::CommandLine:
return process.procfs_get_command_line(builder);
default:
VERIFY_NOT_REACHED();
}
}
ErrorOr<void> ProcFSProcessPropertyInode::refresh_data(OpenFileDescription& description)
{
// For process-specific inodes, hold the process's ptrace lock across refresh
// and refuse to load data if the process is not dumpable.
// Without this, files opened before a process went non-dumpable could still be used for dumping.
auto process = Process::from_pid(associated_pid());
if (!process)
return Error::from_errno(ESRCH);
process->ptrace_lock().lock();
if (!process->is_dumpable()) {
process->ptrace_lock().unlock();
return EPERM;
}
ScopeGuard guard = [&] {
process->ptrace_lock().unlock();
};
MutexLocker locker(m_refresh_lock);
auto& cached_data = description.data();
if (!cached_data) {
cached_data = adopt_own_if_nonnull(new (nothrow) ProcFSInodeData);
if (!cached_data)
return ENOMEM;
}
auto builder = TRY(KBufferBuilder::try_create());
2021-09-05 20:01:38 +03:00
TRY(try_to_acquire_data(*process, builder));
return build_from_cached_data(builder, static_cast<ProcFSInodeData&>(*cached_data));
}
}