From 127307827d966a0c56212e93d1d50c3b79da31ab Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sat, 7 Dec 2024 04:27:15 -0500 Subject: kernel: vcache: Add impl of "local" vcaches This commit implements local vcaches and lazy vcache migration (LZVM) for on the fly vcache type switching. Signed-off-by: Ian Moffett --- sys/include/sys/proc.h | 3 ++ sys/kern/vfs_vcache.c | 92 ++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 84 insertions(+), 11 deletions(-) diff --git a/sys/include/sys/proc.h b/sys/include/sys/proc.h index b10ee41..5925be8 100644 --- a/sys/include/sys/proc.h +++ b/sys/include/sys/proc.h @@ -39,6 +39,7 @@ #include #include #include +#include #if defined(_KERNEL) #include #include @@ -56,6 +57,8 @@ struct proc { struct exec_prog exec; struct ksiginfo *ksig_list[PROC_SIGMAX]; struct filedesc *fds[PROC_MAX_FILEDES]; + struct vcache *vcache; + struct spinlock vcache_lock; struct trapframe tf; struct pcb pcb; size_t priority; diff --git a/sys/kern/vfs_vcache.c b/sys/kern/vfs_vcache.c index e72b12c..d65a42f 100644 --- a/sys/kern/vfs_vcache.c +++ b/sys/kern/vfs_vcache.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,21 @@ static int vcache_type = VCACHE_TYPE_NONE; static struct vcache vcache = { .size = -1 }; __cacheline_aligned static struct spinlock vcache_lock; +static inline int +vcache_proc_new(struct proc *td) +{ + struct vcache *vcp; + + vcp = dynalloc(sizeof(*vcp)); + if (vcp == NULL) { + return -ENOMEM; + } + + vcp->size = -1; + td->vcache = vcp; + return 0; +} + /* * Pull a vnode from the head of a vcache. * Returns NULL if none are found. @@ -163,16 +179,25 @@ vfs_vcache_migrate(int newtype) int vfs_vcache_enter(struct vnode *vp) { + struct proc *td; int retval = 0; switch (vcache_type) { case VCACHE_TYPE_NONE: break; case VCACHE_TYPE_PROC: - /* TODO */ - pr_trace("warn: proc vcache not supported, using global...\n"); - vcache_type = VCACHE_TYPE_GLOBAL; - /* - FALL THROUGH - */ + td = this_td(); + + /* Create a new vcache if needed */ + if (td->vcache == NULL) + retval = vcache_proc_new(td); + if (retval != 0) + return retval; + + spinlock_acquire(&td->vcache_lock); + retval = vcache_add(vp, td->vcache); + spinlock_release(&td->vcache_lock); + break; case VCACHE_TYPE_GLOBAL: spinlock_acquire(&vcache_lock); retval = vcache_add(vp, &vcache); @@ -194,20 +219,65 @@ vfs_vcache_enter(struct vnode *vp) struct vnode * vfs_recycle_vnode(void) { + struct proc *td = this_td(); + struct vcache *vcp = &vcache; + struct spinlock *vclp = &vcache_lock; struct vnode *vp = NULL; switch (vcache_type) { case VCACHE_TYPE_NONE: break; case VCACHE_TYPE_PROC: - /* TODO */ - pr_trace("warn: proc vcache not supported, using global...\n"); - vcache_type = VCACHE_TYPE_GLOBAL; - /* - FALL THROUGH - */ + /* Have no vcache? Make one */ + if (td->vcache == NULL) { + vcache_proc_new(td); + break; + } + + vcp = td->vcache; + vclp = &td->vcache_lock; + + /* + * For LZVM, if we still have entries within the + * global vcache, drain it. + */ + if (!TAILQ_EMPTY(&vcache.q)) { + vcp = &vcache; + vclp = &vcache_lock; + } + + spinlock_acquire(vclp); + vp = vcache_pull(vcp); + spinlock_release(vclp); + break; case VCACHE_TYPE_GLOBAL: - spinlock_acquire(&vcache_lock); - vp = vcache_pull(&vcache); - spinlock_release(&vcache_lock); + vcp = &vcache; + vclp = &vcache_lock; + + /* + * If we've fully drained the local vcache during LZVM, + * we can deallocate and disable it. + */ + if (td->vcache != NULL) { + if (TAILQ_EMPTY(&td->vcache->q)) { + dynfree(td->vcache); + td->vcache = NULL; + } + } + + /* + * For LZVM, if the current process still has a vcache + * despite us being in global mode, just pull an entry + * from it instead. + */ + if (td->vcache != NULL) { + vclp = &td->vcache_lock; + vcp = td->vcache; + } + + spinlock_acquire(vclp); + vp = vcache_pull(vcp); + spinlock_release(vclp); break; default: pr_trace("warn: Bad vcache type, falling back to none\n"); -- cgit v1.2.3