mirror of
https://github.com/RGBCube/serenity
synced 2025-06-29 01:42:11 +00:00
ProcFS: Do not assume there is one of it
The complication is around /proc/sys/ variables, which were attached to inodes. Now they're their own thing, and the corresponding inodes are lazily created (as all other ProcFS inodes are) and simply refer to them by index.
This commit is contained in:
parent
1febd59f83
commit
37cc80fb96
4 changed files with 144 additions and 135 deletions
|
@ -53,6 +53,8 @@ enum ProcFileType {
|
|||
FI_Root_net, // directory
|
||||
__FI_Root_End,
|
||||
|
||||
FI_Root_sys_variable,
|
||||
|
||||
FI_Root_net_adapters,
|
||||
FI_Root_net_tcp,
|
||||
FI_Root_net_udp,
|
||||
|
@ -87,6 +89,11 @@ static inline ProcParentDirectory to_proc_parent_directory(const InodeIdentifier
|
|||
return (ProcParentDirectory)((identifier.index() >> 12) & 0xf);
|
||||
}
|
||||
|
||||
static inline ProcFileType to_proc_file_type(const InodeIdentifier& identifier)
|
||||
{
|
||||
return (ProcFileType)(identifier.index() & 0xff);
|
||||
}
|
||||
|
||||
static inline int to_fd(const InodeIdentifier& identifier)
|
||||
{
|
||||
ASSERT(to_proc_parent_directory(identifier) == PDI_PID_fd);
|
||||
|
@ -96,7 +103,8 @@ static inline int to_fd(const InodeIdentifier& identifier)
|
|||
static inline int to_sys_index(const InodeIdentifier& identifier)
|
||||
{
|
||||
ASSERT(to_proc_parent_directory(identifier) == PDI_Root_sys);
|
||||
return identifier.index() & 0xff;
|
||||
ASSERT(to_proc_file_type(identifier) == FI_Root_sys_variable);
|
||||
return identifier.index() >> 16u;
|
||||
}
|
||||
|
||||
static inline InodeIdentifier to_identifier(unsigned fsid, ProcParentDirectory parent, pid_t pid, ProcFileType proc_file_type)
|
||||
|
@ -112,7 +120,7 @@ static inline InodeIdentifier to_identifier_with_fd(unsigned fsid, pid_t pid, in
|
|||
static inline InodeIdentifier sys_var_to_identifier(unsigned fsid, unsigned index)
|
||||
{
|
||||
ASSERT(index < 256);
|
||||
return { fsid, (PDI_Root_sys << 12u) | index };
|
||||
return { fsid, (PDI_Root_sys << 12u) | (index << 16u) | FI_Root_sys_variable };
|
||||
}
|
||||
|
||||
static inline InodeIdentifier to_parent_id(const InodeIdentifier& identifier)
|
||||
|
@ -140,11 +148,6 @@ static inline u8 to_unused_metadata(const InodeIdentifier& identifier)
|
|||
}
|
||||
#endif
|
||||
|
||||
static inline ProcFileType to_proc_file_type(const InodeIdentifier& identifier)
|
||||
{
|
||||
return (ProcFileType)(identifier.index() & 0xff);
|
||||
}
|
||||
|
||||
static inline bool is_process_related_file(const InodeIdentifier& identifier)
|
||||
{
|
||||
if (to_proc_file_type(identifier) == FI_PID)
|
||||
|
@ -179,14 +182,6 @@ static inline bool is_persistent_inode(const InodeIdentifier& identifier)
|
|||
return to_proc_parent_directory(identifier) == PDI_Root_sys;
|
||||
}
|
||||
|
||||
static ProcFS* s_the;
|
||||
|
||||
ProcFS& ProcFS::the()
|
||||
{
|
||||
ASSERT(s_the);
|
||||
return *s_the;
|
||||
}
|
||||
|
||||
NonnullRefPtr<ProcFS> ProcFS::create()
|
||||
{
|
||||
return adopt(*new ProcFS);
|
||||
|
@ -639,31 +634,54 @@ Optional<KBuffer> procfs$inodes(InodeIdentifier)
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
struct SysVariableData final : public ProcFSInodeCustomData {
|
||||
virtual ~SysVariableData() override {}
|
||||
|
||||
enum Type {
|
||||
struct SysVariable {
|
||||
String name;
|
||||
enum class Type : u8 {
|
||||
Invalid,
|
||||
Boolean,
|
||||
String,
|
||||
};
|
||||
Type type { Invalid };
|
||||
Type type { Type::Invalid };
|
||||
Function<void()> notify_callback;
|
||||
void* address;
|
||||
void* address { nullptr };
|
||||
|
||||
static SysVariable& for_inode(InodeIdentifier);
|
||||
|
||||
void notify()
|
||||
{
|
||||
if (notify_callback)
|
||||
notify_callback();
|
||||
}
|
||||
};
|
||||
|
||||
static Vector<SysVariable, 16>* s_sys_variables;
|
||||
|
||||
static inline Vector<SysVariable, 16>& sys_variables()
|
||||
{
|
||||
if (s_sys_variables == nullptr) {
|
||||
s_sys_variables = new Vector<SysVariable, 16>;
|
||||
s_sys_variables->append({ "", SysVariable::Type::Invalid, nullptr, nullptr });
|
||||
}
|
||||
return *s_sys_variables;
|
||||
}
|
||||
|
||||
SysVariable& SysVariable::for_inode(InodeIdentifier id)
|
||||
{
|
||||
auto index = to_sys_index(id);
|
||||
if (index >= sys_variables().size())
|
||||
return sys_variables()[0];
|
||||
auto& variable = sys_variables()[index];
|
||||
ASSERT(variable.address);
|
||||
return variable;
|
||||
}
|
||||
|
||||
static ByteBuffer read_sys_bool(InodeIdentifier inode_id)
|
||||
{
|
||||
auto inode_ptr = ProcFS::the().get_inode(inode_id);
|
||||
if (!inode_ptr)
|
||||
return {};
|
||||
auto& inode = static_cast<ProcFSInode&>(*inode_ptr);
|
||||
ASSERT(inode.custom_data());
|
||||
auto& variable = SysVariable::for_inode(inode_id);
|
||||
ASSERT(variable.type == SysVariable::Type::Boolean);
|
||||
|
||||
auto buffer = ByteBuffer::create_uninitialized(2);
|
||||
auto& custom_data = *static_cast<const SysVariableData*>(inode.custom_data());
|
||||
ASSERT(custom_data.type == SysVariableData::Boolean);
|
||||
ASSERT(custom_data.address);
|
||||
auto* lockable_bool = reinterpret_cast<Lockable<bool>*>(custom_data.address);
|
||||
auto* lockable_bool = reinterpret_cast<Lockable<bool>*>(variable.address);
|
||||
{
|
||||
LOCKER(lockable_bool->lock());
|
||||
buffer[0] = lockable_bool->resource() ? '1' : '0';
|
||||
|
@ -674,57 +692,42 @@ static ByteBuffer read_sys_bool(InodeIdentifier inode_id)
|
|||
|
||||
static ssize_t write_sys_bool(InodeIdentifier inode_id, const ByteBuffer& data)
|
||||
{
|
||||
auto inode_ptr = ProcFS::the().get_inode(inode_id);
|
||||
if (!inode_ptr)
|
||||
return {};
|
||||
auto& inode = static_cast<ProcFSInode&>(*inode_ptr);
|
||||
ASSERT(inode.custom_data());
|
||||
auto& variable = SysVariable::for_inode(inode_id);
|
||||
ASSERT(variable.type == SysVariable::Type::Boolean);
|
||||
|
||||
if (data.is_empty() || !(data[0] == '0' || data[0] == '1'))
|
||||
return data.size();
|
||||
|
||||
auto& custom_data = *static_cast<const SysVariableData*>(inode.custom_data());
|
||||
auto* lockable_bool = reinterpret_cast<Lockable<bool>*>(custom_data.address);
|
||||
auto* lockable_bool = reinterpret_cast<Lockable<bool>*>(variable.address);
|
||||
{
|
||||
LOCKER(lockable_bool->lock());
|
||||
lockable_bool->resource() = data[0] == '1';
|
||||
}
|
||||
if (custom_data.notify_callback)
|
||||
custom_data.notify_callback();
|
||||
variable.notify();
|
||||
return data.size();
|
||||
}
|
||||
|
||||
static ByteBuffer read_sys_string(InodeIdentifier inode_id)
|
||||
{
|
||||
auto inode_ptr = ProcFS::the().get_inode(inode_id);
|
||||
if (!inode_ptr)
|
||||
return {};
|
||||
auto& inode = static_cast<ProcFSInode&>(*inode_ptr);
|
||||
ASSERT(inode.custom_data());
|
||||
auto buffer = ByteBuffer::create_uninitialized(2);
|
||||
auto& custom_data = *static_cast<const SysVariableData*>(inode.custom_data());
|
||||
ASSERT(custom_data.type == SysVariableData::String);
|
||||
ASSERT(custom_data.address);
|
||||
auto* lockable_string = reinterpret_cast<Lockable<String>*>(custom_data.address);
|
||||
auto& variable = SysVariable::for_inode(inode_id);
|
||||
ASSERT(variable.type == SysVariable::Type::String);
|
||||
|
||||
auto* lockable_string = reinterpret_cast<Lockable<String>*>(variable.address);
|
||||
LOCKER(lockable_string->lock());
|
||||
return lockable_string->resource().to_byte_buffer();
|
||||
}
|
||||
|
||||
static ssize_t write_sys_string(InodeIdentifier inode_id, const ByteBuffer& data)
|
||||
{
|
||||
auto inode_ptr = ProcFS::the().get_inode(inode_id);
|
||||
if (!inode_ptr)
|
||||
return {};
|
||||
auto& inode = static_cast<ProcFSInode&>(*inode_ptr);
|
||||
ASSERT(inode.custom_data());
|
||||
auto& custom_data = *static_cast<const SysVariableData*>(inode.custom_data());
|
||||
ASSERT(custom_data.address);
|
||||
auto& variable = SysVariable::for_inode(inode_id);
|
||||
ASSERT(variable.type == SysVariable::Type::String);
|
||||
|
||||
{
|
||||
auto* lockable_string = reinterpret_cast<Lockable<String>*>(custom_data.address);
|
||||
auto* lockable_string = reinterpret_cast<Lockable<String>*>(variable.address);
|
||||
LOCKER(lockable_string->lock());
|
||||
lockable_string->resource() = String((const char*)data.pointer(), data.size());
|
||||
}
|
||||
if (custom_data.notify_callback)
|
||||
custom_data.notify_callback();
|
||||
variable.notify();
|
||||
return data.size();
|
||||
}
|
||||
|
||||
|
@ -732,32 +735,39 @@ void ProcFS::add_sys_bool(String&& name, Lockable<bool>& var, Function<void()>&&
|
|||
{
|
||||
InterruptDisabler disabler;
|
||||
|
||||
int index = m_sys_entries.size();
|
||||
auto inode = adopt(*new ProcFSInode(*this, sys_var_to_identifier(fsid(), index).index()));
|
||||
auto data = make<SysVariableData>();
|
||||
data->type = SysVariableData::Boolean;
|
||||
data->notify_callback = move(notify_callback);
|
||||
data->address = &var;
|
||||
inode->set_custom_data(move(data));
|
||||
m_sys_entries.empend(strdup(name.characters()), 0, read_sys_bool, write_sys_bool, move(inode));
|
||||
SysVariable variable;
|
||||
variable.name = move(name);
|
||||
variable.type = SysVariable::Type::Boolean;
|
||||
variable.notify_callback = move(notify_callback);
|
||||
variable.address = &var;
|
||||
|
||||
sys_variables().append(move(variable));
|
||||
}
|
||||
|
||||
void ProcFS::add_sys_string(String&& name, Lockable<String>& var, Function<void()>&& notify_callback)
|
||||
{
|
||||
InterruptDisabler disabler;
|
||||
|
||||
int index = m_sys_entries.size();
|
||||
auto inode = adopt(*new ProcFSInode(*this, sys_var_to_identifier(fsid(), index).index()));
|
||||
auto data = make<SysVariableData>();
|
||||
data->type = SysVariableData::String;
|
||||
data->notify_callback = move(notify_callback);
|
||||
data->address = &var;
|
||||
inode->set_custom_data(move(data));
|
||||
m_sys_entries.empend(strdup(name.characters()), 0, read_sys_string, write_sys_string, move(inode));
|
||||
SysVariable variable;
|
||||
variable.name = move(name);
|
||||
variable.type = SysVariable::Type::String;
|
||||
variable.notify_callback = move(notify_callback);
|
||||
variable.address = &var;
|
||||
|
||||
sys_variables().append(move(variable));
|
||||
}
|
||||
|
||||
bool ProcFS::initialize()
|
||||
{
|
||||
static Lockable<bool>* kmalloc_stack_helper;
|
||||
|
||||
if (kmalloc_stack_helper == nullptr) {
|
||||
kmalloc_stack_helper = new Lockable<bool>();
|
||||
kmalloc_stack_helper->resource() = g_dump_kmalloc_stacks;
|
||||
ProcFS::add_sys_bool("kmalloc_stacks", *kmalloc_stack_helper, [] {
|
||||
g_dump_kmalloc_stacks = kmalloc_stack_helper->resource();
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -791,12 +801,6 @@ RefPtr<Inode> ProcFS::get_inode(InodeIdentifier inode_id) const
|
|||
if (inode_id == root_inode())
|
||||
return m_root_inode;
|
||||
|
||||
if (to_proc_parent_directory(inode_id) == ProcParentDirectory::PDI_Root_sys) {
|
||||
auto sys_index = to_sys_index(inode_id);
|
||||
if (sys_index < m_sys_entries.size())
|
||||
return m_sys_entries[sys_index].inode;
|
||||
}
|
||||
|
||||
LOCKER(m_inodes_lock);
|
||||
auto it = m_inodes.find(inode_id.index());
|
||||
if (it == m_inodes.end()) {
|
||||
|
@ -847,11 +851,6 @@ InodeMetadata ProcFSInode::metadata() const
|
|||
return metadata;
|
||||
}
|
||||
|
||||
if (proc_parent_directory == PDI_Root_sys) {
|
||||
metadata.mode = 00100644;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
switch (proc_file_type) {
|
||||
case FI_Root_self:
|
||||
case FI_PID_cwd:
|
||||
|
@ -887,14 +886,30 @@ ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes
|
|||
|
||||
Function<Optional<KBuffer>(InodeIdentifier)> callback_tmp;
|
||||
Function<Optional<KBuffer>(InodeIdentifier)>* read_callback { nullptr };
|
||||
if (directory_entry) {
|
||||
if (directory_entry)
|
||||
read_callback = &directory_entry->read_callback;
|
||||
} else {
|
||||
if (to_proc_parent_directory(identifier()) == PDI_PID_fd) {
|
||||
else
|
||||
switch (to_proc_parent_directory(identifier())) {
|
||||
case PDI_PID_fd:
|
||||
callback_tmp = procfs$pid_fd_entry;
|
||||
read_callback = &callback_tmp;
|
||||
break;
|
||||
case PDI_Root_sys:
|
||||
switch (SysVariable::for_inode(identifier()).type) {
|
||||
case SysVariable::Type::Invalid:
|
||||
ASSERT_NOT_REACHED();
|
||||
case SysVariable::Type::Boolean:
|
||||
callback_tmp = read_sys_bool;
|
||||
break;
|
||||
case SysVariable::Type::String:
|
||||
callback_tmp = read_sys_string;
|
||||
break;
|
||||
}
|
||||
read_callback = &callback_tmp;
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(read_callback);
|
||||
|
||||
|
@ -953,9 +968,9 @@ bool ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntry&)
|
|||
break;
|
||||
|
||||
case FI_Root_sys:
|
||||
for (int i = 0; i < fs().m_sys_entries.size(); ++i) {
|
||||
auto& entry = fs().m_sys_entries[i];
|
||||
callback({ entry.name, (int)strlen(entry.name), sys_var_to_identifier(fsid(), i), 0 });
|
||||
for (int i = 1; i < sys_variables().size(); ++i) {
|
||||
auto& variable = sys_variables()[i];
|
||||
callback({ variable.name.characters(), variable.name.length(), sys_var_to_identifier(fsid(), i), 0 });
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1037,9 +1052,9 @@ InodeIdentifier ProcFSInode::lookup(StringView name)
|
|||
}
|
||||
|
||||
if (proc_file_type == FI_Root_sys) {
|
||||
for (int i = 0; i < fs().m_sys_entries.size(); ++i) {
|
||||
auto& entry = fs().m_sys_entries[i];
|
||||
if (name == entry.name)
|
||||
for (int i = 1; i < sys_variables().size(); ++i) {
|
||||
auto& variable = sys_variables()[i];
|
||||
if (name == variable.name)
|
||||
return sys_var_to_identifier(fsid(), i);
|
||||
}
|
||||
return {};
|
||||
|
@ -1100,12 +1115,35 @@ void ProcFSInode::flush_metadata()
|
|||
ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, FileDescription*)
|
||||
{
|
||||
auto* directory_entry = fs().get_directory_entry(identifier());
|
||||
if (!directory_entry || !directory_entry->write_callback)
|
||||
return -EPERM;
|
||||
|
||||
Function<ssize_t(InodeIdentifier, const ByteBuffer&)> callback_tmp;
|
||||
Function<ssize_t(InodeIdentifier, const ByteBuffer&)>* write_callback { nullptr };
|
||||
|
||||
if (directory_entry == nullptr) {
|
||||
if (to_proc_parent_directory(identifier()) == PDI_Root_sys) {
|
||||
switch (SysVariable::for_inode(identifier()).type) {
|
||||
case SysVariable::Type::Invalid:
|
||||
ASSERT_NOT_REACHED();
|
||||
case SysVariable::Type::Boolean:
|
||||
callback_tmp = write_sys_bool;
|
||||
break;
|
||||
case SysVariable::Type::String:
|
||||
callback_tmp = write_sys_string;
|
||||
break;
|
||||
}
|
||||
write_callback = &callback_tmp;
|
||||
} else
|
||||
return -EPERM;
|
||||
} else {
|
||||
if (!directory_entry->write_callback)
|
||||
return -EPERM;
|
||||
write_callback = &directory_entry->write_callback;
|
||||
}
|
||||
|
||||
ASSERT(is_persistent_inode(identifier()));
|
||||
// FIXME: Being able to write into ProcFS at a non-zero offset seems like something we should maybe support..
|
||||
ASSERT(offset == 0);
|
||||
bool success = directory_entry->write_callback(identifier(), ByteBuffer::wrap(buffer, size));
|
||||
bool success = (*write_callback)(identifier(), ByteBuffer::wrap(buffer, size));
|
||||
ASSERT(success);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1123,10 +1161,6 @@ KResult ProcFSInode::remove_child(const StringView& name)
|
|||
return KResult(-EPERM);
|
||||
}
|
||||
|
||||
ProcFSInodeCustomData::~ProcFSInodeCustomData()
|
||||
{
|
||||
}
|
||||
|
||||
size_t ProcFSInode::directory_entry_count() const
|
||||
{
|
||||
ASSERT(is_directory());
|
||||
|
@ -1145,7 +1179,6 @@ KResult ProcFSInode::chmod(mode_t)
|
|||
|
||||
ProcFS::ProcFS()
|
||||
{
|
||||
s_the = this;
|
||||
m_root_inode = adopt(*new ProcFSInode(*this, 1));
|
||||
m_entries.resize(FI_MaxStaticFileIndex);
|
||||
m_entries[FI_Root_mm] = { "mm", FI_Root_mm, procfs$mm };
|
||||
|
@ -1176,23 +1209,12 @@ ProcFS::ProcFS()
|
|||
m_entries[FI_PID_exe] = { "exe", FI_PID_exe, procfs$pid_exe };
|
||||
m_entries[FI_PID_cwd] = { "cwd", FI_PID_cwd, procfs$pid_cwd };
|
||||
m_entries[FI_PID_fd] = { "fd", FI_PID_fd };
|
||||
|
||||
m_kmalloc_stack_helper.resource() = g_dump_kmalloc_stacks;
|
||||
add_sys_bool("kmalloc_stacks", m_kmalloc_stack_helper, [this] {
|
||||
g_dump_kmalloc_stacks = m_kmalloc_stack_helper.resource();
|
||||
});
|
||||
}
|
||||
|
||||
ProcFS::ProcFSDirectoryEntry* ProcFS::get_directory_entry(InodeIdentifier identifier) const
|
||||
{
|
||||
if (to_proc_parent_directory(identifier) == PDI_Root_sys) {
|
||||
auto sys_index = to_sys_index(identifier);
|
||||
if (sys_index < m_sys_entries.size())
|
||||
return const_cast<ProcFSDirectoryEntry*>(&m_sys_entries[sys_index]);
|
||||
return nullptr;
|
||||
}
|
||||
auto proc_file_type = to_proc_file_type(identifier);
|
||||
if (proc_file_type != FI_Invalid && proc_file_type < FI_MaxStaticFileIndex)
|
||||
if (proc_file_type != FI_Invalid && proc_file_type != FI_Root_sys_variable && proc_file_type < FI_MaxStaticFileIndex)
|
||||
return const_cast<ProcFSDirectoryEntry*>(&m_entries[proc_file_type]);
|
||||
return nullptr;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue