From 6fb9f18fd64cad9b22a4933bdb1d8c9639b2128c Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 23 May 2024 10:10:24 -0400 Subject: kernel: fs: Add procfs support Signed-off-by: Ian Moffett --- sys/fs/procfs.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++++ sys/fs/procfs_subr.c | 109 +++++++++++++++++++++++++ sys/include/fs/procfs.h | 51 ++++++++++++ sys/kern/vfs_init.c | 5 +- 4 files changed, 370 insertions(+), 1 deletion(-) create mode 100644 sys/fs/procfs.c create mode 100644 sys/fs/procfs_subr.c create mode 100644 sys/include/fs/procfs.h diff --git a/sys/fs/procfs.c b/sys/fs/procfs.c new file mode 100644 index 0000000..3a0e2d3 --- /dev/null +++ b/sys/fs/procfs.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct proc_node { + struct spinlock lock; + struct proc_entry *entry; + char *name; + TAILQ_ENTRY(proc_node) link; +}; + +static TAILQ_HEAD(, proc_node) proc_nodes; +static bool nodelist_init = false; + +static struct proc_node * +name_to_node(const char *name) +{ + struct proc_node *n; + + TAILQ_FOREACH(n, &proc_nodes, link) { + if (strcmp(n->name, name) == 0) { + return n; + } + } + + return NULL; +} + +static int +procfs_make_node(const char *name, struct proc_node **res) +{ + size_t name_len = 0; + const char *p = name; + struct proc_node *n; + + /* Disallow paths */ + for (; *p; ++p, ++name_len) { + if (*p == '/') { + return -EINVAL; + } + } + + if (!vfs_is_valid_path(name)) + return -EINVAL; + + n = dynalloc(sizeof(struct proc_node)); + if (n == NULL) + return -ENOMEM; + + n->name = dynalloc(sizeof(char) * name_len); + if (n->name == NULL) + return -ENOMEM; + + memcpy(n->name, name, name_len + 1); + *res = n; + return 0; +} + +struct proc_entry * +procfs_alloc_entry(void) +{ + struct proc_entry *entry; + + entry = dynalloc(sizeof(*entry)); + if (entry == NULL) + return NULL; + + memset(entry, 0, sizeof(*entry)); + return entry; +} + +int +procfs_add_entry(const char *name, struct proc_entry *entry) +{ + struct proc_node *proc; + int status; + + if (name == NULL || entry == NULL) + return -EINVAL; + if ((status = procfs_make_node(name, &proc)) != 0) + return status; + + proc->entry = entry; + TAILQ_INSERT_HEAD(&proc_nodes, proc, link); + return 0; +} + +static int +procfs_init(struct fs_info *info, struct vnode *source) +{ + if (source != NULL) + return -EINVAL; + + + TAILQ_INIT(&proc_nodes); + nodelist_init = true; + procfs_populate(); + return 0; +} + +static int +procfs_rw_vnode(struct vnode *vp, struct sio_txn *sio, bool write) +{ + struct proc_node *proc; + struct proc_entry *entry; + + if (vp == NULL) + return -EIO; + + proc = vp->data; + entry = proc->entry; + + return write ? entry->write(entry, sio) + : entry->read(entry, sio); +} + +static int +vop_write(struct vnode *vp, struct sio_txn *sio) +{ + return procfs_rw_vnode(vp, sio, true); +} + +static int +vop_read(struct vnode *vp, struct sio_txn *sio) +{ + return procfs_rw_vnode(vp, sio, false); +} + +static int +vop_open(struct vnode *vp) +{ + return 0; +} + +static int +vop_close(struct vnode *vp) +{ + return 0; +} + +static int +vop_vget(struct vnode *parent, const char *name, struct vnode **vp) +{ + struct proc_node *proc; + struct vnode *vnode; + int status; + + if (!nodelist_init) + return -EIO; + if ((proc = name_to_node(name)) == NULL) + return -ENOENT; + if ((status = vfs_alloc_vnode(&vnode, NULL, VREG)) != 0) + return status; + + vnode->parent = parent; + vnode->data = proc; + vnode->vops = &g_procfs_vops; + *vp = vnode; + return 0; +} + +struct vfsops g_procfs_ops = { + .init = procfs_init +}; + +struct vops g_procfs_vops = { + .vget = vop_vget, + .read = vop_read, + .write = vop_write, + .open = vop_open, + .close = vop_close +}; diff --git a/sys/fs/procfs_subr.c b/sys/fs/procfs_subr.c new file mode 100644 index 0000000..e368d56 --- /dev/null +++ b/sys/fs/procfs_subr.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +static bool populated = false; + +static int +procfs_ver_read(struct proc_entry *p, struct sio_txn *sio) +{ + char buf[1024]; + size_t len; + + len = snprintf(buf, sizeof(buf), "Hyra/%s v%s: %s (%s)", + HYRA_ARCH, HYRA_VERSION, + HYRA_BUILDDATE, HYRA_BUILDBRANCH); + + /* Truncate if needed */ + if (len > sio->len) + len = sio->len; + + memcpy(sio->buf, buf, len); + return len; +} + +static int +procfs_memstat_read(struct proc_entry *p, struct sio_txn *sio) +{ + struct vm_memstat stat; + struct physmem_stat *pstat; + char buf[1024]; + size_t len; + + stat = vm_memstat(); + pstat = &stat.pmem_stat; + len = snprintf(buf, sizeof(buf), + "TotalMem: %d KiB\n" + "ReservedMem: %d KiB\n" + "AvailableMem: %d KiB\n" + "AllocatedMem: %d KiB\n" + "VMemObjCount: %d", + pstat->total_kib, + pstat->reserved_kib, + pstat->avl_kib, + pstat->alloc_kib, + stat.vmobj_cnt); + + /* Truncate if needed */ + if (len > sio->len) + len = sio->len; + + memcpy(sio->buf, buf, len); + return len; +} + +/* + * Populate procfs with basic misc entries + */ +void +procfs_populate(void) +{ + struct proc_entry *version; + struct proc_entry *memstat; + + if (populated) + return; + + populated = true; + + /* Kernel version */ + version = procfs_alloc_entry(); + version->read = procfs_ver_read; + procfs_add_entry("version", version); + + /* Memstat */ + memstat = procfs_alloc_entry(); + memstat->read = procfs_memstat_read; + procfs_add_entry("memstat", memstat); +} diff --git a/sys/include/fs/procfs.h b/sys/include/fs/procfs.h new file mode 100644 index 0000000..ed3a19f --- /dev/null +++ b/sys/include/fs/procfs.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROCFS_H_ +#define _PROCFS_H_ + +#include +#include +#include + +struct proc_entry { + int(*read)(struct proc_entry *p, struct sio_txn *sio); + int(*write)(struct proc_entry *p, struct sio_txn *sio); +}; + +extern struct vfsops g_procfs_ops; +extern struct vops g_procfs_vops; + +int procfs_add_entry(const char *name, struct proc_entry *entry); +struct proc_entry *procfs_alloc_entry(void); + +/* procfs_subr.c */ +void procfs_populate(void); + +#endif /* !_PROCFS_H_ */ diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c index fa20af3..6754b1f 100644 --- a/sys/kern/vfs_init.c +++ b/sys/kern/vfs_init.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -43,10 +44,12 @@ __KERNEL_META("$Hyra$: vfs.c, Ian Marco Moffett, " #define INITRAMFS_ID 0 #define DEVFS_ID 1 +#define PROCFS_ID 2 static struct fs_info filesystems[] = { [INITRAMFS_ID] = { "initramfs", &g_initramfs_ops, NULL}, - [DEVFS_ID] = { "dev", &g_devfs_ops, &g_devfs_vops } + [DEVFS_ID] = { "dev", &g_devfs_ops, &g_devfs_vops }, + [PROCFS_ID] = { "proc", &g_procfs_ops, &g_procfs_vops } }; struct vnode *g_root_vnode = NULL; -- cgit v1.2.3