1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 08:58:11 +00:00

Kernel: Improve ProcFS behavior in low memory conditions

When ProcFS could no longer allocate KBuffer objects to serve calls to
read, it would just return 0, indicating EOF. This then triggered
parsing errors because code assumed it read the file.

Because read isn't supposed to return ENOMEM, change ProcFS to populate
the file data upon file open or seek to the beginning. This also means
that calls to open can now return ENOMEM if needed. This allows the
caller to either be able to successfully open the file and read it, or
fail to open it in the first place.
This commit is contained in:
Tom 2020-09-17 13:51:09 -06:00 committed by Andreas Kling
parent b36f57e570
commit f98ca35b83
24 changed files with 398 additions and 243 deletions

View file

@ -52,19 +52,23 @@ NonnullRefPtr<FIFO> FIFO::create(uid_t uid)
return adopt(*new FIFO(uid)); return adopt(*new FIFO(uid));
} }
NonnullRefPtr<FileDescription> FIFO::open_direction(FIFO::Direction direction) KResultOr<NonnullRefPtr<FileDescription>> FIFO::open_direction(FIFO::Direction direction)
{ {
auto description = FileDescription::create(*this); auto description = FileDescription::create(*this);
attach(direction); if (!description.is_error()) {
description->set_fifo_direction({}, direction); attach(direction);
description.value()->set_fifo_direction({}, direction);
}
return description; return description;
} }
NonnullRefPtr<FileDescription> FIFO::open_direction_blocking(FIFO::Direction direction) KResultOr<NonnullRefPtr<FileDescription>> FIFO::open_direction_blocking(FIFO::Direction direction)
{ {
Locker locker(m_open_lock); Locker locker(m_open_lock);
auto description = open_direction(direction); auto description = open_direction(direction);
if (description.is_error())
return description;
if (direction == Direction::Reader) { if (direction == Direction::Reader) {
m_read_open_queue.wake_all(); m_read_open_queue.wake_all();

View file

@ -49,8 +49,8 @@ public:
uid_t uid() const { return m_uid; } uid_t uid() const { return m_uid; }
NonnullRefPtr<FileDescription> open_direction(Direction); KResultOr<NonnullRefPtr<FileDescription>> open_direction(Direction);
NonnullRefPtr<FileDescription> open_direction_blocking(Direction); KResultOr<NonnullRefPtr<FileDescription>> open_direction_blocking(Direction);
void attach(Direction); void attach(Direction);
void detach(Direction); void detach(Direction);

View file

@ -42,8 +42,10 @@ File::~File()
KResultOr<NonnullRefPtr<FileDescription>> File::open(int options) KResultOr<NonnullRefPtr<FileDescription>> File::open(int options)
{ {
auto description = FileDescription::create(*this); auto description = FileDescription::create(*this);
description->set_rw_mode(options); if (!description.is_error()) {
description->set_file_flags(options); description.value()->set_rw_mode(options);
description.value()->set_file_flags(options);
}
return description; return description;
} }

View file

@ -108,6 +108,9 @@ public:
virtual bool can_read(const FileDescription&, size_t) const = 0; virtual bool can_read(const FileDescription&, size_t) const = 0;
virtual bool can_write(const FileDescription&, size_t) const = 0; virtual bool can_write(const FileDescription&, size_t) const = 0;
virtual KResult attach(FileDescription&) { return KSuccess; }
virtual void detach(FileDescription&) { }
virtual void did_seek(FileDescription&, off_t) { }
virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) = 0; virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) = 0;
virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) = 0; virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) = 0;
virtual int ioctl(FileDescription&, unsigned request, FlatPtr arg); virtual int ioctl(FileDescription&, unsigned request, FlatPtr arg);

View file

@ -40,18 +40,35 @@
#include <Kernel/VM/MemoryManager.h> #include <Kernel/VM/MemoryManager.h>
#include <LibC/errno_numbers.h> #include <LibC/errno_numbers.h>
//#define FILEDESCRIPTION_DEBUG
namespace Kernel { namespace Kernel {
NonnullRefPtr<FileDescription> FileDescription::create(Custody& custody) KResultOr<NonnullRefPtr<FileDescription>> FileDescription::create(Custody& custody)
{ {
auto description = adopt(*new FileDescription(InodeFile::create(custody.inode()))); auto description = adopt(*new FileDescription(InodeFile::create(custody.inode())));
description->m_custody = custody; description->m_custody = custody;
auto result = description->attach();
if (result.is_error()) {
#ifdef FILEDESCRIPTION_DEBUG
dbg() << "Failed to create file description for custody: " << result;
#endif
return result;
}
return description; return description;
} }
NonnullRefPtr<FileDescription> FileDescription::create(File& file) KResultOr<NonnullRefPtr<FileDescription>> FileDescription::create(File& file)
{ {
return adopt(*new FileDescription(file)); auto description = adopt(*new FileDescription(file));
auto result = description->attach();
if (result.is_error()) {
#ifdef FILEDESCRIPTION_DEBUG
dbg() << "Failed to create file description for file: " << result;
#endif
return result;
}
return description;
} }
FileDescription::FileDescription(File& file) FileDescription::FileDescription(File& file)
@ -59,20 +76,29 @@ FileDescription::FileDescription(File& file)
{ {
if (file.is_inode()) if (file.is_inode())
m_inode = static_cast<InodeFile&>(file).inode(); m_inode = static_cast<InodeFile&>(file).inode();
if (is_socket())
socket()->attach(*this);
m_is_directory = metadata().is_directory(); m_is_directory = metadata().is_directory();
} }
FileDescription::~FileDescription() FileDescription::~FileDescription()
{ {
if (is_socket()) m_file->detach(*this);
socket()->detach(*this);
if (is_fifo()) if (is_fifo())
static_cast<FIFO*>(m_file.ptr())->detach(m_fifo_direction); static_cast<FIFO*>(m_file.ptr())->detach(m_fifo_direction);
// FIXME: Should this error path be observed somehow? // FIXME: Should this error path be observed somehow?
[[maybe_unused]] auto rc = m_file->close(); (void)m_file->close();
m_inode = nullptr; if (m_inode)
m_inode->detach(*this);
}
KResult FileDescription::attach()
{
if (m_inode) {
auto result = m_inode->attach(*this);
if (result.is_error())
return result;
}
return m_file->attach(*this);
} }
Thread::FileBlocker::BlockFlags FileDescription::should_unblock(Thread::FileBlocker::BlockFlags block_flags) const Thread::FileBlocker::BlockFlags FileDescription::should_unblock(Thread::FileBlocker::BlockFlags block_flags) const
@ -133,6 +159,10 @@ off_t FileDescription::seek(off_t offset, int whence)
// FIXME: Return -EINVAL if attempting to seek past the end of a seekable device. // FIXME: Return -EINVAL if attempting to seek past the end of a seekable device.
m_current_offset = new_offset; m_current_offset = new_offset;
m_file->did_seek(*this, new_offset);
if (m_inode)
m_inode->did_seek(*this, new_offset);
evaluate_block_conditions(); evaluate_block_conditions();
return m_current_offset; return m_current_offset;
} }

View file

@ -38,11 +38,16 @@
namespace Kernel { namespace Kernel {
class FileDescriptionData {
public:
virtual ~FileDescriptionData() { }
};
class FileDescription : public RefCounted<FileDescription> { class FileDescription : public RefCounted<FileDescription> {
MAKE_SLAB_ALLOCATED(FileDescription) MAKE_SLAB_ALLOCATED(FileDescription)
public: public:
static NonnullRefPtr<FileDescription> create(Custody&); static KResultOr<NonnullRefPtr<FileDescription>> create(Custody&);
static NonnullRefPtr<FileDescription> create(File&); static KResultOr<NonnullRefPtr<FileDescription>> create(File&);
~FileDescription(); ~FileDescription();
Thread::FileBlocker::BlockFlags should_unblock(Thread::FileBlocker::BlockFlags) const; Thread::FileBlocker::BlockFlags should_unblock(Thread::FileBlocker::BlockFlags) const;
@ -122,7 +127,7 @@ public:
FIFO::Direction fifo_direction() { return m_fifo_direction; } FIFO::Direction fifo_direction() { return m_fifo_direction; }
void set_fifo_direction(Badge<FIFO>, FIFO::Direction direction) { m_fifo_direction = direction; } void set_fifo_direction(Badge<FIFO>, FIFO::Direction direction) { m_fifo_direction = direction; }
OwnPtr<KBuffer>& generator_cache() { return m_generator_cache; } OwnPtr<FileDescriptionData>& data() { return m_data; }
void set_original_inode(Badge<VFS>, NonnullRefPtr<Inode>&& inode) { m_inode = move(inode); } void set_original_inode(Badge<VFS>, NonnullRefPtr<Inode>&& inode) { m_inode = move(inode); }
@ -137,7 +142,8 @@ public:
private: private:
friend class VFS; friend class VFS;
explicit FileDescription(File&); explicit FileDescription(File&);
FileDescription(FIFO&, FIFO::Direction);
KResult attach();
void evaluate_block_conditions() void evaluate_block_conditions()
{ {
@ -150,7 +156,7 @@ private:
off_t m_current_offset { 0 }; off_t m_current_offset { 0 };
OwnPtr<KBuffer> m_generator_cache; OwnPtr<FileDescriptionData> m_data;
u32 m_file_flags { 0 }; u32 m_file_flags { 0 };

View file

@ -69,6 +69,9 @@ public:
KResultOr<NonnullOwnPtr<KBuffer>> read_entire(FileDescription* = nullptr) const; KResultOr<NonnullOwnPtr<KBuffer>> read_entire(FileDescription* = nullptr) const;
virtual KResult attach(FileDescription&) { return KSuccess; }
virtual void detach(FileDescription&) { }
virtual void did_seek(FileDescription&, off_t) { }
virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const = 0; virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const = 0;
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const = 0; virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const = 0;
virtual RefPtr<Inode> lookup(StringView name) = 0; virtual RefPtr<Inode> lookup(StringView name) = 0;

View file

@ -253,6 +253,10 @@ static inline bool is_persistent_inode(const InodeIdentifier& identifier)
return to_proc_parent_directory(identifier) == PDI_Root_sys; return to_proc_parent_directory(identifier) == PDI_Root_sys;
} }
struct ProcFSInodeData : public FileDescriptionData {
RefPtr<KBufferImpl> buffer;
};
NonnullRefPtr<ProcFS> ProcFS::create() NonnullRefPtr<ProcFS> ProcFS::create()
{ {
return adopt(*new ProcFS); return adopt(*new ProcFS);
@ -262,19 +266,18 @@ ProcFS::~ProcFS()
{ {
} }
static OwnPtr<KBuffer> procfs$pid_fds(InodeIdentifier identifier) static bool procfs$pid_fds(InodeIdentifier identifier, KBufferBuilder& builder)
{ {
KBufferBuilder builder;
JsonArraySerializer array { builder }; JsonArraySerializer array { builder };
auto process = Process::from_pid(to_pid(identifier)); auto process = Process::from_pid(to_pid(identifier));
if (!process) { if (!process) {
array.finish(); array.finish();
return builder.build(); return true;
} }
if (process->number_of_open_file_descriptors() == 0) { if (process->number_of_open_file_descriptors() == 0) {
array.finish(); array.finish();
return builder.build(); return true;
} }
for (int i = 0; i < process->max_open_file_descriptors(); ++i) { for (int i = 0; i < process->max_open_file_descriptors(); ++i) {
@ -295,27 +298,27 @@ static OwnPtr<KBuffer> procfs$pid_fds(InodeIdentifier identifier)
description_object.add("can_write", description->can_write()); description_object.add("can_write", description->can_write());
} }
array.finish(); array.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$pid_fd_entry(InodeIdentifier identifier) static bool procfs$pid_fd_entry(InodeIdentifier identifier, KBufferBuilder& builder)
{ {
auto process = Process::from_pid(to_pid(identifier)); auto process = Process::from_pid(to_pid(identifier));
if (!process) if (!process)
return {}; return false;
int fd = to_fd(identifier); int fd = to_fd(identifier);
auto description = process->file_description(fd); auto description = process->file_description(fd);
if (!description) if (!description)
return {}; return false;
return KBuffer::try_create_with_bytes(description->absolute_path().bytes()); builder.append_bytes(description->absolute_path().bytes());
return true;
} }
static OwnPtr<KBuffer> procfs$pid_vm(InodeIdentifier identifier) static bool procfs$pid_vm(InodeIdentifier identifier, KBufferBuilder& builder)
{ {
auto process = Process::from_pid(to_pid(identifier)); auto process = Process::from_pid(to_pid(identifier));
if (!process) if (!process)
return {}; return false;
KBufferBuilder builder;
JsonArraySerializer array { builder }; JsonArraySerializer array { builder };
{ {
ScopedSpinLock lock(process->get_lock()); ScopedSpinLock lock(process->get_lock());
@ -357,12 +360,11 @@ static OwnPtr<KBuffer> procfs$pid_vm(InodeIdentifier identifier)
} }
} }
array.finish(); array.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$pci(InodeIdentifier) static bool procfs$pci(InodeIdentifier, KBufferBuilder& builder)
{ {
KBufferBuilder builder;
JsonArraySerializer array { builder }; JsonArraySerializer array { builder };
PCI::enumerate([&array](PCI::Address address, PCI::ID id) { PCI::enumerate([&array](PCI::Address address, PCI::ID id) {
auto obj = array.add_object(); auto obj = array.add_object();
@ -379,12 +381,11 @@ static OwnPtr<KBuffer> procfs$pci(InodeIdentifier)
obj.add("subsystem_vendor_id", PCI::get_subsystem_vendor_id(address)); obj.add("subsystem_vendor_id", PCI::get_subsystem_vendor_id(address));
}); });
array.finish(); array.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$interrupts(InodeIdentifier) static bool procfs$interrupts(InodeIdentifier, KBufferBuilder& builder)
{ {
KBufferBuilder builder;
JsonArraySerializer array { builder }; JsonArraySerializer array { builder };
InterruptManagement::the().enumerate_interrupt_handlers([&array](GenericInterruptHandler& handler) { InterruptManagement::the().enumerate_interrupt_handlers([&array](GenericInterruptHandler& handler) {
auto obj = array.add_object(); auto obj = array.add_object();
@ -396,21 +397,19 @@ static OwnPtr<KBuffer> procfs$interrupts(InodeIdentifier)
obj.add("call_count", (unsigned)handler.get_invoking_count()); obj.add("call_count", (unsigned)handler.get_invoking_count());
}); });
array.finish(); array.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$keymap(InodeIdentifier) static bool procfs$keymap(InodeIdentifier, KBufferBuilder& builder)
{ {
KBufferBuilder builder;
JsonObjectSerializer<KBufferBuilder> json { builder }; JsonObjectSerializer<KBufferBuilder> json { builder };
json.add("keymap", KeyboardDevice::the().keymap_name()); json.add("keymap", KeyboardDevice::the().keymap_name());
json.finish(); json.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$devices(InodeIdentifier) static bool procfs$devices(InodeIdentifier, KBufferBuilder& builder)
{ {
KBufferBuilder builder;
JsonArraySerializer array { builder }; JsonArraySerializer array { builder };
Device::for_each([&array](auto& device) { Device::for_each([&array](auto& device) {
auto obj = array.add_object(); auto obj = array.add_object();
@ -426,28 +425,25 @@ static OwnPtr<KBuffer> procfs$devices(InodeIdentifier)
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
}); });
array.finish(); array.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$uptime(InodeIdentifier) static bool procfs$uptime(InodeIdentifier, KBufferBuilder& builder)
{ {
KBufferBuilder builder;
builder.appendf("%llu\n", TimeManagement::the().uptime_ms() / 1000); builder.appendf("%llu\n", TimeManagement::the().uptime_ms() / 1000);
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$cmdline(InodeIdentifier) static bool procfs$cmdline(InodeIdentifier, KBufferBuilder& builder)
{ {
KBufferBuilder builder;
builder.append(kernel_command_line().string()); builder.append(kernel_command_line().string());
builder.append('\n'); builder.append('\n');
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$modules(InodeIdentifier) static bool procfs$modules(InodeIdentifier, KBufferBuilder& builder)
{ {
extern HashMap<String, OwnPtr<Module>>* g_modules; extern HashMap<String, OwnPtr<Module>>* g_modules;
KBufferBuilder builder;
JsonArraySerializer array { builder }; JsonArraySerializer array { builder };
for (auto& it : *g_modules) { for (auto& it : *g_modules) {
auto obj = array.add_object(); auto obj = array.add_object();
@ -461,13 +457,12 @@ static OwnPtr<KBuffer> procfs$modules(InodeIdentifier)
obj.add("size", size); obj.add("size", size);
} }
array.finish(); array.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$profile(InodeIdentifier) static bool procfs$profile(InodeIdentifier, KBufferBuilder& builder)
{ {
InterruptDisabler disabler; InterruptDisabler disabler;
KBufferBuilder builder;
JsonObjectSerializer object(builder); JsonObjectSerializer object(builder);
object.add("pid", Profiling::pid().value()); object.add("pid", Profiling::pid().value());
@ -493,12 +488,11 @@ static OwnPtr<KBuffer> procfs$profile(InodeIdentifier)
}); });
array.finish(); array.finish();
object.finish(); object.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$net_adapters(InodeIdentifier) static bool procfs$net_adapters(InodeIdentifier, KBufferBuilder& builder)
{ {
KBufferBuilder builder;
JsonArraySerializer array { builder }; JsonArraySerializer array { builder };
NetworkAdapter::for_each([&array](auto& adapter) { NetworkAdapter::for_each([&array](auto& adapter) {
auto obj = array.add_object(); auto obj = array.add_object();
@ -519,12 +513,11 @@ static OwnPtr<KBuffer> procfs$net_adapters(InodeIdentifier)
obj.add("mtu", adapter.mtu()); obj.add("mtu", adapter.mtu());
}); });
array.finish(); array.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$net_arp(InodeIdentifier) static bool procfs$net_arp(InodeIdentifier, KBufferBuilder& builder)
{ {
KBufferBuilder builder;
JsonArraySerializer array { builder }; JsonArraySerializer array { builder };
LOCKER(arp_table().lock(), Lock::Mode::Shared); LOCKER(arp_table().lock(), Lock::Mode::Shared);
for (auto& it : arp_table().resource()) { for (auto& it : arp_table().resource()) {
@ -533,12 +526,11 @@ static OwnPtr<KBuffer> procfs$net_arp(InodeIdentifier)
obj.add("ip_address", it.key.to_string()); obj.add("ip_address", it.key.to_string());
} }
array.finish(); array.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$net_tcp(InodeIdentifier) static bool procfs$net_tcp(InodeIdentifier, KBufferBuilder& builder)
{ {
KBufferBuilder builder;
JsonArraySerializer array { builder }; JsonArraySerializer array { builder };
TCPSocket::for_each([&array](auto& socket) { TCPSocket::for_each([&array](auto& socket) {
auto obj = array.add_object(); auto obj = array.add_object();
@ -555,12 +547,11 @@ static OwnPtr<KBuffer> procfs$net_tcp(InodeIdentifier)
obj.add("bytes_out", socket.bytes_out()); obj.add("bytes_out", socket.bytes_out());
}); });
array.finish(); array.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$net_udp(InodeIdentifier) static bool procfs$net_udp(InodeIdentifier, KBufferBuilder& builder)
{ {
KBufferBuilder builder;
JsonArraySerializer array { builder }; JsonArraySerializer array { builder };
UDPSocket::for_each([&array](auto& socket) { UDPSocket::for_each([&array](auto& socket) {
auto obj = array.add_object(); auto obj = array.add_object();
@ -570,12 +561,11 @@ static OwnPtr<KBuffer> procfs$net_udp(InodeIdentifier)
obj.add("peer_port", socket.peer_port()); obj.add("peer_port", socket.peer_port());
}); });
array.finish(); array.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$net_local(InodeIdentifier) static bool procfs$net_local(InodeIdentifier, KBufferBuilder& builder)
{ {
KBufferBuilder builder;
JsonArraySerializer array { builder }; JsonArraySerializer array { builder };
LocalSocket::for_each([&array](auto& socket) { LocalSocket::for_each([&array](auto& socket) {
auto obj = array.add_object(); auto obj = array.add_object();
@ -588,15 +578,14 @@ static OwnPtr<KBuffer> procfs$net_local(InodeIdentifier)
obj.add("acceptor_gid", socket.acceptor_gid()); obj.add("acceptor_gid", socket.acceptor_gid());
}); });
array.finish(); array.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$pid_vmobjects(InodeIdentifier identifier) static bool procfs$pid_vmobjects(InodeIdentifier identifier, KBufferBuilder& builder)
{ {
auto process = Process::from_pid(to_pid(identifier)); auto process = Process::from_pid(to_pid(identifier));
if (!process) if (!process)
return {}; return false;
KBufferBuilder builder;
builder.appendf("BEGIN END SIZE NAME\n"); builder.appendf("BEGIN END SIZE NAME\n");
{ {
ScopedSpinLock lock(process->get_lock()); ScopedSpinLock lock(process->get_lock());
@ -623,15 +612,14 @@ static OwnPtr<KBuffer> procfs$pid_vmobjects(InodeIdentifier identifier)
builder.appendf("\n"); builder.appendf("\n");
} }
} }
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$pid_unveil(InodeIdentifier identifier) static bool procfs$pid_unveil(InodeIdentifier identifier, KBufferBuilder& builder)
{ {
auto process = Process::from_pid(to_pid(identifier)); auto process = Process::from_pid(to_pid(identifier));
if (!process) if (!process)
return {}; return false;
KBufferBuilder builder;
JsonArraySerializer array { builder }; JsonArraySerializer array { builder };
for (auto& unveiled_path : process->unveiled_paths()) { for (auto& unveiled_path : process->unveiled_paths()) {
if (!unveiled_path.was_explicitly_unveiled()) if (!unveiled_path.was_explicitly_unveiled())
@ -652,57 +640,57 @@ static OwnPtr<KBuffer> procfs$pid_unveil(InodeIdentifier identifier)
obj.add("permissions", permissions_builder.to_string()); obj.add("permissions", permissions_builder.to_string());
} }
array.finish(); array.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$tid_stack(InodeIdentifier identifier) static bool procfs$tid_stack(InodeIdentifier identifier, KBufferBuilder& builder)
{ {
auto thread = Thread::from_tid(to_tid(identifier)); auto thread = Thread::from_tid(to_tid(identifier));
if (!thread) if (!thread)
return {}; return false;
KBufferBuilder builder;
builder.appendf("Thread %d (%s):\n", thread->tid().value(), thread->name().characters()); builder.appendf("Thread %d (%s):\n", thread->tid().value(), thread->name().characters());
builder.append(thread->backtrace()); builder.append(thread->backtrace());
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$pid_exe(InodeIdentifier identifier) static bool procfs$pid_exe(InodeIdentifier identifier, KBufferBuilder& builder)
{ {
auto process = Process::from_pid(to_pid(identifier)); auto process = Process::from_pid(to_pid(identifier));
if (!process) if (!process)
return {}; return false;
auto* custody = process->executable(); auto* custody = process->executable();
ASSERT(custody); ASSERT(custody);
return KBuffer::try_create_with_bytes(custody->absolute_path().bytes()); builder.append(custody->absolute_path().bytes());
return true;
} }
static OwnPtr<KBuffer> procfs$pid_cwd(InodeIdentifier identifier) static bool procfs$pid_cwd(InodeIdentifier identifier, KBufferBuilder& builder)
{ {
auto process = Process::from_pid(to_pid(identifier)); auto process = Process::from_pid(to_pid(identifier));
if (!process) if (!process)
return {}; return false;
return KBuffer::try_create_with_bytes(process->current_directory().absolute_path().bytes()); builder.append_bytes(process->current_directory().absolute_path().bytes());
return true;
} }
static OwnPtr<KBuffer> procfs$pid_root(InodeIdentifier identifier) static bool procfs$pid_root(InodeIdentifier identifier, KBufferBuilder& builder)
{ {
auto process = Process::from_pid(to_pid(identifier)); auto process = Process::from_pid(to_pid(identifier));
if (!process) if (!process)
return {}; return false;
return KBuffer::try_create_with_bytes(process->root_directory_relative_to_global_root().absolute_path().to_byte_buffer()); builder.append_bytes(process->root_directory_relative_to_global_root().absolute_path().to_byte_buffer());
return false;
} }
static OwnPtr<KBuffer> procfs$self(InodeIdentifier) static bool procfs$self(InodeIdentifier, KBufferBuilder& builder)
{ {
char buffer[16]; builder.appendf("%d", Process::current()->pid().value());
int written = snprintf(buffer, sizeof(buffer), "%d", Process::current()->pid().value()); return true;
return KBuffer::try_create_with_bytes(ReadonlyBytes { buffer, static_cast<size_t>(written) });
} }
OwnPtr<KBuffer> procfs$mm(InodeIdentifier) static bool procfs$mm(InodeIdentifier, KBufferBuilder& builder)
{ {
InterruptDisabler disabler; InterruptDisabler disabler;
KBufferBuilder builder;
u32 vmobject_count = 0; u32 vmobject_count = 0;
MemoryManager::for_each_vmobject([&](auto& vmobject) { MemoryManager::for_each_vmobject([&](auto& vmobject) {
++vmobject_count; ++vmobject_count;
@ -716,22 +704,20 @@ OwnPtr<KBuffer> procfs$mm(InodeIdentifier)
builder.appendf("VMO count: %u\n", vmobject_count); builder.appendf("VMO count: %u\n", vmobject_count);
builder.appendf("Free physical pages: %u\n", MM.user_physical_pages() - MM.user_physical_pages_used()); builder.appendf("Free physical pages: %u\n", MM.user_physical_pages() - MM.user_physical_pages_used());
builder.appendf("Free supervisor physical pages: %u\n", MM.super_physical_pages() - MM.super_physical_pages_used()); builder.appendf("Free supervisor physical pages: %u\n", MM.super_physical_pages() - MM.super_physical_pages_used());
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$dmesg(InodeIdentifier) static bool procfs$dmesg(InodeIdentifier, KBufferBuilder& builder)
{ {
InterruptDisabler disabler; InterruptDisabler disabler;
KBufferBuilder builder;
for (char ch : Console::the().logbuffer()) for (char ch : Console::the().logbuffer())
builder.append(ch); builder.append(ch);
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$mounts(InodeIdentifier) static bool procfs$mounts(InodeIdentifier, KBufferBuilder& builder)
{ {
// FIXME: This is obviously racy against the VFS mounts changing. // FIXME: This is obviously racy against the VFS mounts changing.
KBufferBuilder builder;
VFS::the().for_each_mount([&builder](auto& mount) { VFS::the().for_each_mount([&builder](auto& mount) {
auto& fs = mount.guest_fs(); auto& fs = mount.guest_fs();
builder.appendf("%s @ ", fs.class_name()); builder.appendf("%s @ ", fs.class_name());
@ -744,13 +730,12 @@ static OwnPtr<KBuffer> procfs$mounts(InodeIdentifier)
} }
builder.append('\n'); builder.append('\n');
}); });
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$df(InodeIdentifier) static bool procfs$df(InodeIdentifier, KBufferBuilder& builder)
{ {
// FIXME: This is obviously racy against the VFS mounts changing. // FIXME: This is obviously racy against the VFS mounts changing.
KBufferBuilder builder;
JsonArraySerializer array { builder }; JsonArraySerializer array { builder };
VFS::the().for_each_mount([&array](auto& mount) { VFS::the().for_each_mount([&array](auto& mount) {
auto& fs = mount.guest_fs(); auto& fs = mount.guest_fs();
@ -771,12 +756,11 @@ static OwnPtr<KBuffer> procfs$df(InodeIdentifier)
fs_object.add("source", "none"); fs_object.add("source", "none");
}); });
array.finish(); array.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$cpuinfo(InodeIdentifier) static bool procfs$cpuinfo(InodeIdentifier, KBufferBuilder& builder)
{ {
KBufferBuilder builder;
JsonArraySerializer array { builder }; JsonArraySerializer array { builder };
Processor::for_each( Processor::for_each(
[&](Processor& proc) -> IterationDecision { [&](Processor& proc) -> IterationDecision {
@ -796,17 +780,16 @@ static OwnPtr<KBuffer> procfs$cpuinfo(InodeIdentifier)
return IterationDecision::Continue; return IterationDecision::Continue;
}); });
array.finish(); array.finish();
return builder.build(); return true;
} }
OwnPtr<KBuffer> procfs$memstat(InodeIdentifier) static bool procfs$memstat(InodeIdentifier, KBufferBuilder& builder)
{ {
InterruptDisabler disabler; InterruptDisabler disabler;
kmalloc_stats stats; kmalloc_stats stats;
get_kmalloc_stats(stats); get_kmalloc_stats(stats);
KBufferBuilder builder;
JsonObjectSerializer<KBufferBuilder> json { builder }; JsonObjectSerializer<KBufferBuilder> json { builder };
json.add("kmalloc_allocated", stats.bytes_allocated); json.add("kmalloc_allocated", stats.bytes_allocated);
json.add("kmalloc_available", stats.bytes_free); json.add("kmalloc_available", stats.bytes_free);
@ -823,12 +806,11 @@ OwnPtr<KBuffer> procfs$memstat(InodeIdentifier)
json.add(String::format("%s_num_free", prefix.characters()), num_free); json.add(String::format("%s_num_free", prefix.characters()), num_free);
}); });
json.finish(); json.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$all(InodeIdentifier) static bool procfs$all(InodeIdentifier, KBufferBuilder& builder)
{ {
KBufferBuilder builder;
JsonArraySerializer array { builder }; JsonArraySerializer array { builder };
// Keep this in sync with CProcessStatistics. // Keep this in sync with CProcessStatistics.
@ -914,18 +896,17 @@ static OwnPtr<KBuffer> procfs$all(InodeIdentifier)
for (auto& process : processes) for (auto& process : processes)
build_process(process); build_process(process);
array.finish(); array.finish();
return builder.build(); return true;
} }
static OwnPtr<KBuffer> procfs$inodes(InodeIdentifier) static bool procfs$inodes(InodeIdentifier, KBufferBuilder& builder)
{ {
KBufferBuilder builder;
InterruptDisabler disabler; InterruptDisabler disabler;
ScopedSpinLock all_inodes_lock(Inode::all_inodes_lock()); ScopedSpinLock all_inodes_lock(Inode::all_inodes_lock());
for (auto& inode : Inode::all_with_lock()) { for (auto& inode : Inode::all_with_lock()) {
builder.appendf("Inode{K%x} %02u:%08u (%u)\n", &inode, inode.fsid(), inode.index(), inode.ref_count()); builder.appendf("Inode{K%x} %02u:%08u (%u)\n", &inode, inode.fsid(), inode.index(), inode.ref_count());
} }
return builder.build(); return true;
} }
struct SysVariable { struct SysVariable {
@ -969,7 +950,7 @@ SysVariable& SysVariable::for_inode(InodeIdentifier id)
return variable; return variable;
} }
static OwnPtr<KBuffer> read_sys_bool(InodeIdentifier inode_id) static bool read_sys_bool(InodeIdentifier inode_id, KBufferBuilder& builder)
{ {
auto& variable = SysVariable::for_inode(inode_id); auto& variable = SysVariable::for_inode(inode_id);
ASSERT(variable.type == SysVariable::Type::Boolean); ASSERT(variable.type == SysVariable::Type::Boolean);
@ -981,7 +962,8 @@ static OwnPtr<KBuffer> read_sys_bool(InodeIdentifier inode_id)
buffer[0] = lockable_bool->resource() ? '1' : '0'; buffer[0] = lockable_bool->resource() ? '1' : '0';
} }
buffer[1] = '\n'; buffer[1] = '\n';
return KBuffer::try_create_with_bytes(ReadonlyBytes { buffer, sizeof(buffer) }); builder.append_bytes(ReadonlyBytes { buffer, sizeof(buffer) });
return true;
} }
static ssize_t write_sys_bool(InodeIdentifier inode_id, const UserOrKernelBuffer& buffer, size_t size) static ssize_t write_sys_bool(InodeIdentifier inode_id, const UserOrKernelBuffer& buffer, size_t size)
@ -1013,14 +995,15 @@ static ssize_t write_sys_bool(InodeIdentifier inode_id, const UserOrKernelBuffer
return (ssize_t)size; return (ssize_t)size;
} }
static OwnPtr<KBuffer> read_sys_string(InodeIdentifier inode_id) static bool read_sys_string(InodeIdentifier inode_id, KBufferBuilder& builder)
{ {
auto& variable = SysVariable::for_inode(inode_id); auto& variable = SysVariable::for_inode(inode_id);
ASSERT(variable.type == SysVariable::Type::String); ASSERT(variable.type == SysVariable::Type::String);
auto* lockable_string = reinterpret_cast<Lockable<String>*>(variable.address); auto* lockable_string = reinterpret_cast<Lockable<String>*>(variable.address);
LOCKER(lockable_string->lock(), Lock::Mode::Shared); LOCKER(lockable_string->lock(), Lock::Mode::Shared);
return KBuffer::try_create_with_bytes(lockable_string->resource().bytes()); builder.append_bytes(lockable_string->resource().bytes());
return true;
} }
static ssize_t write_sys_string(InodeIdentifier inode_id, const UserOrKernelBuffer& buffer, size_t size) static ssize_t write_sys_string(InodeIdentifier inode_id, const UserOrKernelBuffer& buffer, size_t size)
@ -1130,6 +1113,83 @@ ProcFSInode::~ProcFSInode()
fs().m_inodes.remove(it); fs().m_inodes.remove(it);
} }
KResult ProcFSInode::refresh_data(FileDescription& description) const
{
auto& cached_data = description.data();
auto* directory_entry = fs().get_directory_entry(identifier());
bool (*read_callback)(InodeIdentifier, KBufferBuilder&) = nullptr;
if (directory_entry) {
if (directory_entry->proc_file_type > (unsigned)FI_Root) {
read_callback = directory_entry->read_callback;
ASSERT(read_callback);
} else {
return KSuccess;
}
} else {
switch (to_proc_parent_directory(identifier())) {
case PDI_PID_fd:
read_callback = procfs$pid_fd_entry;
break;
case PDI_PID_stacks:
read_callback = procfs$tid_stack;
break;
case PDI_Root_sys:
switch (SysVariable::for_inode(identifier()).type) {
case SysVariable::Type::Invalid:
ASSERT_NOT_REACHED();
case SysVariable::Type::Boolean:
read_callback = read_sys_bool;
break;
case SysVariable::Type::String:
read_callback = read_sys_string;
break;
}
break;
default:
ASSERT_NOT_REACHED();
}
ASSERT(read_callback);
}
if (!cached_data)
cached_data = new ProcFSInodeData;
auto& buffer = static_cast<ProcFSInodeData&>(*cached_data).buffer;
if (buffer) {
// If we're reusing the buffer, reset the size to 0 first. This
// ensures we don't accidentally leak previously written data.
buffer->set_size(0);
}
KBufferBuilder builder(buffer, true);
if (!read_callback(identifier(), builder))
return KResult(-ENOENT);
// We don't use builder.build() here, which would steal our buffer
// and turn it into an OwnPtr. Instead, just flush to the buffer so
// that we can read all the data that was written.
if (!builder.flush())
return KResult(-ENOMEM);
if (!buffer)
return KResult(-ENOMEM);
return KSuccess;
}
KResult ProcFSInode::attach(FileDescription& description)
{
return refresh_data(description);
}
void ProcFSInode::did_seek(FileDescription& description, off_t new_offset)
{
if (new_offset != 0)
return;
auto result = refresh_data(description);
if (result.is_error()) {
// Subsequent calls to read will return EIO!
dbg() << "ProcFS: Could not refresh contents: " << result.error();
}
}
InodeMetadata ProcFSInode::metadata() const InodeMetadata ProcFSInode::metadata() const
{ {
#ifdef PROCFS_DEBUG #ifdef PROCFS_DEBUG
@ -1215,68 +1275,29 @@ InodeMetadata ProcFSInode::metadata() const
ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, UserOrKernelBuffer& buffer, FileDescription* description) const ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, UserOrKernelBuffer& buffer, FileDescription* description) const
{ {
#ifdef PROCFS_DEBUG #ifdef PROCFS_DEBUG
dbg() << "ProcFS: read_bytes " << index(); dbg() << "ProcFS: read_bytes offset: " << offset << " count: " << count;
#endif #endif
ASSERT(offset >= 0); ASSERT(offset >= 0);
ASSERT(buffer.user_or_kernel_ptr()); ASSERT(buffer.user_or_kernel_ptr());
auto* directory_entry = fs().get_directory_entry(identifier()); if (!description)
return -EIO;
OwnPtr<KBuffer> (*read_callback)(InodeIdentifier) = nullptr; if (!description->data()) {
if (directory_entry) #ifdef PROCFS_DEBUG
read_callback = directory_entry->read_callback; dbg() << "ProcFS: Do not have cached data!";
else #endif
switch (to_proc_parent_directory(identifier())) { return -EIO;
case PDI_PID_fd:
read_callback = procfs$pid_fd_entry;
break;
case PDI_PID_stacks:
read_callback = procfs$tid_stack;
break;
case PDI_Root_sys:
switch (SysVariable::for_inode(identifier()).type) {
case SysVariable::Type::Invalid:
ASSERT_NOT_REACHED();
case SysVariable::Type::Boolean:
read_callback = read_sys_bool;
break;
case SysVariable::Type::String:
read_callback = read_sys_string;
break;
}
break;
default:
ASSERT_NOT_REACHED();
}
ASSERT(read_callback);
OwnPtr<KBuffer> descriptionless_generated_data;
KBuffer* data = nullptr;
if (!description) {
descriptionless_generated_data = read_callback(identifier());
data = descriptionless_generated_data.ptr();
} else {
if (!description->generator_cache())
description->generator_cache() = (*read_callback)(identifier());
data = description->generator_cache().ptr();
} }
if (!data) // Be sure to keep a reference to data_buffer while we use it!
return 0; RefPtr<KBufferImpl> data_buffer = static_cast<ProcFSInodeData&>(*description->data()).buffer;
if (data->is_null()) {
dbg() << "ProcFS: Not enough memory!";
return 0;
}
if ((size_t)offset >= data->size()) if (!data_buffer || (size_t)offset >= data_buffer->size())
return 0; return 0;
ssize_t nread = min(static_cast<off_t>(data->size() - offset), static_cast<off_t>(count)); ssize_t nread = min(static_cast<off_t>(data_buffer->size() - offset), static_cast<off_t>(count));
if (!buffer.write(data->data() + offset, nread)) if (!buffer.write(data_buffer->data() + offset, nread))
return -EFAULT; return -EFAULT;
if (nread == 0 && description && description->generator_cache())
description->generator_cache().clear();
return nread; return nread;
} }
@ -1599,6 +1620,16 @@ ProcFSProxyInode::~ProcFSProxyInode()
{ {
} }
KResult ProcFSProxyInode::attach(FileDescription& fd)
{
return m_fd->inode()->attach(fd);
}
void ProcFSProxyInode::did_seek(FileDescription& fd, off_t new_offset)
{
return m_fd->inode()->did_seek(fd, new_offset);
}
InodeMetadata ProcFSProxyInode::metadata() const InodeMetadata ProcFSProxyInode::metadata() const
{ {
InodeMetadata metadata = m_fd->metadata(); InodeMetadata metadata = m_fd->metadata();

View file

@ -30,7 +30,7 @@
#include <AK/Types.h> #include <AK/Types.h>
#include <Kernel/FileSystem/FileSystem.h> #include <Kernel/FileSystem/FileSystem.h>
#include <Kernel/FileSystem/Inode.h> #include <Kernel/FileSystem/Inode.h>
#include <Kernel/KBuffer.h> #include <Kernel/KBufferBuilder.h>
#include <Kernel/Lock.h> #include <Kernel/Lock.h>
namespace Kernel { namespace Kernel {
@ -59,7 +59,7 @@ private:
struct ProcFSDirectoryEntry { struct ProcFSDirectoryEntry {
ProcFSDirectoryEntry() { } ProcFSDirectoryEntry() { }
ProcFSDirectoryEntry(const char* a_name, unsigned a_proc_file_type, bool a_supervisor_only, OwnPtr<KBuffer> (*read_callback)(InodeIdentifier) = nullptr, ssize_t (*write_callback)(InodeIdentifier, const UserOrKernelBuffer&, size_t) = nullptr, RefPtr<ProcFSInode>&& a_inode = nullptr) ProcFSDirectoryEntry(const char* a_name, unsigned a_proc_file_type, bool a_supervisor_only, bool (*read_callback)(InodeIdentifier, KBufferBuilder&) = nullptr, ssize_t (*write_callback)(InodeIdentifier, const UserOrKernelBuffer&, size_t) = nullptr, RefPtr<ProcFSInode>&& a_inode = nullptr)
: name(a_name) : name(a_name)
, proc_file_type(a_proc_file_type) , proc_file_type(a_proc_file_type)
, supervisor_only(a_supervisor_only) , supervisor_only(a_supervisor_only)
@ -72,7 +72,7 @@ private:
const char* name { nullptr }; const char* name { nullptr };
unsigned proc_file_type { 0 }; unsigned proc_file_type { 0 };
bool supervisor_only { false }; bool supervisor_only { false };
OwnPtr<KBuffer> (*read_callback)(InodeIdentifier); bool (*read_callback)(InodeIdentifier, KBufferBuilder&);
ssize_t (*write_callback)(InodeIdentifier, const UserOrKernelBuffer&, size_t); ssize_t (*write_callback)(InodeIdentifier, const UserOrKernelBuffer&, size_t);
RefPtr<ProcFSInode> inode; RefPtr<ProcFSInode> inode;
InodeIdentifier identifier(unsigned fsid) const; InodeIdentifier identifier(unsigned fsid) const;
@ -96,6 +96,8 @@ public:
private: private:
// ^Inode // ^Inode
virtual KResult attach(FileDescription&) override;
virtual void did_seek(FileDescription&, off_t) override;
virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override; virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override;
virtual InodeMetadata metadata() const override; virtual InodeMetadata metadata() const override;
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override; virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
@ -110,6 +112,8 @@ private:
virtual KResult chown(uid_t, gid_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 KResultOr<NonnullRefPtr<Custody>> resolve_as_link(Custody& base, RefPtr<Custody>* out_parent = nullptr, int options = 0, int symlink_recursion_level = 0) const override;
KResult refresh_data(FileDescription&) const;
ProcFS& fs() { return static_cast<ProcFS&>(Inode::fs()); } ProcFS& fs() { return static_cast<ProcFS&>(Inode::fs()); }
const ProcFS& fs() const { return static_cast<const ProcFS&>(Inode::fs()); } const ProcFS& fs() const { return static_cast<const ProcFS&>(Inode::fs()); }
ProcFSInode(ProcFS&, unsigned index); ProcFSInode(ProcFS&, unsigned index);
@ -123,6 +127,8 @@ public:
private: private:
// ^Inode // ^Inode
virtual KResult attach(FileDescription&) override;
virtual void did_seek(FileDescription&, off_t) override;
virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer&, FileDescription*) const override { ASSERT_NOT_REACHED(); } virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer&, FileDescription*) const override { ASSERT_NOT_REACHED(); }
virtual InodeMetadata metadata() const override; virtual InodeMetadata metadata() const override;
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override { ASSERT_NOT_REACHED(); } virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override { ASSERT_NOT_REACHED(); }

View file

@ -299,13 +299,19 @@ KResultOr<NonnullRefPtr<FileDescription>> VFS::open(StringView path, int options
if (metadata.is_fifo()) { if (metadata.is_fifo()) {
auto fifo = inode.fifo(); auto fifo = inode.fifo();
if (options & O_WRONLY) { if (options & O_WRONLY) {
auto description = fifo->open_direction_blocking(FIFO::Direction::Writer); auto open_result = fifo->open_direction_blocking(FIFO::Direction::Writer);
if (open_result.is_error())
return open_result.error();
auto& description = open_result.value();
description->set_rw_mode(options); description->set_rw_mode(options);
description->set_file_flags(options); description->set_file_flags(options);
description->set_original_inode({}, inode); description->set_original_inode({}, inode);
return description; return description;
} else if (options & O_RDONLY) { } else if (options & O_RDONLY) {
auto description = fifo->open_direction_blocking(FIFO::Direction::Reader); auto open_result = fifo->open_direction_blocking(FIFO::Direction::Reader);
if (open_result.is_error())
return open_result.error();
auto& description = open_result.value();
description->set_rw_mode(options); description->set_rw_mode(options);
description->set_file_flags(options); description->set_file_flags(options);
description->set_original_inode({}, inode); description->set_original_inode({}, inode);
@ -340,8 +346,10 @@ KResultOr<NonnullRefPtr<FileDescription>> VFS::open(StringView path, int options
inode.set_mtime(kgettimeofday().tv_sec); inode.set_mtime(kgettimeofday().tv_sec);
} }
auto description = FileDescription::create(custody); auto description = FileDescription::create(custody);
description->set_rw_mode(options); if (!description.is_error()) {
description->set_file_flags(options); description.value()->set_rw_mode(options);
description.value()->set_file_flags(options);
}
return description; return description;
} }
@ -400,8 +408,10 @@ KResultOr<NonnullRefPtr<FileDescription>> VFS::create(StringView path, int optio
auto new_custody = Custody::create(&parent_custody, p.basename(), inode_or_error.value(), parent_custody.mount_flags()); auto new_custody = Custody::create(&parent_custody, p.basename(), inode_or_error.value(), parent_custody.mount_flags());
auto description = FileDescription::create(*new_custody); auto description = FileDescription::create(*new_custody);
description->set_rw_mode(options); if (!description.is_error()) {
description->set_file_flags(options); description.value()->set_rw_mode(options);
description.value()->set_file_flags(options);
}
return description; return description;
} }

View file

@ -48,21 +48,21 @@ namespace Kernel {
class KBufferImpl : public RefCounted<KBufferImpl> { class KBufferImpl : public RefCounted<KBufferImpl> {
public: public:
static RefPtr<KBufferImpl> try_create_with_size(size_t size, u8 access, const char* name, AllocationStrategy strategy = AllocationStrategy::Reserve) static RefPtr<KBufferImpl> try_create_with_size(size_t size, u8 access, const char* name = "KBuffer", AllocationStrategy strategy = AllocationStrategy::Reserve)
{ {
auto region = MM.allocate_kernel_region(PAGE_ROUND_UP(size), name, access, false, strategy); auto region = MM.allocate_kernel_region(PAGE_ROUND_UP(size), name, access, false, strategy);
if (!region) if (!region)
return nullptr; return nullptr;
return adopt(*new KBufferImpl(region.release_nonnull(), size)); return adopt(*new KBufferImpl(region.release_nonnull(), size, strategy));
} }
static RefPtr<KBufferImpl> try_create_with_bytes(ReadonlyBytes bytes, u8 access, const char* name, AllocationStrategy strategy = AllocationStrategy::Reserve) static RefPtr<KBufferImpl> try_create_with_bytes(ReadonlyBytes bytes, u8 access, const char* name = "KBuffer", AllocationStrategy strategy = AllocationStrategy::Reserve)
{ {
auto region = MM.allocate_kernel_region(PAGE_ROUND_UP(bytes.size()), name, access, false, strategy); auto region = MM.allocate_kernel_region(PAGE_ROUND_UP(bytes.size()), name, access, false, strategy);
if (!region) if (!region)
return nullptr; return nullptr;
memcpy(region->vaddr().as_ptr(), bytes.data(), bytes.size()); memcpy(region->vaddr().as_ptr(), bytes.data(), bytes.size());
return adopt(*new KBufferImpl(region.release_nonnull(), bytes.size())); return adopt(*new KBufferImpl(region.release_nonnull(), bytes.size(), strategy));
} }
static RefPtr<KBufferImpl> create_with_size(size_t size, u8 access, const char* name, AllocationStrategy strategy = AllocationStrategy::Reserve) static RefPtr<KBufferImpl> create_with_size(size_t size, u8 access, const char* name, AllocationStrategy strategy = AllocationStrategy::Reserve)
@ -79,6 +79,17 @@ public:
return buffer; return buffer;
} }
bool expand(size_t new_capacity)
{
auto new_region = MM.allocate_kernel_region(PAGE_ROUND_UP(new_capacity), m_region->name(), m_region->access(), false, m_allocation_strategy);
if (!new_region)
return false;
if (m_region && m_size > 0)
memcpy(new_region->vaddr().as_ptr(), data(), min(m_region->size(), m_size));
m_region = new_region.release_nonnull();
return true;
}
u8* data() { return m_region->vaddr().as_ptr(); } u8* data() { return m_region->vaddr().as_ptr(); }
const u8* data() const { return m_region->vaddr().as_ptr(); } const u8* data() const { return m_region->vaddr().as_ptr(); }
size_t size() const { return m_size; } size_t size() const { return m_size; }
@ -94,18 +105,25 @@ public:
Region& region() { return *m_region; } Region& region() { return *m_region; }
private: private:
explicit KBufferImpl(NonnullOwnPtr<Region>&& region, size_t size) explicit KBufferImpl(NonnullOwnPtr<Region>&& region, size_t size, AllocationStrategy strategy)
: m_size(size) : m_size(size)
, m_allocation_strategy(strategy)
, m_region(move(region)) , m_region(move(region))
{ {
} }
size_t m_size { 0 }; size_t m_size { 0 };
AllocationStrategy m_allocation_strategy { AllocationStrategy::Reserve };
NonnullOwnPtr<Region> m_region; NonnullOwnPtr<Region> m_region;
}; };
class KBuffer { class KBuffer {
public: public:
explicit KBuffer(RefPtr<KBufferImpl>&& impl)
: m_impl(move(impl))
{
}
static OwnPtr<KBuffer> try_create_with_size(size_t size, u8 access = Region::Access::Read | Region::Access::Write, const char* name = "KBuffer", AllocationStrategy strategy = AllocationStrategy::Reserve) static OwnPtr<KBuffer> try_create_with_size(size_t size, u8 access = Region::Access::Read | Region::Access::Write, const char* name = "KBuffer", AllocationStrategy strategy = AllocationStrategy::Reserve)
{ {
auto impl = KBufferImpl::try_create_with_size(size, access, name, strategy); auto impl = KBufferImpl::try_create_with_size(size, access, name, strategy);
@ -145,6 +163,7 @@ public:
void set_size(size_t size) { m_impl->set_size(size); } void set_size(size_t size) { m_impl->set_size(size); }
const KBufferImpl& impl() const { return *m_impl; } const KBufferImpl& impl() const { return *m_impl; }
RefPtr<KBufferImpl> take_impl() { return move(m_impl); }
KBuffer(const ByteBuffer& buffer, u8 access = Region::Access::Read | Region::Access::Write, const char* name = "KBuffer") KBuffer(const ByteBuffer& buffer, u8 access = Region::Access::Read | Region::Access::Write, const char* name = "KBuffer")
: m_impl(KBufferImpl::copy(buffer.data(), buffer.size(), access, name)) : m_impl(KBufferImpl::copy(buffer.data(), buffer.size(), access, name))
@ -152,11 +171,6 @@ public:
} }
private: private:
explicit KBuffer(RefPtr<KBufferImpl>&& impl)
: m_impl(move(impl))
{
}
RefPtr<KBufferImpl> m_impl; RefPtr<KBufferImpl> m_impl;
}; };

View file

@ -31,32 +31,65 @@
namespace Kernel { namespace Kernel {
inline bool KBufferBuilder::can_append(size_t size) const inline bool KBufferBuilder::check_expand(size_t size)
{ {
if (!m_buffer) if (!m_buffer)
return false; return false;
return ((m_size + size) < m_buffer->size()); if ((m_size + size) < m_buffer->capacity())
return true;
if (!m_can_expand)
return false;
if (Checked<size_t>::addition_would_overflow(m_size, size))
return false;
size_t new_buffer_size = m_size + size;
if (Checked<size_t>::addition_would_overflow(new_buffer_size, 1 * MiB))
return false;
new_buffer_size = PAGE_ROUND_UP(new_buffer_size + 1 * MiB);
return m_buffer->expand(new_buffer_size);
}
bool KBufferBuilder::flush()
{
if (!m_buffer)
return false;
m_buffer->set_size(m_size);
return true;
} }
OwnPtr<KBuffer> KBufferBuilder::build() OwnPtr<KBuffer> KBufferBuilder::build()
{ {
if (!m_buffer) if (!flush())
return {}; return {};
if (!m_buffer->is_null()) return make<KBuffer>(move(m_buffer));
m_buffer->set_size(m_size);
return m_buffer.release_nonnull();
} }
KBufferBuilder::KBufferBuilder() KBufferBuilder::KBufferBuilder(bool can_expand)
: m_buffer(KBuffer::try_create_with_size(4 * MiB, Region::Access::Read | Region::Access::Write)) : m_buffer(KBufferImpl::try_create_with_size(4 * MiB, Region::Access::Read | Region::Access::Write))
, m_can_expand(can_expand)
{ {
} }
KBufferBuilder::KBufferBuilder(RefPtr<KBufferImpl>& buffer, bool can_expand)
: m_buffer(buffer)
, m_can_expand(can_expand)
{
if (!m_buffer)
m_buffer = buffer = KBufferImpl::try_create_with_size(4 * MiB, Region::Access::Read | Region::Access::Write);
}
void KBufferBuilder::append_bytes(ReadonlyBytes bytes)
{
if (!check_expand(bytes.size()))
return;
memcpy(insertion_ptr(), bytes.data(), bytes.size());
m_size += bytes.size();
}
void KBufferBuilder::append(const StringView& str) void KBufferBuilder::append(const StringView& str)
{ {
if (str.is_empty()) if (str.is_empty())
return; return;
if (!can_append(str.length())) if (!check_expand(str.length()))
return; return;
memcpy(insertion_ptr(), str.characters_without_null_termination(), str.length()); memcpy(insertion_ptr(), str.characters_without_null_termination(), str.length());
m_size += str.length(); m_size += str.length();
@ -66,7 +99,7 @@ void KBufferBuilder::append(const char* characters, int length)
{ {
if (!length) if (!length)
return; return;
if (!can_append(length)) if (!check_expand(length))
return; return;
memcpy(insertion_ptr(), characters, length); memcpy(insertion_ptr(), characters, length);
m_size += length; m_size += length;
@ -74,7 +107,7 @@ void KBufferBuilder::append(const char* characters, int length)
void KBufferBuilder::append(char ch) void KBufferBuilder::append(char ch)
{ {
if (!can_append(1)) if (!check_expand(1))
return; return;
insertion_ptr()[0] = ch; insertion_ptr()[0] = ch;
m_size += 1; m_size += 1;

View file

@ -36,7 +36,8 @@ class KBufferBuilder {
public: public:
using OutputType = KBuffer; using OutputType = KBuffer;
explicit KBufferBuilder(); explicit KBufferBuilder(bool can_expand = false);
explicit KBufferBuilder(RefPtr<KBufferImpl>&, bool can_expand = false);
KBufferBuilder(KBufferBuilder&&) = default; KBufferBuilder(KBufferBuilder&&) = default;
~KBufferBuilder() { } ~KBufferBuilder() { }
@ -47,6 +48,7 @@ public:
void appendvf(const char*, va_list); void appendvf(const char*, va_list);
void append_escaped_for_json(const StringView&); void append_escaped_for_json(const StringView&);
void append_bytes(ReadonlyBytes);
template<typename... Parameters> template<typename... Parameters>
void appendff(StringView fmtstr, const Parameters&... parameters) void appendff(StringView fmtstr, const Parameters&... parameters)
@ -56,10 +58,11 @@ public:
append(String::formatted(fmtstr, parameters...)); append(String::formatted(fmtstr, parameters...));
} }
bool flush();
OwnPtr<KBuffer> build(); OwnPtr<KBuffer> build();
private: private:
bool can_append(size_t) const; bool check_expand(size_t);
u8* insertion_ptr() u8* insertion_ptr()
{ {
if (!m_buffer) if (!m_buffer)
@ -67,8 +70,9 @@ private:
return m_buffer->data() + m_size; return m_buffer->data() + m_size;
} }
OwnPtr<KBuffer> m_buffer; RefPtr<KBufferImpl> m_buffer;
size_t m_size { 0 }; size_t m_size { 0 };
bool m_can_expand { false };
}; };
} }

View file

@ -170,14 +170,6 @@ KResult IPv4Socket::connect(FileDescription& description, Userspace<const sockad
return protocol_connect(description, should_block); return protocol_connect(description, should_block);
} }
void IPv4Socket::attach(FileDescription&)
{
}
void IPv4Socket::detach(FileDescription&)
{
}
bool IPv4Socket::can_read(const FileDescription&, size_t) const bool IPv4Socket::can_read(const FileDescription&, size_t) const
{ {
if (m_role == Role::Listener) if (m_role == Role::Listener)

View file

@ -54,8 +54,6 @@ public:
virtual KResult listen(size_t) override; virtual KResult listen(size_t) override;
virtual void get_local_address(sockaddr*, socklen_t*) override; virtual void get_local_address(sockaddr*, socklen_t*) override;
virtual void get_peer_address(sockaddr*, socklen_t*) override; virtual void get_peer_address(sockaddr*, socklen_t*) override;
virtual void attach(FileDescription&) override;
virtual void detach(FileDescription&) override;
virtual bool can_read(const FileDescription&, size_t) const override; virtual bool can_read(const FileDescription&, size_t) const override;
virtual bool can_write(const FileDescription&, size_t) const override; virtual bool can_write(const FileDescription&, size_t) const override;
virtual KResultOr<size_t> sendto(FileDescription&, const UserOrKernelBuffer&, size_t, int, Userspace<const sockaddr*>, socklen_t) override; virtual KResultOr<size_t> sendto(FileDescription&, const UserOrKernelBuffer&, size_t, int, Userspace<const sockaddr*>, socklen_t) override;

View file

@ -224,7 +224,7 @@ KResult LocalSocket::listen(size_t backlog)
return KSuccess; return KSuccess;
} }
void LocalSocket::attach(FileDescription& description) KResult LocalSocket::attach(FileDescription& description)
{ {
ASSERT(!m_accept_side_fd_open); ASSERT(!m_accept_side_fd_open);
if (m_connect_side_role == Role::None) { if (m_connect_side_role == Role::None) {
@ -236,6 +236,7 @@ void LocalSocket::attach(FileDescription& description)
} }
evaluate_block_conditions(); evaluate_block_conditions();
return KSuccess;
} }
void LocalSocket::detach(FileDescription& description) void LocalSocket::detach(FileDescription& description)

View file

@ -56,7 +56,7 @@ public:
virtual KResult listen(size_t) override; virtual KResult listen(size_t) override;
virtual void get_local_address(sockaddr*, socklen_t*) override; virtual void get_local_address(sockaddr*, socklen_t*) override;
virtual void get_peer_address(sockaddr*, socklen_t*) override; virtual void get_peer_address(sockaddr*, socklen_t*) override;
virtual void attach(FileDescription&) override; virtual KResult attach(FileDescription&) override;
virtual void detach(FileDescription&) override; virtual void detach(FileDescription&) override;
virtual bool can_read(const FileDescription&, size_t) const override; virtual bool can_read(const FileDescription&, size_t) const override;
virtual bool can_write(const FileDescription&, size_t) const override; virtual bool can_write(const FileDescription&, size_t) const override;

View file

@ -105,8 +105,6 @@ public:
virtual void get_peer_address(sockaddr*, socklen_t*) = 0; virtual void get_peer_address(sockaddr*, socklen_t*) = 0;
virtual bool is_local() const { return false; } virtual bool is_local() const { return false; }
virtual bool is_ipv4() const { return false; } virtual bool is_ipv4() const { return false; }
virtual void attach(FileDescription&) = 0;
virtual void detach(FileDescription&) = 0;
virtual KResultOr<size_t> sendto(FileDescription&, const UserOrKernelBuffer&, size_t, int flags, Userspace<const sockaddr*>, socklen_t) = 0; virtual KResultOr<size_t> sendto(FileDescription&, const UserOrKernelBuffer&, size_t, int flags, Userspace<const sockaddr*>, socklen_t) = 0;
virtual KResultOr<size_t> recvfrom(FileDescription&, UserOrKernelBuffer&, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>, timeval&) = 0; virtual KResultOr<size_t> recvfrom(FileDescription&, UserOrKernelBuffer&, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>, timeval&) = 0;

View file

@ -196,11 +196,12 @@ RefPtr<BlockDevice> StorageManagement::boot_block_device() const
NonnullRefPtr<FS> StorageManagement::root_filesystem() const NonnullRefPtr<FS> StorageManagement::root_filesystem() const
{ {
if (!boot_block_device()) { auto boot_device_description = boot_block_device();
if (!boot_device_description) {
klog() << "init_stage2: couldn't find a suitable device to boot from"; klog() << "init_stage2: couldn't find a suitable device to boot from";
Processor::halt(); Processor::halt();
} }
auto e2fs = Ext2FS::create(*FileDescription::create(boot_block_device().release_nonnull())); auto e2fs = Ext2FS::create(FileDescription::create(boot_device_description.release_nonnull()).value());
if (!e2fs->initialize()) { if (!e2fs->initialize()) {
klog() << "init_stage2: couldn't open root filesystem"; klog() << "init_stage2: couldn't open root filesystem";
Processor::halt(); Processor::halt();

View file

@ -42,14 +42,21 @@ int Process::sys$pipe(int pipefd[2], int flags)
u32 fd_flags = (flags & O_CLOEXEC) ? FD_CLOEXEC : 0; u32 fd_flags = (flags & O_CLOEXEC) ? FD_CLOEXEC : 0;
auto fifo = FIFO::create(m_uid); auto fifo = FIFO::create(m_uid);
auto open_reader_result = fifo->open_direction(FIFO::Direction::Reader);
if (open_reader_result.is_error())
return open_reader_result.error();
auto open_writer_result = fifo->open_direction(FIFO::Direction::Writer);
if (open_writer_result.is_error())
return open_writer_result.error();
int reader_fd = alloc_fd(); int reader_fd = alloc_fd();
m_fds[reader_fd].set(fifo->open_direction(FIFO::Direction::Reader), fd_flags); m_fds[reader_fd].set(open_reader_result.release_value(), fd_flags);
m_fds[reader_fd].description()->set_readable(true); m_fds[reader_fd].description()->set_readable(true);
if (!copy_to_user(&pipefd[0], &reader_fd)) if (!copy_to_user(&pipefd[0], &reader_fd))
return -EFAULT; return -EFAULT;
int writer_fd = alloc_fd(); int writer_fd = alloc_fd();
m_fds[writer_fd].set(fifo->open_direction(FIFO::Direction::Writer), fd_flags); m_fds[writer_fd].set(open_writer_result.release_value(), fd_flags);
m_fds[writer_fd].description()->set_writable(true); m_fds[writer_fd].description()->set_writable(true);
if (!copy_to_user(&pipefd[1], &writer_fd)) if (!copy_to_user(&pipefd[1], &writer_fd))
return -EFAULT; return -EFAULT;

View file

@ -52,15 +52,17 @@ int Process::sys$socket(int domain, int type, int protocol)
auto result = Socket::create(domain, type, protocol); auto result = Socket::create(domain, type, protocol);
if (result.is_error()) if (result.is_error())
return result.error(); return result.error();
auto description = FileDescription::create(*result.value()); auto description_result = FileDescription::create(*result.value());
description->set_readable(true); if (description_result.is_error())
description->set_writable(true); return description_result.error();
description_result.value()->set_readable(true);
description_result.value()->set_writable(true);
unsigned flags = 0; unsigned flags = 0;
if (type & SOCK_CLOEXEC) if (type & SOCK_CLOEXEC)
flags |= FD_CLOEXEC; flags |= FD_CLOEXEC;
if (type & SOCK_NONBLOCK) if (type & SOCK_NONBLOCK)
description->set_blocking(false); description_result.value()->set_blocking(false);
m_fds[fd].set(move(description), flags); m_fds[fd].set(description_result.release_value(), flags);
return fd; return fd;
} }
@ -132,13 +134,16 @@ int Process::sys$accept(int accepting_socket_fd, Userspace<sockaddr*> user_addre
return -EFAULT; return -EFAULT;
} }
auto accepted_socket_description = FileDescription::create(*accepted_socket); auto accepted_socket_description_result = FileDescription::create(*accepted_socket);
accepted_socket_description->set_readable(true); if (accepted_socket_description_result.is_error())
accepted_socket_description->set_writable(true); return accepted_socket_description_result.error();
accepted_socket_description_result.value()->set_readable(true);
accepted_socket_description_result.value()->set_writable(true);
// NOTE: The accepted socket inherits fd flags from the accepting socket. // NOTE: The accepted socket inherits fd flags from the accepting socket.
// I'm not sure if this matches other systems but it makes sense to me. // I'm not sure if this matches other systems but it makes sense to me.
accepted_socket_description->set_blocking(accepting_socket_description->is_blocking()); accepted_socket_description_result.value()->set_blocking(accepting_socket_description->is_blocking());
m_fds[accepted_socket_fd].set(move(accepted_socket_description), m_fds[accepting_socket_fd].flags()); m_fds[accepted_socket_fd].set(accepted_socket_description_result.release_value(), m_fds[accepting_socket_fd].flags());
// NOTE: Moving this state to Completed is what causes connect() to unblock on the client side. // NOTE: Moving this state to Completed is what causes connect() to unblock on the client side.
accepted_socket->set_setup_state(Socket::SetupState::Completed); accepted_socket->set_setup_state(Socket::SetupState::Completed);

View file

@ -52,7 +52,11 @@ int Process::sys$watch_file(Userspace<const char*> user_path, size_t path_length
if (fd < 0) if (fd < 0)
return fd; return fd;
m_fds[fd].set(FileDescription::create(*InodeWatcher::create(inode))); auto description = FileDescription::create(*InodeWatcher::create(inode));
if (description.is_error())
return description.error();
m_fds[fd].set(description.release_value());
m_fds[fd].description()->set_readable(true); m_fds[fd].description()->set_readable(true);
return fd; return fd;
} }

View file

@ -66,8 +66,10 @@ KResultOr<NonnullRefPtr<FileDescription>> PTYMultiplexer::open(int options)
dbg() << "PTYMultiplexer::open: Vending master " << master->index(); dbg() << "PTYMultiplexer::open: Vending master " << master->index();
#endif #endif
auto description = FileDescription::create(move(master)); auto description = FileDescription::create(move(master));
description->set_rw_mode(options); if (!description.is_error()) {
description->set_file_flags(options); description.value()->set_rw_mode(options);
description.value()->set_file_flags(options);
}
return description; return description;
} }

View file

@ -56,6 +56,7 @@ add_compile_definitions("EXEC_DEBUG")
add_compile_definitions("EXT2_DEBUG") add_compile_definitions("EXT2_DEBUG")
add_compile_definitions("EXT2_VERY_DEBUG") add_compile_definitions("EXT2_VERY_DEBUG")
add_compile_definitions("FIFO_DEBUG") add_compile_definitions("FIFO_DEBUG")
add_compile_definitions("FILEDESCRIPTION_DEBUG")
add_compile_definitions("FILL_PATH_DEBUG") add_compile_definitions("FILL_PATH_DEBUG")
add_compile_definitions("FORK_DEBUG") add_compile_definitions("FORK_DEBUG")
add_compile_definitions("GBOXLAYOUT_DEBUG") add_compile_definitions("GBOXLAYOUT_DEBUG")