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

Re: [PATCH v3 14/18] x86/domain_page: key the directmap fast paths on the loaded view



On Wed, Oct 07, 2026 at 11:40:47AM +0100, George Dunlap wrote:
> map_domain_page() returns directmap addresses whenever it can: for any
> MFN the directmap covers in release builds, and for vCPUs without a
> mapcache.  Once guest contexts may run on the sparse view of the
> directmap, modify this to take the fast path returning the directmap
> address only when the full directmap is loaded.
> 
> The release-build shortcut ahead of the vCPU lookup looks at the vCPU
> whose page-tables are loaded, without completing a lazy context
> switch: if that vCPU is not on the sparse view, its page-tables map
> the page through the directmap, and completing the switch would only
> move the CPU to the idle vCPU's page-tables, which map it too.
> 
> mapcache_current_vcpu() may complete the lazy context switch
> (sync_local_execstate()) and switch us onto the idle vCPU (which has a
> full view), so check again if we can use the directmap afterwards.
> 
> A vCPU on the sparse view always has a mapcache: HVM ones through
> per-vCPU page-tables, PV ones through the domain-wide mapcache, which
> mapcache_domain_init() now sets up for a domain using the sparse view in
> release builds too, rather than only when the directmap does not cover
> all memory.
> 
> map_domain_page_global() mappings must be valid in every context: use
> vmap() for all of them once a sparse view is configured, as
> arch_mfns_in_directmap() then says.
> 
> Add d->arch.sparse_dmap and sparse_dmap_active for this; nothing sets
> them yet.
> 
> No functional change.
> 
> Assisted-by: Claude Code:claude-opus-5-5
> Signed-off-by: George Dunlap <gwd@xxxxxxxxxxxxxx>
> ---
> Changes in v3:
> - New in this version.
> ---
>  xen/arch/x86/domain_page.c                  | 44 +++++++++++++++++++--
>  xen/arch/x86/include/asm/domain.h           |  6 +++
>  xen/arch/x86/include/asm/sparse-directmap.h |  8 ++++
>  xen/arch/x86/sparse-directmap.c             |  1 +
>  4 files changed, 56 insertions(+), 3 deletions(-)
> 
> diff --git a/xen/arch/x86/domain_page.c b/xen/arch/x86/domain_page.c
> index 0500bb9dba..48f85b670d 100644
> --- a/xen/arch/x86/domain_page.c
> +++ b/xen/arch/x86/domain_page.c
> @@ -61,6 +61,16 @@ static inline struct vcpu *mapcache_current_vcpu(void)
>      return ACCESS_ONCE(this_cpu(pgtable_vcpu));
>  }
>  
> +/*
> + * Whether the directmap in @v's page-tables is the sparse view, which maps
> + * none of the heap's memory beyond the xenheap: the mapcache must serve
> + * every mapping then.
> + */
> +static bool on_sparse_dmap(const struct vcpu *v)
> +{
> +    return sparse_dmap_active && v->domain->arch.sparse_dmap;
> +}
> +
>  /*
>   * The accounting for v's mapcache: its own for a vCPU-PT domain, the 
> domain's
>   * otherwise, in which case *dcache is set so the caller takes the 
> domain-wide
> @@ -142,17 +152,39 @@ void *map_domain_page(mfn_t mfn)
>  
>  #ifdef NDEBUG
>      if ( mfn_x(mfn) <= PFN_DOWN(__pa(HYPERVISOR_VIRT_END - 1)) )
> -        return mfn_to_virt(mfn_x(mfn));
> +    {
> +        const struct vcpu *pt_vcpu = this_cpu(pgtable_vcpu);
> +
> +        /*
> +         * The page-tables loaded map @mfn through the directmap, unless they
> +         * carry the sparse view.  Don't complete a lazy context switch to
> +         * find out: it would only move this CPU to the idle vCPU's
> +         * page-tables, which map @mfn too.
> +         */
> +        if ( !pt_vcpu || !on_sparse_dmap(pt_vcpu) )
> +            return mfn_to_virt(mfn_x(mfn));
> +    }
>  #endif
>  
> +    /* No vCPU (early boot), or no mapcache: the full directmap is loaded. */
>      v = mapcache_current_vcpu();
>      if ( !v )
>          return mfn_to_virt(mfn_x(mfn));
>  
> +#ifdef NDEBUG
> +    /* The lookup may have completed a lazy switch off the sparse view. */
> +    if ( !on_sparse_dmap(v) &&
> +         mfn_x(mfn) <= PFN_DOWN(__pa(HYPERVISOR_VIRT_END - 1)) )
> +        return mfn_to_virt(mfn_x(mfn));
> +#endif
> +
>      cache = vcpu_mapcache(v, &dcache);
>      vcache = &v->arch.mapcache;
>      if ( !cache->inuse )
> +    {
> +        ASSERT(!on_sparse_dmap(v));
>          return mfn_to_virt(mfn_x(mfn));
> +    }
>  
>      perfc_incr(map_domain_page_count);
>  
> @@ -307,7 +339,9 @@ void mapcache_domain_init(struct domain *d)
>      ASSERT(is_pv_domain(d));
>  
>  #ifdef NDEBUG
> -    if ( !mem_hotplug && max_page <= PFN_DOWN(__pa(HYPERVISOR_VIRT_END - 1)) 
> )
> +    /* Not needed when the directmap loaded for the domain covers 
> everything. */
> +    if ( !d->arch.sparse_dmap && !mem_hotplug &&
> +         max_page <= PFN_DOWN(__pa(HYPERVISOR_VIRT_END - 1)) )
>          return;
>  #endif
>  
> @@ -392,8 +426,12 @@ void *map_domain_page_global(mfn_t mfn)
>               system_state < SYS_STATE_active) ||
>              local_irq_is_enabled()));
>  
> +    /*
> +     * Global mappings must hold in every context: a sparse view of the
> +     * directmap rules the directmap out.
> +     */
>  #ifdef NDEBUG
> -    if ( mfn_x(mfn) <= PFN_DOWN(__pa(HYPERVISOR_VIRT_END - 1)) )
> +    if ( arch_mfns_in_directmap(mfn_x(mfn), 1) )
>          return mfn_to_virt(mfn_x(mfn));
>  #endif
>  
> diff --git a/xen/arch/x86/include/asm/domain.h 
> b/xen/arch/x86/include/asm/domain.h
> index 80415ab2c2..76a22b4040 100644
> --- a/xen/arch/x86/include/asm/domain.h
> +++ b/xen/arch/x86/include/asm/domain.h
> @@ -499,6 +499,12 @@ struct arch_domain
>       */
>      bool vcpu_pt;
>  
> +    /*
> +     * Root page-tables carry the sparse view of the directmap, once it is
> +     * active (see asm/sparse-directmap.h).
> +     */
> +    bool sparse_dmap;

What do you mean with "once it is active"?  Either a domain is using
the sparse direct map or not, but it shouldn't have an external
dependency on anything.  Or maybe I'm reading the comment the wrong
way.

> +
>      /* Emulated devices enabled bitmap. */
>      uint32_t emulation_flags;
>  } __cacheline_aligned;
> diff --git a/xen/arch/x86/include/asm/sparse-directmap.h 
> b/xen/arch/x86/include/asm/sparse-directmap.h
> index 48c1f3c951..512f8064d6 100644
> --- a/xen/arch/x86/include/asm/sparse-directmap.h
> +++ b/xen/arch/x86/include/asm/sparse-directmap.h
> @@ -22,6 +22,12 @@ extern bool opt_sparse_dmap_pv, opt_sparse_dmap_hvm;
>  /* Root of the sparse view, once built (NULL before, or if not configured). 
> */
>  extern l4_pgentry_t *sparse_dmap_root;
>  
> +/*
> + * Set once guest contexts run on the sparse view: from then on, the root
> + * page-tables of domains with d->arch.sparse_dmap carry it.
> + */
> +extern bool sparse_dmap_active;

Shouldn't sparse_dmap_active be opt_sparse_dmap_pv ||
opt_sparse_dmap_hvm?  I'm afraid I don't understand the point of
tracking whether there are domain using the sparse direct map or not,
that's already tracked by d->arch.sparse_dmap?

Thanks, Roger.



 


Rackspace

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