[PATCH] KVM: arm/arm64: vgic: Add debugfs vgic-state file
André Przywara
andre.przywara at arm.com
Fri Jan 20 15:05:45 PST 2017
On 20/01/17 20:07, Christoffer Dall wrote
Hi Christoffer,
> On Fri, Jan 20, 2017 at 06:07:26PM +0000, Andre Przywara wrote:
>> Hej Christoffer,
>>
>> On 20/01/17 10:33, Christoffer Dall wrote:
>>> Add a file to debugfs to read the in-kernel state of the vgic. We don't
>>> do any locking of the entire VGIC state while traversing all the IRQs,
>>> so if the VM is running the user/developer may not see a quiesced state,
>>> but should take care to pause the VM using facilities in user space for
>>> that purpose.
>>>
>>> We also don't support LPIs yet, but they can be added easily if needed.
>>>
>>> Signed-off-by: Christoffer Dall <christoffer.dall at linaro.org>
>>> ---
>>> arch/arm/kvm/Makefile | 1 +
>>> arch/arm64/kvm/Makefile | 1 +
>>> include/kvm/arm_vgic.h | 5 +
>>> virt/kvm/arm/vgic/vgic-debug.c | 278 +++++++++++++++++++++++++++++++++++++++++
>>> virt/kvm/arm/vgic/vgic-init.c | 4 +
>>> virt/kvm/arm/vgic/vgic.h | 3 +
>>> 6 files changed, 292 insertions(+)
>>> create mode 100644 virt/kvm/arm/vgic/vgic-debug.c
>>>
>>> diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
>>> index d571243..12b6281 100644
>>> --- a/arch/arm/kvm/Makefile
>>> +++ b/arch/arm/kvm/Makefile
>>> @@ -33,5 +33,6 @@ obj-y += $(KVM)/arm/vgic/vgic-mmio-v2.o
>>> obj-y += $(KVM)/arm/vgic/vgic-mmio-v3.o
>>> obj-y += $(KVM)/arm/vgic/vgic-kvm-device.o
>>> obj-y += $(KVM)/arm/vgic/vgic-its.o
>>> +obj-y += $(KVM)/arm/vgic/vgic-debug.o
>>> obj-y += $(KVM)/irqchip.o
>>> obj-y += $(KVM)/arm/arch_timer.o
>>> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
>>> index d50a82a..e025bec 100644
>>> --- a/arch/arm64/kvm/Makefile
>>> +++ b/arch/arm64/kvm/Makefile
>>> @@ -31,6 +31,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v2.o
>>> kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o
>>> kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o
>>> kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o
>>> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-debug.o
>>> kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/irqchip.o
>>> kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
>>> kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>> index 002f092..1087aee 100644
>>> --- a/include/kvm/arm_vgic.h
>>> +++ b/include/kvm/arm_vgic.h
>>> @@ -165,6 +165,8 @@ struct vgic_its {
>>> struct list_head collection_list;
>>> };
>>>
>>> +struct vgic_state_iter;
>>> +
>>> struct vgic_dist {
>>> bool in_kernel;
>>> bool ready;
>>> @@ -212,6 +214,9 @@ struct vgic_dist {
>>> spinlock_t lpi_list_lock;
>>> struct list_head lpi_list_head;
>>> int lpi_list_count;
>>> +
>>> + /* used by vgic-debug */
>>> + struct vgic_state_iter *iter;
>>> };
>>>
>>> struct vgic_v2_cpu_if {
>>> diff --git a/virt/kvm/arm/vgic/vgic-debug.c b/virt/kvm/arm/vgic/vgic-debug.c
>>> new file mode 100644
>>> index 0000000..76e8b11
>>> --- /dev/null
>>> +++ b/virt/kvm/arm/vgic/vgic-debug.c
>>> @@ -0,0 +1,278 @@
>>> +/*
>>> + * Copyright (C) 2016 Linaro
>>> + * Author: Christoffer Dall <christoffer.dall at linaro.org>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>>> + * GNU General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU General Public License
>>> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
>>> + */
>>> +
>>> +#include <linux/cpu.h>
>>> +#include <linux/debugfs.h>
>>> +#include <linux/interrupt.h>
>>> +#include <linux/kvm_host.h>
>>> +#include <linux/seq_file.h>
>>> +#include <linux/uaccess.h>
>>> +#include <kvm/arm_vgic.h>
>>> +#include <asm/kvm_mmu.h>
>>> +#include "vgic.h"
>>> +
>>> +/*
>>> + * Structure to control looping through the entire vgic state. We start at
>>> + * zero for each field and move upwards. So, if dist_id is 0 we print the
>>> + * distributor info. When dist_id is 1, we have already printed it and move
>>> + * on.
>>> + *
>>> + * When vcpu_id < nr_cpus we print the vcpu info until vcpu_id == nr_cpus and
>>> + * so on.
>>> + */
>>> +struct vgic_state_iter {
>>> + int nr_cpus;
>>> + int nr_spis;
>>> + int dist_id;
>>> + int vcpu_id;
>>> + int intid;
>>> +};
>>> +
>>> +static void iter_next(struct vgic_state_iter *iter)
>>> +{
>>> + if (iter->dist_id == 0) {
>>> + iter->dist_id++;
>>> + return;
>>> + }
>>> +
>>> + iter->intid++;
>>> + if (iter->intid == VGIC_NR_PRIVATE_IRQS &&
>>> + ++iter->vcpu_id < iter->nr_cpus)
>>> + iter->intid = 0;
>>> +}
>>> +
>>> +static void iter_init(struct kvm *kvm, struct vgic_state_iter *iter,
>>> + loff_t pos)
>>> +{
>>> + int nr_cpus = atomic_read(&kvm->online_vcpus);
>>> +
>>> + memset(iter, 0, sizeof(*iter));
>>> +
>>> + iter->nr_cpus = nr_cpus;
>>> + iter->nr_spis = kvm->arch.vgic.nr_spis;
>>> +
>>> + /* Fast forward to the right position if needed */
>>> + while (pos--)
>>> + iter_next(iter);
>>> +}
>>> +
>>> +static bool the_end(struct vgic_state_iter *iter)
>>
>> "Of everything that stands, the end"? ;-)
>
> "It's the end of the world as we know it". How appropriate on this day.
And I was reviewing the patch to distract me from that ;-)
Any chance you can talk your son into running for president?
>> I wonder if we really need this. AFAICT the_end never returns true after
>> init has been called, so the only caller is after the iter_next(). So
>> can't we just close the Door(s) and fold the_end() into
>> iter_next()?
>>
>
> see below.
>
>>> +{
>>> + return iter->dist_id > 0 &&
>>> + iter->vcpu_id == iter->nr_cpus &&
>>> + (iter->intid - VGIC_NR_PRIVATE_IRQS) == iter->nr_spis;
>>> +}
>>> +
>>> +static void *debug_start(struct seq_file *s, loff_t *pos)
>>> +{
>>> + struct kvm *kvm = (struct kvm *)s->private;
>>> + struct vgic_state_iter *iter;
>>> +
>>> + mutex_lock(&kvm->lock);
>>> + iter = kvm->arch.vgic.iter;
>>> + if (iter) {
>>> + iter = ERR_PTR(-EBUSY);
>>> + goto out;
>>> + }
>>> +
>>> + iter = kmalloc(sizeof(*iter), GFP_KERNEL);
>>> + if (!iter) {
>>> + iter = ERR_PTR(-ENOMEM);
>>> + goto out;
>>> + }
>>> +
>>> + iter_init(kvm, iter, *pos);
>>> + kvm->arch.vgic.iter = iter;
>>> +
>>> + if (the_end(iter))
>>> + iter = NULL;
>>
>> I don't understand the need for that. If you have just initialized iter,
>> the_end() will never return true, as at least dist_id is always 0.
>> Or is there some magic (maybe future?) feature that I miss here?
>>
>
> This has file position semantics, so it's possible to call debug_start
> with a non-zero offset, and in fact possible to jump all the way ahead
> past the end of the file. In this case, this function must return NULL.
Arrg, sorry, I missed that pos. Shouldn't review "just this one patch
before leaving for the weekend" ...
> I base this on a number of examples out there (there's a recent one on
> lwn.net) and on trying to understand the seq file logic.
Which I admittedly still have to do.
>>> +out:
>>> + mutex_unlock(&kvm->lock);
>>> + return iter;
>>> +}
>>> +
>>> +static void *debug_next(struct seq_file *s, void *v, loff_t *pos)
>>> +{
>>> + struct kvm *kvm = (struct kvm *)s->private;
>>> + struct vgic_state_iter *iter = kvm->arch.vgic.iter;
>>> +
>>> + ++*pos;
>>> + iter_next(iter);
>>> + if (the_end(iter))
>>> + iter = NULL;
>>> + return iter;
>>> +}
>>> +
>>> +static void debug_stop(struct seq_file *s, void *v)
>>> +{
>>> + struct kvm *kvm = (struct kvm *)s->private;
>>> + struct vgic_state_iter *iter;
>>> +
>>> + mutex_lock(&kvm->lock);
>>> + iter = kvm->arch.vgic.iter;
>>> + kfree(iter);
>>> + kvm->arch.vgic.iter = NULL;
>>
>> Would it be better to set the kvm->iter pointer to NULL before we free
>> it? Or doesn't this matter as we are under the lock and the only other
>> code who cares is debug_start()?
>
> Yeah, that would be the definition of a critical section wouldn't it?
>
> I don't mind moving it around though, if it makes some
No, please leave it, I guess I was just confused why you had this iter
variable in the first place.
>> So far, need to wrap my mind around this sequential file operations
>> scheme first ...
>>
>
> Thanks for having a look. I don't think we need to overdo this one,
> it's a debug feature, it seems pretty stable, and you need root access
> to look at it, but of course it shouldn't be entirely shitty either.
No, I insist on some serious bike shedding here ;-)
I will test it quickly on Monday and the give you at least a Tested-by
(since I just disqualified myself for anything else).
Cheers,
Andre.
More information about the linux-arm-kernel
mailing list