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

Re: [Xen-devel] [PATCH v12 1/2] vmx: VT-d posted-interrupt core logic handling



>>> On 19.02.16 at 02:55, <feng.wu@xxxxxxxxx> wrote:
> +static void vmx_vcpu_block(struct vcpu *v)
> +{
> +    unsigned long flags;
> +    unsigned int dest;
> +    spinlock_t *old_lock;
> +    spinlock_t *pi_block_list_lock =
> +                    &per_cpu(pi_blocked_vcpu_lock, v->processor);
> +    struct pi_desc *pi_desc = &v->arch.hvm_vmx.pi_desc;
> +
> +    spin_lock_irqsave(pi_block_list_lock, flags);
> +    old_lock = cmpxchg(&v->arch.hvm_vmx.pi_block_list_lock, NULL,
> +                       &per_cpu(pi_blocked_vcpu_lock, v->processor));

Why don't you use the local variable here?

> +    /*
> +     * 'v->arch.hvm_vmx.pi_block_list_lock' should be NULL before being 
> assigned
> +     * to a new value, since the vCPU is currently running and it cannot be 
> on
> +     * any blocking list.
> +     */
> +    ASSERT(old_lock == NULL);
> +
> +    list_add_tail(&v->arch.hvm_vmx.pi_blocked_vcpu_list,
> +                  &per_cpu(pi_blocked_vcpu, v->processor));
> +    spin_unlock_irqrestore(pi_block_list_lock, flags);
> +
> +    ASSERT(!pi_test_sn(pi_desc));
> +
> +    dest = cpu_physical_id(v->processor);
> +
> +    ASSERT(pi_desc->ndst ==
> +           (x2apic_enabled ? dest : MASK_INSR(dest, PI_xAPIC_NDST_MASK)));

May I ask for consistency between this and ...

> +static void vmx_pi_switch_to(struct vcpu *v)
> +{
> +    struct pi_desc *pi_desc = &v->arch.hvm_vmx.pi_desc;
> +
> +    write_atomic(&pi_desc->ndst, x2apic_enabled ?
> +                 cpu_physical_id(v->processor) :
> +                 MASK_INSR(cpu_physical_id(v->processor), 
> PI_xAPIC_NDST_MASK));

... this? I.e. to either in both cases use a local variable "dest", or
in both cases to avoid doing so?

> +static void vmx_pi_do_resume(struct vcpu *v)
> +{
> +    unsigned long flags;
> +    spinlock_t *pi_block_list_lock;
> +    struct pi_desc *pi_desc = &v->arch.hvm_vmx.pi_desc;
> +
> +    ASSERT(!test_bit(_VPF_blocked, &v->pause_flags));
> +
> +    /*
> +     * Set 'NV' field back to posted_intr_vector, so the
> +     * Posted-Interrupts can be delivered to the vCPU when
> +     * it is running in non-root mode.
> +     */
> +    write_atomic(&pi_desc->nv, posted_intr_vector);
> +
> +    /* The vCPU is not on any blocking list. */
> +    pi_block_list_lock = v->arch.hvm_vmx.pi_block_list_lock;
> +    if ( pi_block_list_lock == NULL )
> +        return;
> +
> +    /* Prevent the compiler from eliminating the local variable.*/
> +    barrier();

As said before - this is too late: This way you still don't guarantee
pi_block_list_lock != NULL. The barrier needs to be after the read,
and _before_ the first use. Also I think the right barrier here
would be smp_rmb().

> +    spin_lock_irqsave(pi_block_list_lock, flags);
> +
> +    /*
> +     * v->arch.hvm_vmx.pi_block_list_lock == NULL here means the vCPU was
> +     * removed from the blocking list while we are acquiring the lock.
> +     */
> +    if ( v->arch.hvm_vmx.pi_block_list_lock != NULL )
> +    {

ASSERT(v->arch.hvm_vmx.pi_block_list_lock == pi_block_list_lock)?

> +/* This function is called when pcidevs_lock is held */
> +void vmx_pi_hooks_assign(struct domain *target)
> +{
> +    if ( !iommu_intpost )
> +        return;
> +
> +    if ( has_hvm_container_domain(target) &&
> +         !target->arch.hvm_domain.vmx.vcpu_block  )
> +    {
> +        target->arch.hvm_domain.vmx.vcpu_block = vmx_vcpu_block;
> +        target->arch.hvm_domain.vmx.pi_switch_from = vmx_pi_switch_from;
> +        target->arch.hvm_domain.vmx.pi_switch_to = vmx_pi_switch_to;
> +        target->arch.hvm_domain.vmx.pi_do_resume = vmx_pi_do_resume;
> +    }
> +}
> +
> +/* This function is called when pcidevs_lock is held */
> +void vmx_pi_hooks_deassign(struct domain *source)
> +{
> +    if ( !iommu_intpost )
> +        return;
> +
> +    if ( has_hvm_container_domain(source) &&
> +         source->arch.hvm_domain.vmx.vcpu_block && !has_arch_pdevs(source) )
> +    {

I think it would be nice for the conditions in both functions to match
up. Since you can't add has_arch_pdevs(target) to the earlier, maybe
it should be the caller of the latter to check !has_arch_pdevs(source)?
And if you then made the caller(s) of vmx_pi_hooks_assign() do so
too, the checks on ->arch.hvm_domain.vmx.vcpu_block could
apparently become ASSERT()-s instead.

Also since neither function now takes two domain pointers anymore,
please name the function parameters just "d". And finally please, in
each function, combine the two if()-s.

> @@ -112,6 +251,10 @@ static int vmx_vcpu_initialise(struct vcpu *v)
>  
>      spin_lock_init(&v->arch.hvm_vmx.vmcs_lock);
>  
> +    INIT_LIST_HEAD(&v->arch.hvm_vmx.pi_blocked_vcpu_list);
> +
> +    v->arch.hvm_vmx.pi_block_list_lock = NULL;

The latter is pointless, as struct vcpu starts out zero-initialized.

> @@ -740,6 +883,8 @@ static void vmx_ctxt_switch_from(struct vcpu *v)
>      vmx_save_guest_msrs(v);
>      vmx_restore_host_msrs();
>      vmx_save_dr(v);
> +    if (v->domain->arch.hvm_domain.vmx.pi_switch_from)
> +        v->domain->arch.hvm_domain.vmx.pi_switch_from(v);

Coding style.

> @@ -752,6 +897,8 @@ static void vmx_ctxt_switch_to(struct vcpu *v)
>  
>      vmx_restore_guest_msrs(v);
>      vmx_restore_dr(v);
> +    if (v->domain->arch.hvm_domain.vmx.pi_switch_to)
> +        v->domain->arch.hvm_domain.vmx.pi_switch_to(v);

Again. I'm pretty sure this has been pointed out before. And there
are more of these.

> --- a/xen/include/asm-x86/hvm/hvm.h
> +++ b/xen/include/asm-x86/hvm/hvm.h
> @@ -565,6 +565,11 @@ const char *hvm_efer_valid(const struct vcpu *v, 
> uint64_t value,
>                             signed int cr0_pg);
>  unsigned long hvm_cr4_guest_reserved_bits(const struct vcpu *v, bool_t 
> restore);
>  
> +#define arch_vcpu_block(v) ({                                               \
> +    if ( (v)->domain->arch.hvm_domain.vmx.vcpu_block )                      \
> +        (v)->domain->arch.hvm_domain.vmx.vcpu_block((v));                   \
> +})

I'd prefer if v got evaluated just once in this macro. Also note
the redundant parentheses in the function argument.

> @@ -160,6 +219,14 @@ struct arch_vmx_struct {
>      struct page_info     *vmwrite_bitmap;
>  
>      struct page_info     *pml_pg;
> +
> +    /*
> +     * Before it is blocked, vCPU is added to the per-cpu list.
> +     * VT-d engine can send wakeup notification event to the
> +     * pCPU and wakeup the related vCPU.
> +     */
> +    struct list_head     pi_blocked_vcpu_list;
> +    spinlock_t           *pi_block_list_lock;
>  };

Didn't we settle on making this a struct with a "list" and a "lock"
member? And along those lines the local per-CPU variables added
to xen/arch/x86/hvm/vmx/vmx.c would also benefit from being
put in a struct, making more obvious their close relationship.

Jan

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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