1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-03 05:32:13 +00:00

Kernel: Remove ProcessInspectionHandle and make Process RefCounted

By making the Process class RefCounted we don't really need
ProcessInspectionHandle anymore. This also fixes some race
conditions where a Process may be deleted while still being
used by ProcFS.

Also make sure to acquire the Process' lock when accessing
regions.

Last but not least, there's no reason why a thread can't be
scheduled while being inspected, though in practice it won't
happen anyway because the scheduler lock is held at the same
time.
This commit is contained in:
Tom 2020-08-01 20:04:56 -06:00 committed by Andreas Kling
parent 5bbf6ed46b
commit 538b985487
13 changed files with 191 additions and 273 deletions

View file

@ -241,22 +241,21 @@ Optional<KBuffer> procfs$pid_fds(InodeIdentifier identifier)
KBufferBuilder builder;
JsonArraySerializer array { builder };
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle) {
auto process = Process::from_pid(to_pid(identifier));
if (!process) {
array.finish();
return builder.build();
}
auto& process = handle->process();
if (process.number_of_open_file_descriptors() == 0) {
if (process->number_of_open_file_descriptors() == 0) {
array.finish();
return builder.build();
}
for (int i = 0; i < process.max_open_file_descriptors(); ++i) {
auto description = process.file_description(i);
for (int i = 0; i < process->max_open_file_descriptors(); ++i) {
auto description = process->file_description(i);
if (!description)
continue;
bool cloexec = process.fd_flags(i) & FD_CLOEXEC;
bool cloexec = process->fd_flags(i) & FD_CLOEXEC;
auto description_object = array.add_object();
description_object.add("fd", i);
@ -275,12 +274,11 @@ Optional<KBuffer> procfs$pid_fds(InodeIdentifier identifier)
Optional<KBuffer> procfs$pid_fd_entry(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
auto process = Process::from_pid(to_pid(identifier));
if (!process)
return {};
auto& process = handle->process();
int fd = to_fd(identifier);
auto description = process.file_description(fd);
auto description = process->file_description(fd);
if (!description)
return {};
return description->absolute_path().to_byte_buffer();
@ -288,46 +286,48 @@ Optional<KBuffer> procfs$pid_fd_entry(InodeIdentifier identifier)
Optional<KBuffer> procfs$pid_vm(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
auto process = Process::from_pid(to_pid(identifier));
if (!process)
return {};
auto& process = handle->process();
KBufferBuilder builder;
JsonArraySerializer array { builder };
for (auto& region : process.regions()) {
if (!region.is_user_accessible() && !Process::current()->is_superuser())
continue;
auto region_object = array.add_object();
region_object.add("readable", region.is_readable());
region_object.add("writable", region.is_writable());
region_object.add("executable", region.is_executable());
region_object.add("stack", region.is_stack());
region_object.add("shared", region.is_shared());
region_object.add("user_accessible", region.is_user_accessible());
region_object.add("purgeable", region.vmobject().is_purgeable());
if (region.vmobject().is_purgeable()) {
region_object.add("volatile", static_cast<const PurgeableVMObject&>(region.vmobject()).is_volatile());
{
ScopedSpinLock lock(process->get_lock());
for (auto& region : process->regions()) {
if (!region.is_user_accessible() && !Process::current()->is_superuser())
continue;
auto region_object = array.add_object();
region_object.add("readable", region.is_readable());
region_object.add("writable", region.is_writable());
region_object.add("executable", region.is_executable());
region_object.add("stack", region.is_stack());
region_object.add("shared", region.is_shared());
region_object.add("user_accessible", region.is_user_accessible());
region_object.add("purgeable", region.vmobject().is_purgeable());
if (region.vmobject().is_purgeable()) {
region_object.add("volatile", static_cast<const PurgeableVMObject&>(region.vmobject()).is_volatile());
}
region_object.add("purgeable", region.vmobject().is_purgeable());
region_object.add("address", region.vaddr().get());
region_object.add("size", region.size());
region_object.add("amount_resident", region.amount_resident());
region_object.add("amount_dirty", region.amount_dirty());
region_object.add("cow_pages", region.cow_pages());
region_object.add("name", region.name());
region_object.add("vmobject", region.vmobject().class_name());
StringBuilder pagemap_builder;
for (size_t i = 0; i < region.page_count(); ++i) {
auto* page = region.physical_page(i);
if (!page)
pagemap_builder.append('N');
else if (page->is_shared_zero_page())
pagemap_builder.append('Z');
else
pagemap_builder.append('P');
}
region_object.add("pagemap", pagemap_builder.to_string());
}
region_object.add("purgeable", region.vmobject().is_purgeable());
region_object.add("address", region.vaddr().get());
region_object.add("size", region.size());
region_object.add("amount_resident", region.amount_resident());
region_object.add("amount_dirty", region.amount_dirty());
region_object.add("cow_pages", region.cow_pages());
region_object.add("name", region.name());
region_object.add("vmobject", region.vmobject().class_name());
StringBuilder pagemap_builder;
for (size_t i = 0; i < region.page_count(); ++i) {
auto* page = region.physical_page(i);
if (!page)
pagemap_builder.append('N');
else if (page->is_shared_zero_page())
pagemap_builder.append('Z');
else
pagemap_builder.append('P');
}
region_object.add("pagemap", pagemap_builder.to_string());
}
array.finish();
return builder.build();
@ -557,46 +557,47 @@ Optional<KBuffer> procfs$net_local(InodeIdentifier)
Optional<KBuffer> procfs$pid_vmobjects(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
auto process = Process::from_pid(to_pid(identifier));
if (!process)
return {};
auto& process = handle->process();
KBufferBuilder builder;
builder.appendf("BEGIN END SIZE NAME\n");
for (auto& region : process.regions()) {
builder.appendf("%x -- %x %x %s\n",
region.vaddr().get(),
region.vaddr().offset(region.size() - 1).get(),
region.size(),
region.name().characters());
builder.appendf("VMO: %s @ %x(%u)\n",
region.vmobject().is_anonymous() ? "anonymous" : "file-backed",
&region.vmobject(),
region.vmobject().ref_count());
for (size_t i = 0; i < region.vmobject().page_count(); ++i) {
auto& physical_page = region.vmobject().physical_pages()[i];
bool should_cow = false;
if (i >= region.first_page_index() && i <= region.last_page_index())
should_cow = region.should_cow(i - region.first_page_index());
builder.appendf("P%x%s(%u) ",
physical_page ? physical_page->paddr().get() : 0,
should_cow ? "!" : "",
physical_page ? physical_page->ref_count() : 0);
{
ScopedSpinLock lock(process->get_lock());
for (auto& region : process->regions()) {
builder.appendf("%x -- %x %x %s\n",
region.vaddr().get(),
region.vaddr().offset(region.size() - 1).get(),
region.size(),
region.name().characters());
builder.appendf("VMO: %s @ %x(%u)\n",
region.vmobject().is_anonymous() ? "anonymous" : "file-backed",
&region.vmobject(),
region.vmobject().ref_count());
for (size_t i = 0; i < region.vmobject().page_count(); ++i) {
auto& physical_page = region.vmobject().physical_pages()[i];
bool should_cow = false;
if (i >= region.first_page_index() && i <= region.last_page_index())
should_cow = region.should_cow(i - region.first_page_index());
builder.appendf("P%x%s(%u) ",
physical_page ? physical_page->paddr().get() : 0,
should_cow ? "!" : "",
physical_page ? physical_page->ref_count() : 0);
}
builder.appendf("\n");
}
builder.appendf("\n");
}
return builder.build();
}
Optional<KBuffer> procfs$pid_unveil(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
auto process = Process::from_pid(to_pid(identifier));
if (!process)
return {};
auto& process = handle->process();
KBufferBuilder builder;
JsonArraySerializer array { builder };
for (auto& unveiled_path : process.unveiled_paths()) {
for (auto& unveiled_path : process->unveiled_paths()) {
auto obj = array.add_object();
obj.add("path", unveiled_path.path);
StringBuilder permissions_builder;
@ -616,38 +617,36 @@ Optional<KBuffer> procfs$pid_unveil(InodeIdentifier identifier)
Optional<KBuffer> procfs$pid_stack(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
auto process = Process::from_pid(to_pid(identifier));
if (!process)
return {};
auto& process = handle->process();
return process.backtrace(*handle);
return process->backtrace();
}
Optional<KBuffer> procfs$pid_exe(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
auto process = Process::from_pid(to_pid(identifier));
if (!process)
return {};
auto& process = handle->process();
auto* custody = process.executable();
auto* custody = process->executable();
ASSERT(custody);
return custody->absolute_path().to_byte_buffer();
}
Optional<KBuffer> procfs$pid_cwd(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
auto process = Process::from_pid(to_pid(identifier));
if (!process)
return {};
return handle->process().current_directory().absolute_path().to_byte_buffer();
return process->current_directory().absolute_path().to_byte_buffer();
}
Optional<KBuffer> procfs$pid_root(InodeIdentifier identifier)
{
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
if (!handle)
auto process = Process::from_pid(to_pid(identifier));
if (!process)
return {};
return handle->process().root_directory_relative_to_global_root().absolute_path().to_byte_buffer();
return process->root_directory_relative_to_global_root().absolute_path().to_byte_buffer();
}
Optional<KBuffer> procfs$self(InodeIdentifier)
@ -783,8 +782,6 @@ Optional<KBuffer> procfs$memstat(InodeIdentifier)
Optional<KBuffer> procfs$all(InodeIdentifier)
{
ScopedSpinLock lock(g_scheduler_lock);
auto processes = Process::all_processes();
KBufferBuilder builder;
JsonArraySerializer array { builder };
@ -856,9 +853,12 @@ Optional<KBuffer> procfs$all(InodeIdentifier)
return IterationDecision::Continue;
});
};
ScopedSpinLock lock(g_scheduler_lock);
auto processes = Process::all_processes();
build_process(*Scheduler::colonel());
for (auto* process : processes)
build_process(*process);
for (auto& process : processes)
build_process(process);
array.finish();
return builder.build();
}
@ -1069,9 +1069,15 @@ InodeMetadata ProcFSInode::metadata() const
#endif
if (is_process_related_file(identifier())) {
auto handle = ProcessInspectionHandle::from_pid(pid);
metadata.uid = handle->process().sys$getuid();
metadata.gid = handle->process().sys$getgid();
auto process = Process::from_pid(pid);
if (process) {
metadata.uid = process->sys$getuid();
metadata.gid = process->sys$getgid();
} else {
// TODO: How to handle this?
metadata.uid = 0;
metadata.gid = 0;
}
}
if (proc_parent_directory == PDI_PID_fd) {
@ -1232,13 +1238,12 @@ KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
break;
case FI_PID: {
auto handle = ProcessInspectionHandle::from_pid(pid);
if (!handle)
auto process = Process::from_pid(pid);
if (!process)
return KResult(-ENOENT);
auto& process = handle->process();
for (auto& entry : fs().m_entries) {
if (entry.proc_file_type > __FI_PID_Start && entry.proc_file_type < __FI_PID_End) {
if (entry.proc_file_type == FI_PID_exe && !process.executable())
if (entry.proc_file_type == FI_PID_exe && !process->executable())
continue;
// FIXME: strlen() here is sad.
callback({ entry.name, strlen(entry.name), to_identifier(fsid(), PDI_PID, pid, (ProcFileType)entry.proc_file_type), 0 });
@ -1247,12 +1252,11 @@ KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
} break;
case FI_PID_fd: {
auto handle = ProcessInspectionHandle::from_pid(pid);
if (!handle)
auto process = Process::from_pid(pid);
if (!process)
return KResult(-ENOENT);
auto& process = handle->process();
for (int i = 0; i < process.max_open_file_descriptors(); ++i) {
auto description = process.file_description(i);
for (int i = 0; i < process->max_open_file_descriptors(); ++i) {
auto description = process->file_description(i);
if (!description)
continue;
char name[16];
@ -1324,13 +1328,12 @@ RefPtr<Inode> ProcFSInode::lookup(StringView name)
}
if (proc_file_type == FI_PID) {
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier()));
if (!handle)
auto process = Process::from_pid(to_pid(identifier()));
if (!process)
return {};
auto& process = handle->process();
for (auto& entry : fs().m_entries) {
if (entry.proc_file_type > __FI_PID_Start && entry.proc_file_type < __FI_PID_End) {
if (entry.proc_file_type == FI_PID_exe && !process.executable())
if (entry.proc_file_type == FI_PID_exe && !process->executable())
continue;
if (entry.name == nullptr)
continue;
@ -1348,8 +1351,7 @@ RefPtr<Inode> ProcFSInode::lookup(StringView name)
return {};
bool fd_exists = false;
{
InterruptDisabler disabler;
if (auto* process = Process::from_pid(to_pid(identifier())))
if (auto process = Process::from_pid(to_pid(identifier())))
fd_exists = process->file_description(name_as_number.value());
}
if (fd_exists)
@ -1415,16 +1417,15 @@ KResultOr<NonnullRefPtr<Custody>> ProcFSInode::resolve_as_link(Custody& base, Re
auto pid = to_pid(identifier());
auto proc_file_type = to_proc_file_type(identifier());
auto handle = ProcessInspectionHandle::from_pid(pid);
if (!handle)
auto process = Process::from_pid(pid);
if (!process)
return KResult(-ENOENT);
auto& process = handle->process();
if (to_proc_parent_directory(identifier()) == PDI_PID_fd) {
if (out_parent)
*out_parent = base;
int fd = to_fd(identifier());
auto description = process.file_description(fd);
auto description = process->file_description(fd);
if (!description)
return KResult(-ENOENT);
auto proxy_inode = ProcFSProxyInode::create(const_cast<ProcFS&>(fs()), *description);
@ -1435,16 +1436,16 @@ KResultOr<NonnullRefPtr<Custody>> ProcFSInode::resolve_as_link(Custody& base, Re
switch (proc_file_type) {
case FI_PID_cwd:
res = &process.current_directory();
res = &process->current_directory();
break;
case FI_PID_exe:
res = process.executable();
res = process->executable();
break;
case FI_PID_root:
// Note: we open root_directory() here, not
// root_directory_relative_to_global_root().
// This seems more useful.
res = &process.root_directory();
res = &process->root_directory();
break;
default:
ASSERT_NOT_REACHED();