diff mbox

KVM: VMX: Do not overwrite vcpu->srcu_idx in vmx_vcpu_reset

Message ID 5141E41B.8080804@siemens.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jan Kiszka March 14, 2013, 2:52 p.m. UTC
vmx_vcpu_reset may now be called while already holding the srcu lock, so
we may overwrite what was already saved there. Also, we lock and unlock
in the same context, thus there was no need to save to the vcpu anyway.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---

Marcelo just suggested this as the simplest fix for the issue caused by
the INIT/SIPI patch. Avoiding srcu lock for TSS handling might still be
possible but more tricky.

 arch/x86/kvm/vmx.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

Comments

Gleb Natapov March 14, 2013, 3 p.m. UTC | #1
On Thu, Mar 14, 2013 at 03:52:11PM +0100, Jan Kiszka wrote:
> vmx_vcpu_reset may now be called while already holding the srcu lock, so
> we may overwrite what was already saved there. Also, we lock and unlock
> in the same context, thus there was no need to save to the vcpu anyway.
> 
> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
> ---
> 
> Marcelo just suggested this as the simplest fix for the issue caused by
> the INIT/SIPI patch. Avoiding srcu lock for TSS handling might still be
> possible but more tricky.
> 
>  arch/x86/kvm/vmx.c |    5 +++--
>  1 files changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> index 958ac3a..be5b1dc 100644
> --- a/arch/x86/kvm/vmx.c
> +++ b/arch/x86/kvm/vmx.c
> @@ -4117,6 +4117,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
>  {
>  	struct vcpu_vmx *vmx = to_vmx(vcpu);
>  	u64 msr;
> +	int idx;
>  
>  	vmx->rmode.vm86_active = 0;
>  
> @@ -4190,9 +4191,9 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
>  		vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid);
>  
>  	vmx->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
> -	vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
> +	idx = srcu_read_lock(&vcpu->kvm->srcu);
>  	vmx_set_cr0(&vmx->vcpu, kvm_read_cr0(vcpu)); /* enter rmode */
> -	srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
> +	srcu_read_unlock(&vcpu->kvm->srcu, idx);
vmx_set_cr0() does:
                srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
                vmx_set_tss_addr(vcpu->kvm, 0xfeffd000);
                vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
So with this change the sequence will be:

vcpu->srcu_idx = srcu_read_lock()
  idx = srcu_read_lock(&vcpu->kvm->srcu); 
   srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
   vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
  srcu_read_unlock(&vcpu->kvm->srcu, idx);
srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);

Not sure this is valid.

>  	vmx_set_cr4(&vmx->vcpu, 0);
>  	vmx_set_efer(&vmx->vcpu, 0);
>  	vmx_fpu_activate(&vmx->vcpu);
> -- 
> 1.7.3.4

--
			Gleb.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jan Kiszka March 14, 2013, 3:03 p.m. UTC | #2
On 2013-03-14 16:00, Gleb Natapov wrote:
> On Thu, Mar 14, 2013 at 03:52:11PM +0100, Jan Kiszka wrote:
>> vmx_vcpu_reset may now be called while already holding the srcu lock, so
>> we may overwrite what was already saved there. Also, we lock and unlock
>> in the same context, thus there was no need to save to the vcpu anyway.
>>
>> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
>> ---
>>
>> Marcelo just suggested this as the simplest fix for the issue caused by
>> the INIT/SIPI patch. Avoiding srcu lock for TSS handling might still be
>> possible but more tricky.
>>
>>  arch/x86/kvm/vmx.c |    5 +++--
>>  1 files changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
>> index 958ac3a..be5b1dc 100644
>> --- a/arch/x86/kvm/vmx.c
>> +++ b/arch/x86/kvm/vmx.c
>> @@ -4117,6 +4117,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
>>  {
>>  	struct vcpu_vmx *vmx = to_vmx(vcpu);
>>  	u64 msr;
>> +	int idx;
>>  
>>  	vmx->rmode.vm86_active = 0;
>>  
>> @@ -4190,9 +4191,9 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
>>  		vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid);
>>  
>>  	vmx->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
>> -	vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
>> +	idx = srcu_read_lock(&vcpu->kvm->srcu);
>>  	vmx_set_cr0(&vmx->vcpu, kvm_read_cr0(vcpu)); /* enter rmode */
>> -	srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>> +	srcu_read_unlock(&vcpu->kvm->srcu, idx);
> vmx_set_cr0() does:
>                 srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>                 vmx_set_tss_addr(vcpu->kvm, 0xfeffd000);
>                 vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
> So with this change the sequence will be:
> 
> vcpu->srcu_idx = srcu_read_lock()
>   idx = srcu_read_lock(&vcpu->kvm->srcu); 
>    srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>    vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
>   srcu_read_unlock(&vcpu->kvm->srcu, idx);
> srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
> 
> Not sure this is valid.

Grmbl, likely not.

Jan
Paolo Bonzini March 14, 2013, 3:08 p.m. UTC | #3
Il 14/03/2013 16:03, Jan Kiszka ha scritto:
>> > vcpu->srcu_idx = srcu_read_lock()
>> >   idx = srcu_read_lock(&vcpu->kvm->srcu); 
>> >    srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>> >    vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
>> >   srcu_read_unlock(&vcpu->kvm->srcu, idx);
>> > srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>> > 
>> > Not sure this is valid.
> Grmbl, likely not.

It might be.

Isn't it the same as two different CPUs doing

CPU 1                                                 CPU 2
------------------------------------------------------------------------------------------------

vcpu->srcu_idx = srcu_read_lock()
                                                      idx = srcu_read_lock(&vcpu->kvm->srcu); 
srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
                                                      srcu_read_unlock(&vcpu->kvm->srcu, idx);
srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);

?

Paolo
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Gleb Natapov March 14, 2013, 3:11 p.m. UTC | #4
On Thu, Mar 14, 2013 at 04:08:42PM +0100, Paolo Bonzini wrote:
> Il 14/03/2013 16:03, Jan Kiszka ha scritto:
> >> > vcpu->srcu_idx = srcu_read_lock()
> >> >   idx = srcu_read_lock(&vcpu->kvm->srcu); 
> >> >    srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
> >> >    vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
> >> >   srcu_read_unlock(&vcpu->kvm->srcu, idx);
> >> > srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
> >> > 
> >> > Not sure this is valid.
> > Grmbl, likely not.
> 
> It might be.
> 
> Isn't it the same as two different CPUs doing
> 
> CPU 1                                                 CPU 2
> ------------------------------------------------------------------------------------------------
> 
> vcpu->srcu_idx = srcu_read_lock()
>                                                       idx = srcu_read_lock(&vcpu->kvm->srcu); 
> srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
> vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
>                                                       srcu_read_unlock(&vcpu->kvm->srcu, idx);
> srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
> 
> ?
> 
Srcu may have per cpu state. We can always ask Paul.

--
			Gleb.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jan Kiszka March 14, 2013, 3:11 p.m. UTC | #5
On 2013-03-14 16:08, Paolo Bonzini wrote:
> Il 14/03/2013 16:03, Jan Kiszka ha scritto:
>>>> vcpu->srcu_idx = srcu_read_lock()
>>>>   idx = srcu_read_lock(&vcpu->kvm->srcu); 
>>>>    srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>>>>    vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
>>>>   srcu_read_unlock(&vcpu->kvm->srcu, idx);
>>>> srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>>>>
>>>> Not sure this is valid.
>> Grmbl, likely not.
> 
> It might be.
> 
> Isn't it the same as two different CPUs doing
> 
> CPU 1                                                 CPU 2
> ------------------------------------------------------------------------------------------------
> 
> vcpu->srcu_idx = srcu_read_lock()
>                                                       idx = srcu_read_lock(&vcpu->kvm->srcu); 
> srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
> vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
>                                                       srcu_read_unlock(&vcpu->kvm->srcu, idx);
> srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
> 
> ?

Isn't there any per-cpu info encoded in idx?

Jan
Paolo Bonzini March 14, 2013, 3:45 p.m. UTC | #6
Il 14/03/2013 16:11, Gleb Natapov ha scritto:
> On Thu, Mar 14, 2013 at 04:08:42PM +0100, Paolo Bonzini wrote:
>> Il 14/03/2013 16:03, Jan Kiszka ha scritto:
>>>>> vcpu->srcu_idx = srcu_read_lock()
>>>>>   idx = srcu_read_lock(&vcpu->kvm->srcu); 
>>>>>    srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>>>>>    vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
>>>>>   srcu_read_unlock(&vcpu->kvm->srcu, idx);
>>>>> srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>>>>>
>>>>> Not sure this is valid.
>>> Grmbl, likely not.
>>
>> It might be.
>>
>> Isn't it the same as two different CPUs doing
>>
>> CPU 1                                                 CPU 2
>> ------------------------------------------------------------------------------------------------
>>
>> vcpu->srcu_idx = srcu_read_lock()
>>                                                       idx = srcu_read_lock(&vcpu->kvm->srcu); 
>> srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>> vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
>>                                                       srcu_read_unlock(&vcpu->kvm->srcu, idx);
>> srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>>
>> ?
>>
> Srcu may have per cpu state. We can always ask Paul.

There is per-CPU state but it is only used as an optimization.
synchronize_srcu only uses the sum of all values.

In fact, SRCU critical sections are preemptable so there's not even a
guarantee that srcu_read_lock() and srcu_read_unlock() run on the same CPU.

Paolo

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Marcelo Tosatti March 14, 2013, 7:14 p.m. UTC | #7
On Thu, Mar 14, 2013 at 05:00:04PM +0200, Gleb Natapov wrote:
> On Thu, Mar 14, 2013 at 03:52:11PM +0100, Jan Kiszka wrote:
> > vmx_vcpu_reset may now be called while already holding the srcu lock, so
> > we may overwrite what was already saved there. Also, we lock and unlock
> > in the same context, thus there was no need to save to the vcpu anyway.
> > 
> > Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
> > ---
> > 
> > Marcelo just suggested this as the simplest fix for the issue caused by
> > the INIT/SIPI patch. Avoiding srcu lock for TSS handling might still be
> > possible but more tricky.
> > 
> >  arch/x86/kvm/vmx.c |    5 +++--
> >  1 files changed, 3 insertions(+), 2 deletions(-)
> > 
> > diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> > index 958ac3a..be5b1dc 100644
> > --- a/arch/x86/kvm/vmx.c
> > +++ b/arch/x86/kvm/vmx.c
> > @@ -4117,6 +4117,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
> >  {
> >  	struct vcpu_vmx *vmx = to_vmx(vcpu);
> >  	u64 msr;
> > +	int idx;
> >  
> >  	vmx->rmode.vm86_active = 0;
> >  
> > @@ -4190,9 +4191,9 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
> >  		vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid);
> >  
> >  	vmx->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
> > -	vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
> > +	idx = srcu_read_lock(&vcpu->kvm->srcu);
> >  	vmx_set_cr0(&vmx->vcpu, kvm_read_cr0(vcpu)); /* enter rmode */
> > -	srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
> > +	srcu_read_unlock(&vcpu->kvm->srcu, idx);
> vmx_set_cr0() does:
>                 srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>                 vmx_set_tss_addr(vcpu->kvm, 0xfeffd000);
>                 vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
> So with this change the sequence will be:
> 
> vcpu->srcu_idx = srcu_read_lock()
>   idx = srcu_read_lock(&vcpu->kvm->srcu); 
>    srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>    vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
>   srcu_read_unlock(&vcpu->kvm->srcu, idx);
> srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
> 
> Not sure this is valid.

The lock/unlocks must be paired.

Pass parameters around to make that happen?

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jan Kiszka March 14, 2013, 7:20 p.m. UTC | #8
On 2013-03-14 20:14, Marcelo Tosatti wrote:
> On Thu, Mar 14, 2013 at 05:00:04PM +0200, Gleb Natapov wrote:
>> On Thu, Mar 14, 2013 at 03:52:11PM +0100, Jan Kiszka wrote:
>>> vmx_vcpu_reset may now be called while already holding the srcu lock, so
>>> we may overwrite what was already saved there. Also, we lock and unlock
>>> in the same context, thus there was no need to save to the vcpu anyway.
>>>
>>> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
>>> ---
>>>
>>> Marcelo just suggested this as the simplest fix for the issue caused by
>>> the INIT/SIPI patch. Avoiding srcu lock for TSS handling might still be
>>> possible but more tricky.
>>>
>>>  arch/x86/kvm/vmx.c |    5 +++--
>>>  1 files changed, 3 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
>>> index 958ac3a..be5b1dc 100644
>>> --- a/arch/x86/kvm/vmx.c
>>> +++ b/arch/x86/kvm/vmx.c
>>> @@ -4117,6 +4117,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
>>>  {
>>>  	struct vcpu_vmx *vmx = to_vmx(vcpu);
>>>  	u64 msr;
>>> +	int idx;
>>>  
>>>  	vmx->rmode.vm86_active = 0;
>>>  
>>> @@ -4190,9 +4191,9 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
>>>  		vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid);
>>>  
>>>  	vmx->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
>>> -	vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
>>> +	idx = srcu_read_lock(&vcpu->kvm->srcu);
>>>  	vmx_set_cr0(&vmx->vcpu, kvm_read_cr0(vcpu)); /* enter rmode */
>>> -	srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>>> +	srcu_read_unlock(&vcpu->kvm->srcu, idx);
>> vmx_set_cr0() does:
>>                 srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>>                 vmx_set_tss_addr(vcpu->kvm, 0xfeffd000);
>>                 vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
>> So with this change the sequence will be:
>>
>> vcpu->srcu_idx = srcu_read_lock()
>>   idx = srcu_read_lock(&vcpu->kvm->srcu); 
>>    srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>>    vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
>>   srcu_read_unlock(&vcpu->kvm->srcu, idx);
>> srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
>>
>> Not sure this is valid.
> 
> The lock/unlocks must be paired.

Did you find out more than what Paolo reported?

> 
> Pass parameters around to make that happen?

Or we save/restore srcu_idx when overwriting.

Jan
Marcelo Tosatti March 14, 2013, 8:02 p.m. UTC | #9
On Thu, Mar 14, 2013 at 08:20:26PM +0100, Jan Kiszka wrote:
> >> Not sure this is valid.
> > 
> > The lock/unlocks must be paired.
> 
> Did you find out more than what Paolo reported?

/**
 * srcu_read_unlock - unregister a old reader from an SRCU-protected
 * structure.
 * @sp: srcu_struct in which to unregister the old reader.
 * @idx: return value from corresponding srcu_read_lock().
 *
 * Exit an SRCU read-side critical section.
 */
static inline void srcu_read_unlock(struct srcu_struct *sp, int idx)
        __releases(sp)
{
        rcu_lock_release(&(sp)->dep_map);
        __srcu_read_unlock(sp, idx);
}

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 958ac3a..be5b1dc 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -4117,6 +4117,7 @@  static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	u64 msr;
+	int idx;
 
 	vmx->rmode.vm86_active = 0;
 
@@ -4190,9 +4191,9 @@  static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
 		vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid);
 
 	vmx->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
-	vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
+	idx = srcu_read_lock(&vcpu->kvm->srcu);
 	vmx_set_cr0(&vmx->vcpu, kvm_read_cr0(vcpu)); /* enter rmode */
-	srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
+	srcu_read_unlock(&vcpu->kvm->srcu, idx);
 	vmx_set_cr4(&vmx->vcpu, 0);
 	vmx_set_efer(&vmx->vcpu, 0);
 	vmx_fpu_activate(&vmx->vcpu);