KVM: arm64: vgic: Undo work in failed ITS restores
authorRicardo Koller <ricarkol@google.com>
Tue, 10 May 2022 00:16:33 +0000 (17:16 -0700)
committerMarc Zyngier <maz@kernel.org>
Mon, 16 May 2022 12:58:04 +0000 (13:58 +0100)
Failed ITS restores should clean up all state restored until the
failure. There is some cleanup already present when failing to restore
some tables, but it's not complete. Add the missing cleanup.

Note that this changes the behavior in case of a failed restore of the
device tables.

restore ioctl:
1. restore collection tables
2. restore device tables

With this commit, failures in 2. clean up everything created so far,
including state created by 1.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Ricardo Koller <ricarkol@google.com>
Reviewed-by: Oliver Upton <oupton@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20220510001633.552496-5-ricarkol@google.com
arch/arm64/kvm/vgic/vgic-its.c

index f34e09cc86dc8d3a3b43af4b4e5412724c17ef43..b50542c98d794d9c9dc449304ebb9e38aa0fd38f 100644 (file)
@@ -2219,8 +2219,10 @@ static int vgic_its_restore_ite(struct vgic_its *its, u32 event_id,
                vcpu = kvm_get_vcpu(kvm, collection->target_addr);
 
        irq = vgic_add_lpi(kvm, lpi_id, vcpu);
-       if (IS_ERR(irq))
+       if (IS_ERR(irq)) {
+               its_free_ite(kvm, ite);
                return PTR_ERR(irq);
+       }
        ite->irq = irq;
 
        return offset;
@@ -2485,6 +2487,9 @@ static int vgic_its_restore_device_tables(struct vgic_its *its)
        if (ret > 0)
                ret = 0;
 
+       if (ret < 0)
+               vgic_its_free_device_list(its->dev->kvm, its);
+
        return ret;
 }
 
@@ -2615,6 +2620,9 @@ static int vgic_its_restore_collection_table(struct vgic_its *its)
        if (ret > 0)
                return 0;
 
+       if (ret < 0)
+               vgic_its_free_collection_list(its->dev->kvm, its);
+
        return ret;
 }
 
@@ -2646,7 +2654,10 @@ static int vgic_its_restore_tables_v0(struct vgic_its *its)
        if (ret)
                return ret;
 
-       return vgic_its_restore_device_tables(its);
+       ret = vgic_its_restore_device_tables(its);
+       if (ret)
+               vgic_its_free_collection_list(its->dev->kvm, its);
+       return ret;
 }
 
 static int vgic_its_commit_v0(struct vgic_its *its)