From d5a4f2a4ad4a15cee99b821de466f239fb1b33a6 Mon Sep 17 00:00:00 2001 From: Matheus Date: Wed, 18 Sep 2024 18:03:07 -0300 Subject: [PATCH] vmmcache: redo how vnode locking is expected --- kernel-src/fs/vfs.c | 28 ++++++++++++++++++++++------ kernel-src/include/kernel/vfs.h | 4 ++-- kernel-src/mm/vmm.c | 3 +-- kernel-src/mm/vmmcache.c | 3 ++- kernel-src/sys/syscalls/open.c | 27 +++++++++++++-------------- kernel-src/sys/syscalls/truncate.c | 4 ++++ 6 files changed, 44 insertions(+), 25 deletions(-) diff --git a/kernel-src/fs/vfs.c b/kernel-src/fs/vfs.c index 2c84f7a5..687cef14 100644 --- a/kernel-src/fs/vfs.c +++ b/kernel-src/fs/vfs.c @@ -228,7 +228,6 @@ 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 (vfs_iscacheable(node)) { *written = 0; @@ -242,8 +241,12 @@ int vfs_write(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t goto leave; } + MUTEX_ACQUIRE(&node->size_lock, false); + vattr_t attr; + VOP_LOCK(node); err = VOP_GETATTR(node, &attr, getcred()); + VOP_UNLOCK(node); if (err) goto leave; @@ -251,14 +254,18 @@ int vfs_write(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t if (node->type == V_TYPE_REGULAR && newsize) { // do resize stuff if regular and applicable + VOP_LOCK(node); err = VOP_RESIZE(node, newsize, ¤t_thread()->proc->cred); + VOP_UNLOCK(node); if (err) goto leave; } else if (node->type == V_TYPE_BLKDEV) { // else just get the disk size and limit the read size blockdesc_t blockdesc; int r; + VOP_LOCK(node); err = VOP_IOCTL(node, BLOCK_IOCTL_GETDESC, &blockdesc, &r, NULL); + VOP_UNLOCK(node); __assert(err == 0); size_t bytesize = blockdesc.blockcapacity * blockdesc.blocksize; @@ -315,18 +322,20 @@ int vfs_write(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t if (err) goto leave; } + + leave: + MUTEX_RELEASE(&node->size_lock); } else { // special file, just write as its not being cached + VOP_LOCK(node); err = VOP_WRITE(node, buffer, size, offset, flags, written, getcred()); + VOP_UNLOCK(node); } - leave: - VOP_UNLOCK(node); return err; } 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 (vfs_iscacheable(node)) { *bytesread = 0; @@ -342,9 +351,12 @@ int vfs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t size_t nodesize = 0; + MUTEX_ACQUIRE(&node->size_lock, false); if (node->type == V_TYPE_REGULAR) { vattr_t attr; + VOP_LOCK(node); err = VOP_GETATTR(node, &attr, getcred()); + VOP_UNLOCK(node); if (err) goto leave; @@ -352,7 +364,9 @@ int vfs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t } else { blockdesc_t blockdesc; int r; + VOP_LOCK(node); err = VOP_IOCTL(node, BLOCK_IOCTL_GETDESC, &blockdesc, &r, NULL); + VOP_UNLOCK(node); __assert(err == 0); nodesize = blockdesc.blockcapacity * blockdesc.blocksize; @@ -404,12 +418,14 @@ int vfs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t } pmm_release(FROM_HHDM(address)); } + leave: + MUTEX_RELEASE(&node->size_lock); } else { // special file, just read as size doesn't matter + VOP_LOCK(node); err = VOP_READ(node, buffer, size, offset, flags, bytesread, getcred()); + VOP_UNLOCK(node); } - leave: - VOP_UNLOCK(node); return err; } diff --git a/kernel-src/include/kernel/vfs.h b/kernel-src/include/kernel/vfs.h index 56c734ec..baf46566 100644 --- a/kernel-src/include/kernel/vfs.h +++ b/kernel-src/include/kernel/vfs.h @@ -92,7 +92,7 @@ typedef struct vfs_t { typedef struct vnode_t { struct vops_t *ops; mutex_t lock; - mutex_t sizelock; + mutex_t size_lock; int refcount; int flags; int type; @@ -161,7 +161,7 @@ typedef struct vops_t { #define VOP_INIT(vn, o, f, t, v) \ (vn)->ops = o; \ MUTEX_INIT(&(vn)->lock); \ - MUTEX_INIT(&(vn)->sizelock); \ + MUTEX_INIT(&(vn)->size_lock); \ (vn)->refcount = 1; \ (vn)->flags = f; \ (vn)->type = t; \ diff --git a/kernel-src/mm/vmm.c b/kernel-src/mm/vmm.c index c719b3fa..0d92ceb6 100644 --- a/kernel-src/mm/vmm.c +++ b/kernel-src/mm/vmm.c @@ -581,9 +581,8 @@ bool vmm_pagefault(void *addr, bool user, int actions) { } else { // cacheable vnode page_t *res = NULL; - VOP_LOCK(range->vnode); int error = vmmcache_getpage(range->vnode, range->offset + mapoffset, &res); - VOP_UNLOCK(range->vnode); + if (error == ENXIO || error == ENOMEM) { if (error == ENOMEM) printf("vmm: out of memory to handle getpage (sending SIGBUS)\n"); diff --git a/kernel-src/mm/vmmcache.c b/kernel-src/mm/vmmcache.c index a7b11448..b2e60784 100644 --- a/kernel-src/mm/vmmcache.c +++ b/kernel-src/mm/vmmcache.c @@ -102,7 +102,6 @@ static void removepage(page_t *page) { --vmmcache_cachedpages; } -// vnode expected locked int vmmcache_getpage(vnode_t *vnode, uintmax_t offset, page_t **res) { __assert(vnode->type == V_TYPE_REGULAR || vnode->type == V_TYPE_BLKDEV); __assert((offset % PAGE_SIZE) == 0); @@ -164,7 +163,9 @@ int vmmcache_getpage(vnode_t *vnode, uintmax_t offset, page_t **res) { RELEASE_LOCK(); + VOP_LOCK(vnode); int error = VOP_GETPAGE(vnode, offset, newpage); + VOP_UNLOCK(vnode); if (error) { // an error happened with GETPAGE, remove the page from the cache, diff --git a/kernel-src/sys/syscalls/open.c b/kernel-src/sys/syscalls/open.c index fd77f412..22798103 100644 --- a/kernel-src/sys/syscalls/open.c +++ b/kernel-src/sys/syscalls/open.c @@ -43,14 +43,14 @@ syscallret_t syscall_openat(context_t *context, int dirfd, char *path, int flags int newfd; ret.errno = fd_new(flags & O_CLOEXEC, &newfile, &newfd); if (ret.errno) - goto cleanup_nounlock; + goto cleanup; vnode_t *vnode = NULL; ret.errno = vfs_open(dirnode, pathbuf, fileflagstovnodeflags(flags), &vnode); if (ret.errno == 0 && (flags & O_CREAT) && (flags & O_EXCL)) { // exclusive and file already exists ret.errno = EEXIST; - goto cleanup_nounlock; + goto cleanup; } else if (ret.errno == ENOENT && (flags & O_CREAT)) { // create file vattr_t attr = { @@ -62,12 +62,7 @@ syscallret_t syscall_openat(context_t *context, int dirfd, char *path, int flags ret.errno = vfs_create(dirnode, pathbuf, &attr, V_TYPE_REGULAR, &vnode); if (ret.errno == EEXIST && (flags & O_EXCL) == 0) goto retry_open; - } else if (ret.errno) { - // any other error - goto cleanup_nounlock; - } else { - // success, lock file - VOP_LOCK(vnode); + VOP_UNLOCK(vnode); } if (ret.errno) @@ -79,12 +74,22 @@ syscallret_t syscall_openat(context_t *context, int dirfd, char *path, int flags } vattr_t attr; + VOP_LOCK(vnode); + ret.errno = VOP_GETATTR(vnode, &attr, ¤t_thread()->proc->cred); + + VOP_UNLOCK(vnode); if (ret.errno) goto cleanup; if (vnode->type == V_TYPE_REGULAR && (flags & O_TRUNC) && (flags & FILE_WRITE)) { + MUTEX_ACQUIRE(&vnode->size_lock, false); + VOP_LOCK(vnode); + ret.errno = VOP_RESIZE(vnode, 0, ¤t_thread()->proc->cred); + + VOP_UNLOCK(vnode); + MUTEX_RELEASE(&vnode->size_lock); if (ret.errno) goto cleanup; } @@ -99,11 +104,6 @@ syscallret_t syscall_openat(context_t *context, int dirfd, char *path, int flags ret.ret = newfd; cleanup: - - if (vnode) - VOP_UNLOCK(vnode); - - cleanup_nounlock: if (vnode && ret.errno) { vfs_close(vnode, fileflagstovnodeflags(flags)); VOP_RELEASE(vnode); @@ -112,7 +112,6 @@ syscallret_t syscall_openat(context_t *context, int dirfd, char *path, int flags if (newfile && ret.errno) __assert(fd_close(newfd) == 0); - if (pathbuf) free(pathbuf); diff --git a/kernel-src/sys/syscalls/truncate.c b/kernel-src/sys/syscalls/truncate.c index ff7906af..3915d0aa 100644 --- a/kernel-src/sys/syscalls/truncate.c +++ b/kernel-src/sys/syscalls/truncate.c @@ -17,9 +17,13 @@ syscallret_t syscall_ftruncate(int fd, size_t size) { goto cleanup; } + MUTEX_ACQUIRE(&file->vnode->size_lock, false); VOP_LOCK(file->vnode); + ret.errno = VOP_RESIZE(file->vnode, size, ¤t_thread()->proc->cred); + VOP_UNLOCK(file->vnode); + MUTEX_RELEASE(&file->vnode->size_lock); ret.ret = ret.errno ? -1 : 0;