KVM: PPC: Book3S HV: Don’t take kvm->lock around kvm_for_each_vcpu [Linux 4.14.129]

KVM: PPC: Book3S HV: Don’t take kvm->lock around kvm_for_each_vcpu [Linux 4.14.129]

This Linux kernel change "KVM: PPC: Book3S HV: Don’t take kvm->lock around kvm_for_each_vcpu" is included in the Linux 4.14.129 release. This change is authored by Paul Mackerras <paulus [at] ozlabs.org> on Thu May 23 16:36:32 2019 +1000. The commit for this change in Linux stable tree is 5390e7f (patch) which is from upstream commit 5a3f493. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 5a3f493.

KVM: PPC: Book3S HV: Don't take kvm->lock around kvm_for_each_vcpu

[ Upstream commit 5a3f49364c3ffa1107bd88f8292406e98c5d206c ]

Currently the HV KVM code takes the kvm->lock around calls to
kvm_for_each_vcpu() and kvm_get_vcpu_by_id() (which can call
kvm_for_each_vcpu() internally).  However, that leads to a lock
order inversion problem, because these are called in contexts where
the vcpu mutex is held, but the vcpu mutexes nest within kvm->lock
according to Documentation/virtual/kvm/locking.txt.  Hence there
is a possibility of deadlock.

To fix this, we simply don't take the kvm->lock mutex around these
calls.  This is safe because the implementations of kvm_for_each_vcpu()
and kvm_get_vcpu_by_id() have been designed to be able to be called
locklessly.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Reviewed-by: C├ędric Le Goater <clg@kaod.org>
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>

There are 9 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 arch/powerpc/kvm/book3s_hv.c | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 5874632..3b7488fce 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -392,12 +392,7 @@ static void kvmppc_dump_regs(struct kvm_vcpu *vcpu)

 static struct kvm_vcpu *kvmppc_find_vcpu(struct kvm *kvm, int id)
 {
-   struct kvm_vcpu *ret;
-
-   mutex_lock(&kvm->lock);
-   ret = kvm_get_vcpu_by_id(kvm, id);
-   mutex_unlock(&kvm->lock);
-   return ret;
+   return kvm_get_vcpu_by_id(kvm, id);
 }

 static void init_vpa(struct kvm_vcpu *vcpu, struct lppaca *vpa)
@@ -1258,7 +1253,6 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
    struct kvmppc_vcore *vc = vcpu->arch.vcore;
    u64 mask;

-   mutex_lock(&kvm->lock);
    spin_lock(&vc->lock);
    /*
     * If ILE (interrupt little-endian) has changed, update the
@@ -1298,7 +1292,6 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
        mask &= 0xFFFFFFFF;
    vc->lpcr = (vc->lpcr & ~mask) | (new_lpcr & mask);
    spin_unlock(&vc->lock);
-   mutex_unlock(&kvm->lock);
 }

 static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,

Leave a Reply

Your email address will not be published. Required fields are marked *