[PATCH v2 4/5] KVM: s390: vsie: Add missing radix_tree_preload() in _gaccess_shadow_fault()
From: Claudio Imbrenda
Date: Wed Jun 10 2026 - 13:00:48 EST
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")
Signed-off-by: Claudio Imbrenda <imbrenda@xxxxxxxxxxxxx>
CC: stable@xxxxxxxxxxxxxxx # 7.1
---
arch/s390/kvm/gaccess.c | 49 +++++++++++++++++++++++++----------------
1 file changed, 30 insertions(+), 19 deletions(-)
diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c
index 20e28b183c1a..c072b6872bf8 100644
--- a/arch/s390/kvm/gaccess.c
+++ b/arch/s390/kvm/gaccess.c
@@ -1582,35 +1582,46 @@ static int _gaccess_do_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *sg,
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)
+{
+ struct gmap *parent;
+ int rc;
+
+ if (kvm_s390_array_needs_retry_safe(vcpu->kvm, seq, walk->raw_entries))
+ return -EAGAIN;
+ parent = READ_ONCE(sg->parent);
+ if (!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)
+ 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)
{
- struct gmap *parent;
int rc;
if (kvm_s390_array_needs_retry_unsafe(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)
- 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);
- }
+
+ do {
+ radix_tree_preload(GFP_KERNEL);
+ 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;
}
--
2.54.0