KVM: arm64: vgic-its: Add collection allocator/destructor
authorMarc Zyngier <marc.zyngier@arm.com>
Sun, 17 Jul 2016 19:01:46 +0000 (20:01 +0100)
committerMarc Zyngier <marc.zyngier@arm.com>
Mon, 18 Jul 2016 17:15:18 +0000 (18:15 +0100)
Instead of spreading random allocations all over the place,
consolidate allocation/init/freeing of collections in a pair
of constructor/destructor.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
virt/kvm/arm/vgic/vgic-its.c

index 2faf1f4..d6f68e9 100644 (file)
@@ -581,14 +581,45 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its,
        return 0;
 }
 
-static void vgic_its_init_collection(struct vgic_its *its,
-                                    struct its_collection *collection,
+static int vgic_its_alloc_collection(struct vgic_its *its,
+                                    struct its_collection **colp,
                                     u32 coll_id)
 {
+       struct its_collection *collection;
+
+       collection = kzalloc(sizeof(*collection), GFP_KERNEL);
+
        collection->collection_id = coll_id;
        collection->target_addr = COLLECTION_NOT_MAPPED;
 
        list_add_tail(&collection->coll_list, &its->collection_list);
+       *colp = collection;
+
+       return 0;
+}
+
+static void vgic_its_free_collection(struct vgic_its *its, u32 coll_id)
+{
+       struct its_collection *collection;
+       struct its_device *device;
+       struct its_itte *itte;
+
+       /*
+        * Clearing the mapping for that collection ID removes the
+        * entry from the list. If there wasn't any before, we can
+        * go home early.
+        */
+       collection = find_collection(its, coll_id);
+       if (!collection)
+               return;
+
+       for_each_lpi_its(device, itte, its)
+               if (itte->collection &&
+                   itte->collection->collection_id == coll_id)
+                       itte->collection = NULL;
+
+       list_del(&collection->coll_list);
+       kfree(collection);
 }
 
 /*
@@ -605,6 +636,7 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
        struct its_device *device;
        struct its_collection *collection, *new_coll = NULL;
        int lpi_nr;
+       int ret;
 
        device = find_its_device(its, device_id);
        if (!device)
@@ -612,9 +644,10 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 
        collection = find_collection(its, coll_id);
        if (!collection) {
-               new_coll = kzalloc(sizeof(struct its_collection), GFP_KERNEL);
-               if (!new_coll)
-                       return -ENOMEM;
+               ret = vgic_its_alloc_collection(its, &collection, coll_id);
+               if (ret)
+                       return ret;
+               new_coll = collection;
        }
 
        if (subcmd == GITS_CMD_MAPTI)
@@ -623,27 +656,22 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
                lpi_nr = event_id;
        if (lpi_nr < GIC_LPI_OFFSET ||
            lpi_nr >= max_lpis_propbaser(kvm->arch.vgic.propbaser)) {
-               kfree(new_coll);
-               return E_ITS_MAPTI_PHYSICALID_OOR;
+               ret = E_ITS_MAPTI_PHYSICALID_OOR;
+               goto err;
        }
 
        itte = find_itte(its, device_id, event_id);
        if (!itte) {
                itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
                if (!itte) {
-                       kfree(new_coll);
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto err;
                }
 
                itte->event_id  = event_id;
                list_add_tail(&itte->itte_list, &device->itt_head);
        }
 
-       if (!collection) {
-               collection = new_coll;
-               vgic_its_init_collection(its, collection, coll_id);
-       }
-
        itte->collection = collection;
        itte->lpi = lpi_nr;
        itte->irq = vgic_add_lpi(kvm, lpi_nr);
@@ -657,6 +685,10 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
        update_lpi_config(kvm, itte->irq, NULL);
 
        return 0;
+err:
+       if (new_coll)
+               vgic_its_free_collection(its, coll_id);
+       return ret;
 }
 
 /* Requires the its_lock to be held. */
@@ -809,34 +841,18 @@ static int vgic_its_cmd_handle_mapc(struct kvm *kvm, struct vgic_its *its,
        if (coll_id >= vgic_its_nr_collection_ids(its))
                return E_ITS_MAPC_COLLECTION_OOR;
 
-       collection = find_collection(its, coll_id);
-
        if (!valid) {
-               struct its_device *device;
-               struct its_itte *itte;
-               /*
-                * Clearing the mapping for that collection ID removes the
-                * entry from the list. If there wasn't any before, we can
-                * go home early.
-                */
-               if (!collection)
-                       return 0;
-
-               for_each_lpi_its(device, itte, its)
-                       if (itte->collection &&
-                           itte->collection->collection_id == coll_id)
-                               itte->collection = NULL;
-
-               list_del(&collection->coll_list);
-               kfree(collection);
+               vgic_its_free_collection(its, coll_id);
        } else {
+               collection = find_collection(its, coll_id);
+
                if (!collection) {
-                       collection = kzalloc(sizeof(struct its_collection),
-                                            GFP_KERNEL);
-                       if (!collection)
-                               return -ENOMEM;
+                       int ret;
 
-                       vgic_its_init_collection(its, collection, coll_id);
+                       ret = vgic_its_alloc_collection(its, &collection,
+                                                       coll_id);
+                       if (ret)
+                               return ret;
                        collection->target_addr = target_addr;
                } else {
                        collection->target_addr = target_addr;