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

Re: [Xen-devel] [PATCH 3/3] xen/arm: p2m: Perform local TLB invalidation on vCPU migration



On Wed, 8 Mar 2017, Julien Grall wrote:
> The ARM architecture allows an OS to have per-CPU page tables, as it
> guarantees that TLBs never migrate from one CPU to another.
> 
> This works fine until this is done in a guest. Consider the following
> scenario:
>     - vcpu-0 maps P to V
>     - vpcu-1 maps P' to V
> 
> If run on the same physical CPU, vcpu-1 can hit in TLBs generated by
> vcpu-0 accesses, and access the wrong physical page.
> 
> The solution to this is to keep a per-p2m map of which vCPU ran the last
> on each given pCPU and invalidate local TLBs if two vPCUs from the same
> VM run on the same CPU.
> 
> Unfortunately it is not possible to allocate per-cpu variable on the
> fly. So for now the size of the array is NR_CPUS, this is fine because
> we still have space in the structure domain. We may want to add an
> helper to allocate per-cpu variable in the future.

I think I understand the problem, thanks for the description. I have a
question: when a vcpu of a different domain is scheduled on a pcpu,
there is no impact on tlb flushes in relation to this problem, is there?

For example:

1) vcpu0/domain1 -> pcpu0
2) vcpu0/domain2 -> pcpu0
3) vcpu1/domain1 -> pcpu0

In 3) we still need to do the flush_tlb_local(), no matter if 2)
happened or not, right?

Also, I have one suggestion below.


> Signed-off-by: Julien Grall <julien.grall@xxxxxxx>
> 
> ---
>     This patch is a candidate for backport to Xen 4.8, 4.7 and 4.6.
> ---
>  xen/arch/arm/p2m.c        | 24 ++++++++++++++++++++++++
>  xen/include/asm-arm/p2m.h |  3 +++
>  2 files changed, 27 insertions(+)
> 
> diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
> index 1fc6ca3bb2..626376090d 100644
> --- a/xen/arch/arm/p2m.c
> +++ b/xen/arch/arm/p2m.c
> @@ -130,6 +130,7 @@ void p2m_restore_state(struct vcpu *n)
>  {
>      register_t hcr;
>      struct p2m_domain *p2m = &n->domain->arch.p2m;
> +    uint8_t *last_vcpu_ran;
>  
>      if ( is_idle_vcpu(n) )
>          return;
> @@ -149,6 +150,17 @@ void p2m_restore_state(struct vcpu *n)
>  
>      WRITE_SYSREG(hcr, HCR_EL2);
>      isb();
> +
> +    last_vcpu_ran = &p2m->last_vcpu_ran[smp_processor_id()];
> +
> +    /*
> +     * Flush local TLB for the domain to prevent wrong TLB translation
> +     * when running multiple vCPU of the same domain on a single pCPU.
> +     */
> +    if ( *last_vcpu_ran != INVALID_VCPU_ID && *last_vcpu_ran != n->vcpu_id )
> +        flush_tlb_local();
> +
> +    *last_vcpu_ran = n->vcpu_id;
>  }
>  
>  static void p2m_flush_tlb(struct p2m_domain *p2m)
> @@ -1247,6 +1259,7 @@ int p2m_init(struct domain *d)
>  {
>      struct p2m_domain *p2m = &d->arch.p2m;
>      int rc = 0;
> +    unsigned int cpu;
>  
>      rwlock_init(&p2m->lock);
>      INIT_PAGE_LIST_HEAD(&p2m->pages);
> @@ -1275,6 +1288,17 @@ int p2m_init(struct domain *d)
>  
>      rc = p2m_alloc_table(d);
>  
> +    /*
> +     * Make sure that the type chosen to is able to store the an vCPU ID
> +     * between 0 and the maximum of virtual CPUS supported as long as
> +     * the INVALID_VCPU_ID.
> +     */
> +    BUILD_BUG_ON((1 << (sizeof(p2m->last_vcpu_ran[0]) * 8)) < MAX_VIRT_CPUS);
> +    BUILD_BUG_ON((1 << (sizeof(p2m->last_vcpu_ran[0])* 8)) < 
> INVALID_VCPU_ID);
> +
> +    for_each_possible_cpu(cpu)
> +       p2m->last_vcpu_ran[cpu] = INVALID_VCPU_ID;
> +
>      return rc;
>  }
>  
> diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h
> index 0899523084..18c57f936e 100644
> --- a/xen/include/asm-arm/p2m.h
> +++ b/xen/include/asm-arm/p2m.h
> @@ -96,6 +96,9 @@ struct p2m_domain {
>  
>      /* back pointer to domain */
>      struct domain *domain;
> +
> +    /* Keeping track on which CPU this p2m was used and for which vCPU */
> +    uint8_t last_vcpu_ran[NR_CPUS];
>  };

NR_CPUS is usually much larger than cpu_possible_map. I think it would
be best to allocate last_vcpu_ran dynamically (after cpu_possible_map is
set). It should reduce the memory impact significantly.

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

 


Rackspace

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