powerpc: kvm: fix rare but potential deadlock scene
Since kvmppc_hv_find_lock_hpte() is called from both virtmode and realmode, so it can trigger the deadlock. Suppose the following scene: Two physical cpuM, cpuN, two VM instances A, B, each VM has a group of vcpus. If on cpuM, vcpu_A_1 holds bitlock X (HPTE_V_HVLOCK), then is switched out, and on cpuN, vcpu_A_2 try to lock X in realmode, then cpuN will be caught in realmode for a long time. What makes things even worse if the following happens, On cpuM, bitlockX is hold, on cpuN, Y is hold. vcpu_B_2 try to lock Y on cpuM in realmode vcpu_A_2 try to lock X on cpuN in realmode Oops! deadlock happens Signed-off-by: Liu Ping Fan <pingfank@linux.vnet.ibm.com> Reviewed-by: Paul Mackerras <paulus@samba.org> CC: stable@vger.kernel.org Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
parent
c9438092ca
commit
91648ec09c
2 changed files with 9 additions and 1 deletions
|
@ -469,11 +469,14 @@ static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||||||
slb_v = vcpu->kvm->arch.vrma_slb_v;
|
slb_v = vcpu->kvm->arch.vrma_slb_v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preempt_disable();
|
||||||
/* Find the HPTE in the hash table */
|
/* Find the HPTE in the hash table */
|
||||||
index = kvmppc_hv_find_lock_hpte(kvm, eaddr, slb_v,
|
index = kvmppc_hv_find_lock_hpte(kvm, eaddr, slb_v,
|
||||||
HPTE_V_VALID | HPTE_V_ABSENT);
|
HPTE_V_VALID | HPTE_V_ABSENT);
|
||||||
if (index < 0)
|
if (index < 0) {
|
||||||
|
preempt_enable();
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
}
|
||||||
hptep = (unsigned long *)(kvm->arch.hpt_virt + (index << 4));
|
hptep = (unsigned long *)(kvm->arch.hpt_virt + (index << 4));
|
||||||
v = hptep[0] & ~HPTE_V_HVLOCK;
|
v = hptep[0] & ~HPTE_V_HVLOCK;
|
||||||
gr = kvm->arch.revmap[index].guest_rpte;
|
gr = kvm->arch.revmap[index].guest_rpte;
|
||||||
|
@ -481,6 +484,7 @@ static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||||||
/* Unlock the HPTE */
|
/* Unlock the HPTE */
|
||||||
asm volatile("lwsync" : : : "memory");
|
asm volatile("lwsync" : : : "memory");
|
||||||
hptep[0] = v;
|
hptep[0] = v;
|
||||||
|
preempt_enable();
|
||||||
|
|
||||||
gpte->eaddr = eaddr;
|
gpte->eaddr = eaddr;
|
||||||
gpte->vpage = ((v & HPTE_V_AVPN) << 4) | ((eaddr >> 12) & 0xfff);
|
gpte->vpage = ((v & HPTE_V_AVPN) << 4) | ((eaddr >> 12) & 0xfff);
|
||||||
|
|
|
@ -749,6 +749,10 @@ static int slb_base_page_shift[4] = {
|
||||||
20, /* 1M, unsupported */
|
20, /* 1M, unsupported */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* When called from virtmode, this func should be protected by
|
||||||
|
* preempt_disable(), otherwise, the holding of HPTE_V_HVLOCK
|
||||||
|
* can trigger deadlock issue.
|
||||||
|
*/
|
||||||
long kvmppc_hv_find_lock_hpte(struct kvm *kvm, gva_t eaddr, unsigned long slb_v,
|
long kvmppc_hv_find_lock_hpte(struct kvm *kvm, gva_t eaddr, unsigned long slb_v,
|
||||||
unsigned long valid)
|
unsigned long valid)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue