From 6852438e3a407b811e045a41454dfe142b592888 Mon Sep 17 00:00:00 2001 From: Jie Deng Date: Tue, 17 Nov 2020 16:22:48 +0800 Subject: [PATCH] hv: Support concurrent split-lock emulation on SMP. For a SMP guest, split-lock check may happen on multiple vCPUs simultaneously. In this case, one vCPU at most can be allowed running in the split-lock emulation window. And if the vCPU is doing the emulation, it should never be blocked in the hypervisor, it should go back to the guest to execute the lock instruction immediately and trap back to the hypervisor with #DB to complete the split-lock emulation. Tracked-On: #5605 Signed-off-by: Jie Deng --- hypervisor/arch/x86/guest/virq.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/hypervisor/arch/x86/guest/virq.c b/hypervisor/arch/x86/guest/virq.c index b5d7860c7..3481431d7 100644 --- a/hypervisor/arch/x86/guest/virq.c +++ b/hypervisor/arch/x86/guest/virq.c @@ -492,6 +492,8 @@ static void vcpu_kick_splitlock_emulation(struct acrn_vcpu *cur_vcpu) uint16_t i; if (cur_vcpu->vm->hw.created_vcpus > 1U) { + get_vm_lock(cur_vcpu->vm); + foreach_vcpu(i, cur_vcpu->vm, other) { if (other != cur_vcpu) { vcpu_make_request(other, ACRN_REQUEST_SPLIT_LOCK); @@ -508,9 +510,24 @@ static void vcpu_complete_splitlock_emulation(struct acrn_vcpu *cur_vcpu) if (cur_vcpu->vm->hw.created_vcpus > 1U) { foreach_vcpu(i, cur_vcpu->vm, other) { if (other != cur_vcpu) { + /* + * Suppose the current vcpu is 0, the other vcpus (1, 2, 3) may wait on the + * "get_vm_lock", the current vcpu need clear the ACRN_REQUEST_SPLIT_LOCK + * explicitly here after finishing the emulation. Otherwise, it make cause + * dead lock. for example: + * 1. Once vcpu 0 "put_vm_lock", let's say vcpu 1 will "get_vm_lock". + * 2. vcpu 1 call "vcpu_make_request" to pause vcpu 0, 2, 3. + * 3. vcpu 1's VCPU_EVENT_SPLIT_LOCK is still not cleared because + * the vcpu 0 called "vcpu_make_request" ever. + * 4. All vcpus will wait for VCPU_EVENT_SPLIT_LOCK in acrn_handle_pending_request. + * We should avoid this dead lock case. + */ + bitmap_clear_lock(ACRN_REQUEST_SPLIT_LOCK, &other->arch.pending_req); signal_event(&other->events[VCPU_EVENT_SPLIT_LOCK]); } } + + put_vm_lock(cur_vcpu->vm); } }