]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: arm64: vgic-v3: Use bare refcount for VGIC LPIs
authorOliver Upton <oliver.upton@linux.dev>
Fri, 5 Sep 2025 10:05:27 +0000 (03:05 -0700)
committerOliver Upton <oliver.upton@linux.dev>
Wed, 10 Sep 2025 09:56:19 +0000 (02:56 -0700)
KVM's use of krefs to manage LPIs isn't adding much, especially
considering vgic_irq_release() is a noop due to the lack of sufficient
context.

Switch to using a regular refcount in anticipation of adding a
meaningful release concept for LPIs.

Reviewed-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20250905100531.282980-3-oliver.upton@linux.dev
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/kvm/vgic/vgic-debug.c
arch/arm64/kvm/vgic/vgic-init.c
arch/arm64/kvm/vgic/vgic-its.c
arch/arm64/kvm/vgic/vgic-v4.c
arch/arm64/kvm/vgic/vgic.c
arch/arm64/kvm/vgic/vgic.h
include/kvm/arm_vgic.h

index 2684f273d9e17a43918568dc5952004957dc4ead..4c1209261b65d4fad8d2213040ace777d0d0eda4 100644 (file)
@@ -69,7 +69,7 @@ static int iter_mark_lpis(struct kvm *kvm)
        int nr_lpis = 0;
 
        xa_for_each(&dist->lpi_xa, intid, irq) {
-               if (!vgic_try_get_irq_kref(irq))
+               if (!vgic_try_get_irq_ref(irq))
                        continue;
 
                xa_set_mark(&dist->lpi_xa, intid, LPI_XA_MARK_DEBUG_ITER);
index 1e680ad6e86359c551a4e335d4cc3b58f9fb1cf0..4c777136ea5ffcc37a68d3a01660f857ba30d4a6 100644 (file)
@@ -208,7 +208,7 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
                raw_spin_lock_init(&irq->irq_lock);
                irq->vcpu = NULL;
                irq->target_vcpu = vcpu0;
-               kref_init(&irq->refcount);
+               refcount_set(&irq->refcount, 0);
                switch (dist->vgic_model) {
                case KVM_DEV_TYPE_ARM_VGIC_V2:
                        irq->targets = 0;
@@ -277,7 +277,7 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type)
                irq->intid = i;
                irq->vcpu = NULL;
                irq->target_vcpu = vcpu;
-               kref_init(&irq->refcount);
+               refcount_set(&irq->refcount, 0);
                if (vgic_irq_is_sgi(i)) {
                        /* SGIs */
                        irq->enabled = 1;
index 7368c13f16b72909e560c612619d6a7728a4d650..f162206adb482ac0d2eb5c709ed36c4d508d1855 100644 (file)
@@ -99,7 +99,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
        raw_spin_lock_init(&irq->irq_lock);
 
        irq->config = VGIC_CONFIG_EDGE;
-       kref_init(&irq->refcount);
+       refcount_set(&irq->refcount, 1);
        irq->intid = intid;
        irq->target_vcpu = vcpu;
        irq->group = 1;
@@ -111,7 +111,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
         * check that we don't add a second list entry with the same LPI.
         */
        oldirq = xa_load(&dist->lpi_xa, intid);
-       if (vgic_try_get_irq_kref(oldirq)) {
+       if (vgic_try_get_irq_ref(oldirq)) {
                /* Someone was faster with adding this LPI, lets use that. */
                kfree(irq);
                irq = oldirq;
@@ -547,7 +547,7 @@ static struct vgic_irq *vgic_its_check_cache(struct kvm *kvm, phys_addr_t db,
        rcu_read_lock();
 
        irq = xa_load(&its->translation_cache, cache_key);
-       if (!vgic_try_get_irq_kref(irq))
+       if (!vgic_try_get_irq_ref(irq))
                irq = NULL;
 
        rcu_read_unlock();
@@ -571,7 +571,7 @@ static void vgic_its_cache_translation(struct kvm *kvm, struct vgic_its *its,
         * its_lock, as the ITE (and the reference it holds) cannot be freed.
         */
        lockdep_assert_held(&its->its_lock);
-       vgic_get_irq_kref(irq);
+       vgic_get_irq_ref(irq);
 
        old = xa_store(&its->translation_cache, cache_key, irq, GFP_KERNEL_ACCOUNT);
 
index 4d9343d2b0b155a1c3db005f800b4f5a4e91faac..548aec9d5a7280dc58d69c3ac5b4b51e298d2ca3 100644 (file)
@@ -518,7 +518,7 @@ static struct vgic_irq *__vgic_host_irq_get_vlpi(struct kvm *kvm, int host_irq)
                if (!irq->hw || irq->host_irq != host_irq)
                        continue;
 
-               if (!vgic_try_get_irq_kref(irq))
+               if (!vgic_try_get_irq_ref(irq))
                        return NULL;
 
                return irq;
index f5148b38120ad7859dac51bb30ff2dd166d7e246..a1d6fab895c4530ced5720eef2028d95b7c2b003 100644 (file)
@@ -71,7 +71,7 @@ static struct vgic_irq *vgic_get_lpi(struct kvm *kvm, u32 intid)
        rcu_read_lock();
 
        irq = xa_load(&dist->lpi_xa, intid);
-       if (!vgic_try_get_irq_kref(irq))
+       if (!vgic_try_get_irq_ref(irq))
                irq = NULL;
 
        rcu_read_unlock();
@@ -114,15 +114,6 @@ struct vgic_irq *vgic_get_vcpu_irq(struct kvm_vcpu *vcpu, u32 intid)
        return vgic_get_irq(vcpu->kvm, intid);
 }
 
-/*
- * We can't do anything in here, because we lack the kvm pointer to
- * lock and remove the item from the lpi_list. So we keep this function
- * empty and use the return value of kref_put() to trigger the freeing.
- */
-static void vgic_irq_release(struct kref *ref)
-{
-}
-
 void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
 {
        struct vgic_dist *dist = &kvm->arch.vgic;
@@ -131,7 +122,7 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
        if (irq->intid < VGIC_MIN_LPI)
                return;
 
-       if (!kref_put(&irq->refcount, vgic_irq_release))
+       if (!refcount_dec_and_test(&irq->refcount))
                return;
 
        xa_lock_irqsave(&dist->lpi_xa, flags);
@@ -399,7 +390,7 @@ retry:
         * now in the ap_list. This is safe as the caller must already hold a
         * reference on the irq.
         */
-       vgic_get_irq_kref(irq);
+       vgic_get_irq_ref(irq);
        list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
        irq->vcpu = vcpu;
 
@@ -657,7 +648,7 @@ retry:
 
                        /*
                         * This vgic_put_irq call matches the
-                        * vgic_get_irq_kref in vgic_queue_irq_unlock,
+                        * vgic_get_irq_ref in vgic_queue_irq_unlock,
                         * where we added the LPI to the ap_list. As
                         * we remove the irq from the list, we drop
                         * also drop the refcount.
index de1c1d3261c3966707aae8e379b09e478ae6070e..ac5f9c5d2b98003d2ae2c1a12ebfd686864aa661 100644 (file)
@@ -267,7 +267,7 @@ void vgic_v2_put(struct kvm_vcpu *vcpu);
 void vgic_v2_save_state(struct kvm_vcpu *vcpu);
 void vgic_v2_restore_state(struct kvm_vcpu *vcpu);
 
-static inline bool vgic_try_get_irq_kref(struct vgic_irq *irq)
+static inline bool vgic_try_get_irq_ref(struct vgic_irq *irq)
 {
        if (!irq)
                return false;
@@ -275,12 +275,12 @@ static inline bool vgic_try_get_irq_kref(struct vgic_irq *irq)
        if (irq->intid < VGIC_MIN_LPI)
                return true;
 
-       return kref_get_unless_zero(&irq->refcount);
+       return refcount_inc_not_zero(&irq->refcount);
 }
 
-static inline void vgic_get_irq_kref(struct vgic_irq *irq)
+static inline void vgic_get_irq_ref(struct vgic_irq *irq)
 {
-       WARN_ON_ONCE(!vgic_try_get_irq_kref(irq));
+       WARN_ON_ONCE(!vgic_try_get_irq_ref(irq));
 }
 
 void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
index 9f8a116925ca35abb1fc18de7f5c4b1c24dd5b59..640555ff5b549734a2c87e4e420ec8a968a21828 100644 (file)
@@ -8,8 +8,8 @@
 #include <linux/bits.h>
 #include <linux/kvm.h>
 #include <linux/irqreturn.h>
-#include <linux/kref.h>
 #include <linux/mutex.h>
+#include <linux/refcount.h>
 #include <linux/spinlock.h>
 #include <linux/static_key.h>
 #include <linux/types.h>
@@ -142,7 +142,7 @@ struct vgic_irq {
        bool active;
        bool enabled;
        bool hw;                        /* Tied to HW IRQ */
-       struct kref refcount;           /* Used for LPIs */
+       refcount_t refcount;            /* Used for LPIs */
        u32 hwintid;                    /* HW INTID number */
        unsigned int host_irq;          /* linux irq corresponding to hwintid */
        union {