From: Minep Date: Mon, 15 Aug 2022 15:03:09 +0000 (+0100) Subject: feat: rename(2), mount(2) and unmount(2) X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/commitdiff_plain/e6dbd781772925dfc07b2facfa0a1350e756ad8f?hp=07dec283edc4b849c42efa9fbd23c6e9247e8788 feat: rename(2), mount(2) and unmount(2) fix: dnode caching hash function chore: code clean up --- diff --git a/README.md b/README.md index 2c0bcb3..ebaf251 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ LunaixOS - 一个简单的,详细的,POSIX兼容的(但愿!),带有 + 内存管理与按需分页(Demand Paging) + 键盘输入 + 多进程 -+ 33个常见的Linux/POSIX系统调用([附录1](#appendix1)) ++ 40个常见的Linux/POSIX系统调用([附录1](#appendix1)) + 用户模式 + 信号机制 + PCI 3.0 @@ -186,6 +186,9 @@ qemu-img create -f vdi machine/disk0.vdi 128M 2. `chdir(2)` 2. `fchdir(2)` 2. `getcwd(2)` +2. `rename(2)` +2. `mount(2)` +2. `unmount` (a.k.a `umount(2)`) ### LunaixOS自有 diff --git a/lunaix-os/includes/lunaix/ds/hstr.h b/lunaix-os/includes/lunaix/ds/hstr.h index f3fa89e..4b6947e 100644 --- a/lunaix-os/includes/lunaix/ds/hstr.h +++ b/lunaix-os/includes/lunaix/ds/hstr.h @@ -7,8 +7,8 @@ struct hstr { - unsigned int hash; - unsigned int len; + uint32_t hash; + uint32_t len; char* value; }; @@ -27,9 +27,12 @@ struct hstr #define HSTR_EQ(str1, str2) ((str1)->hash == (str2)->hash) inline void -hstr_rehash(struct hstr* hash_str, unsigned int truncate_to) +hstr_rehash(struct hstr* hash_str, uint32_t truncate_to) { hash_str->hash = strhash_32(hash_str->value, truncate_to); } +void +hstrcpy(struct hstr* dest, struct hstr* src); + #endif /* __LUNAIX_HSTR_H */ diff --git a/lunaix-os/includes/lunaix/ds/llist.h b/lunaix-os/includes/lunaix/ds/llist.h index 6129ca0..22e0f93 100644 --- a/lunaix-os/includes/lunaix/ds/llist.h +++ b/lunaix-os/includes/lunaix/ds/llist.h @@ -93,8 +93,10 @@ struct hlist_node }; static inline void -hlist_del(struct hlist_node* node) +hlist_delete(struct hlist_node* node) { + if (!node->pprev) + return; *node->pprev = node->next; node->next = 0; node->pprev = 0; diff --git a/lunaix-os/includes/lunaix/fctrl.h b/lunaix-os/includes/lunaix/fctrl.h index dc28872..85f49ac 100644 --- a/lunaix-os/includes/lunaix/fctrl.h +++ b/lunaix-os/includes/lunaix/fctrl.h @@ -25,4 +25,15 @@ __LXSYSCALL4(int, __LXSYSCALL3(int, realpathat, int, fd, char*, buf, size_t, size) +__LXSYSCALL3(int, + mount, + const char*, + source, + const char*, + target, + const char*, + fstype) + +__LXSYSCALL1(int, unmount, const char*, target) + #endif /* __LUNAIX_FCTRL_H */ diff --git a/lunaix-os/includes/lunaix/fs.h b/lunaix-os/includes/lunaix/fs.h index 37c8228..fcca8ab 100644 --- a/lunaix-os/includes/lunaix/fs.h +++ b/lunaix-os/includes/lunaix/fs.h @@ -1,9 +1,8 @@ #ifndef __LUNAIX_VFS_H #define __LUNAIX_VFS_H -#include -#include #include +#include #include #include #include @@ -57,7 +56,7 @@ struct v_superblock { struct llist_header sb_list; int fs_id; - bdev_t dev; + struct device* dev; struct v_dnode* root; struct filesystem* fs; uint32_t iobuf_size; @@ -84,7 +83,6 @@ struct v_file_ops 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 (*seek)(struct v_inode* inode, size_t offset); - int (*rename)(struct v_inode* inode, char* new_name); int (*close)(struct v_file* file); int (*sync)(struct v_inode* inode); }; @@ -107,6 +105,7 @@ struct v_fd struct v_inode { + uint32_t id; mutex_t lock; uint32_t itype; time_t ctime; @@ -131,6 +130,9 @@ struct v_inode int (*read_symlink)(struct v_inode* this, const char** path_out); int (*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; }; @@ -146,10 +148,6 @@ struct v_dnode struct llist_header siblings; struct v_superblock* super_block; atomic_ulong ref_count; - struct - { - void (*destruct)(struct v_dnode* dnode); - } ops; }; struct v_fdtable @@ -204,13 +202,15 @@ vfs_walk(struct v_dnode* start, int walk_options); int -vfs_mount(const char* target, const char* fs_name, bdev_t device); +vfs_mount(const char* target, const char* fs_name, struct device* device); int vfs_unmount(const char* target); int -vfs_mount_at(const char* fs_name, bdev_t device, struct v_dnode* mnt_point); +vfs_mount_at(const char* fs_name, + struct device* device, + struct v_dnode* mnt_point); int vfs_unmount_at(struct v_dnode* mnt_point); diff --git a/lunaix-os/includes/lunaix/lunistd.h b/lunaix-os/includes/lunaix/lunistd.h index cb5af35..d964428 100644 --- a/lunaix-os/includes/lunaix/lunistd.h +++ b/lunaix-os/includes/lunaix/lunistd.h @@ -55,4 +55,6 @@ __LXSYSCALL1(int, fchdir, int, fd) __LXSYSCALL2(char*, getcwd, char*, buf, size_t, size) +__LXSYSCALL2(int, rename, const char*, oldpath, const char*, newpath) + #endif /* __LUNAIX_UNISTD_H */ diff --git a/lunaix-os/includes/lunaix/status.h b/lunaix-os/includes/lunaix/status.h index 3d300f2..a108ea2 100644 --- a/lunaix-os/includes/lunaix/status.h +++ b/lunaix-os/includes/lunaix/status.h @@ -28,5 +28,6 @@ #define ENODEV -23 #define ERANGE -24 #define ENOMEM LXOUTOFMEM +#define ENOTDEV -25 #endif /* __LUNAIX_CODE_H */ diff --git a/lunaix-os/includes/lunaix/syscall.h b/lunaix-os/includes/lunaix/syscall.h index 1e205c2..5e0272f 100644 --- a/lunaix-os/includes/lunaix/syscall.h +++ b/lunaix-os/includes/lunaix/syscall.h @@ -46,6 +46,9 @@ #define __SYSCALL_chdir 38 #define __SYSCALL_fchdir 39 #define __SYSCALL_getcwd 40 +#define __SYSCALL_rename 41 +#define __SYSCALL_mount 42 +#define __SYSCALL_unmount 43 #define __SYSCALL_MAX 0x100 diff --git a/lunaix-os/kernel/asm/x86/syscall.S b/lunaix-os/kernel/asm/x86/syscall.S index b35a217..2d78828 100644 --- a/lunaix-os/kernel/asm/x86/syscall.S +++ b/lunaix-os/kernel/asm/x86/syscall.S @@ -42,12 +42,15 @@ .long __lxsys_link .long __lxsys_fsync .long __lxsys_dup - .long __lxsys_dup2 + .long __lxsys_dup2 /* 35 */ .long __lxsys_realpathat .long __lxsys_symlink .long __lxsys_chdir .long __lxsys_fchdir - .long __lxsys_getcwd + .long __lxsys_getcwd /* 40 */ + .long __lxsys_rename + .long __lxsys_mount + .long __lxsys_unmount 2: .rept __SYSCALL_MAX - (2b - 1b)/4 .long 0 diff --git a/lunaix-os/kernel/ds/hstr.c b/lunaix-os/kernel/ds/hstr.c new file mode 100644 index 0000000..6c043f3 --- /dev/null +++ b/lunaix-os/kernel/ds/hstr.c @@ -0,0 +1,10 @@ +#include +#include + +void +hstrcpy(struct hstr* dest, struct hstr* src) +{ + strcpy(dest->value, src->value); + dest->hash = src->hash; + dest->len = src->len; +} \ 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 506d604..6efc833 100644 --- a/lunaix-os/kernel/fs/twifs/twifs.c +++ b/lunaix-os/kernel/fs/twifs/twifs.c @@ -19,6 +19,8 @@ static struct twifs_node* fs_root; static struct cake_pile* twi_pile; +static volatile int32_t inode_id = 0; + int __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode); @@ -168,6 +170,7 @@ __twifs_create_inode(struct twifs_node* twi_node) inode->itype = twi_node->itype; inode->data = twi_node; + inode->id = inode_id++; inode->ctime = clock_unixtime(); inode->atime = inode->ctime; inode->mtime = inode->ctime; diff --git a/lunaix-os/kernel/fs/vfs.c b/lunaix-os/kernel/fs/vfs.c index 82f409a..207427f 100644 --- a/lunaix-os/kernel/fs/vfs.c +++ b/lunaix-os/kernel/fs/vfs.c @@ -20,6 +20,8 @@ #include #include +#include + #define PATH_DELIM '/' #define DNODE_HASHTABLE_BITS 10 #define DNODE_HASHTABLE_SIZE (1 << DNODE_HASHTABLE_BITS) @@ -82,13 +84,15 @@ vfs_init() } inline struct hbucket* -__dcache_get_bucket(struct v_dnode* parent, unsigned int hash) +__dcache_hash(struct v_dnode* parent, uint32_t* hash) { + uint32_t _hash = *hash; // 与parent的指针值做加法,来减小碰撞的可能性。 - hash += (uint32_t)parent; + _hash += (uint32_t)parent; // 确保低位更加随机 - hash = hash ^ (hash >> DNODE_HASHBITS); - return &dnode_cache[hash & DNODE_HASH_MASK]; + _hash = _hash ^ (_hash >> DNODE_HASHBITS); + *hash = _hash; + return &dnode_cache[_hash & DNODE_HASH_MASK]; } struct v_dnode* @@ -101,12 +105,13 @@ vfs_dcache_lookup(struct v_dnode* parent, struct hstr* str) return parent->parent ? parent->parent : parent; } - struct hbucket* slot = __dcache_get_bucket(parent, str->hash); + uint32_t hash = str->hash; + struct hbucket* slot = __dcache_hash(parent, &hash); struct v_dnode *pos, *n; hashtable_bucket_foreach(slot, pos, n, hash_list) { - if (pos->name.hash == str->hash) { + if (pos->name.hash == hash) { return pos; } } @@ -116,10 +121,18 @@ vfs_dcache_lookup(struct v_dnode* parent, struct hstr* str) void vfs_dcache_add(struct v_dnode* parent, struct v_dnode* dnode) { - struct hbucket* bucket = __dcache_get_bucket(parent, dnode->name.hash); + struct hbucket* bucket = __dcache_hash(parent, &dnode->name.hash); hlist_add(&bucket->head, &dnode->hash_list); } +void +vfs_dcache_rehash(struct v_dnode* parent, struct v_dnode* dnode) +{ + hlist_delete(&dnode->hash_list); + hstr_rehash(&dnode->name, HSTR_FULL_HASH); + vfs_dcache_add(parent, dnode); +} + int __vfs_walk(struct v_dnode* start, const char* path, @@ -186,9 +199,8 @@ __vfs_walk(struct v_dnode* start, if (!dnode) { dnode = vfs_d_alloc(); - dnode->name = HHSTR(valloc(VFS_NAME_MAXLEN), j, name.hash); - strcpy(dnode->name.value, name_content); + hstrcpy(&dnode->name, &name); lock_inode(current_level->inode); @@ -230,7 +242,6 @@ __vfs_walk(struct v_dnode* start, return 0; error: - vfree(dnode->name.value); vfs_d_free(dnode); *dentry = NULL; return errno; @@ -275,7 +286,7 @@ vfs_walk(struct v_dnode* start, } int -vfs_mount(const char* target, const char* fs_name, bdev_t device) +vfs_mount(const char* target, const char* fs_name, struct device* device) { int errno; struct v_dnode* mnt; @@ -301,11 +312,19 @@ vfs_unmount(const char* target) } int -vfs_mount_at(const char* fs_name, bdev_t device, struct v_dnode* mnt_point) +vfs_mount_at(const char* fs_name, + struct device* device, + struct v_dnode* mnt_point) { + if (!(mnt_point->inode->itype & VFS_IFDIR)) { + return ENOTDIR; + } + struct filesystem* fs = fsm_get(fs_name); - if (!fs) + if (!fs) { return ENODEV; + } + struct v_superblock* sb = vfs_sb_alloc(); sb->dev = device; sb->fs_id = fs_id++; @@ -324,6 +343,7 @@ vfs_mount_at(const char* fs_name, bdev_t device, struct v_dnode* mnt_point) int vfs_unmount_at(struct v_dnode* mnt_point) { + // FIXME mnt point check & deal with the detached dcache subtree int errno = 0; struct v_superblock* sb = mnt_point->super_block; if (!sb) { @@ -333,7 +353,9 @@ vfs_unmount_at(struct v_dnode* mnt_point) struct v_dnode* fs_root = sb->root; llist_delete(&fs_root->siblings); llist_delete(&sb->sb_list); + hlist_delete(&fs_root->hash_list); vfs_sb_free(sb); + vfs_d_free(fs_root); } return errno; } @@ -456,20 +478,22 @@ vfs_d_alloc() struct v_dnode* dnode = cake_grab(dnode_pile); memset(dnode, 0, sizeof(*dnode)); llist_init_head(&dnode->children); + llist_init_head(&dnode->siblings); mutex_init(&dnode->lock); dnode->ref_count = ATOMIC_VAR_INIT(0); + dnode->name = HHSTR(vzalloc(VFS_NAME_MAXLEN), 0, 0); - dnode->name = vfs_empty; return dnode; } void vfs_d_free(struct v_dnode* dnode) { - if (dnode->ops.destruct) { - dnode->ops.destruct(dnode); + if (dnode->inode && dnode->inode->link_count) { + dnode->inode->link_count--; } + vfree(dnode->name.value); cake_release(dnode_pile, dnode); } @@ -478,6 +502,7 @@ vfs_i_alloc() { struct v_inode* inode = cake_grab(inode_pile); memset(inode, 0, sizeof(*inode)); + inode->link_count = 1; mutex_init(&inode->lock); return inode; @@ -528,8 +553,7 @@ __vfs_try_locate_file(const char* path, struct v_dnode* parent = *fdir; struct v_dnode* file_new = vfs_d_alloc(); - file_new->name = HHSTR(valloc(VFS_NAME_MAXLEN), name.len, name.hash); - strcpy(file_new->name.value, name_str); + hstrcpy(&file_new->name, &name); if (!(errno = parent->inode->ops.create(parent->inode, file_new))) { *file = file_new; @@ -537,7 +561,6 @@ __vfs_try_locate_file(const char* path, vfs_dcache_add(parent, file_new); llist_append(&parent->children, &file_new->siblings); } else { - vfree(file_new->name.value); vfs_d_free(file_new); } @@ -907,7 +930,14 @@ __DEFINE_LXSYSCALL1(int, rmdir, const char*, pathname) if ((dnode->inode->itype & VFS_IFDIR)) { errno = dnode->inode->ops.rmdir(dnode->inode); - // FIXME remove the dnode from cache & parent. + if (!errno) { + llist_delete(&dnode->siblings); + hlist_delete(&dnode->hash_list); + unlock_inode(dnode->inode); + vfs_d_free(dnode); + + goto done; + } } else { errno = ENOTDIR; } @@ -923,10 +953,9 @@ done: __DEFINE_LXSYSCALL1(int, mkdir, const char*, path) { - struct v_dnode *parent, *dir; - struct hstr component = HSTR(valloc(VFS_NAME_MAXLEN), 0); + struct v_dnode *parent, *dir = vfs_d_alloc(); int errno = - vfs_walk(__current->cwd, path, &parent, &component, VFS_WALK_PARENT); + vfs_walk(__current->cwd, path, &parent, &dir->name, VFS_WALK_PARENT); if (errno) { goto done; } @@ -940,20 +969,16 @@ __DEFINE_LXSYSCALL1(int, mkdir, const char*, path) errno = ENOTSUP; } else if (!(parent->inode->itype & VFS_IFDIR)) { errno = ENOTDIR; - } else { - dir = vfs_d_alloc(); - dir->name = component; - if (!(errno = parent->inode->ops.mkdir(parent->inode, dir))) { - llist_append(&parent->children, &dir->siblings); - } else { - vfs_d_free(dir); - vfree(component.value); - } + } else if (!(errno = parent->inode->ops.mkdir(parent->inode, dir))) { + llist_append(&parent->children, &dir->siblings); + goto cleanup; } + vfs_d_free(dir); + +cleanup: unlock_inode(parent->inode); unlock_dnode(parent); - done: return DO_STATUS(errno); } @@ -978,7 +1003,9 @@ __vfs_do_unlink(struct v_dnode* dnode) errno = inode->ops.unlink(inode); if (!errno) { inode->link_count--; - // FIXME remove the dnode from cache & parent + llist_delete(&dnode->siblings); + hlist_delete(&dnode->hash_list); + vfs_d_free(dnode); } } else { errno = EISDIR; @@ -1240,4 +1267,136 @@ done: return ret_ptr; } -// TODO rename syscall \ No newline at end of file +int +vfs_do_rename(struct v_dnode* current, struct v_dnode* target) +{ + if (current->inode->id == target->inode->id) { + // hard link + return 0; + } + + if (current->ref_count || target->ref_count) { + return EBUSY; + } + + if (current->super_block != target->super_block) { + return EXDEV; + } + + int errno = 0; + + struct v_dnode* oldparent = current->parent; + struct v_dnode* newparent = target->parent; + + lock_dnode(current); + lock_dnode(target); + if (oldparent) + lock_dnode(oldparent); + if (newparent) + lock_dnode(newparent); + + if (!llist_empty(&target->children)) { + errno = ENOTEMPTY; + unlock_dnode(target); + goto cleanup; + } + + if ((errno = current->inode->ops.rename(current->inode, current, target))) { + unlock_dnode(target); + goto cleanup; + } + + // re-position current + current->parent = newparent; + hstrcpy(¤t->name, &target->name); + llist_delete(¤t->siblings); + llist_append(&newparent->children, ¤t->siblings); + vfs_dcache_rehash(newparent, current); + + // detach target + llist_delete(&target->siblings); + hlist_delete(&target->hash_list); + + unlock_dnode(target); + +cleanup: + unlock_dnode(current); + if (oldparent) + unlock_dnode(oldparent); + if (newparent) + unlock_dnode(newparent); + + return errno; +} + +__DEFINE_LXSYSCALL2(int, rename, const char*, oldpath, const char*, newpath) +{ + struct v_dnode *cur, *target_parent, *target; + struct hstr name = HSTR(valloc(VFS_NAME_MAXLEN), 0); + int errno = 0; + + if ((errno = vfs_walk(__current->cwd, oldpath, &cur, NULL, 0))) { + goto done; + } + + if ((errno = vfs_walk( + __current->cwd, newpath, &target_parent, &name, VFS_WALK_PARENT))) { + goto done; + } + + errno = vfs_walk(target_parent, name.value, &target, NULL, 0); + if (errno == ENOENT) { + target = vfs_d_alloc(); + hstrcpy(&target->name, &name); + } else if (errno) { + goto done; + } + + if (!(errno = vfs_do_rename(cur, target))) { + vfs_d_free(target); + } + +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 (!(dev->inode->itype & VFS_IFVOLDEV)) { + errno = ENOTDEV; + goto done; + } + + // FIXME should not touch the underlying fs! + struct device* device = + (struct device*)((struct twifs_node*)dev->inode->data)->data; + + 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 b0aee84..ae98ac1 100644 --- a/lunaix-os/kernel/k_init.c +++ b/lunaix-os/kernel/k_init.c @@ -1,20 +1,15 @@ #include #include -#include #include #include -#include #include #include #include #include #include #include -#include -#include - -#include +#include #include #include @@ -23,9 +18,6 @@ #include #include -#include -#include - extern uint8_t __kernel_start; extern uint8_t __kernel_end; extern uint8_t __init_hhk_end; @@ -39,8 +31,6 @@ x86_page_table* __kernel_ptd; struct proc_info tmp; -LOG_MODULE("BOOT"); - extern void __proc0(); /* proc0.c */ @@ -58,7 +48,6 @@ _kernel_pre_init() pmm_init(MEM_1MB + (_k_init_mb_info->mem_upper << 10)); vmm_init(); - rtc_init(); unsigned int map_size = _k_init_mb_info->mmap_length / sizeof(multiboot_memory_map_t); @@ -89,7 +78,7 @@ _kernel_init() device_init(); // 挂载 TwiFS 为根目录 - vfs_mount("/", "twifs", -1); + vfs_mount("/", "twifs", NULL); lxconsole_init(); diff --git a/lunaix-os/kernel/proc0.c b/lunaix-os/kernel/proc0.c index 5fac5f8..3c2ea5f 100644 --- a/lunaix-os/kernel/proc0.c +++ b/lunaix-os/kernel/proc0.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -15,13 +14,16 @@ #include #include #include -#include +#include #include #include #include #include #include +#include + +#include #include @@ -139,8 +141,10 @@ init_platform() // 锁定所有系统预留页(内存映射IO,ACPI之类的),并且进行1:1映射 lock_reserved_memory(); - assert_msg(kalloc_init(), "Fail to initialize heap"); + // we are using no kalloc! + // assert_msg(kalloc_init(), "Fail to initialize heap"); + rtc_init(); acpi_init(_k_init_mb_info); apic_init(); ioapic_init();