[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH for-4.12 V2] x86/altp2m: fix HVMOP_altp2m_set_domain_state race



>>> On 08.02.19 at 17:30, <rcojocaru@xxxxxxxxxxxxxxx> wrote:
> On 2/8/19 5:50 PM, Jan Beulich wrote:
>>>>> On 08.02.19 at 15:00, <rcojocaru@xxxxxxxxxxxxxxx> wrote:
>>>          /* If the alternate p2m state has changed, handle appropriately */
>>> -        if ( d->arch.altp2m_active != ostate &&
>>> +        if ( nstate != ostate &&
>>>               (ostate || !(rc = p2m_init_altp2m_by_id(d, 0))) )
>>>          {
>>> +            /* First mark altp2m as disabled, then altp2m_vcpu_destroy(). 
>>> */
>>> +            if ( ostate )
>>> +                d->arch.altp2m_active = false;
>> 
>> Why the if()? In the opposite case you'd simply write false into
>> what already holds false.
> 
> The value written into d->arch.altp2m_active is not the point here. The
> point is that if ( ostate ), then we are disabling altp2m (because the
> if above this one makes sure ostate != nstate).
> 
> So in the disable case, first I wanted to set d->arch.altp2m_active to
> false (which immediately causes altp2m_active(d) to return false as
> well), and then actually perform the work.

Sure - I'm not asking to remove everything above, just the if()
(and keep what is now the body). That is because
- in the enable case the value is false and writing false into it is
  benign,
- in the disable case you want to actively change from true to
  false.

>>> @@ -4550,7 +4554,14 @@ static int do_altp2m_op(
>>>  
>>>              if ( ostate )
>>>                  p2m_flush_altp2m(d);
>>> +            else
>>> +                /*
>>> +                 * Wait until altp2m_vcpu_initialise() is done before 
>>> marking
>>> +                 * altp2m as being enabled for the domain.
>>> +                 */
>>> +                d->arch.altp2m_active = true;
>> 
>> Similarly here you could omit the "else" and simply store "nstate" afaict.
> 
> As above, in the enable case I wanted to first setup altp2m on all VCPUs
> with altp2m_vcpu_initialise(), and only after that set
> d->arch.altp2m_active = true.
> 
> In summary, if ( ostate ) we want to set d->arch.altp2m_active before
> the for (we're disabling altp2m), and if ( !ostate ) (which is the else
> above) we want to set d->arch.altp2m_active after said for.
> 
> We can indeed store nstate. I just thought things look clearer with
> "true" and "false", but if you prefer there's no problem assigning nstate.

Well, as always with mm and altp2m code, I'm not the maintainer, so
I don't have the final say. It's just that I think unnecessary conditionals
would better be avoided, even if they're not on a performance critical
path.

>>> --- a/xen/arch/x86/hvm/vmx/vmx.c
>>> +++ b/xen/arch/x86/hvm/vmx/vmx.c
>>> @@ -2150,13 +2150,13 @@ static bool_t vmx_is_singlestep_supported(void)
>>>      return !!cpu_has_monitor_trap_flag;
>>>  }
>>>  
>>> -static void vmx_vcpu_update_eptp(struct vcpu *v)
>>> +static void vmx_vcpu_update_eptp(struct vcpu *v, bool altp2m_enabled)
>>>  {
>>>      struct domain *d = v->domain;
>>>      struct p2m_domain *p2m = NULL;
>>>      struct ept_data *ept;
>>>  
>>> -    if ( altp2m_active(d) )
>>> +    if ( altp2m_enabled )
>>>          p2m = p2m_get_altp2m(v);
>>>      if ( !p2m )
>>>          p2m = p2m_get_hostp2m(d);
>> 
>> Is this an appropriate transformation? That is, can there not be
>> any domains for which altp2m_active() returns false despite
>> altp2m_enabled being true? (Looking at p2m_get_altp2m() I can't
>> really judge whether index would always be INVALID_ALTP2M in
>> such a case.)
> 
> Yes, it should be completely safe (please see below for details).
> 
>>> --- a/xen/arch/x86/mm/p2m.c
>>> +++ b/xen/arch/x86/mm/p2m.c
>>> @@ -2332,7 +2332,7 @@ bool_t p2m_switch_vcpu_altp2m_by_id(struct vcpu *v, 
>>> unsigned int idx)
>>>              atomic_dec(&p2m_get_altp2m(v)->active_vcpus);
>>>              vcpu_altp2m(v).p2midx = idx;
>>>              atomic_inc(&p2m_get_altp2m(v)->active_vcpus);
>>> -            altp2m_vcpu_update_p2m(v);
>>> +            altp2m_vcpu_update_p2m(v, altp2m_active(d));
>>>          }
>>>          rc = 1;
>>>      }
>>> @@ -2573,7 +2573,7 @@ int p2m_switch_domain_altp2m_by_id(struct domain *d, 
>>> unsigned int idx)
>>>                  atomic_dec(&p2m_get_altp2m(v)->active_vcpus);
>>>                  vcpu_altp2m(v).p2midx = idx;
>>>                  atomic_inc(&p2m_get_altp2m(v)->active_vcpus);
>>> -                altp2m_vcpu_update_p2m(v);
>>> +                altp2m_vcpu_update_p2m(v, altp2m_active(d));
>>>              }
>> 
>> In both cases, isn't altp2m_active() going to return true anyway
>> when we get there (related to the question above)?
> 
> Yes, it will return true. In order for it to return false,
> altp2m_vcpu_destroy() would have had to run on that VCPU, which (among
> other things) calls altp2m_vcpu_reset(), which does v->p2midx =
> INVALID_ALTP2M.

Hmm, according to the change further up in this patch, altp2m_active()
returns false before v->p2midx can be set to INVALID_ALTP2M (you
don't change this property). So (related to the change further up)
there's a period of time during which p2m_get_altp2m() will return
non-NULL despite altp2m_active() returning false. Afaict, that is.

Jan

> There's an if() above (not shown in your reply) that says "if ( idx !=
> vcpu_altp2m(v).p2midx )", so, indeed, by the time we end up here we can
> reasonably assume that altp2m_active(d) will return true.
> 
> I've just put in "altp2m_active(d)" to make sure there's absolutely no
> functional change here, but AFAICT it can be safely replaced with "true".
> 
> 
> Thanks,
> Razvan




_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.