From: Marc Zyngier <marc.zyngier@arm.com>
To: Andre Przywara <andre.przywara@arm.com>,
Christoffer Dall <christoffer.dall@linaro.org>
Cc: linux-arm-kernel@lists.infradead.org,
kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org,
Diana Madalina Craciun <diana.craciun@nxp.com>
Subject: Re: [PATCH v8 15/17] KVM: arm64: implement ITS command queue command handlers
Date: Mon, 11 Jul 2016 18:52:10 +0100 [thread overview]
Message-ID: <5783DCCA.6070208@arm.com> (raw)
In-Reply-To: <3d954003-6fcd-5d2b-264b-c7eda68dadb0@arm.com>
On 11/07/16 18:47, Andre Przywara wrote:
> Hi,
>
> On 11/07/16 18:17, Marc Zyngier wrote:
>> On 05/07/16 12:23, Andre Przywara wrote:
>>> The connection between a device, an event ID, the LPI number and the
>>> allocated CPU is stored in in-memory tables in a GICv3, but their
>>> format is not specified by the spec. Instead software uses a command
>>> queue in a ring buffer to let the ITS implementation use their own
>>> format.
>>> Implement handlers for the various ITS commands and let them store
>>> the requested relation into our own data structures. Those data
>>> structures are protected by the its_lock mutex.
>>> Our internal ring buffer read and write pointers are protected by the
>>> its_cmd mutex, so that at most one VCPU per ITS can handle commands at
>>> any given time.
>>> Error handling is very basic at the moment, as we don't have a good
>>> way of communicating errors to the guest (usually a SError).
>>> The INT command handler is missing at this point, as we gain the
>>> capability of actually injecting MSIs into the guest only later on.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>> virt/kvm/arm/vgic/vgic-its.c | 609 ++++++++++++++++++++++++++++++++++++++++++-
>>> 1 file changed, 605 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
>>> index 5de71bd..432daed 100644
>>> --- a/virt/kvm/arm/vgic/vgic-its.c
>>> +++ b/virt/kvm/arm/vgic/vgic-its.c
>>> @@ -58,6 +58,43 @@ out_unlock:
>>> return irq;
>>> }
>>>
>>> +/*
>>> + * Creates a new (reference to a) struct vgic_irq for a given LPI.
>>> + * If this LPI is already mapped on another ITS, we increase its refcount
>>> + * and return a pointer to the existing structure.
>>> + * If this is a "new" LPI, we allocate and initialize a new struct vgic_irq.
>>> + * This function returns a pointer to the _unlocked_ structure.
>>> + */
>>> +static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid)
>>> +{
>>> + struct vgic_dist *dist = &kvm->arch.vgic;
>>> + struct vgic_irq *irq = vgic_its_get_lpi(kvm, intid);
>>
>> So this thing doesn't return with any lock held...
>>
>>> +
>>> + /* In this case there is no put, since we keep the reference. */
>>> + if (irq)
>>> + return irq;
>>> +
>>> + irq = kzalloc(sizeof(struct vgic_irq), GFP_KERNEL);
>>> +
>>> + if (!irq)
>>> + return NULL;
>>> +
>>> + INIT_LIST_HEAD(&irq->lpi_entry);
>>> + INIT_LIST_HEAD(&irq->ap_list);
>>> + spin_lock_init(&irq->irq_lock);
>>> +
>>> + irq->config = VGIC_CONFIG_EDGE;
>>> + kref_init(&irq->refcount);
>>> + irq->intid = intid;
>>
>> which means that two callers can allocate their own irq structure...
>
> In practise this will never happen, because the only caller
> (handle_mapi) takes the its_lock mutex. But I see that this is fragile
Given that the its_lock is per ITS, and that we're dealing with global
objects, this doesn't protect against anything. I can have two VCPUs
firing MAPIs on two ITSs, and hit that path with reasonable chances of
creating mayhem.
> and not safe. I guess I can search the list again after having taken the
> lock.
Please do.
>
>>> +
>>> + spin_lock(&dist->lpi_list_lock);
>>> + list_add_tail(&irq->lpi_entry, &dist->lpi_list_head);
>>> + dist->lpi_list_count++;
>>> + spin_unlock(&dist->lpi_list_lock);
>>
>> and insert it. Not too bad if they are different LPIs, but leading to
>> Armageddon if they are the same. You absolutely need to check for the
>> the presence of the interrupt in this list *while holding the lock*.
>>
>>> +
>>> + return irq;
>>> +}
>>> +
>>> struct its_device {
>>> struct list_head dev_list;
>>>
>
> ....
>
>>> +/*
>>> + * The INVALL command requests flushing of all IRQ data in this collection.
>>> + * Find the VCPU mapped to that collection, then iterate over the VM's list
>>> + * of mapped LPIs and update the configuration for each IRQ which targets
>>> + * the specified vcpu. The configuration will be read from the in-memory
>>> + * configuration table.
>>> + */
>>> +static int vgic_its_cmd_handle_invall(struct kvm *kvm, struct vgic_its *its,
>>> + u64 *its_cmd)
>>> +{
>>> + u32 coll_id = its_cmd_get_collection(its_cmd);
>>> + struct its_collection *collection;
>>> + struct kvm_vcpu *vcpu;
>>> + struct vgic_irq *irq;
>>> + u32 *intids;
>>> + int irq_count, i;
>>> +
>>> + mutex_lock(&its->its_lock);
>>> +
>>> + collection = find_collection(its, coll_id);
>>> + if (!its_is_collection_mapped(collection))
>>> + return E_ITS_INVALL_UNMAPPED_COLLECTION;
>>> +
>>> + vcpu = kvm_get_vcpu(kvm, collection->target_addr);
>>> +
>>> + irq_count = vgic_its_copy_lpi_list(kvm, &intids);
>>> + if (irq_count < 0)
>>> + return irq_count;
>>> +
>>> + for (i = 0; i < irq_count; i++) {
>>> + irq = vgic_get_irq(kvm, NULL, intids[i]);
>>> + if (!irq)
>>> + continue;
>>> + update_lpi_config_filtered(kvm, irq, vcpu);
>>> + vgic_put_irq_locked(kvm, irq);
>>
>> Where is the lpi_list_lock taken?
>
> Argh, good catch!
>
>> And why would we need it since we've
>> copied everything already? By the look of it, this vgic_put_irq_locked
>> should not exist at all, as the only other use case is quite dubious.
>
> Possibly, I don't like it either. Let me check if I can kill that sucker.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
WARNING: multiple messages have this Message-ID (diff)
From: marc.zyngier@arm.com (Marc Zyngier)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v8 15/17] KVM: arm64: implement ITS command queue command handlers
Date: Mon, 11 Jul 2016 18:52:10 +0100 [thread overview]
Message-ID: <5783DCCA.6070208@arm.com> (raw)
In-Reply-To: <3d954003-6fcd-5d2b-264b-c7eda68dadb0@arm.com>
On 11/07/16 18:47, Andre Przywara wrote:
> Hi,
>
> On 11/07/16 18:17, Marc Zyngier wrote:
>> On 05/07/16 12:23, Andre Przywara wrote:
>>> The connection between a device, an event ID, the LPI number and the
>>> allocated CPU is stored in in-memory tables in a GICv3, but their
>>> format is not specified by the spec. Instead software uses a command
>>> queue in a ring buffer to let the ITS implementation use their own
>>> format.
>>> Implement handlers for the various ITS commands and let them store
>>> the requested relation into our own data structures. Those data
>>> structures are protected by the its_lock mutex.
>>> Our internal ring buffer read and write pointers are protected by the
>>> its_cmd mutex, so that at most one VCPU per ITS can handle commands at
>>> any given time.
>>> Error handling is very basic at the moment, as we don't have a good
>>> way of communicating errors to the guest (usually a SError).
>>> The INT command handler is missing at this point, as we gain the
>>> capability of actually injecting MSIs into the guest only later on.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>> virt/kvm/arm/vgic/vgic-its.c | 609 ++++++++++++++++++++++++++++++++++++++++++-
>>> 1 file changed, 605 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
>>> index 5de71bd..432daed 100644
>>> --- a/virt/kvm/arm/vgic/vgic-its.c
>>> +++ b/virt/kvm/arm/vgic/vgic-its.c
>>> @@ -58,6 +58,43 @@ out_unlock:
>>> return irq;
>>> }
>>>
>>> +/*
>>> + * Creates a new (reference to a) struct vgic_irq for a given LPI.
>>> + * If this LPI is already mapped on another ITS, we increase its refcount
>>> + * and return a pointer to the existing structure.
>>> + * If this is a "new" LPI, we allocate and initialize a new struct vgic_irq.
>>> + * This function returns a pointer to the _unlocked_ structure.
>>> + */
>>> +static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid)
>>> +{
>>> + struct vgic_dist *dist = &kvm->arch.vgic;
>>> + struct vgic_irq *irq = vgic_its_get_lpi(kvm, intid);
>>
>> So this thing doesn't return with any lock held...
>>
>>> +
>>> + /* In this case there is no put, since we keep the reference. */
>>> + if (irq)
>>> + return irq;
>>> +
>>> + irq = kzalloc(sizeof(struct vgic_irq), GFP_KERNEL);
>>> +
>>> + if (!irq)
>>> + return NULL;
>>> +
>>> + INIT_LIST_HEAD(&irq->lpi_entry);
>>> + INIT_LIST_HEAD(&irq->ap_list);
>>> + spin_lock_init(&irq->irq_lock);
>>> +
>>> + irq->config = VGIC_CONFIG_EDGE;
>>> + kref_init(&irq->refcount);
>>> + irq->intid = intid;
>>
>> which means that two callers can allocate their own irq structure...
>
> In practise this will never happen, because the only caller
> (handle_mapi) takes the its_lock mutex. But I see that this is fragile
Given that the its_lock is per ITS, and that we're dealing with global
objects, this doesn't protect against anything. I can have two VCPUs
firing MAPIs on two ITSs, and hit that path with reasonable chances of
creating mayhem.
> and not safe. I guess I can search the list again after having taken the
> lock.
Please do.
>
>>> +
>>> + spin_lock(&dist->lpi_list_lock);
>>> + list_add_tail(&irq->lpi_entry, &dist->lpi_list_head);
>>> + dist->lpi_list_count++;
>>> + spin_unlock(&dist->lpi_list_lock);
>>
>> and insert it. Not too bad if they are different LPIs, but leading to
>> Armageddon if they are the same. You absolutely need to check for the
>> the presence of the interrupt in this list *while holding the lock*.
>>
>>> +
>>> + return irq;
>>> +}
>>> +
>>> struct its_device {
>>> struct list_head dev_list;
>>>
>
> ....
>
>>> +/*
>>> + * The INVALL command requests flushing of all IRQ data in this collection.
>>> + * Find the VCPU mapped to that collection, then iterate over the VM's list
>>> + * of mapped LPIs and update the configuration for each IRQ which targets
>>> + * the specified vcpu. The configuration will be read from the in-memory
>>> + * configuration table.
>>> + */
>>> +static int vgic_its_cmd_handle_invall(struct kvm *kvm, struct vgic_its *its,
>>> + u64 *its_cmd)
>>> +{
>>> + u32 coll_id = its_cmd_get_collection(its_cmd);
>>> + struct its_collection *collection;
>>> + struct kvm_vcpu *vcpu;
>>> + struct vgic_irq *irq;
>>> + u32 *intids;
>>> + int irq_count, i;
>>> +
>>> + mutex_lock(&its->its_lock);
>>> +
>>> + collection = find_collection(its, coll_id);
>>> + if (!its_is_collection_mapped(collection))
>>> + return E_ITS_INVALL_UNMAPPED_COLLECTION;
>>> +
>>> + vcpu = kvm_get_vcpu(kvm, collection->target_addr);
>>> +
>>> + irq_count = vgic_its_copy_lpi_list(kvm, &intids);
>>> + if (irq_count < 0)
>>> + return irq_count;
>>> +
>>> + for (i = 0; i < irq_count; i++) {
>>> + irq = vgic_get_irq(kvm, NULL, intids[i]);
>>> + if (!irq)
>>> + continue;
>>> + update_lpi_config_filtered(kvm, irq, vcpu);
>>> + vgic_put_irq_locked(kvm, irq);
>>
>> Where is the lpi_list_lock taken?
>
> Argh, good catch!
>
>> And why would we need it since we've
>> copied everything already? By the look of it, this vgic_put_irq_locked
>> should not exist at all, as the only other use case is quite dubious.
>
> Possibly, I don't like it either. Let me check if I can kill that sucker.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
next prev parent reply other threads:[~2016-07-11 17:46 UTC|newest]
Thread overview: 98+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-07-05 11:22 [PATCH v8 00/17] KVM: arm64: GICv3 ITS emulation Andre Przywara
2016-07-05 11:22 ` Andre Przywara
2016-07-05 11:22 ` [PATCH v8 01/17] KVM: arm/arm64: move redistributor kvm_io_devices Andre Przywara
2016-07-05 11:22 ` Andre Przywara
2016-07-05 11:22 ` [PATCH v8 02/17] KVM: arm/arm64: check return value for kvm_register_vgic_device Andre Przywara
2016-07-05 11:22 ` Andre Przywara
2016-07-05 11:22 ` [PATCH v8 03/17] KVM: extend struct kvm_msi to hold a 32-bit device ID Andre Przywara
2016-07-05 11:22 ` Andre Przywara
2016-07-06 21:06 ` Christoffer Dall
2016-07-06 21:06 ` Christoffer Dall
2016-07-06 21:54 ` André Przywara
2016-07-06 21:54 ` André Przywara
2016-07-07 9:37 ` Christoffer Dall
2016-07-07 9:37 ` Christoffer Dall
2016-07-05 11:22 ` [PATCH v8 04/17] KVM: arm/arm64: extend arch CAP checks to allow per-VM capabilities Andre Przywara
2016-07-05 11:22 ` Andre Przywara
2016-07-05 11:22 ` [PATCH v8 05/17] KVM: kvm_io_bus: add kvm_io_bus_get_dev() call Andre Przywara
2016-07-05 11:22 ` Andre Przywara
2016-07-06 21:15 ` Christoffer Dall
2016-07-06 21:15 ` Christoffer Dall
2016-07-06 21:36 ` André Przywara
2016-07-06 21:36 ` André Przywara
2016-07-05 11:22 ` [PATCH v8 06/17] KVM: arm/arm64: VGIC: add refcounting for IRQs Andre Przywara
2016-07-05 11:22 ` Andre Przywara
2016-07-07 13:13 ` Christoffer Dall
2016-07-07 13:13 ` Christoffer Dall
2016-07-07 15:00 ` Marc Zyngier
2016-07-07 15:00 ` Marc Zyngier
2016-07-08 10:28 ` Andre Przywara
2016-07-08 10:28 ` Andre Przywara
2016-07-08 10:50 ` Marc Zyngier
2016-07-08 10:50 ` Marc Zyngier
2016-07-08 12:54 ` André Przywara
2016-07-08 12:54 ` André Przywara
2016-07-08 13:09 ` Marc Zyngier
2016-07-08 13:09 ` Marc Zyngier
2016-07-08 13:14 ` André Przywara
2016-07-08 13:14 ` André Przywara
2016-07-05 11:22 ` [PATCH v8 07/17] irqchip: refactor and add GICv3 definitions Andre Przywara
2016-07-05 11:22 ` Andre Przywara
2016-07-05 11:23 ` [PATCH v8 08/17] KVM: arm64: handle ITS related GICv3 redistributor registers Andre Przywara
2016-07-05 11:23 ` Andre Przywara
2016-07-08 15:40 ` Christoffer Dall
2016-07-08 15:40 ` Christoffer Dall
2016-07-11 7:45 ` André Przywara
2016-07-11 7:45 ` André Przywara
2016-07-05 11:23 ` [PATCH v8 09/17] KVM: arm64: introduce ITS emulation file with MMIO framework Andre Przywara
2016-07-05 11:23 ` Andre Przywara
2016-07-08 13:34 ` Marc Zyngier
2016-07-08 13:34 ` Marc Zyngier
2016-07-08 13:55 ` Marc Zyngier
2016-07-08 13:55 ` Marc Zyngier
2016-07-08 14:04 ` André Przywara
2016-07-08 14:04 ` André Przywara
2016-07-05 11:23 ` [PATCH v8 10/17] KVM: arm64: introduce new KVM ITS device Andre Przywara
2016-07-05 11:23 ` Andre Przywara
2016-07-05 11:23 ` [PATCH v8 11/17] KVM: arm64: implement basic ITS register handlers Andre Przywara
2016-07-05 11:23 ` Andre Przywara
2016-07-08 14:58 ` Marc Zyngier
2016-07-08 14:58 ` Marc Zyngier
2016-07-11 9:00 ` Andre Przywara
2016-07-11 9:00 ` Andre Przywara
2016-07-11 14:21 ` Marc Zyngier
2016-07-11 14:21 ` Marc Zyngier
2016-07-05 11:23 ` [PATCH v8 12/17] KVM: arm64: connect LPIs to the VGIC emulation Andre Przywara
2016-07-05 11:23 ` Andre Przywara
2016-07-11 16:20 ` Marc Zyngier
2016-07-11 16:20 ` Marc Zyngier
2016-07-05 11:23 ` [PATCH v8 13/17] KVM: arm64: read initial LPI pending table Andre Przywara
2016-07-05 11:23 ` Andre Przywara
2016-07-11 16:50 ` Marc Zyngier
2016-07-11 16:50 ` Marc Zyngier
2016-07-11 17:38 ` Andre Przywara
2016-07-11 17:38 ` Andre Przywara
2016-07-12 11:33 ` Andre Przywara
2016-07-12 11:33 ` Andre Przywara
2016-07-12 12:39 ` Marc Zyngier
2016-07-12 12:39 ` Marc Zyngier
2016-07-05 11:23 ` [PATCH v8 14/17] KVM: arm64: allow updates of LPI configuration table Andre Przywara
2016-07-05 11:23 ` Andre Przywara
2016-07-11 16:59 ` Marc Zyngier
2016-07-11 16:59 ` Marc Zyngier
2016-07-05 11:23 ` [PATCH v8 15/17] KVM: arm64: implement ITS command queue command handlers Andre Przywara
2016-07-05 11:23 ` Andre Przywara
2016-07-11 17:17 ` Marc Zyngier
2016-07-11 17:17 ` Marc Zyngier
2016-07-11 17:47 ` Andre Przywara
2016-07-11 17:47 ` Andre Przywara
2016-07-11 17:52 ` Marc Zyngier [this message]
2016-07-11 17:52 ` Marc Zyngier
2016-07-05 11:23 ` [PATCH v8 16/17] KVM: arm64: implement MSI injection in ITS emulation Andre Przywara
2016-07-05 11:23 ` Andre Przywara
2016-07-05 11:23 ` [PATCH v8 17/17] KVM: arm64: enable ITS emulation as a virtual MSI controller Andre Przywara
2016-07-05 11:23 ` Andre Przywara
2016-07-06 8:52 ` [PATCH v8 00/17] KVM: arm64: GICv3 ITS emulation Auger Eric
2016-07-06 8:52 ` Auger Eric
2016-07-11 17:36 ` Marc Zyngier
2016-07-11 17:36 ` Marc Zyngier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5783DCCA.6070208@arm.com \
--to=marc.zyngier@arm.com \
--cc=andre.przywara@arm.com \
--cc=christoffer.dall@linaro.org \
--cc=diana.craciun@nxp.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.