Calls to idr_alloc() in __prealloc_nested() are not currently synchronized.
According to the documentation [1], the caller should provide their own
locking to prevent concurrent modifications to the idr to prevent bugs.

Wrap the call to __prealloc_nested() in a spinlock to prevent concurrent
modifications to idr.

[1]: lib/idr.c

Fixes: c0f00a18e2a8 ("KVM: PPC: Book3S HV Nested: Change nested guest lookup to 
use idr")
Cc: [email protected] # 5.19+
Co-developed-by: Ritesh Harjani (IBM) <[email protected]>
Signed-off-by: Ritesh Harjani (IBM) <[email protected]>
Signed-off-by: Gautam Menghani <[email protected]>
---
 arch/powerpc/kvm/book3s_hv_nested.c | 34 +++++++++--------------------
 1 file changed, 10 insertions(+), 24 deletions(-)

diff --git a/arch/powerpc/kvm/book3s_hv_nested.c 
b/arch/powerpc/kvm/book3s_hv_nested.c
index a6ff42d7666c..e893fdd24f0a 100644
--- a/arch/powerpc/kvm/book3s_hv_nested.c
+++ b/arch/powerpc/kvm/book3s_hv_nested.c
@@ -702,20 +702,6 @@ static struct kvm_nested_guest *__find_nested(struct kvm 
*kvm, int lpid)
        return idr_find(&kvm->arch.kvm_nested_guest_idr, lpid);
 }
 
-static bool __prealloc_nested(struct kvm *kvm, int lpid)
-{
-       if (idr_alloc(&kvm->arch.kvm_nested_guest_idr,
-                               NULL, lpid, lpid + 1, GFP_KERNEL) != lpid)
-               return false;
-       return true;
-}
-
-static void __add_nested(struct kvm *kvm, int lpid, struct kvm_nested_guest 
*gp)
-{
-       if (idr_replace(&kvm->arch.kvm_nested_guest_idr, gp, lpid))
-               WARN_ON(1);
-}
-
 static void __remove_nested(struct kvm *kvm, int lpid)
 {
        idr_remove(&kvm->arch.kvm_nested_guest_idr, lpid);
@@ -862,21 +848,21 @@ struct kvm_nested_guest *kvmhv_get_nested(struct kvm 
*kvm, int l1_lpid,
        if (!newgp)
                return NULL;
 
-       if (!__prealloc_nested(kvm, l1_lpid)) {
-               kvmhv_release_nested(newgp);
-               return NULL;
-       }
-
+       idr_preload(GFP_KERNEL);
        spin_lock(&kvm->mmu_lock);
        gp = __find_nested(kvm, l1_lpid);
        if (!gp) {
-               __add_nested(kvm, l1_lpid, newgp);
-               ++newgp->refcnt;
-               gp = newgp;
-               newgp = NULL;
+               if (idr_alloc(&kvm->arch.kvm_nested_guest_idr, newgp,
+                             l1_lpid, l1_lpid + 1, GFP_NOWAIT) >= 0) {
+                       ++newgp->refcnt;
+                       gp = newgp;
+                       newgp = NULL;
+               }
        }
-       ++gp->refcnt;
+       if (gp)
+               ++gp->refcnt;
        spin_unlock(&kvm->mmu_lock);
+       idr_preload_end();
 
        if (newgp)
                kvmhv_release_nested(newgp);
-- 
2.52.0


Reply via email to