| From 91648ec09c1ef69c4d840ab6dab391bfb452d554 Mon Sep 17 00:00:00 2001 |
| From: pingfan liu <qemulist@gmail.com> |
| Date: Fri, 15 Nov 2013 16:35:00 +0800 |
| Subject: powerpc: kvm: fix rare but potential deadlock scene |
| |
| From: pingfan liu <qemulist@gmail.com> |
| |
| commit 91648ec09c1ef69c4d840ab6dab391bfb452d554 upstream. |
| |
| 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> |
| Signed-off-by: Alexander Graf <agraf@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/powerpc/kvm/book3s_64_mmu_hv.c | 6 +++++- |
| arch/powerpc/kvm/book3s_hv_rm_mmu.c | 4 ++++ |
| 2 files changed, 9 insertions(+), 1 deletion(-) |
| |
| --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c |
| +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c |
| @@ -393,11 +393,14 @@ static int kvmppc_mmu_book3s_64_hv_xlate |
| slb_v = vcpu->kvm->arch.vrma_slb_v; |
| } |
| |
| + preempt_disable(); |
| /* Find the HPTE in the hash table */ |
| index = kvmppc_hv_find_lock_hpte(kvm, eaddr, slb_v, |
| HPTE_V_VALID | HPTE_V_ABSENT); |
| - if (index < 0) |
| + if (index < 0) { |
| + preempt_enable(); |
| return -ENOENT; |
| + } |
| hptep = (unsigned long *)(kvm->arch.hpt_virt + (index << 4)); |
| v = hptep[0] & ~HPTE_V_HVLOCK; |
| gr = kvm->arch.revmap[index].guest_rpte; |
| @@ -405,6 +408,7 @@ static int kvmppc_mmu_book3s_64_hv_xlate |
| /* Unlock the HPTE */ |
| asm volatile("lwsync" : : : "memory"); |
| hptep[0] = v; |
| + preempt_enable(); |
| |
| gpte->eaddr = eaddr; |
| gpte->vpage = ((v & HPTE_V_AVPN) << 4) | ((eaddr >> 12) & 0xfff); |
| --- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c |
| +++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c |
| @@ -649,6 +649,10 @@ static int slb_base_page_shift[4] = { |
| 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, |
| unsigned long valid) |
| { |