From 96e23fa3c6eabf8a6efebac24b740c5d4a2a1050 Mon Sep 17 00:00:00 2001 From: Minep Date: Sun, 21 Aug 2022 16:03:15 +0100 Subject: [PATCH] feat: (devfs) a new filesystem for device exposure. chore: fixes and refactorings. --- lunaix-os/includes/lunaix/device.h | 25 ++++- lunaix-os/includes/lunaix/ds/llist.h | 6 ++ lunaix-os/includes/lunaix/fs/devfs.h | 7 ++ lunaix-os/kernel/device.c | 110 -------------------- lunaix-os/kernel/device/devfs.c | 147 +++++++++++++++++++++++++++ lunaix-os/kernel/device/device.c | 127 +++++++++++++++++++++++ lunaix-os/kernel/fs/fs_setup.c | 5 +- lunaix-os/kernel/fs/mount.c | 2 +- lunaix-os/kernel/fs/vfs.c | 1 + lunaix-os/kernel/k_init.c | 10 +- lunaix-os/kernel/proc0.c | 5 +- 11 files changed, 320 insertions(+), 125 deletions(-) create mode 100644 lunaix-os/includes/lunaix/fs/devfs.h delete mode 100644 lunaix-os/kernel/device.c create mode 100644 lunaix-os/kernel/device/devfs.c create mode 100644 lunaix-os/kernel/device/device.c diff --git a/lunaix-os/includes/lunaix/device.h b/lunaix-os/includes/lunaix/device.h index 414809a..c0ed989 100644 --- a/lunaix-os/includes/lunaix/device.h +++ b/lunaix-os/includes/lunaix/device.h @@ -6,31 +6,46 @@ #include #include +#define DEV_MSKIF 0x00000003 + +#define DEV_IFVOL 0x0 // volumetric (block) device +#define DEV_IFSEQ 0x1 // sequential (character) device +#define DEV_IFCAT 0x2 // a device category (as device groupping) + typedef unsigned int dev_t; struct device { - struct llist_header dev_list; + struct llist_header siblings; struct device* parent; struct hstr name; dev_t dev_id; + int dev_type; char name_val[DEVICE_NAME_SIZE]; void* underlay; - void* fs_node; int (*read)(struct device* dev, void* buf, size_t offset, size_t len); int (*write)(struct device* dev, void* buf, size_t offset, size_t len); }; -void -device_init(); - struct device* device_addseq(struct device* parent, void* underlay, char* name_fmt, ...); struct device* device_addvol(struct device* parent, void* underlay, char* name_fmt, ...); +struct device* +device_addcat(struct device* parent, char* name_fmt, ...); + void device_remove(struct device* dev); +struct device* +device_getbyid(struct llist_header* devlist, dev_t id); + +struct device* +device_getbyname(struct llist_header* devlist, struct hstr* name); + +struct device* +device_getbyoffset(struct llist_header* devlist, int pos); + #endif /* __LUNAIX_DEVICE_H */ diff --git a/lunaix-os/includes/lunaix/ds/llist.h b/lunaix-os/includes/lunaix/ds/llist.h index 22e0f93..a4797c3 100644 --- a/lunaix-os/includes/lunaix/ds/llist.h +++ b/lunaix-os/includes/lunaix/ds/llist.h @@ -67,6 +67,12 @@ llist_empty(struct llist_header* elem) return elem->next == elem && elem->prev == elem; } +#define DEFINE_LLIST(name) \ + struct llist_header name = (struct llist_header) \ + { \ + .prev = &name, .next = &name \ + } + /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. diff --git a/lunaix-os/includes/lunaix/fs/devfs.h b/lunaix-os/includes/lunaix/fs/devfs.h new file mode 100644 index 0000000..324706c --- /dev/null +++ b/lunaix-os/includes/lunaix/fs/devfs.h @@ -0,0 +1,7 @@ +#ifndef __LUNAIX_DEVFS_H +#define __LUNAIX_DEVFS_H + +void +devfs_init(); + +#endif /* __LUNAIX_DEVFS_H */ diff --git a/lunaix-os/kernel/device.c b/lunaix-os/kernel/device.c deleted file mode 100644 index 017f3b3..0000000 --- a/lunaix-os/kernel/device.c +++ /dev/null @@ -1,110 +0,0 @@ -#include -#include -#include -#include - -struct llist_header dev_list; - -static struct twifs_node* dev_root; - -int -__dev_read(struct v_inode* inode, void* buffer, size_t len, size_t fpos); - -int -__dev_write(struct v_inode* inode, void* buffer, size_t len, size_t fpos); - -void -device_init() -{ - dev_root = twifs_toplevel_node("dev", 3, 0); - - llist_init_head(&dev_list); -} - -struct device* -__device_add(struct device* parent, - void* underlay, - char* name_fmt, - uint32_t type, - va_list args) -{ - struct device* dev = vzalloc(sizeof(struct device)); - - size_t strlen = - __sprintf_internal(dev->name_val, name_fmt, DEVICE_NAME_SIZE, args); - - dev->name = HSTR(dev->name_val, strlen); - dev->parent = parent; - dev->underlay = underlay; - - hstr_rehash(&dev->name, HSTR_FULL_HASH); - llist_append(&dev_list, &dev->dev_list); - - struct twifs_node* dev_node = - twifs_file_node(dev_root, dev->name_val, strlen, type); - dev_node->data = dev; - dev_node->ops.read = __dev_read; - dev_node->ops.write = __dev_write; - - dev->fs_node = dev_node; - - return dev; -} - -struct device* -device_addseq(struct device* parent, void* underlay, char* name_fmt, ...) -{ - va_list args; - va_start(args, name_fmt); - - struct device* dev = - __device_add(parent, underlay, name_fmt, VFS_IFSEQDEV, args); - - va_end(args); - return dev; -} - -struct device* -device_addvol(struct device* parent, void* underlay, char* name_fmt, ...) -{ - va_list args; - va_start(args, name_fmt); - - struct device* dev = - __device_add(parent, underlay, name_fmt, VFS_IFVOLDEV, args); - - va_end(args); - return dev; -} - -int -__dev_read(struct v_inode* inode, void* buffer, size_t len, size_t fpos) -{ - struct twifs_node* dev_node = (struct twifs_node*)inode->data; - struct device* dev = (struct device*)dev_node->data; - - if (!dev->read) { - return ENOTSUP; - } - return dev->read(dev, buffer, fpos, len); -} - -int -__dev_write(struct v_inode* inode, void* buffer, size_t len, size_t fpos) -{ - struct twifs_node* dev_node = (struct twifs_node*)inode->data; - struct device* dev = (struct device*)dev_node->data; - - if (!dev->write) { - return ENOTSUP; - } - return dev->write(dev, buffer, fpos, len); -} - -void -device_remove(struct device* dev) -{ - llist_delete(&dev->dev_list); - twifs_rm_node((struct twifs_node*)dev->fs_node); - vfree(dev); -} \ No newline at end of file diff --git a/lunaix-os/kernel/device/devfs.c b/lunaix-os/kernel/device/devfs.c new file mode 100644 index 0000000..73abac7 --- /dev/null +++ b/lunaix-os/kernel/device/devfs.c @@ -0,0 +1,147 @@ +#include +#include +#include +#include + +extern struct v_inode_ops devfs_inode_ops; +extern struct v_file_ops devfs_file_ops; + +int +devfs_read(struct v_inode* inode, void* buffer, size_t len, size_t fpos) +{ + assert(inode->data); + + struct device* dev = (struct device*)inode->data; + + if (!dev->read) { + return ENOTSUP; + } + + return dev->read(dev, buffer, fpos, len); +} + +int +devfs_write(struct v_inode* inode, void* buffer, size_t len, size_t fpos) +{ + assert(inode->data); + + struct device* dev = (struct device*)inode->data; + + if (!dev->write) { + return ENOTSUP; + } + + return dev->write(dev, buffer, fpos, len); +} + +int +devfs_get_itype(struct device* dev) +{ + int itype = VFS_IFFILE; + int dev_if = dev->dev_type & DEV_MSKIF; + if (dev_if == DEV_IFCAT) { + itype = VFS_IFDIR; + } else if (dev_if == DEV_IFVOL) { + itype |= VFS_IFVOLDEV; + } else { + itype |= VFS_IFSEQDEV; + } + return itype; +} + +int +devfs_mknod(struct v_dnode* dnode, struct device* dev) +{ + assert(dev); + + struct v_inode* devnod = vfs_i_find(dnode->super_block, dev->dev_id); + if (!devnod) { + if ((devnod = vfs_i_alloc(dnode->super_block))) { + devnod->id = dev->dev_id; + devnod->data = dev; + devnod->itype = devfs_get_itype(dev); + + vfs_i_addhash(devnod); + } else { + return ENOMEM; + } + } + + vfs_assign_inode(dnode, devnod); + return 0; +} + +int +devfs_dirlookup(struct v_inode* this, struct v_dnode* dnode) +{ + struct device* dev = device_getbyname(this->data, &dnode->name); + if (!dev) { + return ENOENT; + } + return devfs_mknod(dnode, dev); +} + +int +devfs_readdir(struct v_file* file, struct dir_context* dctx) +{ + struct device* dev = device_getbyoffset(file->inode->data, dctx->index); + if (!dev) { + return 0; + } + dctx->read_complete_callback( + dctx, dev->name.value, dev->name.len, devfs_get_itype(dev)); + return 1; +} + +void +devfs_init_inode(struct v_superblock* vsb, struct v_inode* inode) +{ + inode->ops = &devfs_inode_ops; + inode->default_fops = &devfs_file_ops; +} + +int +devfs_mount(struct v_superblock* vsb, struct v_dnode* mount_point) +{ + vsb->ops.init_inode = devfs_init_inode; + + struct v_inode* rootnod = vfs_i_alloc(vsb); + + if (!rootnod) { + return ENOMEM; + } + + rootnod->id = -1; + rootnod->itype = VFS_IFDIR; + + vfs_i_addhash(rootnod); + vfs_assign_inode(mount_point, rootnod); + + return 0; +} + +int +devfs_unmount(struct v_superblock* vsb) +{ + return 0; +} + +void +devfs_init() +{ + struct filesystem* fs = fsm_new_fs("devfs", 5); + fsm_register(fs); + fs->mount = devfs_mount; + fs->unmount = devfs_unmount; +} + +struct v_inode_ops devfs_inode_ops = { .dir_lookup = devfs_dirlookup, + .open = default_inode_open, + .mkdir = default_inode_mkdir, + .rmdir = default_inode_rmdir }; + +struct v_file_ops devfs_file_ops = { .close = default_file_close, + .read = devfs_read, + .write = devfs_write, + .seek = default_file_seek, + .readdir = devfs_readdir }; \ No newline at end of file diff --git a/lunaix-os/kernel/device/device.c b/lunaix-os/kernel/device/device.c new file mode 100644 index 0000000..aafdf0e --- /dev/null +++ b/lunaix-os/kernel/device/device.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include + +static DEFINE_LLIST(root_list); + +static volatile dev_t devid = 0; + +struct device* +__device_add(struct device* parent, + void* underlay, + char* name_fmt, + uint32_t type, + va_list args) +{ + struct device* dev = vzalloc(sizeof(struct device)); + + if (parent) { + assert((parent->dev_type & DEV_MSKIF) == DEV_IFCAT); + } + + size_t strlen = + __sprintf_internal(dev->name_val, name_fmt, DEVICE_NAME_SIZE, args); + + dev->dev_id = devid++; + dev->name = HSTR(dev->name_val, strlen); + dev->parent = parent; + dev->underlay = underlay; + dev->dev_type = type; + + hstr_rehash(&dev->name, HSTR_FULL_HASH); + llist_append(&root_list, &dev->siblings); + + return dev; +} + +struct device* +device_addseq(struct device* parent, void* underlay, char* name_fmt, ...) +{ + va_list args; + va_start(args, name_fmt); + + struct device* dev = + __device_add(parent, underlay, name_fmt, DEV_IFSEQ, args); + + va_end(args); + return dev; +} + +struct device* +device_addvol(struct device* parent, void* underlay, char* name_fmt, ...) +{ + va_list args; + va_start(args, name_fmt); + + struct device* dev = + __device_add(parent, underlay, name_fmt, DEV_IFVOL, args); + + va_end(args); + return dev; +} + +struct device* +device_addcat(struct device* parent, char* name_fmt, ...) +{ + va_list args; + va_start(args, name_fmt); + + struct device* dev = __device_add(parent, NULL, name_fmt, DEV_IFCAT, args); + + va_end(args); + return dev; +} + +struct device* +device_getbyid(struct llist_header* devlist, dev_t id) +{ + devlist = devlist ? devlist : &root_list; + struct device *pos, *n; + llist_for_each(pos, n, devlist, siblings) + { + if (pos->dev_id == id) { + return pos; + } + } + + return NULL; +} + +struct device* +device_getbyname(struct llist_header* devlist, struct hstr* name) +{ + devlist = devlist ? devlist : &root_list; + struct device *pos, *n; + llist_for_each(pos, n, devlist, siblings) + { + if (HSTR_EQ(&pos->name, name)) { + return pos; + } + } + + return NULL; +} + +void +device_remove(struct device* dev) +{ + llist_delete(&dev->siblings); + vfree(dev); +} + +struct device* +device_getbyoffset(struct llist_header* devlist, int offset) +{ + devlist = devlist ? devlist : &root_list; + struct device *pos, *n; + int off = 0; + llist_for_each(pos, n, devlist, siblings) + { + if (off++ >= offset) { + return pos; + } + } + return NULL; +} \ No newline at end of file diff --git a/lunaix-os/kernel/fs/fs_setup.c b/lunaix-os/kernel/fs/fs_setup.c index 74fdef7..6de3f38 100644 --- a/lunaix-os/kernel/fs/fs_setup.c +++ b/lunaix-os/kernel/fs/fs_setup.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -7,5 +8,7 @@ fsm_register_all() { ramfs_init(); twifs_init(); - // Add more fs implementation + devfs_init(); + + // ... more fs implementation } \ No newline at end of file diff --git a/lunaix-os/kernel/fs/mount.c b/lunaix-os/kernel/fs/mount.c index 7b83757..486d695 100644 --- a/lunaix-os/kernel/fs/mount.c +++ b/lunaix-os/kernel/fs/mount.c @@ -233,7 +233,7 @@ __DEFINE_LXSYSCALL4(int, // By our convention. // XXX could we do better? - struct device* device = (struct device*)dev->data; + struct device* device = (struct device*)dev->inode->data; if (!(dev->inode->itype & VFS_IFVOLDEV) || !device) { errno = ENOTDEV; diff --git a/lunaix-os/kernel/fs/vfs.c b/lunaix-os/kernel/fs/vfs.c index 83bd0bd..7fbc226 100644 --- a/lunaix-os/kernel/fs/vfs.c +++ b/lunaix-os/kernel/fs/vfs.c @@ -367,6 +367,7 @@ vfs_d_alloc(struct v_dnode* parent, struct hstr* name) if (parent) { dnode->super_block = parent->super_block; + dnode->mnt = parent->mnt; } lru_use_one(dnode_lru, &dnode->lru); diff --git a/lunaix-os/kernel/k_init.c b/lunaix-os/kernel/k_init.c index 30e06ca..a443ec0 100644 --- a/lunaix-os/kernel/k_init.c +++ b/lunaix-os/kernel/k_init.c @@ -72,19 +72,17 @@ _kernel_init() cake_init(); valloc_init(); + lxconsole_init(); + vfs_init(); fsm_init(); - device_init(); - if ((errno = vfs_mount_root("ramfs", NULL))) { panickf("Fail to mount root. (errno=%d)", errno); } - // FIXME replace with more specific fs for device. - vfs_mount("/dev", "twifs", NULL, MNT_RO); - - lxconsole_init(); + vfs_mount("/dev", "devfs", NULL, 0); + vfs_mount("/sys", "twifs", NULL, MNT_RO); sched_init(); diff --git a/lunaix-os/kernel/proc0.c b/lunaix-os/kernel/proc0.c index e137b8e..32e1eff 100644 --- a/lunaix-os/kernel/proc0.c +++ b/lunaix-os/kernel/proc0.c @@ -46,8 +46,8 @@ __do_reserved_memory(int unlock); #define USE_DEMO // #define DEMO_SIGNAL -#define DEMO_READDIR -//#define DEMO_IOTEST +//#define DEMO_READDIR +#define DEMO_IOTEST extern void _pconsole_main(); @@ -90,6 +90,7 @@ __proc0_usr() #else _lxinit_main(); #endif + _exit(0); } waitpid(p, 0, 0); -- 2.27.0