|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |