If a vcpu has issued a HLT instruction with interrupts disabled then it sleeps
forever in vm_handle_hlt(). This is usually not an issue as long as one of the other vcpus properly resets or powers off the virtual machine. However, if the bhyve(8) process is killed with a signal the halted vcpu cannot be woken up because it's sleep cannot be interrupted. Fix this by waking up periodically and returning from vm_handle_hlt() if TDF_ASTPENDING is set. Reported by: Leon Dang Sponsored by: Nahanni Systems
This commit is contained in:
parent
1edccd0f30
commit
f008d1571d
@ -270,6 +270,14 @@ vcpu_is_running(struct vm *vm, int vcpu, int *hostcpu)
|
||||
return (vcpu_get_state(vm, vcpu, hostcpu) == VCPU_RUNNING);
|
||||
}
|
||||
|
||||
#ifdef _SYS_PROC_H_
|
||||
static int __inline
|
||||
vcpu_should_yield(struct vm *vm, int vcpu)
|
||||
{
|
||||
return (curthread->td_flags & (TDF_ASTPENDING | TDF_NEEDRESCHED));
|
||||
}
|
||||
#endif
|
||||
|
||||
void *vcpu_stats(struct vm *vm, int vcpu);
|
||||
void vcpu_notify_event(struct vm *vm, int vcpuid, bool lapic_intr);
|
||||
struct vmspace *vm_get_vmspace(struct vm *vm);
|
||||
|
@ -2559,7 +2559,7 @@ vmx_run(void *arg, int vcpu, register_t startrip, pmap_t pmap,
|
||||
break;
|
||||
}
|
||||
|
||||
if (curthread->td_flags & (TDF_ASTPENDING | TDF_NEEDRESCHED)) {
|
||||
if (vcpu_should_yield(vm, vcpu)) {
|
||||
enable_intr();
|
||||
vm_exit_astpending(vmx->vm, vcpu, vmcs_guest_rip());
|
||||
vmx_astpending_trace(vmx, vcpu, vmexit->rip);
|
||||
|
@ -1105,6 +1105,10 @@ vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled, bool *retu)
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't go to sleep if the vcpu thread needs to yield */
|
||||
if (vcpu_should_yield(vm, vcpuid))
|
||||
break;
|
||||
|
||||
/*
|
||||
* Some Linux guests implement "halt" by having all vcpus
|
||||
* execute HLT with interrupts disabled. 'halted_cpus' keeps
|
||||
@ -1128,7 +1132,11 @@ vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled, bool *retu)
|
||||
|
||||
t = ticks;
|
||||
vcpu_require_state_locked(vcpu, VCPU_SLEEPING);
|
||||
msleep_spin(vcpu, &vcpu->mtx, wmesg, 0);
|
||||
/*
|
||||
* XXX msleep_spin() cannot be interrupted by signals so
|
||||
* wake up periodically to check pending signals.
|
||||
*/
|
||||
msleep_spin(vcpu, &vcpu->mtx, wmesg, hz);
|
||||
vcpu_require_state_locked(vcpu, VCPU_FROZEN);
|
||||
vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user