]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails
authorClaudio Imbrenda <imbrenda@linux.ibm.com>
Mon, 3 Aug 2026 12:40:37 +0000 (14:40 +0200)
committerClaudio Imbrenda <imbrenda@linux.ibm.com>
Mon, 3 Aug 2026 14:51:34 +0000 (16:51 +0200)
The mmu cache is the first thing that is allocated in
kvm_arch_vcpu_create(), but in case of failure it was not freed.

Fix by freeing the mmu cache in case of failure.

Refactor kvm_arch_vcpu_create() to use scope-based cleanup instead of
gotos.

Fixes: e38c884df921 ("KVM: s390: Switch to new gmap")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260803124040.126471-11-imbrenda@linux.ibm.com>

arch/s390/kvm/kvm-s390.c

index 2741ca323edea50da7134d40cfcbf65c84599531..9b8a35e7dc822ef64df68dbab6da457d8b8f16df 100644 (file)
@@ -3800,21 +3800,21 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
        return 0;
 }
 
+DEFINE_FREE(sie_page, struct sie_page *, if (_T) free_page((unsigned long)(_T)))
+
 int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 {
-       struct sie_page *sie_page;
+       struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
+       struct sie_page *sie_page __free(sie_page) = NULL;
        int rc;
 
        BUILD_BUG_ON(sizeof(struct sie_page) != 4096);
-       vcpu->arch.mc = kvm_s390_new_mmu_cache();
-       if (!vcpu->arch.mc)
+       mc = kvm_s390_new_mmu_cache();
+       if (!mc)
                return -ENOMEM;
        sie_page = (struct sie_page *) get_zeroed_page(GFP_KERNEL_ACCOUNT);
-       if (!sie_page) {
-               kvm_s390_free_mmu_cache(vcpu->arch.mc);
-               vcpu->arch.mc = NULL;
+       if (!sie_page)
                return -ENOMEM;
-       }
 
        vcpu->arch.sie_block = &sie_page->sie_block;
        vcpu->arch.sie_block->itdba = virt_to_phys(&sie_page->itdb);
@@ -3856,10 +3856,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
                vcpu->run->kvm_valid_regs |= KVM_SYNC_FPRS;
 
        if (kvm_is_ucontrol(vcpu->kvm)) {
-               rc = -ENOMEM;
                vcpu->arch.gmap = gmap_new_child(vcpu->kvm->arch.gmap, -1UL);
                if (!vcpu->arch.gmap)
-                       goto out_free_sie_block;
+                       return -ENOMEM;
        }
 
        VM_EVENT(vcpu->kvm, 3, "create cpu %d at 0x%p, sie block at 0x%p",
@@ -3867,22 +3866,19 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
        trace_kvm_s390_create_vcpu(vcpu->vcpu_id, vcpu, vcpu->arch.sie_block);
 
        rc = kvm_s390_vcpu_setup(vcpu);
-       if (rc)
-               goto out_ucontrol_uninit;
+       if (rc) {
+               if (kvm_is_ucontrol(vcpu->kvm)) {
+                       scoped_guard(spinlock, &vcpu->kvm->arch.gmap->children_lock)
+                               gmap_remove_child(vcpu->arch.gmap);
+                       vcpu->arch.gmap = gmap_put(vcpu->arch.gmap);
+               }
+               return rc;
+       }
 
+       vcpu->arch.mc = no_free_ptr(mc);
+       sie_page = NULL;
        kvm_s390_update_topology_change_report(vcpu->kvm, 1);
        return 0;
-
-out_ucontrol_uninit:
-       if (kvm_is_ucontrol(vcpu->kvm)) {
-               spin_lock(&vcpu->kvm->arch.gmap->children_lock);
-               gmap_remove_child(vcpu->arch.gmap);
-               spin_unlock(&vcpu->kvm->arch.gmap->children_lock);
-               vcpu->arch.gmap = gmap_put(vcpu->arch.gmap);
-       }
-out_free_sie_block:
-       free_page((unsigned long)(vcpu->arch.sie_block));
-       return rc;
 }
 
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)