Kernel: Use KBuffers for ProcFS and SynthFS

Instead of generating ByteBuffers and keeping those lying around, have
these filesystems generate KBuffers instead. These are way less spooky
to leave around for a while.

Since FileDescription will keep a generated file buffer around until
userspace has read the whole thing, this prevents trivially exhausting
the kmalloc heap by opening many files in /proc for example.

The code responsible for generating each /proc file is not perfectly
efficient and many of them still use ByteBuffers internally but they
at least go away when we return now. :^)
This commit is contained in:
Andreas Kling 2019-08-05 11:35:49 +02:00
parent 6b6b86fbf3
commit 79e22acb22
Notes: sideshowbarker 2024-07-19 12:52:47 +09:00
7 changed files with 58 additions and 43 deletions

View file

@ -8,6 +8,7 @@
#include <Kernel/FileSystem/Inode.h>
#include <Kernel/FileSystem/InodeMetadata.h>
#include <Kernel/FileSystem/VirtualFileSystem.h>
#include <Kernel/KBuffer.h>
#include <Kernel/Net/Socket.h>
#include <Kernel/VM/VirtualAddress.h>
@ -90,7 +91,7 @@ public:
SharedMemory* shared_memory();
const SharedMemory* shared_memory() const;
ByteBuffer& generator_cache() { return m_generator_cache; }
Optional<KBuffer>& generator_cache() { return m_generator_cache; }
void set_original_inode(Badge<VFS>, NonnullRefPtr<Inode>&& inode) { m_inode = move(inode); }
@ -114,7 +115,7 @@ private:
off_t m_current_offset { 0 };
ByteBuffer m_generator_cache;
Optional<KBuffer> m_generator_cache;
u32 m_file_flags { 0 };

View file

@ -185,7 +185,7 @@ ProcFS::~ProcFS()
{
}
ByteBuffer procfs$pid_fds(InodeIdentifier identifier)
Optional<KBuffer> procfs$pid_fds(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
@ -209,7 +209,7 @@ ByteBuffer procfs$pid_fds(InodeIdentifier identifier)
return array.serialized().to_byte_buffer();
}
ByteBuffer procfs$pid_fd_entry(InodeIdentifier identifier)
Optional<KBuffer> procfs$pid_fd_entry(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
@ -222,7 +222,7 @@ ByteBuffer procfs$pid_fd_entry(InodeIdentifier identifier)
return description->absolute_path().to_byte_buffer();
}
ByteBuffer procfs$pid_vm(InodeIdentifier identifier)
Optional<KBuffer> procfs$pid_vm(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
@ -242,7 +242,7 @@ ByteBuffer procfs$pid_vm(InodeIdentifier identifier)
return array.serialized().to_byte_buffer();
}
ByteBuffer procfs$pci(InodeIdentifier)
Optional<KBuffer> procfs$pci(InodeIdentifier)
{
StringBuilder builder;
PCI::enumerate_all([&builder](PCI::Address address, PCI::ID id) {
@ -251,21 +251,21 @@ ByteBuffer procfs$pci(InodeIdentifier)
return builder.to_byte_buffer();
}
ByteBuffer procfs$uptime(InodeIdentifier)
Optional<KBuffer> procfs$uptime(InodeIdentifier)
{
StringBuilder builder;
builder.appendf("%u\n", (u32)(g_uptime / 1000));
return builder.to_byte_buffer();
}
ByteBuffer procfs$cmdline(InodeIdentifier)
Optional<KBuffer> procfs$cmdline(InodeIdentifier)
{
StringBuilder builder;
builder.appendf("%s\n", KParams::the().cmdline().characters());
return builder.to_byte_buffer();
}
ByteBuffer procfs$netadapters(InodeIdentifier)
Optional<KBuffer> procfs$netadapters(InodeIdentifier)
{
StringBuilder builder;
NetworkAdapter::for_each([&builder](auto& adapter) {
@ -278,7 +278,7 @@ ByteBuffer procfs$netadapters(InodeIdentifier)
return builder.to_byte_buffer();
}
ByteBuffer procfs$pid_vmo(InodeIdentifier identifier)
Optional<KBuffer> procfs$pid_vmo(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
@ -309,7 +309,7 @@ ByteBuffer procfs$pid_vmo(InodeIdentifier identifier)
return builder.to_byte_buffer();
}
ByteBuffer procfs$pid_stack(InodeIdentifier identifier)
Optional<KBuffer> procfs$pid_stack(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
@ -318,7 +318,7 @@ ByteBuffer procfs$pid_stack(InodeIdentifier identifier)
return process.backtrace(*handle).to_byte_buffer();
}
ByteBuffer procfs$pid_regs(InodeIdentifier identifier)
Optional<KBuffer> procfs$pid_regs(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
@ -344,7 +344,7 @@ ByteBuffer procfs$pid_regs(InodeIdentifier identifier)
return builder.to_byte_buffer();
}
ByteBuffer procfs$pid_exe(InodeIdentifier identifier)
Optional<KBuffer> procfs$pid_exe(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
@ -355,7 +355,7 @@ ByteBuffer procfs$pid_exe(InodeIdentifier identifier)
return custody->absolute_path().to_byte_buffer();
}
ByteBuffer procfs$pid_cwd(InodeIdentifier identifier)
Optional<KBuffer> procfs$pid_cwd(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
@ -363,14 +363,14 @@ ByteBuffer procfs$pid_cwd(InodeIdentifier identifier)
return handle->process().current_directory().absolute_path().to_byte_buffer();
}
ByteBuffer procfs$self(InodeIdentifier)
Optional<KBuffer> procfs$self(InodeIdentifier)
{
char buffer[16];
ksprintf(buffer, "%u", current->pid());
return ByteBuffer::copy((const u8*)buffer, strlen(buffer));
return KBuffer::copy((const u8*)buffer, strlen(buffer));
}
ByteBuffer procfs$mm(InodeIdentifier)
Optional<KBuffer> procfs$mm(InodeIdentifier)
{
// FIXME: Implement
InterruptDisabler disabler;
@ -389,7 +389,7 @@ ByteBuffer procfs$mm(InodeIdentifier)
return builder.to_byte_buffer();
}
ByteBuffer procfs$dmesg(InodeIdentifier)
Optional<KBuffer> procfs$dmesg(InodeIdentifier)
{
InterruptDisabler disabler;
StringBuilder builder;
@ -398,7 +398,7 @@ ByteBuffer procfs$dmesg(InodeIdentifier)
return builder.to_byte_buffer();
}
ByteBuffer procfs$mounts(InodeIdentifier)
Optional<KBuffer> procfs$mounts(InodeIdentifier)
{
// FIXME: This is obviously racy against the VFS mounts changing.
StringBuilder builder;
@ -417,7 +417,7 @@ ByteBuffer procfs$mounts(InodeIdentifier)
return builder.to_byte_buffer();
}
ByteBuffer procfs$df(InodeIdentifier)
Optional<KBuffer> procfs$df(InodeIdentifier)
{
// FIXME: This is obviously racy against the VFS mounts changing.
JsonArray json;
@ -435,7 +435,7 @@ ByteBuffer procfs$df(InodeIdentifier)
return json.serialized().to_byte_buffer();
}
ByteBuffer procfs$cpuinfo(InodeIdentifier)
Optional<KBuffer> procfs$cpuinfo(InodeIdentifier)
{
StringBuilder builder;
{
@ -498,7 +498,7 @@ ByteBuffer procfs$cpuinfo(InodeIdentifier)
return builder.to_byte_buffer();
}
ByteBuffer procfs$kmalloc(InodeIdentifier)
Optional<KBuffer> procfs$kmalloc(InodeIdentifier)
{
StringBuilder builder;
builder.appendf(
@ -511,7 +511,7 @@ ByteBuffer procfs$kmalloc(InodeIdentifier)
return builder.to_byte_buffer();
}
ByteBuffer procfs$memstat(InodeIdentifier)
Optional<KBuffer> procfs$memstat(InodeIdentifier)
{
InterruptDisabler disabler;
JsonObject json;
@ -527,7 +527,7 @@ ByteBuffer procfs$memstat(InodeIdentifier)
return json.serialized().to_byte_buffer();
}
ByteBuffer procfs$all(InodeIdentifier)
Optional<KBuffer> procfs$all(InodeIdentifier)
{
InterruptDisabler disabler;
auto processes = Process::all_processes();
@ -563,7 +563,7 @@ ByteBuffer procfs$all(InodeIdentifier)
return array.serialized().to_byte_buffer();
}
ByteBuffer procfs$inodes(InodeIdentifier)
Optional<KBuffer> procfs$inodes(InodeIdentifier)
{
extern HashTable<Inode*>& all_inodes();
StringBuilder builder;
@ -819,8 +819,8 @@ ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes
auto* directory_entry = fs().get_directory_entry(identifier());
Function<ByteBuffer(InodeIdentifier)> callback_tmp;
Function<ByteBuffer(InodeIdentifier)>* read_callback { nullptr };
Function<Optional<KBuffer>(InodeIdentifier)> callback_tmp;
Function<Optional<KBuffer>(InodeIdentifier)>* read_callback { nullptr };
if (directory_entry) {
read_callback = &directory_entry->read_callback;
} else {
@ -832,7 +832,7 @@ ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes
ASSERT(read_callback);
ByteBuffer generated_data;
Optional<KBuffer> generated_data;
if (!description) {
generated_data = (*read_callback)(identifier());
} else {
@ -842,8 +842,8 @@ ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes
}
auto& data = generated_data;
ssize_t nread = min(static_cast<off_t>(data.size() - offset), static_cast<off_t>(count));
memcpy(buffer, data.pointer() + offset, nread);
ssize_t nread = min(static_cast<off_t>(data.value().size() - offset), static_cast<off_t>(count));
memcpy(buffer, data.value().data() + offset, nread);
if (nread == 0 && description && description->generator_cache())
description->generator_cache().clear();
return nread;

View file

@ -3,6 +3,7 @@
#include <AK/Types.h>
#include <Kernel/FileSystem/FileSystem.h>
#include <Kernel/FileSystem/Inode.h>
#include <Kernel/KBuffer.h>
#include <Kernel/Lock.h>
class Process;
@ -36,7 +37,7 @@ private:
struct ProcFSDirectoryEntry {
ProcFSDirectoryEntry() {}
ProcFSDirectoryEntry(const char* a_name, unsigned a_proc_file_type, Function<ByteBuffer(InodeIdentifier)>&& a_read_callback = nullptr, Function<ssize_t(InodeIdentifier, const ByteBuffer&)>&& a_write_callback = nullptr, RefPtr<ProcFSInode>&& a_inode = nullptr)
ProcFSDirectoryEntry(const char* a_name, unsigned a_proc_file_type, Function<Optional<KBuffer>(InodeIdentifier)>&& a_read_callback = nullptr, Function<ssize_t(InodeIdentifier, const ByteBuffer&)>&& a_write_callback = nullptr, RefPtr<ProcFSInode>&& a_inode = nullptr)
: name(a_name)
, proc_file_type(a_proc_file_type)
, read_callback(move(a_read_callback))
@ -47,7 +48,7 @@ private:
const char* name { nullptr };
unsigned proc_file_type { 0 };
Function<ByteBuffer(InodeIdentifier)> read_callback;
Function<Optional<KBuffer>(InodeIdentifier)> read_callback;
Function<ssize_t(InodeIdentifier, const ByteBuffer&)> write_callback;
RefPtr<ProcFSInode> inode;
InodeIdentifier identifier(unsigned fsid) const;

View file

@ -50,7 +50,7 @@ NonnullRefPtr<SynthFSInode> SynthFS::create_text_file(String&& name, ByteBuffer&
auto file = adopt(*new SynthFSInode(*this, generate_inode_index()));
file->m_data = contents;
file->m_name = move(name);
file->m_metadata.size = file->m_data.size();
file->m_metadata.size = file->m_data.value().size();
file->m_metadata.uid = 100;
file->m_metadata.gid = 200;
file->m_metadata.mode = mode;
@ -194,7 +194,7 @@ ssize_t SynthFSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDe
ASSERT(offset >= 0);
ASSERT(buffer);
ByteBuffer generated_data;
Optional<KBuffer> generated_data;
if (m_generator) {
if (!description) {
generated_data = m_generator(const_cast<SynthFSInode&>(*this));
@ -205,9 +205,15 @@ ssize_t SynthFSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDe
}
}
auto* data = generated_data ? &generated_data : &m_data;
const KBuffer* data_to_use = nullptr;
if (generated_data.has_value())
data_to_use = &generated_data.value();
else if (m_data.has_value())
data_to_use = &m_data.value();
else
ASSERT_NOT_REACHED();
ssize_t nread = min(static_cast<off_t>(data->size() - offset), static_cast<off_t>(count));
memcpy(buffer, data->pointer() + offset, nread);
memcpy(buffer, data->data() + offset, nread);
if (nread == 0 && description && description->generator_cache())
description->generator_cache().clear();
return nread;

View file

@ -3,6 +3,7 @@
#include <AK/HashMap.h>
#include <Kernel/FileSystem/FileSystem.h>
#include <Kernel/FileSystem/Inode.h>
#include <Kernel/KBuffer.h>
#include <Kernel/UnixTypes.h>
class SynthFSInode;
@ -75,8 +76,8 @@ private:
String m_name;
InodeIdentifier m_parent;
ByteBuffer m_data;
Function<ByteBuffer(SynthFSInode&)> m_generator;
Optional<KBuffer> m_data;
Function<KBuffer(SynthFSInode&)> m_generator;
Function<ssize_t(SynthFSInode&, const ByteBuffer&)> m_write_callback;
Vector<SynthFSInode*> m_children;
InodeMetadata m_metadata;

View file

@ -65,11 +65,16 @@ public:
const KBufferImpl& impl() const { return m_impl; }
KBuffer(NonnullRefPtr<KBufferImpl>&& impl)
: m_impl(move(impl))
KBuffer(const ByteBuffer& buffer)
: m_impl(KBufferImpl::copy(buffer.data(), buffer.size()))
{
}
private:
explicit KBuffer(NonnullRefPtr<KBufferImpl>&& impl)
: m_impl(move(impl))
{
}
NonnullRefPtr<KBufferImpl> m_impl;
};

View file

@ -6,8 +6,8 @@
#include <AK/ByteBuffer.h>
#include <AK/HashTable.h>
#include <AK/NonnullRefPtrVector.h>
#include <AK/RefPtr.h>
#include <AK/RefCounted.h>
#include <AK/RefPtr.h>
#include <AK/Types.h>
#include <AK/Vector.h>
#include <AK/Weakable.h>
@ -20,6 +20,7 @@
#define PAGE_ROUND_UP(x) ((((u32)(x)) + PAGE_SIZE - 1) & (~(PAGE_SIZE - 1)))
class KBuffer;
class SynthFSInode;
enum class PageFaultResponse {
@ -36,8 +37,8 @@ class MemoryManager {
friend class PhysicalRegion;
friend class Region;
friend class VMObject;
friend ByteBuffer procfs$mm(InodeIdentifier);
friend ByteBuffer procfs$memstat(InodeIdentifier);
friend Optional<KBuffer> procfs$mm(InodeIdentifier);
friend Optional<KBuffer> procfs$memstat(InodeIdentifier);
public:
static MemoryManager& the();