kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Maxim Levitsky <mlevitsk@redhat.com>
To: Paolo Bonzini <pbonzini@redhat.com>, kvm@vger.kernel.org
Cc: Thomas Gleixner <tglx@linutronix.de>,
	Sean Christopherson <seanjc@google.com>,
	Wanpeng Li <wanpengli@tencent.com>,
	Vitaly Kuznetsov <vkuznets@redhat.com>,
	Joerg Roedel <joro@8bytes.org>, Borislav Petkov <bp@alien8.de>,
	"H. Peter Anvin" <hpa@zytor.com>, Ingo Molnar <mingo@redhat.com>,
	"open list:X86 ARCHITECTURE (32-BIT AND 64-BIT)" 
	<linux-kernel@vger.kernel.org>,
	"maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT)"
	<x86@kernel.org>, Jim Mattson <jmattson@google.com>
Subject: Re: [PATCH 02/10] KVM: x86: APICv: fix race in kvm_request_apicv_update on SVM
Date: Wed, 07 Jul 2021 15:57:26 +0300	[thread overview]
Message-ID: <9413056ebbd5997a35b446f2841589973484ba02.camel@redhat.com> (raw)
In-Reply-To: <43ef1a1ea488977db11d40ec9672b524ec816112.camel@redhat.com>

On Thu, 2021-06-24 at 11:07 +0300, Maxim Levitsky wrote:
> On Wed, 2021-06-23 at 23:50 +0200, Paolo Bonzini wrote:
> > On 23/06/21 13:29, Maxim Levitsky wrote:
> > > +	kvm_block_guest_entries(kvm);
> > > +
> > >   	trace_kvm_apicv_update_request(activate, bit);
> > >   	if (kvm_x86_ops.pre_update_apicv_exec_ctrl)
> > >   		static_call(kvm_x86_pre_update_apicv_exec_ctrl)(kvm, activate);
> > > @@ -9243,6 +9245,8 @@ void kvm_request_apicv_update(struct kvm *kvm, bool activate, ulong bit)
> > >   	except = kvm_get_running_vcpu();
> > >   	kvm_make_all_cpus_request_except(kvm, KVM_REQ_APICV_UPDATE,
> > >   					 except);
> > > +
> > > +	kvm_allow_guest_entries(kvm);
> > 
> > Doesn't this cause a busy loop during synchronize_rcu?
> 
> Hi,
> 
> If you mean busy loop on other vcpus, then the answer is sadly yes.
> Other option is to use a mutex, which is what I did in a former
> version of this patch, but at last minute I decided that this
> way it was done in this patch would be simplier. 
> AVIC updates don't happen often.
> Also with a request, the KVM_REQ_APICV_UPDATE can be handled in parallel,
> while mutex enforces unneeded mutual execution of it.
> 
> 
> >   It should be 
> > possible to request the vmexit of other CPUs from 
> > avic_update_access_page, and do a lock/unlock of kvm->slots_lock to wait 
> > for the memslot to be updated.
> 
> This would still keep the race. The other vCPUs must not enter the guest mode
> from the moment the memslot update was started and until the KVM_REQ_APICV_UPDATE
> is raised.
>  
> If I were to do any kind of synchronization in avic_update_access_page, then I will
> have to drop the lock/request there, and from this point and till the common code
> raises the KVM_REQ_APICV_UPDATE there is a possibility of a vCPU reentering the
> guest mode without updating its AVIC.
>  
>  
> Here is an older version of this patch that does use mutex instead. 
> Please let me know if you prefer it.
> 
> I copy pasted it here, thus its likely not to apply as my email client
> probably destroys whitespace.
>   
> Thanks for the review,
> 	Best regards,
> 		Maxim Levitsky
> 
> 
> --
> 
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index fdc6b8a4348f..b7dc7fd7b63d 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -9183,11 +9183,8 @@ void kvm_make_scan_ioapic_request(struct kvm *kvm)
>  	kvm_make_all_cpus_request(kvm, KVM_REQ_SCAN_IOAPIC);
>  }
>  
> -void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu)
> +void __kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu)
>  {
> -	if (!lapic_in_kernel(vcpu))
> -		return;
> -
>  	vcpu->arch.apicv_active = kvm_apicv_activated(vcpu->kvm);
>  	kvm_apic_update_apicv(vcpu);
>  	static_call(kvm_x86_refresh_apicv_exec_ctrl)(vcpu);
> @@ -9201,6 +9198,16 @@ void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu)
>  	if (!vcpu->arch.apicv_active)
>  		kvm_make_request(KVM_REQ_EVENT, vcpu);
>  }
> +
> +void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu)
> +{
> +	if (!lapic_in_kernel(vcpu))
> +		return;
> +
> +	mutex_lock(&vcpu->kvm->apicv_update_lock);
> +	__kvm_vcpu_update_apicv(vcpu);
> +	mutex_unlock(&vcpu->kvm->apicv_update_lock);
> +}
>  EXPORT_SYMBOL_GPL(kvm_vcpu_update_apicv);
>  
>  /*
> @@ -9213,30 +9220,26 @@ EXPORT_SYMBOL_GPL(kvm_vcpu_update_apicv);
>  void kvm_request_apicv_update(struct kvm *kvm, bool activate, ulong bit)
>  {
>  	struct kvm_vcpu *except;
> -	unsigned long old, new, expected;
> +	unsigned long old, new;
>  
>  	if (!kvm_x86_ops.check_apicv_inhibit_reasons ||
>  	    !static_call(kvm_x86_check_apicv_inhibit_reasons)(bit))
>  		return;
>  
> -	old = READ_ONCE(kvm->arch.apicv_inhibit_reasons);
> -	do {
> -		expected = new = old;
> -		if (activate)
> -			__clear_bit(bit, &new);
> -		else
> -			__set_bit(bit, &new);
> -		if (new == old)
> -			break;
> -		old = cmpxchg(&kvm->arch.apicv_inhibit_reasons, expected, new);
> -	} while (old != expected);
> +	mutex_lock(&kvm->apicv_update_lock);
> +
> +	old = new = kvm->arch.apicv_inhibit_reasons;
> +	if (activate)
> +		__clear_bit(bit, &new);
> +	else
> +		__set_bit(bit, &new);
> +
> +	WRITE_ONCE(kvm->arch.apicv_inhibit_reasons, new);
>  
>  	if (!!old == !!new)
> -		return;
> +		goto out;
>  
>  	trace_kvm_apicv_update_request(activate, bit);
> -	if (kvm_x86_ops.pre_update_apicv_exec_ctrl)
> -		static_call(kvm_x86_pre_update_apicv_exec_ctrl)(kvm, activate);
>  
>  	/*
>  	 * Sending request to update APICV for all other vcpus,
> @@ -9244,10 +9247,24 @@ void kvm_request_apicv_update(struct kvm *kvm, bool activate, ulong bit)
>  	 * waiting for another #VMEXIT to handle the request.
>  	 */
>  	except = kvm_get_running_vcpu();
> +
> +	/*
> +	 * on SVM, raising the KVM_REQ_APICV_UPDATE request while holding the
> +	 *  apicv_update_lock ensures that we kick all vCPUs out of the
> +	 *  guest mode and let them wait until the AVIC memslot update
> +	 *  has completed.
> +	 */
> +
>  	kvm_make_all_cpus_request_except(kvm, KVM_REQ_APICV_UPDATE,
>  					 except);
> +
> +	if (kvm_x86_ops.pre_update_apicv_exec_ctrl)
> +		static_call(kvm_x86_pre_update_apicv_exec_ctrl)(kvm, activate);
> +
>  	if (except)
> -		kvm_vcpu_update_apicv(except);
> +		__kvm_vcpu_update_apicv(except);
> +out:
> +	mutex_unlock(&kvm->apicv_update_lock);
>  }
>  EXPORT_SYMBOL_GPL(kvm_request_apicv_update);
>  
> @@ -9454,8 +9471,11 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
>  		 */
>  		if (kvm_check_request(KVM_REQ_HV_STIMER, vcpu))
>  			kvm_hv_process_stimers(vcpu);
> -		if (kvm_check_request(KVM_REQ_APICV_UPDATE, vcpu))
> +		if (kvm_check_request(KVM_REQ_APICV_UPDATE, vcpu)) {
> +			srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>  			kvm_vcpu_update_apicv(vcpu);
> +			vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
> +		}
>  		if (kvm_check_request(KVM_REQ_APF_READY, vcpu))
>  			kvm_check_async_pf_completion(vcpu);
>  		if (kvm_check_request(KVM_REQ_MSR_FILTER_CHANGED, vcpu))
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index 37cbb56ccd09..0364d35d43dc 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -524,6 +524,7 @@ struct kvm {
>  #endif /* KVM_HAVE_MMU_RWLOCK */
>  
>  	struct mutex slots_lock;
> +	struct mutex apicv_update_lock;
>  
>  	/*
>  	 * Protects the arch-specific fields of struct kvm_memory_slots in
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index ed4d1581d502..ba5d5d9ebc64 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -943,6 +943,7 @@ static struct kvm *kvm_create_vm(unsigned long type)
>  	mutex_init(&kvm->irq_lock);
>  	mutex_init(&kvm->slots_lock);
>  	mutex_init(&kvm->slots_arch_lock);
> +	mutex_init(&kvm->apicv_update_lock);
>  	INIT_LIST_HEAD(&kvm->devices);
>  
>  	BUILD_BUG_ON(KVM_MEM_SLOTS_NUM > SHRT_MAX);
> 
> 
> 
> > (As an aside, I'd like to get rid of KVM_REQ_MCLOCK_IN_PROGRESS in 5.15...).
> > 
> > Paolo
> > 


Hi!
Any update? should I use a lock for this?


Best regards,
	Maxim Levitsky



  reply	other threads:[~2021-07-07 12:57 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-23 11:29 [PATCH 00/10] My AVIC patch queue Maxim Levitsky
2021-06-23 11:29 ` [PATCH 01/10] KVM: x86: extract block/allow guest enteries Maxim Levitsky
2021-06-23 11:29 ` [PATCH 02/10] KVM: x86: APICv: fix race in kvm_request_apicv_update on SVM Maxim Levitsky
2021-06-23 21:50   ` Paolo Bonzini
2021-06-24  8:07     ` Maxim Levitsky
2021-07-07 12:57       ` Maxim Levitsky [this message]
2021-07-07 13:58         ` Paolo Bonzini
2021-06-23 11:29 ` [PATCH 03/10] KVM: x86: rename apic_access_page_done to apic_access_memslot_enabled Maxim Levitsky
2021-06-23 21:50   ` Paolo Bonzini
2021-06-23 11:29 ` [PATCH 04/10] KVM: SVM: add warning for mistmatch between AVIC state and AVIC access page state Maxim Levitsky
2021-06-23 21:53   ` Paolo Bonzini
2021-06-24  8:13     ` Maxim Levitsky
2021-06-23 11:29 ` [PATCH 05/10] KVM: SVM: svm_set_vintr don't warn if AVIC is active but is about to be deactivated Maxim Levitsky
2021-06-23 11:29 ` [PATCH 06/10] KVM: SVM: tweak warning about enabled AVIC on nested entry Maxim Levitsky
2021-06-23 21:52   ` Paolo Bonzini
2021-06-23 11:29 ` [PATCH 07/10] KVM: SVM: use vmcb01 in svm_refresh_apicv_exec_ctrl Maxim Levitsky
2021-06-23 21:54   ` Paolo Bonzini
2021-06-24  8:16     ` Maxim Levitsky
2021-06-23 11:30 ` [PATCH 08/10] KVM: x86: APICv: drop immediate APICv disablement on current vCPU Maxim Levitsky
2021-06-23 11:30 ` [PATCH 09/10] KVM: SVM: call avic_vcpu_load/avic_vcpu_put when enabling/disabling AVIC Maxim Levitsky
2021-06-23 11:30 ` [PATCH 10/10] KVM: x86: hyper-v: Deactivate APICv only when AutoEOI feature is in use Maxim Levitsky

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=9413056ebbd5997a35b446f2841589973484ba02.camel@redhat.com \
    --to=mlevitsk@redhat.com \
    --cc=bp@alien8.de \
    --cc=hpa@zytor.com \
    --cc=jmattson@google.com \
    --cc=joro@8bytes.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=seanjc@google.com \
    --cc=tglx@linutronix.de \
    --cc=vkuznets@redhat.com \
    --cc=wanpengli@tencent.com \
    --cc=x86@kernel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).