Stop acquiring the lpi_list_lock in favor of RCU for protecting
the read-side critical section in vgic_get_lpi(). In order for this to
be safe, we also need to be careful not to take a reference on an irq
with a refcount of 0, as it is about to be freed.
Reviewed-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20240221054253.3848076-9-oliver.upton@linux.dev
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
 {
        struct vgic_dist *dist = &kvm->arch.vgic;
        struct vgic_irq *irq = NULL;
-       unsigned long flags;
 
-       raw_spin_lock_irqsave(&dist->lpi_list_lock, flags);
+       rcu_read_lock();
 
        irq = xa_load(&dist->lpi_xa, intid);
-       if (irq)
-               vgic_get_irq_kref(irq);
+       if (!vgic_try_get_irq_kref(irq))
+               irq = NULL;
 
-       raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
+       rcu_read_unlock();
 
        return irq;
 }
 
 void vgic_v2_save_state(struct kvm_vcpu *vcpu);
 void vgic_v2_restore_state(struct kvm_vcpu *vcpu);
 
-static inline void vgic_get_irq_kref(struct vgic_irq *irq)
+static inline bool vgic_try_get_irq_kref(struct vgic_irq *irq)
 {
+       if (!irq)
+               return false;
+
        if (irq->intid < VGIC_MIN_LPI)
-               return;
+               return true;
 
-       kref_get(&irq->refcount);
+       return kref_get_unless_zero(&irq->refcount);
+}
+
+static inline void vgic_get_irq_kref(struct vgic_irq *irq)
+{
+       WARN_ON_ONCE(!vgic_try_get_irq_kref(irq));
 }
 
 void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);