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.
This commit is contained in:
Liav A 2021-06-12 04:23:58 +03:00 committed by Andreas Kling
parent 1baa05d6b2
commit 12b6e69150
Notes: sideshowbarker 2024-07-18 11:16:36 +09:00
12 changed files with 2294 additions and 1774 deletions

View File

@ -148,6 +148,7 @@ set(KERNEL_SOURCES
Panic.cpp
PerformanceEventBuffer.cpp
Process.cpp
ProcessExposed.cpp
ProcessGroup.cpp
RTC.cpp
Random.cpp

View File

@ -5,12 +5,17 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/JsonArray.h>
#include <AK/JsonArraySerializer.h>
#include <AK/JsonObjectSerializer.h>
#include <AK/Platform.h>
#include <Kernel/CommandLine.h>
#include <Kernel/Debug.h>
#include <Kernel/Devices/USB/UHCIController.h>
#include <Kernel/Devices/USB/USBRequest.h>
#include <Kernel/KBufferBuilder.h>
#include <Kernel/Process.h>
#include <Kernel/ProcessExposed.h>
#include <Kernel/Sections.h>
#include <Kernel/StdLib.h>
#include <Kernel/Time/TimeManagement.h>
@ -65,6 +70,144 @@ static constexpr u16 UHCI_PORTSC_SUSPEND = 0x1000;
static constexpr u8 UHCI_NUMBER_OF_ISOCHRONOUS_TDS = 128;
static constexpr u16 UHCI_NUMBER_OF_FRAMES = 1024;
class ProcFSUSBBusFolder;
static ProcFSUSBBusFolder* s_procfs_usb_bus_folder;
class ProcFSUSBDeviceInformation : public ProcFSGlobalInformation {
friend class ProcFSUSBBusFolder;
public:
virtual ~ProcFSUSBDeviceInformation() override {};
static NonnullRefPtr<ProcFSUSBDeviceInformation> create(USB::Device&);
RefPtr<USB::Device> device() const { return m_device; }
protected:
explicit ProcFSUSBDeviceInformation(USB::Device& device)
: ProcFSGlobalInformation(String::formatted("{}", device.address()))
, m_device(device)
{
}
virtual bool output(KBufferBuilder& builder) override
{
VERIFY(m_device); // Something has gone very wrong if this isn't true
JsonArraySerializer array { builder };
auto obj = array.add_object();
obj.add("usb_spec_compliance_bcd", m_device->device_descriptor().usb_spec_compliance_bcd);
obj.add("device_class", m_device->device_descriptor().device_class);
obj.add("device_sub_class", m_device->device_descriptor().device_sub_class);
obj.add("device_protocol", m_device->device_descriptor().device_protocol);
obj.add("max_packet_size", m_device->device_descriptor().max_packet_size);
obj.add("vendor_id", m_device->device_descriptor().vendor_id);
obj.add("product_id", m_device->device_descriptor().product_id);
obj.add("device_release_bcd", m_device->device_descriptor().device_release_bcd);
obj.add("manufacturer_id_descriptor_index", m_device->device_descriptor().manufacturer_id_descriptor_index);
obj.add("product_string_descriptor_index", m_device->device_descriptor().product_string_descriptor_index);
obj.add("serial_number_descriptor_index", m_device->device_descriptor().serial_number_descriptor_index);
obj.add("num_configurations", m_device->device_descriptor().num_configurations);
obj.finish();
array.finish();
return true;
}
IntrusiveListNode<ProcFSUSBDeviceInformation, RefPtr<ProcFSUSBDeviceInformation>> m_list_node;
RefPtr<USB::Device> m_device;
};
class ProcFSUSBBusFolder final : public ProcFSExposedFolder {
friend class ProcFSComponentsRegistrar;
public:
static void initialize();
void plug(USB::Device&);
void unplug(USB::Device&);
virtual KResultOr<size_t> entries_count() const override;
virtual KResult traverse_as_directory(unsigned, Function<bool(const FS::DirectoryEntryView&)>) const override;
virtual RefPtr<ProcFSExposedComponent> lookup(StringView name) override;
private:
ProcFSUSBBusFolder(const ProcFSBusDirectory&);
RefPtr<ProcFSUSBDeviceInformation> device_node_for(USB::Device& device);
IntrusiveList<ProcFSUSBDeviceInformation, RefPtr<ProcFSUSBDeviceInformation>, &ProcFSUSBDeviceInformation::m_list_node> m_device_nodes;
mutable SpinLock<u8> m_lock;
};
KResultOr<size_t> ProcFSUSBBusFolder::entries_count() const
{
ScopedSpinLock lock(m_lock);
return m_device_nodes.size_slow();
}
KResult ProcFSUSBBusFolder::traverse_as_directory(unsigned fsid, Function<bool(const FS::DirectoryEntryView&)> callback) const
{
ScopedSpinLock lock(m_lock);
VERIFY(m_parent_folder);
callback({ ".", { fsid, component_index() }, 0 });
callback({ "..", { fsid, m_parent_folder->component_index() }, 0 });
for (auto& device_node : m_device_nodes) {
InodeIdentifier identifier = { fsid, device_node.component_index() };
callback({ device_node.name(), identifier, 0 });
}
return KSuccess;
}
RefPtr<ProcFSExposedComponent> ProcFSUSBBusFolder::lookup(StringView name)
{
ScopedSpinLock lock(m_lock);
for (auto& device_node : m_device_nodes) {
if (device_node.name() == name) {
return device_node;
}
}
return {};
}
RefPtr<ProcFSUSBDeviceInformation> ProcFSUSBBusFolder::device_node_for(USB::Device& device)
{
RefPtr<USB::Device> checked_device = device;
for (auto& device_node : m_device_nodes) {
if (device_node.device().ptr() == checked_device.ptr())
return device_node;
}
return {};
}
void ProcFSUSBBusFolder::plug(USB::Device& new_device)
{
ScopedSpinLock lock(m_lock);
auto device_node = device_node_for(new_device);
VERIFY(!device_node);
m_device_nodes.append(ProcFSUSBDeviceInformation::create(new_device));
}
void ProcFSUSBBusFolder::unplug(USB::Device& deleted_device)
{
ScopedSpinLock lock(m_lock);
auto device_node = device_node_for(deleted_device);
VERIFY(device_node);
device_node->m_list_node.remove();
}
UNMAP_AFTER_INIT ProcFSUSBBusFolder::ProcFSUSBBusFolder(const ProcFSBusDirectory& buses_folder)
: ProcFSExposedFolder("usb"sv, buses_folder)
{
}
UNMAP_AFTER_INIT void ProcFSUSBBusFolder::initialize()
{
auto folder = adopt_ref(*new ProcFSUSBBusFolder(ProcFSComponentsRegistrar::the().buses_folder()));
ProcFSComponentsRegistrar::the().register_new_bus_folder(folder);
s_procfs_usb_bus_folder = folder;
}
NonnullRefPtr<ProcFSUSBDeviceInformation> ProcFSUSBDeviceInformation::create(USB::Device& device)
{
return adopt_ref(*new ProcFSUSBDeviceInformation(device));
}
UHCIController& UHCIController::the()
{
return *s_the;
@ -75,6 +218,10 @@ UNMAP_AFTER_INIT void UHCIController::detect()
if (kernel_command_line().disable_uhci_controller())
return;
// FIXME: We create the /proc/bus/usb representation here, but it should really be handled
// in a more broad singleton than this once we refactor things in USB subsystem.
ProcFSUSBBusFolder::initialize();
PCI::enumerate([&](const PCI::Address& address, PCI::ID id) {
if (address.is_null())
return;
@ -569,8 +716,14 @@ void UHCIController::spawn_port_proc()
dmesgln("UHCI: Device creation failed on port 1 ({})", device.error());
m_devices.at(0) = device.value();
VERIFY(s_procfs_usb_bus_folder);
s_procfs_usb_bus_folder->plug(device.value());
} else {
// FIXME: Clean up (and properly) the RefPtr to the device in m_devices
VERIFY(s_procfs_usb_bus_folder);
VERIFY(m_devices.at(0));
dmesgln("UHCI: Device detach detected on Root Port 1");
s_procfs_usb_bus_folder->unplug(*m_devices.at(0));
}
}
} else {
@ -601,8 +754,14 @@ void UHCIController::spawn_port_proc()
dmesgln("UHCI: Device creation failed on port 2 ({})", device.error());
m_devices.at(1) = device.value();
VERIFY(s_procfs_usb_bus_folder);
s_procfs_usb_bus_folder->plug(device.value());
} else {
// FIXME: Clean up (and properly) the RefPtr to the device in m_devices
VERIFY(s_procfs_usb_bus_folder);
VERIFY(m_devices.at(1));
dmesgln("UHCI: Device detach detected on Root Port 2");
s_procfs_usb_bus_folder->unplug(*m_devices.at(1));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -12,130 +12,91 @@
#include <Kernel/FileSystem/Inode.h>
#include <Kernel/KBufferBuilder.h>
#include <Kernel/Lock.h>
#include <Kernel/ProcessExposed.h>
namespace Kernel {
class Process;
class ProcFSInode;
class ProcFSDirectoryInode;
class ProcFS final : public FS {
friend class ProcFSInode;
friend class ProcFSDirectoryInode;
public:
virtual ~ProcFS() override;
static RefPtr<ProcFS> create();
virtual bool initialize() override;
virtual const char* class_name() const override;
virtual const char* class_name() const override { return "ProcFS"; }
virtual NonnullRefPtr<Inode> root_inode() const override;
static void add_sys_bool(String&&, Lockable<bool>&, Function<void()>&& notify_callback = nullptr);
private:
ProcFS();
struct ProcFSDirectoryEntry {
ProcFSDirectoryEntry() = default;
ProcFSDirectoryEntry(const char* a_name, unsigned a_proc_file_type, bool a_supervisor_only, bool (*read_callback)(InodeIdentifier, KBufferBuilder&) = nullptr, KResultOr<size_t> (*write_callback)(InodeIdentifier, const UserOrKernelBuffer&, size_t) = nullptr, RefPtr<ProcFSInode>&& a_inode = nullptr)
: name(a_name)
, proc_file_type(a_proc_file_type)
, supervisor_only(a_supervisor_only)
, read_callback(read_callback)
, write_callback(write_callback)
, inode(move(a_inode))
{
}
const char* name { nullptr };
unsigned proc_file_type { 0 };
bool supervisor_only { false };
bool (*read_callback)(InodeIdentifier, KBufferBuilder&);
KResultOr<size_t> (*write_callback)(InodeIdentifier, const UserOrKernelBuffer&, size_t);
RefPtr<ProcFSInode> inode;
InodeIdentifier identifier(unsigned fsid) const;
};
RefPtr<Inode> get_inode(InodeIdentifier) const;
ProcFSDirectoryEntry* get_directory_entry(InodeIdentifier) const;
Vector<ProcFSDirectoryEntry> m_entries;
mutable Lock m_inodes_lock;
mutable HashMap<unsigned, ProcFSInode*> m_inodes;
RefPtr<ProcFSInode> m_root_inode;
NonnullRefPtr<ProcFSDirectoryInode> m_root_inode;
};
class ProcFSInode final : public Inode {
class ProcFSInode : public Inode {
friend class ProcFS;
public:
static NonnullRefPtr<ProcFSInode> create(const ProcFS&, const ProcFSExposedComponent&);
virtual ~ProcFSInode() override;
StringView name() const;
protected:
ProcFSInode(const ProcFS&, const ProcFSExposedComponent&);
private:
// ^Inode
virtual KResult attach(FileDescription&) override;
virtual void did_seek(FileDescription&, off_t) override;
virtual KResult attach(FileDescription& description) override;
virtual KResultOr<size_t> read_bytes(off_t, size_t, UserOrKernelBuffer& buffer, FileDescription*) const override;
virtual InodeMetadata metadata() const override;
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
virtual RefPtr<Inode> lookup(StringView name) override;
virtual void flush_metadata() override;
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(const String& 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 KResultOr<size_t> directory_entry_count() const override;
virtual KResult chmod(mode_t) override;
virtual KResult chown(uid_t, gid_t) override;
virtual KResultOr<NonnullRefPtr<Custody>> resolve_as_link(Custody& base, RefPtr<Custody>* out_parent = nullptr, int options = 0, int symlink_recursion_level = 0) const override;
virtual KResult set_mtime(time_t) override;
virtual KResult truncate(u64) override;
KResult refresh_data(FileDescription&) const;
RefPtr<Process> process() const;
ProcFS& fs() { return static_cast<ProcFS&>(Inode::fs()); }
const ProcFS& fs() const { return static_cast<const ProcFS&>(Inode::fs()); }
ProcFSInode(ProcFS&, InodeIndex);
NonnullRefPtr<ProcFSExposedComponent> m_associated_component;
};
class ProcFSProxyInode final : public Inode {
friend class ProcFSInode;
class ProcFSLinkInode : public ProcFSInode {
friend class ProcFS;
public:
virtual ~ProcFSProxyInode() override;
static NonnullRefPtr<ProcFSLinkInode> create(const ProcFS&, const ProcFSExposedComponent&);
private:
// ^Inode
virtual KResult attach(FileDescription&) override;
virtual void did_seek(FileDescription&, off_t) override;
virtual KResultOr<size_t> read_bytes(off_t, size_t, UserOrKernelBuffer&, FileDescription*) const override { VERIFY_NOT_REACHED(); }
protected:
ProcFSLinkInode(const ProcFS&, const ProcFSExposedComponent&);
virtual InodeMetadata metadata() const override;
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override { VERIFY_NOT_REACHED(); }
virtual RefPtr<Inode> lookup(StringView name) override;
virtual void flush_metadata() override {};
virtual KResultOr<size_t> write_bytes(off_t, size_t, const UserOrKernelBuffer&, FileDescription*) override { VERIFY_NOT_REACHED(); }
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& 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 KResultOr<size_t> directory_entry_count() const override;
virtual KResult chmod(mode_t) override { return EINVAL; }
virtual KResult chown(uid_t, gid_t) override { return EINVAL; }
virtual KResultOr<NonnullRefPtr<Custody>> resolve_as_link(Custody&, RefPtr<Custody>*, int, int) const override { VERIFY_NOT_REACHED(); }
virtual FileDescription* preopen_fd() override { return m_fd; }
ProcFS& fs() { return static_cast<ProcFS&>(Inode::fs()); }
const ProcFS& fs() const { return static_cast<const ProcFS&>(Inode::fs()); }
ProcFSProxyInode(ProcFS&, FileDescription&);
static NonnullRefPtr<ProcFSProxyInode> create(ProcFS& fs, FileDescription& fd)
{
return adopt_ref(*new ProcFSProxyInode(fs, fd));
}
NonnullRefPtr<FileDescription> m_fd;
};
class ProcFSDirectoryInode : public ProcFSInode {
friend class ProcFS;
public:
static NonnullRefPtr<ProcFSDirectoryInode> create(const ProcFS&, const ProcFSExposedComponent&);
virtual ~ProcFSDirectoryInode() override;
protected:
ProcFSDirectoryInode(const ProcFS&, const ProcFSExposedComponent&);
// ^Inode
virtual InodeMetadata metadata() const override;
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
virtual RefPtr<Inode> lookup(StringView name) override;
virtual KResultOr<size_t> directory_entry_count() const override;
ProcFS& m_parent_fs;
};
}

View File

@ -24,6 +24,7 @@
#include <Kernel/PerformanceEventBuffer.h>
#include <Kernel/PerformanceManager.h>
#include <Kernel/Process.h>
#include <Kernel/ProcessExposed.h>
#include <Kernel/RTC.h>
#include <Kernel/Sections.h>
#include <Kernel/StdLib.h>
@ -129,6 +130,15 @@ void Process::kill_all_threads()
});
}
void Process::register_new(Process& process)
{
// Note: this is essentially the same like process->ref()
RefPtr<Process> new_process = process;
ScopedSpinLock lock(g_processes_lock);
g_processes->prepend(process);
ProcFSComponentsRegistrar::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)
{
auto parts = path.split('/');
@ -166,11 +176,7 @@ RefPtr<Process> Process::create_user_process(RefPtr<Thread>& first_thread, const
return {};
}
{
process->ref();
ScopedSpinLock lock(g_processes_lock);
g_processes->prepend(*process);
}
register_new(*process);
error = 0;
return process;
}
@ -189,9 +195,7 @@ RefPtr<Process> Process::create_kernel_process(RefPtr<Thread>& first_thread, Str
#endif
if (process->pid() != 0) {
process->ref();
ScopedSpinLock lock(g_processes_lock);
g_processes->prepend(*process);
register_new(*process);
}
ScopedSpinLock lock(g_scheduler_lock);
@ -391,6 +395,7 @@ RefPtr<Process> Process::from_pid(ProcessID pid)
RefPtr<FileDescription> Process::file_description(int fd) const
{
ScopedSpinLock lock(m_fds_lock);
if (fd < 0)
return nullptr;
if (static_cast<size_t>(fd) < m_fds.size())
@ -400,6 +405,7 @@ RefPtr<FileDescription> Process::file_description(int fd) const
int Process::fd_flags(int fd) const
{
ScopedSpinLock lock(m_fds_lock);
if (fd < 0)
return -1;
if (static_cast<size_t>(fd) < m_fds.size())
@ -409,9 +415,10 @@ int Process::fd_flags(int fd) const
int Process::number_of_open_file_descriptors() const
{
ScopedSpinLock lock(m_fds_lock);
int count = 0;
for (auto& description : m_fds) {
if (description)
for (size_t index = 0; index < m_fds.size(); index++) {
if (m_fds[index].is_valid())
++count;
}
return count;
@ -419,6 +426,7 @@ int Process::number_of_open_file_descriptors() const
int Process::alloc_fd(int first_candidate_fd)
{
ScopedSpinLock lock(m_fds_lock);
for (int i = first_candidate_fd; i < (int)m_max_open_file_descriptors; ++i) {
if (!m_fds[i])
return i;
@ -535,6 +543,12 @@ 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.
ProcFSComponentsRegistrar::the().unregister_process(*this);
m_dead = true;
{
@ -676,14 +690,24 @@ RefPtr<Thread> Process::create_kernel_thread(void (*entry)(void*), void* entry_d
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 = ProcFSComponentsRegistrar::the().allocate_inode_index();
}
void Process::FileDescriptionAndFlags::set(NonnullRefPtr<FileDescription>&& description, u32 flags)
{
// FIXME: Verify Process::m_fds_lock is locked!
m_description = move(description);
m_flags = flags;
m_global_procfs_inode_index = ProcFSComponentsRegistrar::the().allocate_inode_index();
}
Custody& Process::root_directory()

View File

@ -17,6 +17,7 @@
#include <AK/WeakPtr.h>
#include <AK/Weakable.h>
#include <Kernel/API/Syscall.h>
#include <Kernel/FileSystem/FileDescription.h>
#include <Kernel/FileSystem/InodeMetadata.h>
#include <Kernel/Forward.h>
#include <Kernel/FutexQueue.h>
@ -129,6 +130,7 @@ class Process
friend class Thread;
friend class CoreDump;
friend class ProcFSProcessFileDescriptions;
// Helper class to temporarily unprotect a process's protected data so you can write to it.
class ProtectedDataMutationScope {
@ -169,6 +171,7 @@ public:
static RefPtr<Process> create_kernel_process(RefPtr<Thread>& first_thread, String&& name, void (*entry)(void*), void* entry_data = nullptr, u32 affinity = THREAD_AFFINITY_DEFAULT);
static RefPtr<Process> create_user_process(RefPtr<Thread>& first_thread, const String& path, uid_t, gid_t, ProcessID ppid, int& error, Vector<String>&& arguments = Vector<String>(), Vector<String>&& environment = Vector<String>(), TTY* = nullptr);
static void register_new(Process&);
~Process();
static Vector<ProcessID> all_pids();
@ -585,23 +588,41 @@ private:
static constexpr int m_max_open_file_descriptors { FD_SETSIZE };
public:
class FileDescriptionAndFlags {
friend class FileDescriptionRegistrar;
public:
operator bool() const { return !!m_description; }
bool is_valid() const { return !m_description.is_null(); }
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;
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;
};
// FIXME: We create a copy when trying to iterate the Vector because
// we don't want to put lots of locking when accessing this Vector.
// Maybe try to encapsulate the Vector inside a protective class with locking
// mechanism.
Vector<FileDescriptionAndFlags> fds() const { return m_fds; }
private:
Vector<FileDescriptionAndFlags> m_fds;
mutable RecursiveSpinLock m_thread_list_lock;
@ -638,6 +659,7 @@ private:
FutexQueues m_futex_queues;
SpinLock<u8> m_futex_lock;
mutable SpinLock<u8> m_fds_lock;
// This member is used in the implementation of ptrace's PT_TRACEME flag.
// If it is set to true, the process will stop at the next execve syscall

1626
Kernel/ProcessExposed.cpp Normal file

File diff suppressed because it is too large Load Diff

254
Kernel/ProcessExposed.h Normal file
View File

@ -0,0 +1,254 @@
/*
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Function.h>
#include <AK/RefCounted.h>
#include <AK/RefPtr.h>
#include <AK/String.h>
#include <AK/Types.h>
#include <Kernel/Arch/x86/CPU.h>
#include <Kernel/FileSystem/File.h>
#include <Kernel/FileSystem/FileSystem.h>
#include <Kernel/KBufferBuilder.h>
#include <Kernel/KResult.h>
#include <Kernel/Process.h>
#include <Kernel/UserOrKernelBuffer.h>
namespace Kernel {
class ProcFS;
class ProcFSExposedComponent;
class ProcFSExposedFolder;
class ProcFSRootFolder;
class ProcFSBusDirectory;
class ProcFSSystemBoolean;
class ProcFSComponentsRegistrar {
friend class ProcFS;
friend class ProcFSExposedComponent;
friend class ProcFSExposedFolder;
friend class ProcFSRootFolder;
public:
static ProcFSComponentsRegistrar& the();
static void initialize();
InodeIndex allocate_inode_index() const;
ProcFSComponentsRegistrar();
void register_new_bus_folder(ProcFSExposedFolder&);
const ProcFSBusDirectory& buses_folder() const;
void register_new_process(Process&);
void unregister_process(Process&);
ProcFSRootFolder& root_folder() { return *m_root_folder; }
private:
Lock m_lock;
NonnullRefPtr<ProcFSRootFolder> m_root_folder;
};
class ProcFSExposedComponent : public RefCounted<ProcFSExposedComponent> {
public:
virtual KResultOr<size_t> entries_count() const { VERIFY_NOT_REACHED(); };
StringView name() const { return m_name->view(); }
virtual KResultOr<size_t> read_bytes(off_t, size_t, UserOrKernelBuffer&, FileDescription*) const { VERIFY_NOT_REACHED(); }
virtual KResult traverse_as_directory(unsigned, Function<bool(const FS::DirectoryEntryView&)>) const { VERIFY_NOT_REACHED(); }
virtual RefPtr<ProcFSExposedComponent> lookup(StringView) { VERIFY_NOT_REACHED(); };
virtual KResultOr<size_t> write_bytes(off_t, size_t, const UserOrKernelBuffer&, FileDescription*) { return KResult(EROFS); }
virtual size_t size() const { return 0; }
virtual mode_t required_mode() const { return 0444; }
virtual uid_t owner_user() const { return 0; }
virtual gid_t owner_group() const { return 0; }
virtual void prepare_for_deletion() { }
virtual KResult refresh_data(FileDescription&) const
{
return KSuccess;
}
virtual NonnullRefPtr<Inode> to_inode(const ProcFS& procfs_instance) const;
size_t component_index() const { return m_component_index; };
virtual ~ProcFSExposedComponent() = default;
protected:
explicit ProcFSExposedComponent(StringView name);
ProcFSExposedComponent(StringView name, InodeIndex preallocated_index);
private:
OwnPtr<KString> m_name;
size_t m_component_index;
};
class ProcFSExposedFolder : public ProcFSExposedComponent {
friend class ProcFSProcessFolder;
friend class ProcFSComponentsRegistrar;
public:
virtual KResultOr<size_t> entries_count() const override { return m_components.size(); };
virtual KResult traverse_as_directory(unsigned, Function<bool(const FS::DirectoryEntryView&)>) const override;
virtual RefPtr<ProcFSExposedComponent> lookup(StringView name) override;
void add_component(const ProcFSExposedComponent&);
virtual void prepare_for_deletion() override
{
m_components.clear();
m_parent_folder.clear();
}
virtual mode_t required_mode() const override { return 0555; }
virtual NonnullRefPtr<Inode> to_inode(const ProcFS& procfs_instance) const override final;
protected:
explicit ProcFSExposedFolder(StringView name);
ProcFSExposedFolder(StringView name, const ProcFSExposedFolder& parent_folder);
NonnullRefPtrVector<ProcFSExposedComponent> m_components;
RefPtr<ProcFSExposedFolder> m_parent_folder;
};
class ProcFSExposedLink : public ProcFSExposedComponent {
public:
virtual NonnullRefPtr<Inode> to_inode(const ProcFS& procfs_instance) const override final;
virtual KResultOr<size_t> read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription* description) const override;
protected:
virtual bool acquire_link(KBufferBuilder& builder) = 0;
explicit ProcFSExposedLink(StringView name);
ProcFSExposedLink(StringView name, InodeIndex preallocated_index);
mutable Lock m_lock { "ProcFSLink" };
};
class ProcFSRootFolder;
class ProcFSProcessInformation;
class ProcFSProcessFolder final : public ProcFSExposedFolder {
friend class ProcFSComponentsRegistrar;
friend class ProcFSRootFolder;
friend class ProcFSProcessInformation;
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<ProcFSProcessFolder> create(const Process&);
NonnullRefPtr<Process> associated_process() { return m_associated_process; }
virtual uid_t owner_user() const override { return m_associated_process->uid(); }
virtual gid_t owner_group() const override { return m_associated_process->gid(); }
private:
IntrusiveListNode<ProcFSProcessFolder, RefPtr<ProcFSProcessFolder>> m_list_node;
explicit ProcFSProcessFolder(const Process&);
NonnullRefPtr<Process> m_associated_process;
};
class ProcFSRootFolder;
class ProcFSBusDirectory : public ProcFSExposedFolder {
friend class ProcFSComponentsRegistrar;
public:
static NonnullRefPtr<ProcFSBusDirectory> must_create(const ProcFSRootFolder& parent_folder);
private:
ProcFSBusDirectory(const ProcFSRootFolder& parent_folder);
};
class ProcFSRootFolder final : public ProcFSExposedFolder {
friend class ProcFSComponentsRegistrar;
public:
virtual RefPtr<ProcFSExposedComponent> lookup(StringView name) override;
RefPtr<ProcFSProcessFolder> process_folder_for(Process&);
static NonnullRefPtr<ProcFSRootFolder> must_create();
virtual ~ProcFSRootFolder();
private:
virtual KResult traverse_as_directory(unsigned, Function<bool(const FS::DirectoryEntryView&)>) const override;
ProcFSRootFolder();
RefPtr<ProcFSBusDirectory> m_buses_folder;
IntrusiveList<ProcFSProcessFolder, RefPtr<ProcFSProcessFolder>, &ProcFSProcessFolder::m_list_node> m_process_folders;
};
class ProcFSGlobalInformation : public ProcFSExposedComponent {
public:
virtual ~ProcFSGlobalInformation() override {};
virtual KResultOr<size_t> read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, FileDescription* description) const override;
virtual mode_t required_mode() const override { return 0444; }
protected:
explicit ProcFSGlobalInformation(StringView name)
: ProcFSExposedComponent(name)
{
}
virtual KResult refresh_data(FileDescription&) const override;
virtual bool output(KBufferBuilder& builder) = 0;
mutable SpinLock<u8> m_refresh_lock;
};
class ProcFSSystemBoolean : public ProcFSGlobalInformation {
public:
virtual bool value() const = 0;
virtual void set_value(bool new_value) = 0;
protected:
explicit ProcFSSystemBoolean(StringView name)
: ProcFSGlobalInformation(name)
{
}
virtual bool output(KBufferBuilder& builder) override
{
builder.appendff("{}\n", value());
return true;
}
};
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 { return m_parent_folder->m_associated_process->uid(); }
virtual gid_t owner_group() const override { return m_parent_folder->m_associated_process->gid(); }
protected:
ProcFSProcessInformation(StringView name, const ProcFSProcessFolder& process_folder)
: ProcFSExposedComponent(name)
, m_parent_folder(process_folder)
{
}
virtual KResult refresh_data(FileDescription&) const override;
virtual bool output(KBufferBuilder& builder) = 0;
NonnullRefPtr<ProcFSProcessFolder> m_parent_folder;
mutable SpinLock<u8> m_refresh_lock;
};
}

View File

@ -109,8 +109,7 @@ KResultOr<FlatPtr> Process::sys$fork(RegisterState& regs)
child->m_master_tls_region = child_region;
}
ScopedSpinLock processes_lock(g_processes_lock);
g_processes->prepend(*child);
Process::register_new(*child);
}
PerformanceManager::add_process_created_event(*child);

View File

@ -16,6 +16,7 @@
#include <Kernel/Panic.h>
#include <Kernel/PerformanceEventBuffer.h>
#include <Kernel/Process.h>
#include <Kernel/ProcessExposed.h>
#include <Kernel/Scheduler.h>
#include <Kernel/Sections.h>
#include <Kernel/Thread.h>
@ -59,6 +60,7 @@ Thread::Thread(NonnullRefPtr<Process> process, NonnullOwnPtr<Region> kernel_stac
, m_kernel_stack_region(move(kernel_stack_region))
, m_name(m_process->name())
, m_block_timer(block_timer)
, m_global_procfs_inode_index(ProcFSComponentsRegistrar::the().allocate_inode_index())
{
bool is_first_thread = m_process->add_thread(*this);
if (is_first_thread) {

View File

@ -22,6 +22,7 @@
#include <Kernel/Arch/x86/RegisterState.h>
#include <Kernel/Arch/x86/SafeMem.h>
#include <Kernel/Debug.h>
#include <Kernel/FileSystem/InodeIdentifier.h>
#include <Kernel/Forward.h>
#include <Kernel/KResult.h>
#include <Kernel/LockMode.h>
@ -1184,6 +1185,7 @@ public:
bool may_die_immediately() const { return m_may_die_immediately; }
void set_may_die_immediately(bool flag) { m_may_die_immediately = flag; }
InodeIndex global_procfs_inode_index() const { return m_global_procfs_inode_index; }
private:
Thread(NonnullRefPtr<Process>, NonnullOwnPtr<Region>, NonnullRefPtr<Timer>);
@ -1328,6 +1330,10 @@ 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_without_holding_big_lock();

View File

@ -8,8 +8,8 @@
#include <Kernel/ACPI/DynamicParser.h>
#include <Kernel/ACPI/Initialize.h>
#include <Kernel/ACPI/MultiProcessorParser.h>
#include <Kernel/Arch/x86/Processor.h>
#include <Kernel/Arch/PC/BIOS.h>
#include <Kernel/Arch/x86/Processor.h>
#include <Kernel/CMOS.h>
#include <Kernel/CommandLine.h>
#include <Kernel/Devices/FullDevice.h>
@ -40,6 +40,7 @@
#include <Kernel/PCI/Initializer.h>
#include <Kernel/Panic.h>
#include <Kernel/Process.h>
#include <Kernel/ProcessExposed.h>
#include <Kernel/RTC.h>
#include <Kernel/Random.h>
#include <Kernel/Scheduler.h>
@ -148,6 +149,7 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT void init()
// Initialize the PCI Bus as early as possible, for early boot (PCI based) serial logging
SystemRegistrar::initialize();
ProcFSComponentsRegistrar::initialize();
PCI::initialize();
PCISerialDevice::detect();