diff --git a/kernel-src/arch/x86-64/syscall.asm b/kernel-src/arch/x86-64/syscall.asm index 241d0928..44bddf9f 100644 --- a/kernel-src/arch/x86-64/syscall.asm +++ b/kernel-src/arch/x86-64/syscall.asm @@ -65,6 +65,7 @@ extern syscall_sigreturn extern syscall_uname extern syscall_hostname extern syscall_sync +extern syscall_fsync syscalltab: dq syscall_print dq syscall_mmap @@ -132,7 +133,8 @@ dq syscall_sigreturn dq syscall_uname dq syscall_hostname dq syscall_sync -syscallcount equ 66 +dq syscall_fsync +syscallcount equ 67 section .text global arch_syscall_entry ; on entry: diff --git a/kernel-src/arch/x86-64/syscalllog.c b/kernel-src/arch/x86-64/syscalllog.c index e38aaa4a..b4ef52b0 100644 --- a/kernel-src/arch/x86-64/syscalllog.c +++ b/kernel-src/arch/x86-64/syscalllog.c @@ -4,7 +4,7 @@ #ifdef SYSCALL_LOGGING -#define SYSCALL_COUNT 66 +#define SYSCALL_COUNT 67 #define LOGSTR(x) arch_e9_puts(x) static char *name[] = { @@ -73,7 +73,8 @@ static char *name[] = { "sigreturn", "uname", "hostname", - "sync" + "sync", + "fsync" }; static char *args[] = { @@ -142,7 +143,8 @@ static char *args[] = { "N/A", // sigreturn "utsname %p", // uname "new %p newsize %lu old %p oldsize %lu", // hostname - "N/A" // sync + "N/A", // sync + "fd %d" // fsync }; #endif diff --git a/kernel-src/fs/ext2.c b/kernel-src/fs/ext2.c index 45e760aa..a27d3209 100644 --- a/kernel-src/fs/ext2.c +++ b/kernel-src/fs/ext2.c @@ -1654,6 +1654,15 @@ static int ext2_rename(vnode_t *sourcedir, char *oldname, vnode_t *targetdir, ch return err; } +static int ext2_sync(vnode_t *vnode) { + int e = vmmcache_sync(vnode); + ext2fs_t *fs = (ext2fs_t *)vnode->vfs; + // TODO don't sync the entire disk but rather only the inodes and blocks + int e2 = vmmcache_sync(fs->backing); + // only the first errors are reported + return e ? e : e2; +} + static int ext2_inactive(vnode_t *vnode) { ext2node_t *node = (ext2node_t *)vnode; ext2fs_t *fs = (ext2fs_t *)vnode->vfs; @@ -1829,7 +1838,8 @@ static vops_t vnops = { .inactive = ext2_inactive, .rename = ext2_rename, .getpage = ext2_getpage, - .putpage = ext2_putpage + .putpage = ext2_putpage, + .sync = ext2_sync }; void ext2_init() { diff --git a/kernel-src/fs/pipefs.c b/kernel-src/fs/pipefs.c index 8274ab9b..3cbacc8e 100644 --- a/kernel-src/fs/pipefs.c +++ b/kernel-src/fs/pipefs.c @@ -260,7 +260,8 @@ static vops_t vnops = { .resize = pipefs_enodev, .rename = pipefs_enodev, .putpage = pipefs_enodev, - .getpage = pipefs_enodev + .getpage = pipefs_enodev, + .sync = pipefs_enodev }; static void ctor(scache_t *cache, void *obj) { diff --git a/kernel-src/fs/sockfs.c b/kernel-src/fs/sockfs.c index ae153e89..a22633fa 100644 --- a/kernel-src/fs/sockfs.c +++ b/kernel-src/fs/sockfs.c @@ -186,7 +186,8 @@ static vops_t vnops = { .rename = sockfs_enodev, .ioctl = sockfs_ioctl, .putpage = sockfs_enodev, - .getpage = sockfs_enodev + .getpage = sockfs_enodev, + .sync = sockfs_enodev }; static void ctor(scache_t *cache, void *obj) { diff --git a/kernel-src/fs/tmpfs.c b/kernel-src/fs/tmpfs.c index 2d940c04..7abfed8c 100644 --- a/kernel-src/fs/tmpfs.c +++ b/kernel-src/fs/tmpfs.c @@ -493,6 +493,11 @@ static int tmpfs_putpage(vnode_t *node, uintmax_t offset, struct page_t *page) { return 0; } +static int tmpfs_sync(vnode_t *node) { + // sync is a no-op on tmpfs + return 0; +} + static vfsops_t vfsops = { .mount = tmpfs_mount, .root = tmpfs_root @@ -520,7 +525,8 @@ static vops_t vnops = { .resize = tmpfs_resize, .rename = tmpfs_rename, .getpage = tmpfs_getpage, - .putpage = tmpfs_putpage + .putpage = tmpfs_putpage, + .sync = tmpfs_sync }; static tmpfsnode_t *newnode(vfs_t *vfs, int type) { diff --git a/kernel-src/include/kernel/vfs.h b/kernel-src/include/kernel/vfs.h index f3803500..ff24b09a 100644 --- a/kernel-src/include/kernel/vfs.h +++ b/kernel-src/include/kernel/vfs.h @@ -105,6 +105,7 @@ typedef struct vops_t { int (*rename)(vnode_t *source, char *oldname, vnode_t *target, char *newname, int flags); int (*getpage)(vnode_t *node, uintmax_t offset, struct page_t *page); int (*putpage)(vnode_t *node, uintmax_t offset, struct page_t *page); + int (*sync)(vnode_t *node); } vops_t; #define VFS_INIT(v, o, f) \ @@ -156,6 +157,7 @@ typedef struct vops_t { #define VOP_RENAME(s, o, t, n, f) (s)->ops->rename(s, o, t, n, f) #define VOP_GETPAGE(v, o, p) (v)->ops->getpage(v, o, p) #define VOP_PUTPAGE(v, o, p) (v)->ops->putpage(v, o, p) +#define VOP_SYNC(v) (v)->ops->sync(v) #define VOP_HOLD(v) __atomic_add_fetch(&(v)->refcount, 1, __ATOMIC_SEQ_CST) #define VOP_RELEASE(v) {\ if (__atomic_sub_fetch(&(v)->refcount, 1, __ATOMIC_SEQ_CST) == 0) {\ diff --git a/kernel-src/include/kernel/vmmcache.h b/kernel-src/include/kernel/vmmcache.h index 334e9df4..97c436fb 100644 --- a/kernel-src/include/kernel/vmmcache.h +++ b/kernel-src/include/kernel/vmmcache.h @@ -9,7 +9,7 @@ int vmmcache_getpage(vnode_t *vnode, uintmax_t offset, page_t **res); int vmmcache_takepage(page_t *page); int vmmcache_makedirty(page_t *page); int vmmcache_truncate(vnode_t *vnode, uintmax_t offset); -int vmmcache_syncvnode(vnode_t *vnode); +int vmmcache_syncvnode(vnode_t *vnode, uintmax_t startoffset, size_t size); int vmmcache_sync(); #endif diff --git a/kernel-src/mm/vmmcache.c b/kernel-src/mm/vmmcache.c index 999e313c..b2d11ee6 100644 --- a/kernel-src/mm/vmmcache.c +++ b/kernel-src/mm/vmmcache.c @@ -232,12 +232,73 @@ int vmmcache_truncate(vnode_t *vnode, uintmax_t offset) { return 0; } -int vmmcache_syncvnode(vnode_t *vnode) { - __assert(!"unimplemented"); +// called with lock held +// returns with lock released +static int syncpage(page_t *page) { + __assert(page->flags & PAGE_FLAGS_DIRTY); + page->flags &= ~PAGE_FLAGS_DIRTY; + RELEASE_LOCK(); + int e = 0; + if ((page->flags & PAGE_FLAGS_TRUNCATED) == 0) { + e = VOP_PUTPAGE(page->backing, page->offset, (page_t *)page); + VOP_RELEASE(page->backing); + } + + pmm_release(pmm_getpageaddress((page_t *)page)); + return e; } static page_t *dirtylist; +int vmmcache_syncvnode(vnode_t *vnode, uintmax_t offset, size_t size) { + offset = ROUND_DOWN(offset, PAGE_SIZE); + uintmax_t top = offset + size; + // overflow check + __assert(top > offset); + HOLD_LOCK(); + + // loop through all vnode pages in memory and check which ones are in the range and are dirty + // TODO create a proper vnode dirty list as to not have to loop through the ENTIRE thing in memory + page_t *page = vnode->pages; + page_t *vnodedirtylist = NULL; + for (; page; page = page->vnodenext) { + if (page->offset < offset || page->offset >= top) + continue; + + // remove from write list and add to an internal list using the write pointers + // in a singly linked list way + if (page->writenext) + page->writenext->writeprev = page->writeprev; + + if (page->writeprev) + page->writeprev->writenext = page->writenext; + else + dirtylist = page->writenext; + + page->writenext = vnodedirtylist; + page->writeprev = NULL; + vnodedirtylist = page; + } + + RELEASE_LOCK(); + + int e = 0; + while (vnodedirtylist) { + // in the case of failure, only the first error to occur will be reported and we will not + // retry the write and keep on syncing the pages to disk + HOLD_LOCK(); + page_t *page = vnodedirtylist; + vnodedirtylist = vnodedirtylist->writenext; + page->writenext = NULL; + int error = syncpage(page); + if (e == 0) + e = error; + // syncpage returns with lock released + } + + return e; +} + int vmmcache_sync() { polldesc_t polldesc = {0}; int e = poll_initdesc(&polldesc, 1); @@ -313,22 +374,13 @@ static void writer() { continue; } - __assert(page->flags & PAGE_FLAGS_DIRTY); - page->flags &= ~PAGE_FLAGS_DIRTY; - dirtylist = page->writenext; if (dirtylist) dirtylist->writeprev = NULL; page->writenext = NULL; - - RELEASE_LOCK(); - if ((page->flags & PAGE_FLAGS_TRUNCATED) == 0) { - VOP_PUTPAGE(page->backing, page->offset, (page_t *)page); - VOP_RELEASE(page->backing); - } - - pmm_release(pmm_getpageaddress((page_t *)page)); + // TODO notify error on vmmcache_syncvnode + syncpage((page_t *)page); } } diff --git a/kernel-src/sys/syscalls/sync.c b/kernel-src/sys/syscalls/sync.c index 6ea965c4..a2b768a2 100644 --- a/kernel-src/sys/syscalls/sync.c +++ b/kernel-src/sys/syscalls/sync.c @@ -6,3 +6,20 @@ syscallret_t syscall_sync(context_t *) { vmmcache_sync(); return ret; } + +syscallret_t syscall_fsync(context_t *context, int fd) { + syscallret_t ret = { + .ret = -1 + }; + + file_t *file = fd_get(fd); + if (file == NULL) { + ret.errno = EBADF; + return ret; + } + + ret.errno = VOP_SYNC(file->vnode); + + fd_release(file); + return ret; +} diff --git a/patches/mlibc/jinx-working-patch.patch b/patches/mlibc/jinx-working-patch.patch index ff12cb54..f8dbe108 100644 --- a/patches/mlibc/jinx-working-patch.patch +++ b/patches/mlibc/jinx-working-patch.patch @@ -192,10 +192,10 @@ index 0000000..e5b087a + diff --git mlibc-workdir/sysdeps/astral/generic/generic.cpp mlibc-workdir/sysdeps/astral/generic/generic.cpp new file mode 100644 -index 0000000..12da52c +index 0000000..e94f84f --- /dev/null +++ mlibc-workdir/sysdeps/astral/generic/generic.cpp -@@ -0,0 +1,695 @@ +@@ -0,0 +1,694 @@ +#include +#include +#include @@ -248,8 +248,7 @@ index 0000000..12da52c +} +#endif + -+namespace mlibc { -+ ++namespace mlibc { + int sys_setuid(uid_t id) { + // TODO UNSTUB + return 0; @@ -279,6 +278,16 @@ index 0000000..12da52c + // TODO UNSTUB + return 0; + } ++ ++ int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) { ++ // TODO unstub ++ return ENOSYS; ++ } ++ ++ int sys_fsync(int fd) { ++ long ret; ++ return syscall(SYSCALL_FSYNC, &ret, fd); ++ } + + pid_t sys_getppid() { + long ret; @@ -320,16 +329,6 @@ index 0000000..12da52c + syscall(SYSCALL_SYNC, &ret); + } + -+ int sys_fsync(int fd) { -+ // TODO as the VFS does not do caching as of yet, this system call is stubbed and should be implemented once caching is done -+ return 0; -+ } -+ -+ int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) { -+ // TODO unstub -+ return ENOSYS; -+ } -+ + #ifndef MLIBC_BUILDING_RTLD + int sys_getentropy(void *buffer, size_t length) { + int fd; @@ -910,10 +909,10 @@ index 0000000..990eca0 +#endif diff --git mlibc-workdir/sysdeps/astral/include/astral/syscall.h mlibc-workdir/sysdeps/astral/include/astral/syscall.h new file mode 100644 -index 0000000..7daaf11 +index 0000000..5148ce4 --- /dev/null +++ mlibc-workdir/sysdeps/astral/include/astral/syscall.h -@@ -0,0 +1,89 @@ +@@ -0,0 +1,90 @@ +#ifndef _SYSCALL_H_INCLUDE +#define _SYSCALL_H_INCLUDE + @@ -983,6 +982,7 @@ index 0000000..7daaf11 +#define SYSCALL_UNAME 63 +#define SYSCALL_HOSTNAME 64 +#define SYSCALL_SYNC 65 ++#define SYSCALL_FSYNC 66 + +#include +#include