Re: [PATCH RESEND v2 07/17] KVM: Move running VCPU from ARM to common code

Paolo Bonzini
2020-01-08T17:48:01Z

On 21/12/19 02:49, Peter Xu wrote:
> From: Paolo Bonzini <pbonzini@redhat.com>
>
> For ring-based dirty log tracking, it will be more efficient to account
> writes during schedule-out or schedule-in to the currently running VCPU.
> We would like to do it even if the write doesn't use the current VCPU's
> address space, as is the case for cached writes (see commit 4e335d9e7ddb,
> "Revert "KVM: Support vCPU-based gfn->hva cache"", 2017-05-02).
>
> Therefore, add a mechanism to track the currently-loaded kvm_vcpu struct.
> There is already something similar in KVM/ARM; one important difference
> is that kvm_arch_vcpu_{load,put} have two callers in virt/kvm/kvm_main.c:
> we have to update both the architecture-independent vcpu_{load,put} and
> the preempt notifiers.
>
> Another change made in the process is to allow using kvm_get_running_vcpu()
> in preemptible code. This is allowed because preempt notifiers ensure
> that the value does not change even after the VCPU thread is migrated.
>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Peter Xu <peterx@redhat.com>
> ---
> arch/arm/include/asm/kvm_host.h | 2 --
> arch/arm64/include/asm/kvm_host.h | 2 --
> include/linux/kvm_host.h | 3 +++
> virt/kvm/arm/arch_timer.c | 2 +-
> virt/kvm/arm/arm.c | 29 -----------------------------
> virt/kvm/arm/perf.c | 6 +++---
> virt/kvm/arm/vgic/vgic-mmio.c | 15 +++------------
> virt/kvm/kvm_main.c | 25 ++++++++++++++++++++++++-
> 8 files changed, 34 insertions(+), 50 deletions(-)
>
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index 8a37c8e89777..40eff9cc3744 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -274,8 +274,6 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
> int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
> int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
>
> -struct kvm_vcpu *kvm_arm_get_running_vcpu(void);
> -struct kvm_vcpu __percpu **kvm_get_running_vcpus(void);
> void kvm_arm_halt_guest(struct kvm *kvm);
> void kvm_arm_resume_guest(struct kvm *kvm);
>
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index f656169db8c3..df8d72f7c20e 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -430,8 +430,6 @@ int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
> int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
> int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
>
> -struct kvm_vcpu *kvm_arm_get_running_vcpu(void);
> -struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void);
> void kvm_arm_halt_guest(struct kvm *kvm);
> void kvm_arm_resume_guest(struct kvm *kvm);
>
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index 24854c9e3717..b4f7bef38e0d 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -1323,6 +1323,9 @@ static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val)
> }
> #endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */
>
> +struct kvm_vcpu *kvm_get_running_vcpu(void);
> +struct kvm_vcpu __percpu **kvm_get_running_vcpus(void);
> +
> #ifdef CONFIG_HAVE_KVM_IRQ_BYPASS
> bool kvm_arch_has_irq_bypass(void);
> int kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *,
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index e2bb5bd60227..085e7fed850c 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -1022,7 +1022,7 @@ static bool timer_irqs_are_valid(struct kvm_vcpu *vcpu)
>
> bool kvm_arch_timer_get_input_level(int vintid)
> {
> - struct kvm_vcpu *vcpu = kvm_arm_get_running_vcpu();
> + struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
> struct arch_timer_context *timer;
>
> if (vintid == vcpu_vtimer(vcpu)->irq.irq)
> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index 86c6aa1cb58e..f7dbb94ec525 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -47,9 +47,6 @@ __asm__(".arch_extension virt");
> DEFINE_PER_CPU(kvm_host_data_t, kvm_host_data);
> static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page);
>
> -/* Per-CPU variable containing the currently running vcpu. */
> -static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_arm_running_vcpu);
> -
> /* The VMID used in the VTTBR */
> static atomic64_t kvm_vmid_gen = ATOMIC64_INIT(1);
> static u32 kvm_next_vmid;
> @@ -58,31 +55,8 @@ static DEFINE_SPINLOCK(kvm_vmid_lock);
> static bool vgic_present;
>
> static DEFINE_PER_CPU(unsigned char, kvm_arm_hardware_enabled);
> -
> -static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
> -{
> - __this_cpu_write(kvm_arm_running_vcpu, vcpu);
> -}
> -
> DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
>
> -/**
> - * kvm_arm_get_running_vcpu - get the vcpu running on the current CPU.
> - * Must be called from non-preemptible context
> - */
> -struct kvm_vcpu *kvm_arm_get_running_vcpu(void)
> -{
> - return __this_cpu_read(kvm_arm_running_vcpu);
> -}
> -
> -/**
> - * kvm_arm_get_running_vcpus - get the per-CPU array of currently running vcpus.
> - */
> -struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void)
> -{
> - return &kvm_arm_running_vcpu;
> -}
> -
> int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
> {
> return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
> @@ -374,7 +348,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> vcpu->cpu = cpu;
> vcpu->arch.host_cpu_context = &cpu_data->host_ctxt;
>
> - kvm_arm_set_running_vcpu(vcpu);
> kvm_vgic_load(vcpu);
> kvm_timer_vcpu_load(vcpu);
> kvm_vcpu_load_sysregs(vcpu);
> @@ -398,8 +371,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
> kvm_vcpu_pmu_restore_host(vcpu);
>
> vcpu->cpu = -1;
> -
> - kvm_arm_set_running_vcpu(NULL);
> }
>
> static void vcpu_power_off(struct kvm_vcpu *vcpu)
> diff --git a/virt/kvm/arm/perf.c b/virt/kvm/arm/perf.c
> index 918cdc3839ea..d45b8b9a4415 100644
> --- a/virt/kvm/arm/perf.c
> +++ b/virt/kvm/arm/perf.c
> @@ -13,14 +13,14 @@
>
> static int kvm_is_in_guest(void)
> {
> - return kvm_arm_get_running_vcpu() != NULL;
> + return kvm_get_running_vcpu() != NULL;
> }
>
> static int kvm_is_user_mode(void)
> {
> struct kvm_vcpu *vcpu;
>
> - vcpu = kvm_arm_get_running_vcpu();
> + vcpu = kvm_get_running_vcpu();
>
> if (vcpu)
> return !vcpu_mode_priv(vcpu);
> @@ -32,7 +32,7 @@ static unsigned long kvm_get_guest_ip(void)
> {
> struct kvm_vcpu *vcpu;
>
> - vcpu = kvm_arm_get_running_vcpu();
> + vcpu = kvm_get_running_vcpu();
>
> if (vcpu)
> return *vcpu_pc(vcpu);
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 0d090482720d..d656ebd5f9d4 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -190,15 +190,6 @@ unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
> * value later will give us the same value as we update the per-CPU variable
> * in the preempt notifier handlers.
> */
> -static struct kvm_vcpu *vgic_get_mmio_requester_vcpu(void)
> -{
> - struct kvm_vcpu *vcpu;
> -
> - preempt_disable();
> - vcpu = kvm_arm_get_running_vcpu();
> - preempt_enable();
> - return vcpu;
> -}
>
> /* Must be called with irq->irq_lock held */
> static void vgic_hw_irq_spending(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
> @@ -221,7 +212,7 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
> gpa_t addr, unsigned int len,
> unsigned long val)
> {
> - bool is_uaccess = !vgic_get_mmio_requester_vcpu();
> + bool is_uaccess = !kvm_get_running_vcpu();
> u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
> int i;
> unsigned long flags;
> @@ -274,7 +265,7 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
> gpa_t addr, unsigned int len,
> unsigned long val)
> {
> - bool is_uaccess = !vgic_get_mmio_requester_vcpu();
> + bool is_uaccess = !kvm_get_running_vcpu();
> u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
> int i;
> unsigned long flags;
> @@ -335,7 +326,7 @@ static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
> bool active)
> {
> unsigned long flags;
> - struct kvm_vcpu *requester_vcpu = vgic_get_mmio_requester_vcpu();
> + struct kvm_vcpu *requester_vcpu = kvm_get_running_vcpu();
>
> raw_spin_lock_irqsave(&irq->irq_lock, flags);
>
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 17969cf110dd..5c606d158854 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -108,6 +108,7 @@ struct kmem_cache *kvm_vcpu_cache;
> EXPORT_SYMBOL_GPL(kvm_vcpu_cache);
>
> static __read_mostly struct preempt_ops kvm_preempt_ops;
> +static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_running_vcpu);
>
> struct dentry *kvm_debugfs_dir;
> EXPORT_SYMBOL_GPL(kvm_debugfs_dir);
> @@ -199,6 +200,8 @@ bool kvm_is_reserved_pfn(kvm_pfn_t pfn)
> void vcpu_load(struct kvm_vcpu *vcpu)
> {
> int cpu = get_cpu();
> +
> + __this_cpu_write(kvm_running_vcpu, vcpu);
> preempt_notifier_register(&vcpu->preempt_notifier);
> kvm_arch_vcpu_load(vcpu, cpu);
> put_cpu();
> @@ -210,6 +213,7 @@ void vcpu_put(struct kvm_vcpu *vcpu)
> preempt_disable();
> kvm_arch_vcpu_put(vcpu);
> preempt_notifier_unregister(&vcpu->preempt_notifier);
> + __this_cpu_write(kvm_running_vcpu, NULL);
> preempt_enable();
> }
> EXPORT_SYMBOL_GPL(vcpu_put);
> @@ -4294,8 +4298,8 @@ static void kvm_sched_in(struct preempt_notifier *pn, int cpu)
> WRITE_ONCE(vcpu->preempted, false);
> WRITE_ONCE(vcpu->ready, false);
>
> + __this_cpu_write(kvm_running_vcpu, vcpu);
> kvm_arch_sched_in(vcpu, cpu);
> -
> kvm_arch_vcpu_load(vcpu, cpu);
> }
>
> @@ -4309,6 +4313,25 @@ static void kvm_sched_out(struct preempt_notifier *pn,
> WRITE_ONCE(vcpu->ready, true);
> }
> kvm_arch_vcpu_put(vcpu);
> + __this_cpu_write(kvm_running_vcpu, NULL);
> +}
> +
> +/**
> + * kvm_get_running_vcpu - get the vcpu running on the current CPU.
> + * Thanks to preempt notifiers, this can also be called from
> + * preemptible context.
> + */
> +struct kvm_vcpu *kvm_get_running_vcpu(void)
> +{
> + return __this_cpu_read(kvm_running_vcpu);
> +}
> +
> +/**
> + * kvm_get_running_vcpus - get the per-CPU array of currently running vcpus.
> + */
> +struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void)
> +{
> + return &kvm_running_vcpu;
> }
>
> static void check_processor_compat(void *rtn)
>

Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>