mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 11:44:58 +00:00

This step would ideally not have been necessary (increases amount of refactoring and templates necessary, which in turn increases build times), but it gives us a couple of nice properties: - SpinlockProtected inside Singleton (a very common combination) can now obtain any lock rank just via the template parameter. It was not previously possible to do this with SingletonInstanceCreator magic. - SpinlockProtected's lock rank is now mandatory; this is the majority of cases and allows us to see where we're still missing proper ranks. - The type already informs us what lock rank a lock has, which aids code readability and (possibly, if gdb cooperates) lock mismatch debugging. - The rank of a lock can no longer be dynamic, which is not something we wanted in the first place (or made use of). Locks randomly changing their rank sounds like a disaster waiting to happen. - In some places, we might be able to statically check that locks are taken in the right order (with the right lock rank checking implementation) as rank information is fully statically known. This refactoring even more exposes the fact that Mutex has no lock rank capabilites, which is not fixed here.
247 lines
8.5 KiB
C++
247 lines
8.5 KiB
C++
/*
|
|
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <Kernel/Debug.h>
|
|
#include <Kernel/FileSystem/ProcFS/DirectoryInode.h>
|
|
#include <Kernel/FileSystem/ProcFS/LinkInode.h>
|
|
#include <Kernel/KBufferBuilder.h>
|
|
#include <Kernel/PerformanceEventBuffer.h>
|
|
#include <Kernel/Process.h>
|
|
#include <Kernel/ProcessExposed.h>
|
|
|
|
namespace Kernel {
|
|
|
|
static Spinlock<LockRank::None> s_index_lock {};
|
|
static InodeIndex s_next_inode_index = 0;
|
|
|
|
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::OpenFileDescriptions, fd);
|
|
}
|
|
|
|
InodeIndex build_segmented_index_for_children(ProcessID pid, ProcessID child_pid)
|
|
{
|
|
return build_segmented_index_with_unknown_property(pid, ProcessSubDirectory::Children, child_pid.value());
|
|
}
|
|
|
|
}
|
|
|
|
static size_t s_allocate_global_inode_index()
|
|
{
|
|
SpinlockLocker 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();
|
|
}
|
|
|
|
ProcFSExposedComponent::ProcFSExposedComponent() = default;
|
|
|
|
ProcFSExposedComponent::ProcFSExposedComponent(StringView name)
|
|
: m_component_index(s_allocate_global_inode_index())
|
|
{
|
|
auto name_or_error = KString::try_create(name);
|
|
if (name_or_error.is_error())
|
|
TODO();
|
|
m_name = name_or_error.release_value();
|
|
}
|
|
|
|
ProcFSExposedDirectory::ProcFSExposedDirectory(StringView name)
|
|
: ProcFSExposedComponent(name)
|
|
{
|
|
}
|
|
|
|
ProcFSExposedDirectory::ProcFSExposedDirectory(StringView name, ProcFSExposedDirectory const& parent_directory)
|
|
: ProcFSExposedComponent(name)
|
|
, m_parent_directory(parent_directory)
|
|
{
|
|
}
|
|
|
|
ProcFSExposedLink::ProcFSExposedLink(StringView name)
|
|
: ProcFSExposedComponent(name)
|
|
{
|
|
}
|
|
|
|
ErrorOr<size_t> ProcFSExposedLink::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription*) const
|
|
{
|
|
VERIFY(offset == 0);
|
|
MutexLocker locker(m_lock);
|
|
auto builder = TRY(KBufferBuilder::try_create());
|
|
if (!const_cast<ProcFSExposedLink&>(*this).acquire_link(builder))
|
|
return Error::from_errno(EFAULT);
|
|
auto blob = builder.build();
|
|
if (!blob)
|
|
return Error::from_errno(EFAULT);
|
|
|
|
ssize_t nread = min(static_cast<off_t>(blob->size() - offset), static_cast<off_t>(count));
|
|
TRY(buffer.write(blob->data() + offset, nread));
|
|
return nread;
|
|
}
|
|
|
|
ErrorOr<NonnullLockRefPtr<Inode>> ProcFSExposedLink::to_inode(ProcFS const& procfs_instance) const
|
|
{
|
|
return TRY(ProcFSLinkInode::try_create(procfs_instance, *this));
|
|
}
|
|
|
|
ErrorOr<NonnullLockRefPtr<Inode>> ProcFSExposedDirectory::to_inode(ProcFS const& procfs_instance) const
|
|
{
|
|
return TRY(ProcFSDirectoryInode::try_create(procfs_instance, *this));
|
|
}
|
|
|
|
void ProcFSExposedDirectory::add_component(ProcFSExposedComponent const&)
|
|
{
|
|
TODO();
|
|
}
|
|
|
|
ErrorOr<NonnullLockRefPtr<ProcFSExposedComponent>> ProcFSExposedDirectory::lookup(StringView name)
|
|
{
|
|
for (auto& component : m_components) {
|
|
if (component.name() == name) {
|
|
return component;
|
|
}
|
|
}
|
|
return ENOENT;
|
|
}
|
|
|
|
ErrorOr<void> ProcFSExposedDirectory::traverse_as_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
|
|
{
|
|
MutexLocker locker(ProcFSComponentRegistry::the().get_lock());
|
|
auto parent_directory = m_parent_directory.strong_ref();
|
|
if (parent_directory.is_null())
|
|
return Error::from_errno(EINVAL);
|
|
TRY(callback({ "."sv, { fsid, component_index() }, DT_DIR }));
|
|
TRY(callback({ ".."sv, { fsid, parent_directory->component_index() }, DT_DIR }));
|
|
|
|
for (auto const& component : m_components) {
|
|
InodeIdentifier identifier = { fsid, component.component_index() };
|
|
TRY(callback({ component.name(), identifier, 0 }));
|
|
}
|
|
return {};
|
|
}
|
|
|
|
class ProcFSSelfProcessDirectory final : public ProcFSExposedLink {
|
|
public:
|
|
static NonnullLockRefPtr<ProcFSSelfProcessDirectory> must_create();
|
|
|
|
private:
|
|
ProcFSSelfProcessDirectory();
|
|
virtual bool acquire_link(KBufferBuilder& builder) override
|
|
{
|
|
return !builder.appendff("{}", Process::current().pid().value()).is_error();
|
|
}
|
|
};
|
|
UNMAP_AFTER_INIT NonnullLockRefPtr<ProcFSSelfProcessDirectory> ProcFSSelfProcessDirectory::must_create()
|
|
{
|
|
return adopt_lock_ref_if_nonnull(new (nothrow) ProcFSSelfProcessDirectory()).release_nonnull();
|
|
}
|
|
UNMAP_AFTER_INIT ProcFSSelfProcessDirectory::ProcFSSelfProcessDirectory()
|
|
: ProcFSExposedLink("self"sv)
|
|
{
|
|
}
|
|
|
|
UNMAP_AFTER_INIT NonnullLockRefPtr<ProcFSRootDirectory> ProcFSRootDirectory::must_create()
|
|
{
|
|
auto directory = adopt_lock_ref(*new (nothrow) ProcFSRootDirectory);
|
|
directory->m_components.append(ProcFSSelfProcessDirectory::must_create());
|
|
return directory;
|
|
}
|
|
|
|
ErrorOr<void> ProcFSRootDirectory::traverse_as_directory(FileSystemID fsid, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
|
|
{
|
|
MutexLocker locker(ProcFSComponentRegistry::the().get_lock());
|
|
TRY(callback({ "."sv, { fsid, component_index() }, 0 }));
|
|
TRY(callback({ ".."sv, { fsid, 0 }, 0 }));
|
|
|
|
for (auto const& component : m_components) {
|
|
InodeIdentifier identifier = { fsid, component.component_index() };
|
|
TRY(callback({ component.name(), identifier, 0 }));
|
|
}
|
|
|
|
return Process::for_each_in_same_jail([&](Process& process) -> ErrorOr<void> {
|
|
VERIFY(!(process.pid() < 0));
|
|
u64 process_id = (u64)process.pid().value();
|
|
InodeIdentifier identifier = { fsid, static_cast<InodeIndex>(process_id << 36) };
|
|
auto process_id_string = TRY(KString::formatted("{:d}", process_id));
|
|
TRY(callback({ process_id_string->view(), identifier, 0 }));
|
|
return {};
|
|
});
|
|
}
|
|
|
|
ErrorOr<NonnullLockRefPtr<ProcFSExposedComponent>> ProcFSRootDirectory::lookup(StringView name)
|
|
{
|
|
auto maybe_candidate = ProcFSExposedDirectory::lookup(name);
|
|
if (maybe_candidate.is_error()) {
|
|
if (maybe_candidate.error().code() != ENOENT) {
|
|
return maybe_candidate.release_error();
|
|
}
|
|
} else {
|
|
return maybe_candidate.release_value();
|
|
}
|
|
|
|
auto pid = name.to_uint<unsigned>();
|
|
if (!pid.has_value())
|
|
return ESRCH;
|
|
auto actual_pid = pid.value();
|
|
|
|
if (auto maybe_process = Process::from_pid_in_same_jail(actual_pid))
|
|
return maybe_process->procfs_traits();
|
|
|
|
return ENOENT;
|
|
}
|
|
|
|
UNMAP_AFTER_INIT ProcFSRootDirectory::~ProcFSRootDirectory() = default;
|
|
|
|
UNMAP_AFTER_INIT ProcFSRootDirectory::ProcFSRootDirectory()
|
|
: ProcFSExposedDirectory("."sv)
|
|
{
|
|
}
|
|
|
|
}
|