From f79fc989674536f9fe3112715fcdd8ac2acbd5c8 Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 12 Jul 2020 17:10:51 +0300 Subject: [PATCH] Add procfs --- fs/node.c | 1 + fs/sysfs.c | 56 ++++++++++++------------- include/fs/sysfs.h | 2 + include/sys/thread.h | 6 ++- sys/execve.c | 6 +++ sys/thread.c | 97 ++++++++++++++++++++++++++++++++++++++++---- sys/wait.c | 16 +++++--- 7 files changed, 141 insertions(+), 43 deletions(-) diff --git a/fs/node.c b/fs/node.c index f42b143..d606987 100644 --- a/fs/node.c +++ b/fs/node.c @@ -30,6 +30,7 @@ struct vnode *vnode_create(enum vnode_type t, const char *name) { void vnode_destroy(struct vnode *vn) { _assert(vnode_cache); + _assert(!vn->open_count); slab_free(vnode_cache, vn); } diff --git a/fs/sysfs.c b/fs/sysfs.c index 506c723..c212b50 100644 --- a/fs/sysfs.c +++ b/fs/sysfs.c @@ -146,7 +146,6 @@ static int sysfs_vnode_stat(struct vnode *node, struct stat *st) { //// - int sysfs_config_getter(void *ctx, char *buf, size_t lim) { sysfs_buf_puts(buf, lim, ctx); sysfs_buf_puts(buf, lim, "\n"); @@ -159,6 +158,33 @@ int sysfs_config_int64_getter(void *ctx, char *buf, size_t lim) { return 0; } +int sysfs_del_ent(struct vnode *ent) { + _assert(ent); + _assert(ent->parent); + vnode_detach(ent); + + switch (ent->type) { + case VN_LNK: + break; + case VN_REG: + _assert(ent->op == &g_sysfs_vnode_ops); + _assert(ent->fs_data); + kfree(ent->fs_data); + break; + case VN_DIR: + while (ent->first_child) { + sysfs_del_ent(ent->first_child); + } + break; + default: + panic("Unsupported sysfs node type\n"); + break; + } + + vnode_destroy(ent); + return 0; +} + int sysfs_add_dir(struct vnode *at, const char *name, struct vnode **res) { struct vnode *tmp; sysfs_ensure_root(); @@ -172,7 +198,7 @@ int sysfs_add_dir(struct vnode *at, const char *name, struct vnode **res) { kdebug("Can't find %s in %s, creating\n", name, at->name); tmp = vnode_create(VN_DIR, name); tmp->flags |= VN_MEMORY; - tmp->op = &g_sysfs_vnode_ops; + //tmp->op = &g_sysfs_vnode_ops; tmp->mode = S_IXUSR | S_IXGRP | S_IXOTH | S_IRUSR | S_IRGRP | S_IROTH; @@ -218,28 +244,6 @@ int sysfs_add_config_endpoint(struct vnode *at, const char *name, mode_t mode, s return 0; } -// TODO: move this to an appropriate place -#define PROC_PROP_PID 1 -#define PROC_PROP_NAME 2 - -static int proc_property_getter(void *ctx, char *buf, size_t lim) { - uint64_t prop = (uint64_t) ctx; - struct process *proc = thread_self->proc; - _assert(proc); - - switch (prop) { - case PROC_PROP_PID: - sysfs_buf_printf(buf, lim, "%d\n", (int) proc->pid); - break; - case PROC_PROP_NAME: - sysfs_buf_puts(buf, lim, proc->name); - sysfs_buf_puts(buf, lim, "\n"); - break; - } - - return 0; -} - static int system_uptime_getter(void *ctx, char *buf, size_t lim) { char *p = buf; uint64_t t = system_time / 1000000000ULL; @@ -295,10 +299,6 @@ void sysfs_populate(void) { sysfs_add_config_endpoint(dir, "uptime", SYSFS_MODE_DEFAULT, 32, NULL, system_uptime_getter, NULL); sysfs_add_config_endpoint(dir, "modules", SYSFS_MODE_DEFAULT, 512, NULL, mod_list, NULL); - sysfs_add_dir(NULL, "self", &dir); - sysfs_add_config_endpoint(dir, "pid", SYSFS_MODE_DEFAULT, 16, (void *) PROC_PROP_PID, proc_property_getter, NULL); - sysfs_add_config_endpoint(dir, "name", SYSFS_MODE_DEFAULT, 128, (void *) PROC_PROP_NAME, proc_property_getter, NULL); - sysfs_add_config_endpoint(NULL, "mem", SYSFS_MODE_DEFAULT, 512, NULL, system_mem_getter, NULL); } diff --git a/include/fs/sysfs.h b/include/fs/sysfs.h index bf007e0..398b885 100644 --- a/include/fs/sysfs.h +++ b/include/fs/sysfs.h @@ -36,6 +36,8 @@ int sysfs_config_getter(void *ctx, char *buf, size_t lim); // ctx: a pointer to an (u)int64_t value int sysfs_config_int64_getter(void *ctx, char *buf, size_t lim); +int sysfs_del_ent(struct vnode *dir); + int sysfs_add_dir(struct vnode *at, const char *path, struct vnode **result); int sysfs_add_config_endpoint(struct vnode *at, const char *name, mode_t mode, size_t bufsz, void *ctx, cfg_read_func_t read, cfg_write_func_t write); void sysfs_populate(void); diff --git a/include/sys/thread.h b/include/sys/thread.h index 9b137a0..854c3b0 100644 --- a/include/sys/thread.h +++ b/include/sys/thread.h @@ -87,6 +87,9 @@ struct process { // Signal uint64_t sigq; + // procfs + struct vnode *fs_entry; + // State char name[256]; uint32_t flags; @@ -113,7 +116,8 @@ struct thread *process_first_thread(struct process *proc); #define THR_INIT_STACK_SET (1 << 1) int thread_init(struct thread *thr, uintptr_t entry, void *arg, int flags); void thread_dump(struct thread *thr); -//void thread_cleanup(struct thread *thr); + +void proc_add_entry(struct process *proc); struct process *process_child(struct process *of, pid_t pid); void process_unchild(struct process *proc); diff --git a/sys/execve.c b/sys/execve.c index c717d4c..592eb27 100644 --- a/sys/execve.c +++ b/sys/execve.c @@ -131,6 +131,7 @@ int sys_execve(const char *path, const char **argv, const char **envp) { uintptr_t entry; size_t argc; int res; + int was_kernel = 0; if ((res = vfs_stat(&proc->ioctx, path, &st)) != 0) { kerror("execve(%s): %s\n", path, kstrerror(res)); @@ -205,6 +206,7 @@ int sys_execve(const char *path, const char **argv, const char **envp) { } if (proc->space == mm_kernel) { + was_kernel = 1; // Have to allocate a new PID for kernel -> userspace transition proc->pid = process_alloc_pid(1); //thread_alloc_pid(1); proc->pgid = proc->pid; @@ -281,6 +283,10 @@ int sys_execve(const char *path, const char **argv, const char **envp) { thr->data.rsp3_base = ustack; thr->data.rsp3_size = 4 * MM_PAGE_SIZE; + if (was_kernel) { + proc_add_entry(proc); + } + // Up to 4095 argc and envc _assert(procv_vecp[0] < 4096); _assert(procv_vecp[2] < 4096); diff --git a/sys/thread.c b/sys/thread.c index 6402074..b732a9e 100644 --- a/sys/thread.c +++ b/sys/thread.c @@ -5,6 +5,7 @@ #include "sys/binfmt_elf.h" #include "sys/sys_proc.h" #include "sys/mem/phys.h" +#include "sys/snprintf.h" #include "user/signum.h" #include "user/errno.h" #include "user/fcntl.h" @@ -13,6 +14,7 @@ #include "sys/thread.h" #include "sys/sched.h" #include "sys/debug.h" +#include "fs/sysfs.h" #include "fs/ofile.h" #include "sys/heap.h" @@ -37,6 +39,60 @@ static pid_t last_kernel_pid = 0; static pid_t last_user_pid = 0; // TODO: MAKE THIS PER-PROCESSOR static uint64_t fxsave_buf[FXSAVE_REGION / 8] __attribute__((aligned(16))); +static struct vnode *g_sysfs_proc_dir; + +static int sysfs_proc_name(void *ctx, char *buf, size_t lim) { + sysfs_buf_printf(buf, lim, "%s\n", ((struct process *) ctx)->name); + return 0; +} + +static int sysfs_proc_ioctx(void *ctx, char *buf, size_t lim) { + struct process *proc = ctx; + sysfs_buf_printf(buf, lim, "%d:%d\n", proc->ioctx.uid, proc->ioctx.gid); + return 0; +} + +static struct vnode *sysfs_proc_self(struct thread *ctx, struct vnode *link) { + _assert(ctx && ctx->proc); + return ctx->proc->fs_entry; +} + +static void proc_ensure_dir(void) { + if (!g_sysfs_proc_dir) { + _assert(sysfs_add_dir(NULL, "proc", &g_sysfs_proc_dir) == 0); + + struct vnode *vn = vnode_create(VN_LNK, "self"); + vn->flags = VN_MEMORY | VN_PER_PROCESS; + vn->target_func = sysfs_proc_self; + vnode_attach(g_sysfs_proc_dir, vn); + } +} + +void proc_add_entry(struct process *proc) { + char name[16]; + _assert(proc && !(proc->flags & THREAD_KERNEL)); + _assert(proc->pid > 0); + + proc_ensure_dir(); + + kdebug("BEGIN ADD ENTRY %d\n", proc->pid); + snprintf(name, sizeof(name), "%d", proc->pid); + _assert(sysfs_add_dir(g_sysfs_proc_dir, name, &proc->fs_entry) == 0); + + _assert(sysfs_add_config_endpoint(proc->fs_entry, "name", SYSFS_MODE_DEFAULT, 64, + proc, sysfs_proc_name, NULL) == 0); + _assert(sysfs_add_config_endpoint(proc->fs_entry, "ioctx", SYSFS_MODE_DEFAULT, 64, + proc, sysfs_proc_ioctx, NULL) == 0); + kdebug("END ADD ENTRY %d\n", proc->pid); +} + +void proc_del_entry(struct process *proc) { + _assert(proc && !(proc->flags & THREAD_KERNEL)); + _assert(proc->pid > 0); + kdebug("BEGIN DEL ENTRY %d\n", proc->pid); + sysfs_del_ent(proc->fs_entry); + kdebug("END DEL ENTRY %d\n", proc->pid); +} void context_save_fpu(struct thread *new, struct thread *old) { _assert(old); @@ -45,7 +101,6 @@ void context_save_fpu(struct thread *new, struct thread *old) { memcpy(old->data.fxsave, fxsave_buf, FXSAVE_REGION); old->flags |= THREAD_FPU_SAVED; } - } void context_restore_fpu(struct thread *new, struct thread *old) { @@ -86,8 +141,6 @@ void process_ioctx_fork(struct process *dst, struct process *src) { } } - - int process_signal_pgid(pid_t pgid, int signum) { int ret = 0; @@ -99,7 +152,18 @@ int process_signal_pgid(pid_t pgid, int signum) { } } - return ret == 0 ? -1 : ret; + return ret == 0 ? -ECHILD : ret; +} + +int process_signal_children(struct process *proc, int signum) { + int ret = 0; + for (struct process *chld = proc->first_child; chld; chld = chld->next_child) { + if (proc->proc_state != PROC_FINISHED) { + process_signal(chld, signum); + ++ret; + } + } + return ret == 0 ? -ECHILD : 0; } struct process *process_find(pid_t pid) { @@ -156,6 +220,8 @@ void process_unchild(struct process *proc) { void process_cleanup(struct process *proc) { // Leave only the system context required for hierachy tracking and error code/pid + proc_del_entry(proc); + _assert(proc->proc_state == PROC_FINISHED); _assert(proc->thread_count == 1); proc->flags |= PROC_EMPTY; @@ -176,6 +242,13 @@ void process_free(struct process *proc) { // only main remains _assert(proc->thread_count == 1); + // Reparent children to #1 if any + for (struct process *chld = proc->first_child; chld; chld = chld->next_child) { + panic("Not implemented: #%d (%s) has children: #%d (%s)\n", + proc->pid, proc->name, + chld->pid, chld->name); + } + // Sure that no code of this thread will be running anymore - // can clean up its stuff process_cleanup(proc); @@ -248,6 +321,9 @@ int process_init_thread(struct process *proc, uintptr_t entry, void *arg, int us proc->proc_state = PROC_ACTIVE; list_add(&proc->g_link, &proc_all_head); + if (user) { + proc_add_entry(proc); + } return 0; } @@ -441,6 +517,10 @@ int sys_fork(struct sys_fork_frame *frame) { struct process *src = src_thread->proc; _assert(src); + if (src->flags & THREAD_KERNEL) { + panic("XXX: kthread fork()ing not implemented\n"); + } + if (src->thread_count != 1) { panic("XXX: fork() a multithreaded process\n"); } @@ -567,6 +647,7 @@ int sys_fork(struct sys_fork_frame *frame) { dst_thread->data.rsp0 = (uintptr_t) stack; list_add(&dst->g_link, &proc_all_head); + proc_add_entry(dst); sched_queue(dst_thread); return dst->pid; @@ -739,10 +820,10 @@ int sys_kill(pid_t pid, int signum) { } else if (pid == 0) { proc = thread_self->proc; } else if (pid < -1) { - // TODO: check if there's any process in that group - process_signal_pgid(-pid, signum); - - return 0; + return process_signal_pgid(-pid, signum); + } else if (pid == -1) { + proc = thread_self->proc; + return process_signal_children(proc, signum); } else { panic("Not implemented\n"); } diff --git a/sys/wait.c b/sys/wait.c index 3f50466..2657dc4 100644 --- a/sys/wait.c +++ b/sys/wait.c @@ -144,7 +144,7 @@ static int wait_check_pid(struct process *chld, int flags) { static int wait_check_pgrp(struct process *proc_self, pid_t pgrp, int flags, struct process **chld) { for (struct process *_chld = proc_self->first_child; _chld; _chld = _chld->next_child) { - if (_chld->pgid == pgrp) { + if (pgrp == -1 || _chld->pgid == -pgrp) { if (wait_check_pid(_chld, flags) == 0) { *chld = _chld; return 0; @@ -155,6 +155,7 @@ static int wait_check_pgrp(struct process *proc_self, pid_t pgrp, int flags, str } int sys_waitpid(pid_t pid, int *status, int flags) { + pid_t result_pid = -ECHILD; struct thread *thr = thread_self; _assert(thr); struct process *proc_self = thr->proc; @@ -180,7 +181,7 @@ int sys_waitpid(pid_t pid, int *status, int flags) { if (!any_proc) { return -ECHILD; } - } else { + } else if (pid != -1) { panic("Not implemented: waitpid(%d, ...)\n", pid); } @@ -191,16 +192,16 @@ int sys_waitpid(pid_t pid, int *status, int flags) { } res = thread_wait_io(thr, &chld->pid_notify); - } else if (pid < -1) { + } else if (pid <= -1) { // Check if anybody in pgrp has changed status - if (wait_check_pgrp(proc_self, -pid, flags, &chld) == 0) { + if (wait_check_pgrp(proc_self, pid, flags, &chld) == 0) { _assert(chld); break; } // Build wait list for (struct process *_chld = proc_self->first_child; _chld; _chld = _chld->next_child) { - if (_chld->pgid == -pid) { + if (pid == -1 || _chld->pgid == -pid) { thread_wait_io_add(thr, &_chld->pid_notify); } } @@ -209,6 +210,8 @@ int sys_waitpid(pid_t pid, int *status, int flags) { res = thread_wait_io_any(thr, ¬ify); thread_wait_io_clear(thr); + } else { + panic("Shouldn't run\n"); } if (res < 0) { @@ -217,6 +220,7 @@ int sys_waitpid(pid_t pid, int *status, int flags) { } } + result_pid = chld->pid; if (chld->proc_state == PROC_FINISHED) { if (status) { *status = chld->exit_status; @@ -234,5 +238,5 @@ int sys_waitpid(pid_t pid, int *status, int flags) { } } - return 0; + return result_pid; }