|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] x86/vm_event: fix race between vmx_vmexit_handler() and vm_event_resume()
On 04/27/17 11:01, Jan Beulich wrote:
>>>> On 27.04.17 at 09:22, <rcojocaru@xxxxxxxxxxxxxxx> wrote:
>> The introspection agent can reply to a vm_event faster than
>> vmx_vmexit_handler() can complete in some cases, where it is then
>> not safe for vm_event_set_registers() to modify v->arch.user_regs.
>
> This needs more explanation: I cannot see the connection between
> vmx_vmexit_handler() completing and (un)safety of modification of
> v->arch.user_regs. The latter is unsafe as long as the vCPU hasn't
> gone through __context_switch(), and the former doesn't call that
> function directly or indirectly (i.e. I think it is more than just
> vmx_vmexit_handler() which needs to be completed by the time
> register modification becomes safe to do).
Indeed, this is exactly the case (__context_switch() doesn't go
through). I'll re-word the commit message.
>> This patch ensures that vm_event_resume() code only sets per-VCPU
>> data to be used for the actual setting of registers only in
>> hvm_do_resume() (similar to the model used to control setting of CRs
>> and MSRs).
>
> I think the second "only" would better be "later".
Yes, it's actually redundant (sorry). I'll change it to "later".
>> The patch additionally removes the sync_vcpu_execstate(v) call from
>> vm_event_resume(), which is no longer necessary, which removes the
>> associated broadcast TLB flush (read: performance improvement).
>
> Depending on the better explanation above, it may or may not be
> further necessary to also better explain the "no longer necessary"
> part here.
>
>> --- a/xen/arch/x86/hvm/hvm.c
>> +++ b/xen/arch/x86/hvm/hvm.c
>> @@ -473,6 +473,39 @@ static bool hvm_get_pending_event(struct vcpu *v,
>> struct x86_event *info)
>> return hvm_funcs.get_pending_event(v, info);
>> }
>>
>> +static void hvm_vm_event_set_registers(struct vcpu *v)
>
> This could be const, as *v itself isn't being modified, but maybe it's
> better to leave it non-const indeed.
I have no problem changing it if there are no objections.
>> +{
>> + ASSERT(v == current);
>> +
>> + if ( v->arch.vm_event->set_gprs )
>
> I think we will want an unlikely() here. We anyway can only hope for
> the compiler to always inline this function, such that non-VM-event
> setups don't get penalized by the extra call here. Strictly speaking
> the function doesn't belong into this file ...
Should I move it to the x86 vm_event code?
>> + {
>> + struct cpu_user_regs *regs = guest_cpu_user_regs();
>> +
>> + regs->rax = v->arch.vm_event->gprs.rax;
>> + regs->rbx = v->arch.vm_event->gprs.rbx;
>> + regs->rcx = v->arch.vm_event->gprs.rcx;
>> + regs->rdx = v->arch.vm_event->gprs.rdx;
>> + regs->rsp = v->arch.vm_event->gprs.rsp;
>> + regs->rbp = v->arch.vm_event->gprs.rbp;
>> + regs->rsi = v->arch.vm_event->gprs.rsi;
>> + regs->rdi = v->arch.vm_event->gprs.rdi;
>> +
>> + regs->r8 = v->arch.vm_event->gprs.r8;
>> + regs->r9 = v->arch.vm_event->gprs.r9;
>> + regs->r10 = v->arch.vm_event->gprs.r10;
>> + regs->r11 = v->arch.vm_event->gprs.r11;
>> + regs->r12 = v->arch.vm_event->gprs.r12;
>> + regs->r13 = v->arch.vm_event->gprs.r13;
>> + regs->r14 = v->arch.vm_event->gprs.r14;
>> + regs->r15 = v->arch.vm_event->gprs.r15;
>> +
>> + regs->rflags = v->arch.vm_event->gprs.rflags;
>> + regs->rip = v->arch.vm_event->gprs.rip;
>> +
>> + v->arch.vm_event->set_gprs = 0;
>
> false (and true/bool elsewhere)
I'll change it to bool.
>> --- a/xen/common/vm_event.c
>> +++ b/xen/common/vm_event.c
>> @@ -357,6 +357,13 @@ void vm_event_resume(struct domain *d, struct
>> vm_event_domain *ved)
>> {
>> vm_event_response_t rsp;
>>
>> + /*
>> + * vm_event_resume() runs either from XEN_DOMCTL_VM_EVENT_OP_*, or
>> + * EVTCHN_send from the introspection consumer. Both contexts are
>> + * guaranteed not to be the subject of vm_event responses.
>> + */
>> + ASSERT(d != current->domain);
>
> What is this meant to guard against? It surely isn't ...
>
>> @@ -375,13 +382,6 @@ void vm_event_resume(struct domain *d, struct
>> vm_event_domain *ved)
>> v = d->vcpu[rsp.vcpu_id];
>>
>> /*
>> - * Make sure the vCPU state has been synchronized for the custom
>> - * handlers.
>> - */
>> - if ( atomic_read(&v->vm_event_pause_count) )
>> - sync_vcpu_execstate(v);
>
> ... a "replacement" for this, as the state of "current" doesn't reflect
> whether register state has been saved (that's this_cpu(curr_vcpu)
> instead). Nor would a comparison of domains seem to be the right
> thing - a comparison of vcpus ought to suffice (and be less strict,
> allowing for something hypothetical like self-introspection).
This part (the ASSERT and comment) is from Andrew, he can help us here.
Thanks,
Razvan
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |