Hi Marc, On 13/07/16 13:15, Marc Zyngier wrote: > On 13/07/16 02:58, Andre Przywara wrote: >> In the moment our struct vgic_irq's are statically allocated at guest >> creation time. So getting a pointer to an IRQ structure is trivial and >> safe. LPIs are more dynamic, they can be mapped and unmapped at any time >> during the guest's _runtime_. >> In preparation for supporting LPIs we introduce reference counting for >> those structures using the kernel's kref infrastructure. >> Since private IRQs and SPIs are statically allocated, the refcount never >> drops to 0 at the moment, but we increase it when an IRQ gets onto a VCPU >> list and decrease it when it gets removed. >> This introduces vgic_put_irq(), which wraps kref_put and hides the >> release function from the callers. >> >> Signed-off-by: Andre Przywara <andre.przyw...@arm.com> >> --- >> include/kvm/arm_vgic.h | 1 + >> virt/kvm/arm/vgic/vgic-init.c | 2 ++ >> virt/kvm/arm/vgic/vgic-mmio-v2.c | 8 ++++++ >> virt/kvm/arm/vgic/vgic-mmio-v3.c | 20 +++++++++------ >> virt/kvm/arm/vgic/vgic-mmio.c | 25 ++++++++++++++++++- >> virt/kvm/arm/vgic/vgic-v2.c | 1 + >> virt/kvm/arm/vgic/vgic-v3.c | 1 + >> virt/kvm/arm/vgic/vgic.c | 53 >> ++++++++++++++++++++++++++++++++-------- >> virt/kvm/arm/vgic/vgic.h | 1 + >> 9 files changed, 94 insertions(+), 18 deletions(-) > > [...] > >> --- a/virt/kvm/arm/vgic/vgic.c >> +++ b/virt/kvm/arm/vgic/vgic.c >> @@ -48,13 +48,20 @@ struct vgic_global __section(.hyp.text) >> kvm_vgic_global_state; >> struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu, >> u32 intid) >> { >> - /* SGIs and PPIs */ >> - if (intid <= VGIC_MAX_PRIVATE) >> - return &vcpu->arch.vgic_cpu.private_irqs[intid]; >> + struct vgic_dist *dist = &kvm->arch.vgic; >> + struct vgic_irq *irq; >> >> - /* SPIs */ >> - if (intid <= VGIC_MAX_SPI) >> - return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS]; >> + if (intid <= VGIC_MAX_PRIVATE) { /* SGIs and PPIs */ >> + irq = &vcpu->arch.vgic_cpu.private_irqs[intid]; >> + kref_get(&irq->refcount); >> + return irq; >> + } >> + >> + if (intid <= VGIC_MAX_SPI) { /* SPIs */ >> + irq = &dist->spis[intid - VGIC_NR_PRIVATE_IRQS]; >> + kref_get(&irq->refcount); >> + return irq; >> + } > > I'm a bit concerned by the fact that we perform the refcounting on > objects that shouldn't be concerned by it. None of the static interrupts > should have to suffer from the overhead, as they cannot be freed. > So I came up with the following patch: > > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c > index c7cd1a3..6bbff9a 100644 > --- a/virt/kvm/arm/vgic/vgic.c > +++ b/virt/kvm/arm/vgic/vgic.c > @@ -91,19 +91,12 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct > kvm_vcpu *vcpu, > u32 intid) > { > struct vgic_dist *dist = &kvm->arch.vgic; > - struct vgic_irq *irq; > > - if (intid <= VGIC_MAX_PRIVATE) { /* SGIs and PPIs */ > - irq = &vcpu->arch.vgic_cpu.private_irqs[intid]; > - kref_get(&irq->refcount); > - return irq; > - } > + if (intid <= VGIC_MAX_PRIVATE) /* SGIs and PPIs */ > + return &vcpu->arch.vgic_cpu.private_irqs[intid]; > > - if (intid <= VGIC_MAX_SPI) { /* SPIs */ > - irq = &dist->spis[intid - VGIC_NR_PRIVATE_IRQS]; > - kref_get(&irq->refcount); > - return irq; > - } > + if (intid <= VGIC_MAX_SPI) /* SPIs */ > + return &dist->spis[intid - VGIC_NR_PRIVATE_IRQS]; > > if (intid >= VGIC_MIN_LPI) /* LPIs */ > return vgic_get_lpi(kvm, intid); > @@ -112,6 +105,14 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct > kvm_vcpu *vcpu, > return NULL; > } > > +static void vgic_get_irq_kref(struct vgic_irq *irq) > +{ > + if (irq->intid < VGIC_MIN_LPI) > + return; > + > + kref_get(&irq->refcount); > +} > + > /* > * 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 > @@ -125,10 +126,10 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq) > { > struct vgic_dist *dist; > > - if (!kref_put(&irq->refcount, vgic_irq_release)) > + if (irq->intid < VGIC_MIN_LPI) > return; > > - if (irq->intid < VGIC_MIN_LPI) > + if (!kref_put(&irq->refcount, vgic_irq_release)) > return; > > dist = &kvm->arch.vgic; > @@ -313,7 +314,11 @@ retry: > goto retry; > } > > - kref_get(&irq->refcount); > + /* > + * Grab a reference to the irq to reflect the fact that it is > + * now in the ap_list. > + */ > + vgic_get_irq_kref(irq); > list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head); > irq->vcpu = vcpu; > > @@ -473,8 +478,11 @@ retry: > spin_unlock(&irq->irq_lock); > > /* > - * This put matches the get when we added the LPI to > - * the ap_list. We now drop the reference from the list. > + * This vgic_put_irq call matches the > + * vgic_get_irq_kref 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. > */ > vgic_put_irq(vcpu->kvm, irq); > continue; > > Thoughts?
Looks good to me, I checked the code and quickly tested it as well, without any issues. I'd integrate this in next respin. Thanks! Andre. _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm