From 4b6190b935dd75d8ddd514a05c7c7343e32c0cdc Mon Sep 17 00:00:00 2001 From: Minep Date: Wed, 31 Aug 2022 14:50:03 +0100 Subject: [PATCH] feat: simple read/write lock implementation feat: mutex lock owenership checking feat: mount points export chore: cleanups and fixes --- lunaix-os/includes/lunaix/ds/mutex.h | 38 +++++++++++------- lunaix-os/includes/lunaix/ds/rwlock.h | 28 +++++++++++++ lunaix-os/includes/lunaix/ds/waitq.h | 8 +++- lunaix-os/includes/lunaix/fs.h | 9 +++++ lunaix-os/kernel/demos/simple_sh.c | 4 +- lunaix-os/kernel/ds/mutex.c | 24 +++++++++++ lunaix-os/kernel/ds/rwlock.c | 58 +++++++++++++++++++++++++++ lunaix-os/kernel/fs/fs_export.c | 47 ++++++++++++++++++++++ lunaix-os/kernel/fs/mount.c | 2 +- lunaix-os/kernel/fs/vfs.c | 43 ++++++++++++-------- lunaix-os/kernel/k_init.c | 2 + lunaix-os/kernel/process/sched.c | 2 +- 12 files changed, 229 insertions(+), 36 deletions(-) create mode 100644 lunaix-os/includes/lunaix/ds/rwlock.h create mode 100644 lunaix-os/kernel/ds/mutex.c create mode 100644 lunaix-os/kernel/ds/rwlock.c create mode 100644 lunaix-os/kernel/fs/fs_export.c diff --git a/lunaix-os/includes/lunaix/ds/mutex.h b/lunaix-os/includes/lunaix/ds/mutex.h index 5e166e5..97101ef 100644 --- a/lunaix-os/includes/lunaix/ds/mutex.h +++ b/lunaix-os/includes/lunaix/ds/mutex.h @@ -2,25 +2,33 @@ #define __LUNAIX_MUTEX_H #include "semaphore.h" - -// TODO: implement mutex lock - -typedef struct sem_t mutex_t; - -static inline void mutex_init(mutex_t *mutex) { - sem_init(mutex, 1); +#include + +typedef struct mutex_s +{ + struct sem_t sem; + pid_t owner; +} mutex_t; + +static inline void +mutex_init(mutex_t* mutex) +{ + sem_init(&mutex->sem, 1); } -static inline unsigned int mutex_on_hold(mutex_t *mutex) { - return !atomic_load(&mutex->counter); +static inline int +mutex_on_hold(mutex_t* mutex) +{ + return !atomic_load(&mutex->sem.counter); } -static inline void mutex_lock(mutex_t *mutex) { - sem_wait(mutex); -} +void +mutex_lock(mutex_t* mutex); -static inline void mutex_unlock(mutex_t *mutex) { - sem_post(mutex); -} +void +mutex_unlock(mutex_t* mutex); + +void +mutex_unlock_for(mutex_t* mutex, pid_t pid); #endif /* __LUNAIX_MUTEX_H */ diff --git a/lunaix-os/includes/lunaix/ds/rwlock.h b/lunaix-os/includes/lunaix/ds/rwlock.h new file mode 100644 index 0000000..7dda9ad --- /dev/null +++ b/lunaix-os/includes/lunaix/ds/rwlock.h @@ -0,0 +1,28 @@ +#ifndef __LUNAIX_RWLOCK_H +#define __LUNAIX_RWLOCK_H + +#include "mutex.h" +#include "waitq.h" +#include + +typedef struct rwlock_s +{ + atomic_uint readers; + atomic_flag writer; + waitq_t waiting_readers; + waitq_t waiting_writers; +} rwlock_t; + +void +rwlock_begin_read(rwlock_t* rwlock); + +void +rwlock_end_read(rwlock_t* rwlock); + +void +rwlock_begin_write(rwlock_t* rwlock); + +void +rwlock_end_write(rwlock_t* rwlock); + +#endif /* __LUNAIX_RWLOCK_H */ diff --git a/lunaix-os/includes/lunaix/ds/waitq.h b/lunaix-os/includes/lunaix/ds/waitq.h index dfeb7c3..4014d05 100644 --- a/lunaix-os/includes/lunaix/ds/waitq.h +++ b/lunaix-os/includes/lunaix/ds/waitq.h @@ -8,12 +8,18 @@ typedef struct waitq struct llist_header waiters; } waitq_t; -inline void +static inline void waitq_init(waitq_t* waitq) { llist_init_head(&waitq->waiters); } +static inline int +waitq_empty(waitq_t* waitq) +{ + return llist_empty(&waitq->waiters); +} + void pwait(waitq_t* queue); diff --git a/lunaix-os/includes/lunaix/fs.h b/lunaix-os/includes/lunaix/fs.h index 2fee2f2..d106178 100644 --- a/lunaix-os/includes/lunaix/fs.h +++ b/lunaix-os/includes/lunaix/fs.h @@ -281,6 +281,9 @@ fsm_get(const char* fs_name); void vfs_init(); +void +vfs_export_attributes(); + struct v_dnode* vfs_dcache_lookup(struct v_dnode* parent, struct hstr* str); @@ -330,6 +333,9 @@ vfs_mkdir(const char* path, struct v_dnode** dentry); int vfs_open(struct v_dnode* dnode, struct v_file** file); +int +vfs_pclose(struct v_file* file, pid_t pid); + int vfs_close(struct v_file* file); @@ -378,6 +384,9 @@ vfs_ref_dnode(struct v_dnode* dnode); void vfs_unref_dnode(struct v_dnode* dnode); +int +vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth); + void pcache_init(struct pcache* pcache); diff --git a/lunaix-os/kernel/demos/simple_sh.c b/lunaix-os/kernel/demos/simple_sh.c index 5e89194..3a1e1bb 100644 --- a/lunaix-os/kernel/demos/simple_sh.c +++ b/lunaix-os/kernel/demos/simple_sh.c @@ -124,8 +124,8 @@ sh_loop() pid_t p; signal(_SIGINT, sigint_handle); - // set our shell as foreground process (unistd.h:tcsetpgrp is wrapper of - // this) + // set our shell as foreground process + // (unistd.h:tcsetpgrp is essentially a wrapper of this) // stdout (by default, unless user did smth) is the tty we are currently at ioctl(stdout, TIOCSPGRP, getpgid()); diff --git a/lunaix-os/kernel/ds/mutex.c b/lunaix-os/kernel/ds/mutex.c new file mode 100644 index 0000000..7bfbf10 --- /dev/null +++ b/lunaix-os/kernel/ds/mutex.c @@ -0,0 +1,24 @@ +#include +#include + +void +mutex_lock(mutex_t* mutex) +{ + sem_wait(&mutex->sem); + mutex->owner = __current->pid; +} + +void +mutex_unlock(mutex_t* mutex) +{ + mutex_unlock_for(mutex, __current->pid); +} + +void +mutex_unlock_for(mutex_t* mutex, pid_t pid) +{ + if (mutex->owner != pid) { + return; + } + sem_post(&mutex->sem); +} \ No newline at end of file diff --git a/lunaix-os/kernel/ds/rwlock.c b/lunaix-os/kernel/ds/rwlock.c new file mode 100644 index 0000000..383e4c4 --- /dev/null +++ b/lunaix-os/kernel/ds/rwlock.c @@ -0,0 +1,58 @@ +#include +#include + +void +rwlock_init(rwlock_t* rwlock) +{ + waitq_init(&rwlock->waiting_readers); + waitq_init(&rwlock->waiting_writers); + atomic_init(&rwlock->readers, 0); + atomic_flag_clear(&rwlock->writer); +} + +void +rwlock_begin_read(rwlock_t* rwlock) +{ + while (atomic_flag_test_and_set(&rwlock->writer)) { + pwait(&rwlock->waiting_readers); + } + atomic_fetch_add(&rwlock->readers, 1); + atomic_flag_clear(&rwlock->writer); + pwake_all(&rwlock->waiting_readers); +} + +void +rwlock_end_read(rwlock_t* rwlock) +{ + assert(atomic_load(&rwlock->readers) > 0); + atomic_fetch_sub(&rwlock->readers, 1); + + if (!atomic_load(&rwlock->readers)) { + pwake_one(&rwlock->waiting_writers); + } +} + +void +rwlock_begin_write(rwlock_t* rwlock) +{ + // first, acquire writer lock, prevent any incoming readers + while (atomic_flag_test_and_set(&rwlock->writer)) { + pwait(&rwlock->waiting_writers); + } + + // then, wait for reader finish the read. + while (atomic_load(&rwlock->readers)) { + pwait(&rwlock->waiting_writers); + } +} + +void +rwlock_end_write(rwlock_t* rwlock) +{ + atomic_flag_clear(&rwlock->writer); + if (waitq_empty(&rwlock->waiting_writers)) { + pwake_all(&rwlock->waiting_readers); + } else { + pwake_one(&rwlock->waiting_writers); + } +} \ No newline at end of file diff --git a/lunaix-os/kernel/fs/fs_export.c b/lunaix-os/kernel/fs/fs_export.c new file mode 100644 index 0000000..13d6557 --- /dev/null +++ b/lunaix-os/kernel/fs/fs_export.c @@ -0,0 +1,47 @@ +#include +#include +#include + +extern struct llist_header all_mnts; + +void +__mount_read(struct twimap* map) +{ + char path[512]; + struct v_mount* mnt = twimap_index(map, struct v_mount*); + size_t len = vfs_get_path(mnt->mnt_point, path, 511, 0); + path[len] = '\0'; + twimap_printf(map, "%s at %s", mnt->super_block->fs->fs_name.value, path); + if ((mnt->flags & MNT_RO)) { + twimap_printf(map, ", ro"); + } else { + twimap_printf(map, ", rw"); + } + twimap_printf(map, "\n"); +} + +int +__mount_next(struct twimap* map) +{ + struct v_mount* mnt = twimap_index(map, struct v_mount*); + if (mnt->list.next == &all_mnts) { + return 0; + } + map->index = container_of(mnt->list.next, struct v_mount, list); + return 1; +} + +void +__mount_reset(struct twimap* map) +{ + map->index = container_of(all_mnts.next, struct v_mount, list); +} + +void +vfs_export_attributes() +{ + struct twimap* map = twifs_mapping(NULL, NULL, "mounts"); + map->read = __mount_read; + map->go_next = __mount_next; + map->reset = __mount_reset; +} \ No newline at end of file diff --git a/lunaix-os/kernel/fs/mount.c b/lunaix-os/kernel/fs/mount.c index 38258ee..ff8d46b 100644 --- a/lunaix-os/kernel/fs/mount.c +++ b/lunaix-os/kernel/fs/mount.c @@ -4,7 +4,7 @@ #include #include -static struct llist_header all_mnts = { .next = &all_mnts, .prev = &all_mnts }; +struct llist_header all_mnts = { .next = &all_mnts, .prev = &all_mnts }; struct v_mount* vfs_create_mount(struct v_mount* parent, struct v_dnode* mnt_point) diff --git a/lunaix-os/kernel/fs/vfs.c b/lunaix-os/kernel/fs/vfs.c index 476b00b..c9431ba 100644 --- a/lunaix-os/kernel/fs/vfs.c +++ b/lunaix-os/kernel/fs/vfs.c @@ -254,7 +254,7 @@ vfs_link(struct v_dnode* to_link, struct v_dnode* name) } int -vfs_close(struct v_file* file) +vfs_pclose(struct v_file* file, pid_t pid) { int errno = 0; if (file->ref_count > 1) { @@ -263,26 +263,25 @@ vfs_close(struct v_file* file) atomic_fetch_sub(&file->dnode->ref_count, 1); file->inode->open_count--; - // Remove dead lock. + // Prevent dead lock. // This happened when process is terminated while blocking on read. // In that case, the process is still holding the inode lock and it will // never get released. - // FIXME is this a good solution? /* - * Consider two process both open the same file both with fd=x. + * The unlocking should also include ownership check. + * + * To see why, consider two process both open the same file both with + * fd=x. * Process A: busy on reading x * Process B: do nothing with x - * Assume that, after a very short time, process B get terminated while - * process A is still busy in it's reading business. By this design, the - * inode lock of this file x is get released by B rather than A. And - * this will cause a probable race condition on A if other process is - * writing to this file later after B exit. - * - * A possible solution is to add a owner identification in the lock - * context, so only the lock holder can do the release. + * Assuming that, after a very short time, process B get terminated + * while process A is still busy in it's reading business. By this + * design, the inode lock of this file x is get released by B rather + * than A. And this will cause a probable race condition on A if other + * process is writing to this file later after B exit. */ if (mutex_on_hold(&file->inode->lock)) { - unlock_inode(file->inode); + mutex_unlock_for(&file->inode->lock, pid); } mnt_chillax(file->dnode->mnt); @@ -292,6 +291,12 @@ vfs_close(struct v_file* file) return errno; } +int +vfs_close(struct v_file* file) +{ + return vfs_pclose(file, __current->pid); +} + int vfs_fsync(struct v_file* file) { @@ -773,7 +778,7 @@ done: int vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth) { - if (!dnode || dnode->parent == dnode) { + if (!dnode) { return 0; } @@ -781,13 +786,19 @@ vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth) return ENAMETOOLONG; } - size_t len = vfs_get_path(dnode->parent, buf, size, depth + 1); + size_t len = 0; + + if (dnode->parent != dnode) { + len = vfs_get_path(dnode->parent, buf, size, depth + 1); + } if (len >= size) { return len; } - buf[len++] = VFS_PATH_DELIM; + if (!len || buf[len - 1] != VFS_PATH_DELIM) { + buf[len++] = VFS_PATH_DELIM; + } size_t cpy_size = MIN(dnode->name.len, size - len); strncpy(buf + len, dnode->name.value, cpy_size); diff --git a/lunaix-os/kernel/k_init.c b/lunaix-os/kernel/k_init.c index fc6c51c..fe9cf90 100644 --- a/lunaix-os/kernel/k_init.c +++ b/lunaix-os/kernel/k_init.c @@ -78,6 +78,8 @@ _kernel_init() fsm_init(); input_init(); + vfs_export_attributes(); + if ((errno = vfs_mount_root("ramfs", NULL))) { panickf("Fail to mount root. (errno=%d)", errno); } diff --git a/lunaix-os/kernel/process/sched.c b/lunaix-os/kernel/process/sched.c index c48de8e..0a9cea2 100644 --- a/lunaix-os/kernel/process/sched.c +++ b/lunaix-os/kernel/process/sched.c @@ -342,7 +342,7 @@ destroy_process(pid_t pid) for (size_t i = 0; i < VFS_MAX_FD; i++) { struct v_fd* fd = proc->fdtable->fds[i]; if (fd) - vfs_close(fd->file); + vfs_pclose(fd->file, pid); } vfree(proc->fdtable); -- 2.27.0