From ee254a81e952cb45a3ef85233337ba088195dc29 Mon Sep 17 00:00:00 2001 From: Matheus Date: Wed, 4 Sep 2024 21:33:59 -0300 Subject: [PATCH] vfs: vfs_iscacheable --- kernel-src/fs/vfs.c | 4 ++-- kernel-src/include/kernel/vfs.h | 10 ++++++++++ kernel-src/mm/vmm.c | 16 ++++++++-------- kernel-src/sys/syscalls/mmap.c | 5 ++--- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/kernel-src/fs/vfs.c b/kernel-src/fs/vfs.c index feeecd11..4728e334 100644 --- a/kernel-src/fs/vfs.c +++ b/kernel-src/fs/vfs.c @@ -230,7 +230,7 @@ static int writenocache(vnode_t *node, page_t *page, uintmax_t pageoffset) { int vfs_write(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t *written, int flags) { VOP_LOCK(node); int err = 0; - if (node->type == V_TYPE_REGULAR || node->type == V_TYPE_BLKDEV) { + if (vfs_iscacheable(node)) { *written = 0; // can't write a size 0 buffer if (size == 0) @@ -328,7 +328,7 @@ int vfs_write(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t int vfs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t *bytesread, int flags) { VOP_LOCK(node); int err = 0; - if (node->type == V_TYPE_REGULAR || node->type == V_TYPE_BLKDEV) { + if (vfs_iscacheable(node)) { *bytesread = 0; // can't read 0 bytes from the cache if (size == 0) diff --git a/kernel-src/include/kernel/vfs.h b/kernel-src/include/kernel/vfs.h index eebe6678..56c734ec 100644 --- a/kernel-src/include/kernel/vfs.h +++ b/kernel-src/include/kernel/vfs.h @@ -270,4 +270,14 @@ static inline mode_t vfs_getsystemtype(int type) { } } +static inline bool vfs_iscacheable(vnode_t *vnode) { + int type = vnode->type; + // vnodes will be cacheable if: + // - the vnode is a regular or block device + // AND + // - the filesystem implementation exposes the VOP_*PAGE operations. + + return (type == V_TYPE_REGULAR || type == V_TYPE_BLKDEV) && vnode->ops->putpage && vnode->ops->getpage; +} + #endif diff --git a/kernel-src/mm/vmm.c b/kernel-src/mm/vmm.c index 641e59b9..b9c65840 100644 --- a/kernel-src/mm/vmm.c +++ b/kernel-src/mm/vmm.c @@ -227,10 +227,10 @@ static void destroyrange(vmmrange_t *range, uintmax_t _offset, size_t size, int proc_t *proc = thread ? thread->proc : NULL; cred_t *cred = proc ? &proc->cred : NULL; - if ((range->flags & VMM_FLAGS_FILE) && ((range->flags & VMM_FLAGS_SHARED) || range->vnode->type == V_TYPE_CHDEV)) { - // shared file mapping or character device mapping - if (range->vnode->type == V_TYPE_CHDEV) { - // character device mapping + if ((range->flags & VMM_FLAGS_FILE) && ((range->flags & VMM_FLAGS_SHARED) || vfs_iscacheable(range->vnode) == false)) { + // shared file mapping or non cacheable mapping + if (vfs_iscacheable(range->vnode) == false) { + // non cacheable mapping VOP_LOCK(range->vnode); __assert(VOP_MUNMAP(range->vnode, vaddr, range->offset + offset, mmuflagstovnodeflags(range->mmuflags) | (range->flags & VMM_FLAGS_SHARED ? V_FFLAGS_SHARED : 0), cred) == 0); VOP_UNLOCK(range->vnode); @@ -280,7 +280,7 @@ static void changemmurange(vmmrange_t *range, void *base, size_t size, mmuflags_ CHANGE_MASK_CHECK(mask, ARCH_MMU_FLAGS_USER, currentflags, newflags); CHANGE_MASK_CHECK(mask, ARCH_MMU_FLAGS_NOEXEC, currentflags, newflags); - if ((range->flags & VMM_FLAGS_FILE) && (range->flags & VMM_FLAGS_SHARED) && (mask & ARCH_MMU_FLAGS_WRITE)) { + if ((range->flags & VMM_FLAGS_FILE) && (range->flags & VMM_FLAGS_SHARED) && (mask & ARCH_MMU_FLAGS_WRITE) && vfs_iscacheable(range->vnode)) { // removing write permissions from a writeable dirty shared mapped page, mark it as dirty, as // it won't be marked dirty upon a vmm_unmap after this page_t *page = pmm_getpage(physical); @@ -568,7 +568,7 @@ bool vmm_pagefault(void *addr, bool user, int actions) { // page not present in the page tables if (range->flags & VMM_FLAGS_FILE) { uintmax_t mapoffset = (uintptr_t)addr - (uintptr_t)range->start; - if (range->vnode->type != V_TYPE_BLKDEV && range->vnode->type != V_TYPE_REGULAR) { + if (vfs_iscacheable(range->vnode) == false) { // map non cacheable vnodes VOP_LOCK(range->vnode); __assert(VOP_MMAP(range->vnode, addr, range->offset + mapoffset, mmuflagstovnodeflags(range->mmuflags) | (range->flags & VMM_FLAGS_SHARED ? V_FFLAGS_SHARED : 0), cred) == 0); @@ -617,7 +617,7 @@ bool vmm_pagefault(void *addr, bool user, int actions) { if ((range->flags & VMM_FLAGS_FILE) && (range->flags & VMM_FLAGS_SHARED)) { // shared file, remap it as writable arch_mmu_remap(_cpu()->vmmctx->pagetable, oldphys, addr, range->mmuflags); - if (range->vnode->type != V_TYPE_CHDEV) { + if (vfs_iscacheable(range->vnode)) { // and if its a cache page, mark it as dirty VOP_LOCK(range->vnode); vmmcache_makedirty(pmm_getpage(oldphys)); @@ -635,7 +635,7 @@ bool vmm_pagefault(void *addr, bool user, int actions) { } else { memcpy(MAKE_HHDM(newphys), MAKE_HHDM(oldphys), PAGE_SIZE); arch_mmu_remap(_cpu()->vmmctx->pagetable, newphys, addr, range->mmuflags); - if ((range->flags & VMM_FLAGS_FILE) == 0 || range->vnode->type != V_TYPE_CHDEV) + if ((range->flags & VMM_FLAGS_FILE) == 0 || vfs_iscacheable(range->vnode)) pmm_release(oldphys); status = true; diff --git a/kernel-src/sys/syscalls/mmap.c b/kernel-src/sys/syscalls/mmap.c index 726c0d42..7f8b53bc 100644 --- a/kernel-src/sys/syscalls/mmap.c +++ b/kernel-src/sys/syscalls/mmap.c @@ -78,10 +78,9 @@ syscallret_t syscall_mmap(context_t *context, void *hint, size_t len, int prot, goto cleanup; } - // not all charcter devices support mapping, so check if its supported - // (regular files and block devices go through the page cache) + // if the vnode is not cacheable, we need to make sure we can map it // TODO move this check to vmm_map once the return value of mmap is fixed to return an errno - if (type == V_TYPE_CHDEV) { + if (vfs_iscacheable(file->vnode) == false) { ret.errno = VOP_MMAP(file->vnode, VOP_MMAP_ADDRESS_MMAP_SUPPORTED, 0, 0, NULL); if (ret.errno) goto cleanup;