From: Minep Date: Fri, 19 Aug 2022 18:08:00 +0000 (+0100) Subject: refactor: add a simple ramfs for rootfs. Twifs should have more specific job in future. X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/commitdiff_plain/a7384053efe345d199440720b437a28e91058ff3?hp=c4d08ac5260bb26db10bcfd9dc6fd2db60efebe9 refactor: add a simple ramfs for rootfs. Twifs should have more specific job in future. refactor: inode creation, inode cache lookup and it's hashing are now separated. refactor: reduce the v_inode and v_file size due to ops invariants. chores: minor refactoring and fixings. --- diff --git a/lunaix-os/includes/lunaix/fs.h b/lunaix-os/includes/lunaix/fs.h index e95fbad..d43293b 100644 --- a/lunaix-os/includes/lunaix/fs.h +++ b/lunaix-os/includes/lunaix/fs.h @@ -24,7 +24,7 @@ #define VFS_WALK_MKPARENT 0x1 #define VFS_WALK_FSRELATIVE 0x2 #define VFS_WALK_PARENT 0x4 -#define VFS_WALK_NOFOLLOW 0x4 +#define VFS_WALK_NOFOLLOW 0x8 #define VFS_HASHTABLE_BITS 10 #define VFS_HASHTABLE_SIZE (1 << VFS_HASHTABLE_BITS) @@ -33,29 +33,40 @@ #define FSTYPE_ROFS 0x1 +#define DO_STATUS(errno) SYSCALL_ESTATUS(__current->k_status = errno) +#define DO_STATUS_OR_RETURN(errno) ({ errno < 0 ? DO_STATUS(errno) : errno; }) + +#define TEST_FD(fd) (fd >= 0 && fd < VFS_MAX_FD) + #define VFS_VALID_CHAR(chr) \ (('A' <= (chr) && (chr) <= 'Z') || ('a' <= (chr) && (chr) <= 'z') || \ ('0' <= (chr) && (chr) <= '9') || (chr) == '.' || (chr) == '_' || \ (chr) == '-') -extern struct hstr vfs_ddot; -extern struct hstr vfs_dot; - typedef uint32_t inode_t; struct v_dnode; struct v_inode; struct v_superblock; struct v_file; +struct v_file_ops; +struct v_inode_ops; struct v_fd; struct pcache; +extern struct v_file_ops default_file_ops; +extern struct v_inode_ops default_inode_ops; + +extern struct hstr vfs_ddot; +extern struct hstr vfs_dot; +extern struct v_dnode* vfs_sysroot; + struct filesystem { struct hlist_node fs_list; struct hstr fs_name; uint32_t types; - int fs_id; // can be used to detect fs type on partition + int fs_id; int (*mount)(struct v_superblock* vsb, struct v_dnode* mount_point); int (*unmount)(struct v_superblock* vsb); }; @@ -72,6 +83,7 @@ struct v_superblock { uint32_t (*read_capacity)(struct v_superblock* vsb); uint32_t (*read_usage)(struct v_superblock* vsb); + void (*init_inode)(struct v_superblock* vsb, struct v_inode* inode); } ops; }; @@ -89,10 +101,27 @@ struct v_file_ops { int (*write)(struct v_inode* inode, void* buffer, size_t len, size_t fpos); int (*read)(struct v_inode* inode, void* buffer, size_t len, size_t fpos); - int (*readdir)(struct v_inode* inode, struct dir_context* dctx); + int (*readdir)(struct v_file* file, struct dir_context* dctx); int (*seek)(struct v_inode* inode, size_t offset); int (*close)(struct v_file* file); - int (*sync)(struct v_inode* inode); + int (*sync)(struct v_file* file); +}; + +struct v_inode_ops +{ + int (*create)(struct v_inode* this, struct v_dnode* dnode); + int (*open)(struct v_inode* this, struct v_file* file); + int (*sync)(struct v_inode* this); + int (*mkdir)(struct v_inode* this, struct v_dnode* dnode); + int (*rmdir)(struct v_inode* this, struct v_dnode* dir); + int (*unlink)(struct v_inode* this); + int (*link)(struct v_inode* this, struct v_dnode* new_name); + int (*read_symlink)(struct v_inode* this, const char** path_out); + int (*set_symlink)(struct v_inode* this, const char* target); + int (*dir_lookup)(struct v_inode* this, struct v_dnode* dnode); + int (*rename)(struct v_inode* from_inode, + struct v_dnode* from_dnode, + struct v_dnode* to_dnode); }; struct v_file @@ -102,7 +131,7 @@ struct v_file struct llist_header* f_list; uint32_t f_pos; atomic_ulong ref_count; - struct v_file_ops ops; + struct v_file_ops* ops; // for caching }; struct v_fd @@ -124,27 +153,13 @@ struct v_inode uint32_t link_count; uint32_t lb_usage; uint32_t fsize; + struct v_superblock* sb; struct hlist_node hash_list; struct lru_node lru; struct pcache* pg_cache; void* data; // 允许底层FS绑定他的一些专有数据 - struct - { - int (*create)(struct v_inode* this, struct v_dnode* dnode); - int (*open)(struct v_inode* this, struct v_file* file); - int (*sync)(struct v_inode* this); - int (*mkdir)(struct v_inode* this, struct v_dnode* dnode); - int (*rmdir)(struct v_inode* this, struct v_dnode* dir); - int (*unlink)(struct v_inode* this); - int (*link)(struct v_inode* this, struct v_dnode* new_name); - int (*read_symlink)(struct v_inode* this, const char** path_out); - int (*set_symlink)(struct v_inode* this, const char* target); - int (*dir_lookup)(struct v_inode* this, struct v_dnode* dnode); - int (*rename)(struct v_inode* from_inode, - struct v_dnode* from_dnode, - struct v_dnode* to_dnode); - } ops; - struct v_file_ops default_fops; + struct v_inode_ops* ops; + struct v_file_ops* default_fops; }; struct v_mount @@ -205,6 +220,12 @@ struct pcache_pg void fsm_init(); +void +fsm_register_all(); + +struct filesystem* +fsm_new_fs(char* name, size_t name_len); + void fsm_register(struct filesystem* fs); @@ -269,10 +290,13 @@ void vfs_d_free(struct v_dnode* dnode); struct v_inode* -vfs_i_alloc(struct v_superblock* sb, - uint32_t inode_id, - void (*init)(struct v_inode* inode, void* data), - void* data); +vfs_i_find(struct v_superblock* sb, uint32_t i_id); + +void +vfs_i_addhash(struct v_inode* inode); + +struct v_inode* +vfs_i_alloc(struct v_superblock* sb); void vfs_i_free(struct v_inode* inode); @@ -332,6 +356,45 @@ mnt_mkbusy(struct v_mount* mnt); void mnt_chillax(struct v_mount* mnt); +int +vfs_mount_root(const char* fs_name, struct device* device); + struct v_mount* vfs_create_mount(struct v_mount* parent, struct v_dnode* mnt_point); + +int +default_file_read(struct v_inode* inode, void* buffer, size_t len, size_t fpos); + +int +default_file_write(struct v_inode* inode, + void* buffer, + size_t len, + size_t fpos); + +int +default_file_readdir(struct v_file* file, struct dir_context* dctx); + +int +default_inode_dirlookup(struct v_inode* this, struct v_dnode* dnode); + +int +default_inode_rename(struct v_inode* from_inode, + struct v_dnode* from_dnode, + struct v_dnode* to_dnode); + +int +default_file_close(struct v_file* file); + +int +default_file_seek(struct v_inode* inode, size_t offset); + +int +default_inode_open(struct v_inode* this, struct v_file* file); + +int +default_inode_rmdir(struct v_inode* this, struct v_dnode* dir); + +int +default_inode_mkdir(struct v_inode* this, struct v_dnode* dir); + #endif /* __LUNAIX_VFS_H */ diff --git a/lunaix-os/includes/lunaix/fs/ramfs.h b/lunaix-os/includes/lunaix/fs/ramfs.h new file mode 100644 index 0000000..f7f8e27 --- /dev/null +++ b/lunaix-os/includes/lunaix/fs/ramfs.h @@ -0,0 +1,7 @@ +#ifndef __LUNAIX_RAMFS_H +#define __LUNAIX_RAMFS_H + +void +ramfs_init(); + +#endif /* __LUNAIX_RAMFS_H */ diff --git a/lunaix-os/includes/lunaix/spike.h b/lunaix-os/includes/lunaix/spike.h index 4363b41..274bcf6 100644 --- a/lunaix-os/includes/lunaix/spike.h +++ b/lunaix-os/includes/lunaix/spike.h @@ -92,6 +92,9 @@ __assert_fail(const char* expr, const char* file, unsigned int line) void panick(const char* msg); +void +panickf(const char* fmt, ...); + #define wait_until(cond) \ while (!(cond)) \ ; diff --git a/lunaix-os/kernel/demos/dir_read.c b/lunaix-os/kernel/demos/dir_read.c index caa88cc..0d62a79 100644 --- a/lunaix-os/kernel/demos/dir_read.c +++ b/lunaix-os/kernel/demos/dir_read.c @@ -26,7 +26,7 @@ _readdir_main() struct dirent ent = { .d_offset = 0 }; - while (!readdir(fd, &ent)) { + while (readdir(fd, &ent) == 1) { kprintf(KINFO "%s\n", ent.d_name); } diff --git a/lunaix-os/kernel/fs/defaults.c b/lunaix-os/kernel/fs/defaults.c new file mode 100644 index 0000000..145d9ca --- /dev/null +++ b/lunaix-os/kernel/fs/defaults.c @@ -0,0 +1,90 @@ +#include + +int +default_file_close(struct v_file* file) +{ + return 0; +} + +int +default_file_seek(struct v_inode* inode, size_t offset) +{ + return 0; +} + +int +default_inode_open(struct v_inode* this, struct v_file* file) +{ + return 0; +} + +int +default_file_read(struct v_inode* inode, void* buffer, size_t len, size_t fpos) +{ + return ENOTSUP; +} + +int +default_file_write(struct v_inode* inode, void* buffer, size_t len, size_t fpos) +{ + return ENOTSUP; +} + +int +default_file_readdir(struct v_file* file, struct dir_context* dctx) +{ + int i = 0; + struct v_dnode *pos, *n; + llist_for_each(pos, n, &file->dnode->children, siblings) + { + if (i < dctx->index) { + i++; + continue; + } + dctx->read_complete_callback(dctx, pos->name.value, pos->name.len, 0); + break; + } +} + +int +default_inode_dirlookup(struct v_inode* this, struct v_dnode* dnode) +{ + return ENOENT; +} + +int +default_inode_rename(struct v_inode* from_inode, + struct v_dnode* from_dnode, + struct v_dnode* to_dnode) +{ + return 0; +} + +int +default_inode_sync(struct v_inode* this) +{ + return 0; +} + +int +default_inode_rmdir(struct v_inode* this, struct v_dnode* dir) +{ + return ENOTSUP; +} + +int +default_inode_mkdir(struct v_inode* this, struct v_dnode* dir) +{ + return ENOTSUP; +} + +struct v_file_ops default_file_ops = { .close = default_file_close, + .read = default_file_read, + .seek = default_file_seek, + .readdir = default_file_readdir }; + +struct v_inode_ops default_inode_ops = { .dir_lookup = default_inode_dirlookup, + .sync = default_inode_sync, + .open = default_inode_open, + .rename = default_inode_rename, + .rmdir = default_inode_rmdir }; \ No newline at end of file diff --git a/lunaix-os/kernel/fs/fs_setup.c b/lunaix-os/kernel/fs/fs_setup.c new file mode 100644 index 0000000..74fdef7 --- /dev/null +++ b/lunaix-os/kernel/fs/fs_setup.c @@ -0,0 +1,11 @@ +#include +#include +#include + +void +fsm_register_all() +{ + ramfs_init(); + twifs_init(); + // Add more fs implementation +} \ No newline at end of file diff --git a/lunaix-os/kernel/fs/fsm.c b/lunaix-os/kernel/fs/fsm.c index 10e766a..bce983a 100644 --- a/lunaix-os/kernel/fs/fsm.c +++ b/lunaix-os/kernel/fs/fsm.c @@ -11,6 +11,7 @@ #include #include #include +#include #define HASH_BUCKET_BITS 4 #define HASH_BUCKET_NUM (1 << HASH_BUCKET_BITS) @@ -21,6 +22,8 @@ void fsm_init() { hashtable_init(fs_registry); + + fsm_register_all(); } void @@ -45,4 +48,12 @@ fsm_get(const char* fs_name) } return NULL; +} + +struct filesystem* +fsm_new_fs(char* name, size_t name_len) +{ + struct filesystem* fs = vzalloc(sizeof(*fs)); + fs->fs_name = HHSTR(name, name_len, 0); + return fs; } \ No newline at end of file diff --git a/lunaix-os/kernel/fs/mount.c b/lunaix-os/kernel/fs/mount.c index 3d4b0be..aa4acef 100644 --- a/lunaix-os/kernel/fs/mount.c +++ b/lunaix-os/kernel/fs/mount.c @@ -88,13 +88,24 @@ mnt_chillax(struct v_mount* mnt) } } +int +vfs_mount_root(const char* fs_name, struct device* device) +{ + int errno = 0; + if (vfs_sysroot->mnt && (errno = vfs_unmount_at(vfs_sysroot))) { + return errno; + } + return vfs_mount_at(fs_name, device, vfs_sysroot); +} + int vfs_mount(const char* target, const char* fs_name, struct device* device) { int errno; struct v_dnode* mnt; - if (!(errno = vfs_walk(__current->cwd, target, &mnt, NULL, 0))) { + if (!(errno = + vfs_walk(__current->cwd, target, &mnt, NULL, VFS_WALK_MKPARENT))) { errno = vfs_mount_at(fs_name, device, mnt); } @@ -134,17 +145,23 @@ vfs_mount_at(const char* fs_name, int errno = 0; if (!(errno = fs->mount(sb, mnt_point))) { + mnt_point->super_block = sb; sb->fs = fs; sb->root = mnt_point; - mnt_point->super_block = sb; if (!(mnt_point->mnt = vfs_create_mount(parent_mnt, mnt_point))) { errno = ENOMEM; - vfs_sb_free(sb); + goto cleanup; } + } else { + goto cleanup; } return errno; + +cleanup: + vfs_sb_free(sb); + return errno; } int @@ -170,3 +187,48 @@ vfs_unmount_at(struct v_dnode* mnt_point) return errno; } + +__DEFINE_LXSYSCALL3(int, + mount, + const char*, + source, + const char*, + target, + const char*, + fstype) +{ + struct v_dnode *dev, *mnt; + int errno = 0; + + if ((errno = vfs_walk(__current->cwd, source, &dev, NULL, 0))) { + goto done; + } + + if ((errno = vfs_walk(__current->cwd, target, &mnt, NULL, 0))) { + goto done; + } + + if (mnt->ref_count > 1) { + errno = EBUSY; + goto done; + } + + // By our convention. + // XXX could we do better? + struct device* device = (struct device*)dev->data; + + if (!(dev->inode->itype & VFS_IFVOLDEV) || !device) { + errno = ENOTDEV; + goto done; + } + + errno = vfs_mount_at(fstype, device, mnt); + +done: + return DO_STATUS(errno); +} + +__DEFINE_LXSYSCALL1(int, unmount, const char*, target) +{ + return vfs_unmount(target); +} \ No newline at end of file diff --git a/lunaix-os/kernel/fs/pcache.c b/lunaix-os/kernel/fs/pcache.c index 8ef8fc8..0094ec4 100644 --- a/lunaix-os/kernel/fs/pcache.c +++ b/lunaix-os/kernel/fs/pcache.c @@ -137,7 +137,7 @@ pcache_read(struct v_inode* inode, void* data, uint32_t len, uint32_t fpos) } // Filling up the page - errno = inode->default_fops.read(inode, pg->pg, PG_SIZE, pg->fpos); + errno = inode->default_fops->read(inode, pg->pg, PG_SIZE, pg->fpos); if (errno >= 0 && errno < PG_SIZE) { // EOF len = buf_off + errno; @@ -175,7 +175,8 @@ pcache_commit(struct v_inode* inode, struct pcache_pg* page) return; } - int errno = inode->default_fops.write(inode, page->pg, PG_SIZE, page->fpos); + int errno = + inode->default_fops->write(inode, page->pg, PG_SIZE, page->fpos); if (!errno) { page->flags &= ~PCACHE_DIRTY; diff --git a/lunaix-os/kernel/fs/ramfs/ramfs.c b/lunaix-os/kernel/fs/ramfs/ramfs.c new file mode 100644 index 0000000..3dcbd59 --- /dev/null +++ b/lunaix-os/kernel/fs/ramfs/ramfs.c @@ -0,0 +1,130 @@ +/** + * @file ramfs.c + * @author Lunaixsky + * @brief RamFS - a file system sit in RAM + * @version 0.1 + * @date 2022-08-18 + * + * @copyright Copyright (c) 2022 + * + */ +#include +#include +#include + +/* + A RAM FS will play a role of being a root. + + This is an temporary meaure as we don't have any concrete fs + yet. In the near future, we will have an ISO-9660 as our first + fs and mount our boot medium as root. And similar thing could + be done when we have installed our OS into hard disk, in that + case, our rootfs will be something like ext2. + + RamFS vs. TwiFS: Indeed, they are both fs that lives in RAM so + there is no foundmentally differences. However, TwiFS is designed + to be a 'virtual FIlesystem for KERnel space' (FIKER), so other + kernel sub-modules can just create node and attach their own + implementation of read/write, without brothering to create a + full featured concrete filesystem. This particularly useful for + kernel state exposure. In Lunaix, TwiFS is summation of procfs, + sysfs and kernfs in Linux world. + + However, there is a smell of bad-design in the concept of TwiFS. + Since it tries to integrate too much responsibility. The TwiFS may + be replaced by more specific fs in the future. + + On the other hand, RamFS is designed to be act like a dummy fs + that just ensure 'something there at least' and thus provide basic + 'mountibility' for other fs. +*/ + +volatile static inode_t ino = 0; + +extern const struct v_inode_ops ramfs_inode_ops; + +int +ramfs_readdir(struct v_file* file, struct dir_context* dctx) +{ + int i = 0; + struct v_dnode *pos, *n; + llist_for_each(pos, n, &file->dnode->children, siblings) + { + if (i++ >= dctx->index) { + dctx->read_complete_callback( + dctx, pos->name.value, pos->name.len, 0); + return 1; + } + } + return 0; +} + +int +ramfs_mkdir(struct v_inode* this, struct v_dnode* dnode) +{ + struct v_inode* inode = vfs_i_alloc(dnode->super_block); + inode->itype = VFS_IFDIR; + + vfs_i_addhash(inode); + vfs_assign_inode(dnode, inode); + + return 0; +} + +int +ramfs_create(struct v_inode* this, struct v_dnode* dnode) +{ + struct v_inode* inode = vfs_i_alloc(dnode->super_block); + inode->itype = VFS_IFFILE; + + vfs_i_addhash(inode); + vfs_assign_inode(dnode, inode); + + return 0; +} + +void +ramfs_inode_init(struct v_superblock* vsb, struct v_inode* inode) +{ + inode->id = ino++; + inode->ops = &ramfs_inode_ops; + inode->default_fops = &default_file_ops; +} + +int +ramfs_mount(struct v_superblock* vsb, struct v_dnode* mount_point) +{ + vsb->ops.init_inode = ramfs_inode_init; + + struct v_inode* inode = vfs_i_alloc(vsb); + inode->itype = VFS_IFDIR; + + vfs_i_addhash(inode); + vfs_assign_inode(mount_point, inode); + + return 0; +} + +int +ramfs_unmount(struct v_superblock* vsb) +{ + return 0; +} + +void +ramfs_init() +{ + struct filesystem* ramfs = fsm_new_fs("ramfs", 5); + ramfs->mount = ramfs_mount; + ramfs->unmount = ramfs_unmount; + + fsm_register(ramfs); +} + +const struct v_inode_ops ramfs_inode_ops = { .mkdir = ramfs_mkdir, + .rmdir = default_inode_rmdir, + .dir_lookup = + default_inode_dirlookup, + .create = ramfs_create, + .open = default_inode_open, + .rename = default_inode_rename }; \ No newline at end of file diff --git a/lunaix-os/kernel/fs/twifs/twifs.c b/lunaix-os/kernel/fs/twifs/twifs.c index 6049861..d452d0b 100644 --- a/lunaix-os/kernel/fs/twifs/twifs.c +++ b/lunaix-os/kernel/fs/twifs/twifs.c @@ -19,53 +19,10 @@ static struct twifs_node* fs_root; static struct cake_pile* twi_pile; -static volatile int32_t inode_id = 0; +static volatile uint32_t inode_id = 0; -int -__twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode); - -int -__twifs_openfile(struct v_inode* inode, struct v_file* file); - -struct twifs_node* -__twifs_get_node(struct twifs_node* parent, struct hstr* name); - -struct v_inode* -__twifs_get_inode(struct twifs_node* twi_node); - -int -__twifs_iterate_dir(struct v_inode* inode, struct dir_context* dctx); - -int -__twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point); - -int -__twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode); - -int -__twifs_rmstuff(struct v_inode* inode, struct v_dnode* dir); - -int -__twifs_fwrite(struct v_inode* inode, void* buffer, size_t len, size_t fpos); - -int -__twifs_fread(struct v_inode* inode, void* buffer, size_t len, size_t fpos); - -void -twifs_init() -{ - twi_pile = cake_new_pile("twifs_node", sizeof(struct twifs_node), 1, 0); - - struct filesystem* twifs = vzalloc(sizeof(struct filesystem)); - twifs->fs_name = HSTR("twifs", 5); - twifs->mount = __twifs_mount; - twifs->types = FSTYPE_ROFS; - twifs->fs_id = 0; - - fsm_register(twifs); - - fs_root = twifs_dir_node(NULL, NULL, 0, 0); -} +extern const struct v_file_ops twifs_file_ops; +extern const struct v_inode_ops twifs_inode_ops; struct twifs_node* __twifs_new_node(struct twifs_node* parent, @@ -89,93 +46,29 @@ __twifs_new_node(struct twifs_node* parent, return node; } -int -twifs_rm_node(struct twifs_node* node) -{ - if ((node->itype & VFS_IFDIR) && !llist_empty(&node->children)) { - return ENOTEMPTY; - } - llist_delete(&node->siblings); - cake_release(twi_pile, node); - return 0; -} - -struct twifs_node* -twifs_file_node(struct twifs_node* parent, - const char* name, - int name_len, - uint32_t itype) -{ - struct twifs_node* twi_node = - __twifs_new_node(parent, name, name_len, VFS_IFFILE | itype); - - return twi_node; -} - -struct twifs_node* -twifs_dir_node(struct twifs_node* parent, - const char* name, - int name_len, - uint32_t itype) -{ - struct hstr hname = HSTR(name, name_len); - hstr_rehash(&hname, HSTR_FULL_HASH); - struct twifs_node* node = __twifs_get_node(parent, &hname); - if (node) { - return node; - } - - struct twifs_node* twi_node = - __twifs_new_node(parent, name, name_len, VFS_IFDIR | itype); - - return twi_node; -} - -struct twifs_node* -twifs_toplevel_node(const char* name, int name_len, uint32_t itype) -{ - return twifs_dir_node(fs_root, name, name_len, itype); -} - -int -__twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode) -{ - return ENOTSUP; -} - void -__twifs_init_inode(struct v_inode* inode, void* data) +__twifs_init_inode(struct v_superblock* vsb, struct v_inode* inode) { - struct twifs_node* twi_node = (struct twifs_node*)data; - - inode->itype = twi_node->itype; - inode->data = twi_node; - - inode->ctime = clock_unixtime(); - inode->atime = inode->ctime; - inode->mtime = inode->ctime; - - inode->ops.dir_lookup = __twifs_dirlookup; - inode->ops.mkdir = __twifs_mkdir; - inode->ops.rmdir = __twifs_rmstuff; - inode->ops.open = __twifs_openfile; - - inode->default_fops = (struct v_file_ops){ .read = __twifs_fread, - .write = __twifs_fwrite, - .readdir = __twifs_iterate_dir }; - - return inode; + inode->ops = &twifs_inode_ops; + inode->default_fops = &twifs_file_ops; } int __twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point) { vsb->dev = 1; - struct v_inode* inode = - vfs_i_alloc(vsb, fs_root->ino_id, __twifs_init_inode, fs_root); + vsb->ops.init_inode = __twifs_init_inode; + + struct v_inode* inode = vfs_i_alloc(vsb); if (!inode) { return ENOMEM; } + + inode->id = fs_root->ino_id; + inode->itype = fs_root->itype; + inode->data = fs_root; + + vfs_i_addhash(inode); vfs_assign_inode(mount_point, inode); return 0; } @@ -216,12 +109,6 @@ __twifs_get_node(struct twifs_node* parent, struct hstr* name) return NULL; } -int -__twifs_rmstuff(struct v_inode* inode, struct v_dnode* dir) -{ - return ENOTSUP; -} - int __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode) { @@ -233,15 +120,23 @@ __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode) struct twifs_node* child_node = __twifs_get_node(twi_node, &dnode->name); if (child_node) { - struct v_inode* inode = vfs_i_alloc(dnode->super_block, - child_node->ino_id, - __twifs_init_inode, - child_node); - if (!inode) { + struct v_inode* inode = vfs_i_find(inode->sb, child_node->ino_id); + if (inode) { + goto done; + } + + if (!(inode = vfs_i_alloc(inode->sb))) { return ENOENT; } - dnode->data = twi_node->data; + inode->id = child_node->ino_id; + inode->itype = child_node->itype; + inode->data = child_node; + + vfs_i_addhash(inode); + + done: + dnode->data = child_node->data; vfs_assign_inode(dnode, inode); return 0; } @@ -249,9 +144,9 @@ __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode) } int -__twifs_iterate_dir(struct v_inode* inode, struct dir_context* dctx) +__twifs_iterate_dir(struct v_file* file, struct dir_context* dctx) { - struct twifs_node* twi_node = (struct twifs_node*)(inode->data); + struct twifs_node* twi_node = (struct twifs_node*)(file->inode->data); int counter = 0; struct twifs_node *pos, *n; @@ -261,11 +156,11 @@ __twifs_iterate_dir(struct v_inode* inode, struct dir_context* dctx) dctx->index = counter; dctx->read_complete_callback( dctx, pos->name.value, pos->name.len, pos->itype); - return 0; + return 1; } } - return 1; + return 0; } int @@ -277,3 +172,77 @@ __twifs_openfile(struct v_inode* inode, struct v_file* file) } return ENOTSUP; } + +int +twifs_rm_node(struct twifs_node* node) +{ + if ((node->itype & VFS_IFDIR) && !llist_empty(&node->children)) { + return ENOTEMPTY; + } + llist_delete(&node->siblings); + cake_release(twi_pile, node); + return 0; +} + +struct twifs_node* +twifs_file_node(struct twifs_node* parent, + const char* name, + int name_len, + uint32_t itype) +{ + struct twifs_node* twi_node = + __twifs_new_node(parent, name, name_len, VFS_IFFILE | itype); + + return twi_node; +} + +struct twifs_node* +twifs_dir_node(struct twifs_node* parent, + const char* name, + int name_len, + uint32_t itype) +{ + struct hstr hname = HSTR(name, name_len); + hstr_rehash(&hname, HSTR_FULL_HASH); + struct twifs_node* node = __twifs_get_node(parent, &hname); + if (node) { + return node; + } + + struct twifs_node* twi_node = + __twifs_new_node(parent, name, name_len, VFS_IFDIR | itype); + + return twi_node; +} + +struct twifs_node* +twifs_toplevel_node(const char* name, int name_len, uint32_t itype) +{ + return twifs_dir_node(fs_root, name, name_len, itype); +} + +void +twifs_init() +{ + twi_pile = cake_new_pile("twifs_node", sizeof(struct twifs_node), 1, 0); + + struct filesystem* twifs = vzalloc(sizeof(struct filesystem)); + twifs->fs_name = HSTR("twifs", 5); + twifs->mount = __twifs_mount; + twifs->types = FSTYPE_ROFS; + twifs->fs_id = 0; + + fsm_register(twifs); + + fs_root = twifs_dir_node(NULL, NULL, 0, 0); +} + +const struct v_file_ops twifs_file_ops = { .close = default_file_close, + .read = __twifs_fread, + .write = __twifs_fwrite, + .readdir = __twifs_iterate_dir }; + +const struct v_inode_ops twifs_inode_ops = { .dir_lookup = __twifs_dirlookup, + .mkdir = default_inode_mkdir, + .rmdir = default_inode_rmdir, + .open = __twifs_openfile }; \ No newline at end of file diff --git a/lunaix-os/kernel/fs/vfs.c b/lunaix-os/kernel/fs/vfs.c index e219c52..b879185 100644 --- a/lunaix-os/kernel/fs/vfs.c +++ b/lunaix-os/kernel/fs/vfs.c @@ -78,7 +78,7 @@ static struct cake_pile* file_pile; static struct cake_pile* superblock_pile; static struct cake_pile* fd_pile; -static struct v_dnode* sysroot; +struct v_dnode* vfs_sysroot; static struct hbucket* dnode_cache; static struct lru_zone *dnode_lru, *inode_lru; @@ -119,8 +119,8 @@ vfs_init() hstr_rehash(&vfs_dot, HSTR_FULL_HASH); // 创建一个根dnode。 - sysroot = vfs_d_alloc(NULL, &vfs_empty); - atomic_fetch_add(&sysroot->ref_count, 1); + vfs_sysroot = vfs_d_alloc(NULL, &vfs_empty); + atomic_fetch_add(&vfs_sysroot->ref_count, 1); } inline struct hbucket* @@ -203,7 +203,10 @@ __vfs_walk(struct v_dnode* start, if ((walk_options & VFS_WALK_FSRELATIVE) && start) { start = start->super_block->root; } else { - start = sysroot; + start = vfs_sysroot; + if (!vfs_sysroot->mnt) { + panick("vfs: no root"); + } } i++; } @@ -261,22 +264,22 @@ __vfs_walk(struct v_dnode* start, goto error; } - lock_inode(current_level->inode); + struct v_inode* current_inode = current_level->inode; - errno = - current_level->inode->ops.dir_lookup(current_level->inode, dnode); + lock_inode(current_inode); + + errno = current_inode->ops->dir_lookup(current_inode, dnode); if (errno == ENOENT && (walk_options & VFS_WALK_MKPARENT)) { - if (!current_level->inode->ops.mkdir) { + if (!current_inode->ops->mkdir) { errno = ENOTSUP; } else { - errno = current_level->inode->ops.mkdir( - current_level->inode, dnode); + errno = current_inode->ops->mkdir(current_inode, dnode); } } vfs_dcache_add(current_level, dnode); - unlock_inode(current_level->inode); + unlock_inode(current_inode); if (errno) { unlock_dnode(current_level); @@ -316,16 +319,18 @@ vfs_walk(struct v_dnode* start, int errno = __vfs_walk(start, path, &interim, component, options); int counter = 0; + // FIXME This is NOT a correct way to resolve symlink! while (!errno && interim->inode && (options & VFS_WALK_NOFOLLOW)) { if (counter >= VFS_MAX_SYMLINK) { errno = ELOOP; continue; } if ((interim->inode->itype & VFS_IFSYMLINK) && - interim->inode->ops.read_symlink) { + interim->inode->ops->read_symlink) { lock_inode(interim->inode); - errno = interim->inode->ops.read_symlink(interim->inode, &pathname); + errno = + interim->inode->ops->read_symlink(interim->inode, &pathname); unlock_inode(interim->inode); if (errno) { @@ -346,7 +351,7 @@ vfs_walk(struct v_dnode* start, int vfs_open(struct v_dnode* dnode, struct v_file** file) { - if (!dnode->inode || !dnode->inode->ops.open) { + if (!dnode->inode || !dnode->inode->ops->open) { return ENOTSUP; } @@ -369,7 +374,7 @@ vfs_open(struct v_dnode* dnode, struct v_file** file) inode->pg_cache = pcache; } - int errno = inode->ops.open(inode, vfile); + int errno = inode->ops->open(inode, vfile); if (errno) { cake_release(file_pile, vfile); } else { @@ -403,9 +408,9 @@ vfs_link(struct v_dnode* to_link, struct v_dnode* name) lock_inode(to_link->inode); if (to_link->super_block->root != name->super_block->root) { errno = EXDEV; - } else if (!to_link->inode->ops.link) { + } else if (!to_link->inode->ops->link) { errno = ENOTSUP; - } else if (!(errno = to_link->inode->ops.link(to_link->inode, name))) { + } else if (!(errno = to_link->inode->ops->link(to_link->inode, name))) { vfs_assign_inode(name, to_link->inode); } unlock_inode(to_link->inode); @@ -417,7 +422,7 @@ int vfs_close(struct v_file* file) { int errno = 0; - if (!file->ops.close || !(errno = file->ops.close(file))) { + if (!(errno = file->ops->close(file))) { atomic_fetch_sub(&file->dnode->ref_count, 1); file->inode->open_count--; mnt_chillax(file->dnode->mnt); @@ -435,8 +440,9 @@ vfs_fsync(struct v_file* file) int errno = ENOTSUP; pcache_commit_all(file->inode); - if (file->ops.sync) { - errno = file->ops.sync(file->inode); + + if (file->ops->sync) { + errno = file->ops->sync(file); } unlock_inode(file->inode); @@ -553,42 +559,56 @@ vfs_d_free(struct v_dnode* dnode) } struct v_inode* -vfs_i_alloc(struct v_superblock* sb, - uint32_t inode_id, - void (*init)(struct v_inode* inode, void* data), - void* data) +vfs_i_find(struct v_superblock* sb, uint32_t i_id) { - // 每个超级块儿维护一个inode缓存哈希表。 - // 他们的hash value自然就是inode id了。 - struct hbucket* slot = &sb->i_cache[inode_id & VFS_HASH_MASK]; + struct hbucket* slot = &sb->i_cache[i_id & VFS_HASH_MASK]; struct v_inode *pos, *n; hashtable_bucket_foreach(slot, pos, n, hash_list) { - if (pos->id == inode_id) { - goto done; + if (pos->id == i_id) { + lru_use_one(inode_lru, &pos->lru); + return pos; } } - if (!(pos = cake_grab(inode_pile))) { + return NULL; +} + +void +vfs_i_addhash(struct v_inode* inode) +{ + struct hbucket* slot = &inode->sb->i_cache[inode->id & VFS_HASH_MASK]; + + hlist_delete(&inode->hash_list); + hlist_add(&slot->head, &inode->hash_list); +} + +struct v_inode* +vfs_i_alloc(struct v_superblock* sb) +{ + assert(sb->ops.init_inode); + + struct v_inode* inode; + if (!(inode = cake_grab(inode_pile))) { lru_evict_half(inode_lru); - if (!(pos = cake_grab(inode_pile))) { + if (!(inode = cake_grab(inode_pile))) { return NULL; } } - memset(pos, 0, sizeof(*pos)); - - pos->id = inode_id; + memset(inode, 0, sizeof(*inode)); + mutex_init(&inode->lock); - mutex_init(&pos->lock); + sb->ops.init_inode(sb, inode); - init(pos, data); - - hlist_add(&slot->head, &pos->hash_list); + inode->sb = sb; + inode->ctime = clock_unixtime(); + inode->atime = inode->ctime; + inode->mtime = inode->ctime; done: - lru_use_one(inode_lru, &pos->lru); - return pos; + lru_use_one(inode_lru, &inode->lru); + return inode; } void @@ -598,7 +618,7 @@ vfs_i_free(struct v_inode* inode) pcache_release(inode->pg_cache); vfree(inode->pg_cache); } - inode->ops.sync(inode); + inode->ops->sync(inode); hlist_delete(&inode->hash_list); cake_release(inode_pile, inode); } @@ -607,11 +627,6 @@ vfs_i_free(struct v_inode* inode) #define FLOCATE_CREATE_EMPTY 1 -#define DO_STATUS(errno) SYSCALL_ESTATUS(__current->k_status = errno) -#define DO_STATUS_OR_RETURN(errno) ({ errno < 0 ? DO_STATUS(errno) : errno; }) - -#define TEST_FD(fd) (fd >= 0 && fd < VFS_MAX_FD) - int __vfs_getfd(int fd, struct v_fd** fd_s) { @@ -649,7 +664,7 @@ __vfs_try_locate_file(const char* path, lock_dnode(parent); - if (!(errno = parent->inode->ops.create(parent->inode, file_new))) { + if (!(errno = parent->inode->ops->create(parent->inode, file_new))) { vfs_dcache_add(parent, file_new); *file = file_new; } else { @@ -676,11 +691,6 @@ vfs_do_open(const char* path, int options) } struct v_inode* o_inode = ofile->inode; - if (!(o_inode->itype & VFS_IFSEQDEV) && !(options & FO_DIRECT)) { - // XXX Change here accordingly when signature of pcache_r/w changed. - ofile->ops.read = pcache_read; - ofile->ops.write = pcache_write; - } if (!errno && !(errno = vfs_alloc_fdslot(&fd))) { struct v_fd* fd_s = vzalloc(sizeof(*fd_s)); @@ -746,7 +756,7 @@ __DEFINE_LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent) lock_inode(inode); - if (!(fd_s->file->inode->itype & VFS_IFDIR)) { + if (!(inode->itype & VFS_IFDIR)) { errno = ENOTDIR; } else { struct dir_context dctx = @@ -754,25 +764,25 @@ __DEFINE_LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent) .index = dent->d_offset, .read_complete_callback = __vfs_readdir_callback }; + errno = 1; if (dent->d_offset == 0) { __vfs_readdir_callback(&dctx, vfs_dot.value, vfs_dot.len, 0); } else if (dent->d_offset == 1) { __vfs_readdir_callback(&dctx, vfs_ddot.value, vfs_ddot.len, 0); } else { dctx.index -= 2; - if ((errno = fd_s->file->ops.readdir(inode, &dctx))) { + if ((errno = fd_s->file->ops->readdir(fd_s->file, &dctx)) != 1) { unlock_inode(inode); goto done; } } - errno = 0; dent->d_offset++; } unlock_inode(inode); done: - return DO_STATUS(errno); + return DO_STATUS_OR_RETURN(errno); } __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count) @@ -793,8 +803,13 @@ __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count) file->inode->atime = clock_unixtime(); - __SYSCALL_INTERRUPTIBLE( - { errno = file->ops.read(file->inode, buf, count, file->f_pos); }) + __SYSCALL_INTERRUPTIBLE({ + if ((file->inode->itype & VFS_IFSEQDEV) || (fd_s->flags & FO_DIRECT)) { + errno = file->ops->read(file->inode, buf, count, file->f_pos); + } else { + errno = pcache_read(file->inode, buf, count, file->f_pos); + } + }) if (errno > 0) { file->f_pos += errno; @@ -826,8 +841,13 @@ __DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count) file->inode->mtime = clock_unixtime(); - __SYSCALL_INTERRUPTIBLE( - { errno = file->ops.write(file->inode, buf, count, file->f_pos); }) + __SYSCALL_INTERRUPTIBLE({ + if ((file->inode->itype & VFS_IFSEQDEV) || (fd_s->flags & FO_DIRECT)) { + errno = file->ops->write(file->inode, buf, count, file->f_pos); + } else { + errno = pcache_write(file->inode, buf, count, file->f_pos); + } + }) if (errno > 0) { file->f_pos += errno; @@ -865,7 +885,7 @@ __DEFINE_LXSYSCALL3(int, lseek, int, fd, int, offset, int, options) fpos = offset; break; } - if (!file->ops.seek || !(errno = file->ops.seek(file->inode, fpos))) { + if (!(errno = file->ops->seek(file->inode, fpos))) { file->f_pos = fpos; } @@ -908,10 +928,10 @@ vfs_readlink(struct v_dnode* dnode, char* buf, size_t size) { const char* link; struct v_inode* inode = dnode->inode; - if (inode->ops.read_symlink) { + if (inode->ops->read_symlink) { lock_inode(inode); - int errno = inode->ops.read_symlink(inode, &link); + int errno = inode->ops->read_symlink(inode, &link); strncpy(buf, link, size); unlock_inode(inode); @@ -1030,7 +1050,7 @@ __DEFINE_LXSYSCALL1(int, rmdir, const char*, pathname) lock_inode(parent->inode); if ((dnode->inode->itype & VFS_IFDIR)) { - errno = parent->inode->ops.rmdir(parent->inode, dnode); + errno = parent->inode->ops->rmdir(parent->inode, dnode); if (!errno) { vfs_dcache_remove(dnode); } @@ -1070,11 +1090,11 @@ __DEFINE_LXSYSCALL1(int, mkdir, const char*, path) if ((parent->super_block->fs->types & FSTYPE_ROFS)) { errno = ENOTSUP; - } else if (!parent->inode->ops.mkdir) { + } else if (!parent->inode->ops->mkdir) { errno = ENOTSUP; } else if (!(parent->inode->itype & VFS_IFDIR)) { errno = ENOTDIR; - } else if (!(errno = parent->inode->ops.mkdir(parent->inode, dir))) { + } else if (!(errno = parent->inode->ops->mkdir(parent->inode, dir))) { vfs_dcache_add(parent, dir); goto cleanup; } @@ -1105,7 +1125,7 @@ __vfs_do_unlink(struct v_dnode* dnode) } else if (!(inode->itype & VFS_IFDIR)) { // The underlying unlink implementation should handle // symlink case - errno = inode->ops.unlink(inode); + errno = inode->ops->unlink(inode); if (!errno) { vfs_d_free(dnode); } @@ -1268,14 +1288,14 @@ __DEFINE_LXSYSCALL2(int, errno = EROFS; goto done; } - if (!dnode->inode->ops.set_symlink) { + if (!dnode->inode->ops->set_symlink) { errno = ENOTSUP; goto done; } lock_inode(dnode->inode); - errno = dnode->inode->ops.set_symlink(dnode->inode, link_target); + errno = dnode->inode->ops->set_symlink(dnode->inode, link_target); unlock_inode(dnode->inode); @@ -1405,7 +1425,8 @@ vfs_do_rename(struct v_dnode* current, struct v_dnode* target) goto cleanup; } - if ((errno = current->inode->ops.rename(current->inode, current, target))) { + if ((errno = + current->inode->ops->rename(current->inode, current, target))) { unlock_dnode(target); goto cleanup; } @@ -1462,49 +1483,4 @@ __DEFINE_LXSYSCALL2(int, rename, const char*, oldpath, const char*, newpath) done: vfree(name.value); return DO_STATUS(errno); -} - -__DEFINE_LXSYSCALL3(int, - mount, - const char*, - source, - const char*, - target, - const char*, - fstype) -{ - struct v_dnode *dev, *mnt; - int errno = 0; - - if ((errno = vfs_walk(__current->cwd, source, &dev, NULL, 0))) { - goto done; - } - - if ((errno = vfs_walk(__current->cwd, target, &mnt, NULL, 0))) { - goto done; - } - - if (mnt->ref_count > 1) { - errno = EBUSY; - goto done; - } - - // By our convention. - // XXX could we do better? - struct device* device = (struct device*)dev->data; - - if (!(dev->inode->itype & VFS_IFVOLDEV) || !device) { - errno = ENOTDEV; - goto done; - } - - errno = vfs_mount_at(fstype, device, mnt); - -done: - return DO_STATUS(errno); -} - -__DEFINE_LXSYSCALL1(int, unmount, const char*, target) -{ - return vfs_unmount(target); } \ No newline at end of file diff --git a/lunaix-os/kernel/k_init.c b/lunaix-os/kernel/k_init.c index ae98ac1..1682859 100644 --- a/lunaix-os/kernel/k_init.c +++ b/lunaix-os/kernel/k_init.c @@ -67,18 +67,21 @@ _kernel_pre_init() void _kernel_init() { - + int errno = 0; cake_init(); valloc_init(); - fsm_init(); vfs_init(); - twifs_init(); + fsm_init(); device_init(); - // 挂载 TwiFS 为根目录 - vfs_mount("/", "twifs", NULL); + 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); lxconsole_init(); diff --git a/lunaix-os/kernel/proc0.c b/lunaix-os/kernel/proc0.c index 3c2ea5f..e137b8e 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(); diff --git a/lunaix-os/kernel/spike.c b/lunaix-os/kernel/spike.c index 5aa0137..87726b0 100644 --- a/lunaix-os/kernel/spike.c +++ b/lunaix-os/kernel/spike.c @@ -24,3 +24,15 @@ panick(const char* msg) asm("int %0" ::"i"(LUNAIX_SYS_PANIC), "D"(msg)); spin(); } + +void +panickf(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + __sprintf_internal(buffer, fmt, 1024, args); + va_end(args); + + asm("int %0" ::"i"(LUNAIX_SYS_PANIC), "D"(buffer)); + spin(); +}