]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: s390: vsie: Add missing radix_tree_preload() in _gaccess_shadow_fault()
authorClaudio Imbrenda <imbrenda@linux.ibm.com>
Thu, 11 Jun 2026 10:48:49 +0000 (12:48 +0200)
committerClaudio Imbrenda <imbrenda@linux.ibm.com>
Thu, 11 Jun 2026 11:50:09 +0000 (13:50 +0200)
Add missing radix_tree_preload() in _gaccess_shadow_fault() to
guarantee forward progress. The core of _gaccess_shadow_fault() has
been split into ___gaccess_shadow_fault() in order to simplify locking.

Fixes: e38c884df921 ("KVM: s390: Switch to new gmap")
CC: stable@vger.kernel.org # 7.1
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260611104850.110313-5-imbrenda@linux.ibm.com>

arch/s390/kvm/gaccess.c

index 20e28b183c1ac047e70fab3228c7c4772ca71a7a..0584fc91606faab930ba6d9c31f42b3fd472e170 100644 (file)
@@ -1582,35 +1582,48 @@ real_address_space:
        return _do_shadow_crste(sg, saddr, host, table, entries + LEVEL_MEM, w->p);
 }
 
-static inline int _gaccess_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg, gpa_t saddr,
-                                       unsigned long seq, struct pgtwalk *walk)
+static inline int ___gaccess_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg, gpa_t saddr,
+                                         unsigned long seq, struct pgtwalk *walk)
 {
        struct gmap *parent;
        int rc;
 
-       if (kvm_s390_array_needs_retry_unsafe(vcpu->kvm, seq, walk->raw_entries))
+       if (kvm_s390_array_needs_retry_safe(vcpu->kvm, seq, walk->raw_entries))
                return -EAGAIN;
-again:
-       rc = kvm_s390_mmu_cache_topup(vcpu->arch.mc);
-       if (rc)
-               return rc;
-       scoped_guard(read_lock, &vcpu->kvm->mmu_lock) {
-               if (kvm_s390_array_needs_retry_safe(vcpu->kvm, seq, walk->raw_entries))
-                       return -EAGAIN;
-               parent = READ_ONCE(sg->parent);
-               if (!parent)
+       parent = READ_ONCE(sg->parent);
+       if (!parent)
+               return -EAGAIN;
+       scoped_guard(spinlock, &parent->children_lock) {
+               if (READ_ONCE(sg->parent) != parent)
                        return -EAGAIN;
-               scoped_guard(spinlock, &parent->children_lock) {
-                       if (READ_ONCE(sg->parent) != parent)
-                               return -EAGAIN;
-                       sg->invalidated = false;
-                       rc = _gaccess_do_shadow(vcpu->arch.mc, sg, saddr, walk);
-               }
-               if (rc == -ENOMEM)
-                       goto again;
-               if (!rc)
-                       kvm_s390_release_faultin_array(vcpu->kvm, walk->raw_entries, false);
+               sg->invalidated = false;
+               rc = _gaccess_do_shadow(vcpu->arch.mc, sg, saddr, walk);
        }
+       if (!rc)
+               kvm_s390_release_faultin_array(vcpu->kvm, walk->raw_entries, false);
+       return rc;
+}
+
+static inline int _gaccess_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg, gpa_t saddr,
+                                       unsigned long seq, struct pgtwalk *walk)
+{
+       int rc;
+
+       if (kvm_s390_array_needs_retry_unsafe(vcpu->kvm, seq, walk->raw_entries))
+               return -EAGAIN;
+
+       do {
+               rc = kvm_s390_mmu_cache_topup(vcpu->arch.mc);
+               if (rc)
+                       return rc;
+               rc = radix_tree_preload(GFP_KERNEL);
+               if (rc)
+                       return rc;
+               scoped_guard(read_lock, &vcpu->kvm->mmu_lock)
+                       rc = ___gaccess_shadow_fault(vcpu, sg, saddr, seq, walk);
+               radix_tree_preload_end();
+       } while (rc == -ENOMEM);
+
        return rc;
 }