Re: [PATCH v2 32/43] KVM: VMX: Move preemption timer <=> hrtimer dance to common x86

Maxim Levitsky <[email protected]>
Newsgroups org.kernel.vger.kvm-ppc,dev.linux.lists.kvmarm,org.infradead.lists.kvm-riscv,org.infradead.lists.linux-arm-kernel,org.infradead.lists.linux-riscv,org.kernel.vger.kvm,org.kernel.vger.linux-kernel,org.kernel.vger.linux-mips
Message-ID <[email protected]>
On Fri, 2021-10-08 at 19:12 -0700, Sean Christopherson wrote:
> Handle the switch to/from the hypervisor/software timer when a vCPU is
> blocking in common x86 instead of in VMX.  Even though VMX is the only
> user of a hypervisor timer, the logic and all functions involved are
> generic x86 (unless future CPUs do something completely different and
> implement a hypervisor timer that runs regardless of mode).
> 
> Handling the switch in common x86 will allow for the elimination of the
> pre/post_blocks hooks, and also lets KVM switch back to the hypervisor
> timer if and only if it was in use (without additional params).  Add a
> comment explaining why the switch cannot be deferred to kvm_sched_out()
> or kvm_vcpu_block().
> 
> Signed-off-by: Sean Christopherson <[email protected]>
> ---
>  arch/x86/kvm/vmx/vmx.c |  6 +-----
>  arch/x86/kvm/x86.c     | 21 +++++++++++++++++++++
>  2 files changed, 22 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index b3bb2031a7ac..a24f19874716 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -7464,16 +7464,12 @@ void vmx_update_cpu_dirty_logging(struct kvm_vcpu *vcpu)
>  
>  static int vmx_pre_block(struct kvm_vcpu *vcpu)
>  {
> -	if (kvm_lapic_hv_timer_in_use(vcpu))
> -		kvm_lapic_switch_to_sw_timer(vcpu);
> -
>  	return 0;
>  }
>  
>  static void vmx_post_block(struct kvm_vcpu *vcpu)
>  {
> -	if (kvm_x86_ops.set_hv_timer)
> -		kvm_lapic_switch_to_hv_timer(vcpu);
> +
>  }
>  
>  static void vmx_setup_mce(struct kvm_vcpu *vcpu)
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index e0219acfd9cf..909e932a7ae7 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -9896,8 +9896,21 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
>  
>  static inline int vcpu_block(struct kvm *kvm, struct kvm_vcpu *vcpu)
>  {
> +	bool hv_timer;
> +
>  	if (!kvm_arch_vcpu_runnable(vcpu) &&
>  	    (!kvm_x86_ops.pre_block || static_call(kvm_x86_pre_block)(vcpu) = 0)) {
> +		/*
> +		 * Switch to the software timer before halt-polling/blocking as
> +		 * the guest's timer may be a break event for the vCPU, and the
> +		 * hypervisor timer runs only when the CPU is in guest mode.
> +		 * Switch before halt-polling so that KVM recognizes an expired
> +		 * timer before blocking.
> +		 */

I didn't knew about this until now but it all makes sense. The comment is very good.

> +		hv_timer = kvm_lapic_hv_timer_in_use(vcpu);
> +		if (hv_timer)
> +			kvm_lapic_switch_to_sw_timer(vcpu);
> +
>  		srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
>  		if (vcpu->arch.mp_state = KVM_MP_STATE_HALTED)
>  			kvm_vcpu_halt(vcpu);
> @@ -9905,6 +9918,9 @@ static inline int vcpu_block(struct kvm *kvm, struct kvm_vcpu *vcpu)
>  			kvm_vcpu_block(vcpu);
>  		vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
>  
> +		if (hv_timer)
> +			kvm_lapic_switch_to_hv_timer(vcpu);
> +
>  		if (kvm_x86_ops.post_block)
>  			static_call(kvm_x86_post_block)(vcpu);
>  
> @@ -10136,6 +10152,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
>  			r = -EINTR;
>  			goto out;
>  		}
> +		/*
> +		 * It should be impossible for the hypervisor timer to be in
> +		 * use before KVM has ever run the vCPU.
> +		 */
> +		WARN_ON_ONCE(kvm_lapic_hv_timer_in_use(vcpu));
>  		kvm_vcpu_block(vcpu);
>  		if (kvm_apic_accept_events(vcpu) < 0) {
>  			r = 0;

Reviewed-by: Maxim Levitsky <[email protected]>

Best regards,
	Maxim Levitsky
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.