[PATCH] KVM: arm64: vgic-its: Fix O(C*I) loop in vgic_its_free_collection_list
Jing Zhang <[email protected]>
| Newsgroups | dev.linux.lists.kvmarm,org.kernel.vger.kvm |
|---|---|
| Message-ID | <[email protected]> |
When destroying the vgic-its collection list, vgic_its_free_collection_list() iterates over every collection and for each, calls vgic_its_free_collection(). This function walks every Interrupt Translation Entry (ITE) across all devices via for_each_lpi_its() to nullify the collection pointer. A guest can allocate up to 65536 collections and hundreds of thousands of ITEs. By clearing GITS_CTLR.Enable and writing Valid=0 to GITS_BASER1, the guest can trigger this teardown path from a single MMIO exit. The resulting O(Collections * ITEs) nested loop executes billions of iterations without a single cond_resched(). This pins a physical CPU and stalls RCU grace periods for seconds or minutes on PREEMPT_NONE kernels. Fix this by replacing the O(Collections * ITEs) teardown with an O(Collections + ITEs) pass. Since the entire collection list is being freed, we can safely bulk-clear the collection pointers from all ITEs in a single pass, and then free all the collections in a second pass. Signed-off-by: Jing Zhang <[email protected]> --- arch/arm64/kvm/vgic/vgic-its.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index 36ab3e4929154..a8e819fe97898 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -1133,9 +1133,21 @@ static void vgic_its_free_device_list(struct kvm *kvm, struct vgic_its *its) static void vgic_its_free_collection_list(struct kvm *kvm, struct vgic_its *its) { struct its_collection *cur, *temp; + struct its_device *device; + struct its_ite *ite; - list_for_each_entry_safe(cur, temp, &its->collection_list, coll_list) - vgic_its_free_collection(its, cur->collection_id); + /* + * Bulk-clear the collection pointers for all ITEs. + * This transforms the teardown complexity from O(Collections * ITEs) + * to O(Collections + ITEs), avoiding guest-triggered host RCU stalls. + */ + for_each_lpi_its(device, ite, its) + ite->collection = NULL; + + list_for_each_entry_safe(cur, temp, &its->collection_list, coll_list) { + list_del(&cur->coll_list); + kfree(cur); + } } /* Must be called with its_lock mutex held */ -- 2.55.0.737.g08866a6d13-goog