Fixes vmm_struct_cleanup Cleanup is called from __proc_free, and I don't want to sleep in there. Running the existing code with the lock debugger will flip out. Even attempting to qlock while holding a spinlock will panic, rightly so. The lock held happens to be the parent's child lock, which it holds when it decrefs the child. Regardless, proc_decref is called all over the place, and I'd rather not sleep in the release method. I considered removing the qlock and having a multi-state atomic_t that we CAS on, solving the issue of multiple potential initializers and cleanup not checking the lock. But that's a bit of overkill.
diff --git a/kern/arch/x86/vmm/vmm.c b/kern/arch/x86/vmm/vmm.c index 7a8f8d2..4af9853 100644 --- a/kern/arch/x86/vmm/vmm.c +++ b/kern/arch/x86/vmm/vmm.c
@@ -80,6 +80,8 @@ qunlock(&vmm->qlock); return 0; } + /* Set this early, so cleanup checks the gpc array */ + vmm->vmmcp = TRUE; nr_guest_pcores = MIN(nr_guest_pcores, num_cpus); vmm->amd = 0; vmm->guest_pcores = kzmalloc(sizeof(void*) * nr_guest_pcores, KMALLOC_WAIT); @@ -92,23 +94,21 @@ } } vmm->nr_guest_pcores = i; - vmm->vmmcp = TRUE; qunlock(&vmm->qlock); return i; } -void vmm_struct_cleanup(struct vmm *vmm) +/* Has no concurrency protection - only call this when you know you have the + * only ref to vmm. For instance, from __proc_free, where there is only one ref + * to the proc (and thus proc.vmm). */ +void __vmm_struct_cleanup(struct vmm *vmm) { - qlock(&vmm->qlock); - if (!vmm->vmmcp) { - qunlock(&vmm->qlock); + if (!vmm->vmmcp) return; - } for (int i = 0; i < vmm->nr_guest_pcores; i++) { if (vmm->guest_pcores[i]) vmx_destroy_vcpu(vmm->guest_pcores[i]); } kfree(vmm->guest_pcores); vmm->vmmcp = FALSE; - qunlock(&vmm->qlock); }
diff --git a/kern/arch/x86/vmm/vmm.h b/kern/arch/x86/vmm/vmm.h index 27f248b..5945df5 100644 --- a/kern/arch/x86/vmm/vmm.h +++ b/kern/arch/x86/vmm/vmm.h
@@ -41,7 +41,7 @@ void vmm_pcpu_init(void); int vmm_struct_init(struct vmm *vmm, unsigned int nr_guest_pcores); -void vmm_struct_cleanup(struct vmm *vmm); +void __vmm_struct_cleanup(struct vmm *vmm); int vm_run(uint64_t,uint64_t, uint64_t); int intel_vmx_start(int id);
diff --git a/kern/src/process.c b/kern/src/process.c index 68b3357..3b05c08 100644 --- a/kern/src/process.c +++ b/kern/src/process.c
@@ -458,7 +458,7 @@ assert(kref_refcnt(&p->p_kref) == 0); assert(TAILQ_EMPTY(&p->alarmset.list)); - vmm_struct_cleanup(&p->vmm); + __vmm_struct_cleanup(&p->vmm); p->progname[0] = 0; cclose(p->dot); cclose(p->slash);