|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v5 2/2] xen/arm: p2m: Populate pages for GICv2 mapping in p2m_init()
Hi Henry,
> On 18 Oct 2022, at 15:23, Henry Wang <Henry.Wang@xxxxxxx> wrote:
>
> Hardware using GICv2 needs to create a P2M mapping of 8KB GICv2 area
> when the domain is created. Considering the worst case of page tables
> which requires 6 P2M pages as the two pages will be consecutive but not
> necessarily in the same L3 page table and keep a buffer, populate 16
> pages as the default value to the P2M pages pool in p2m_init() at the
> domain creation stage to satisfy the GICv2 requirement. For GICv3, the
> above-mentioned P2M mapping is not necessary, but since the allocated
> 16 pages here would not be lost, hence populate these pages
> unconditionally.
>
> With the default 16 P2M pages populated, there would be a case that
> failures would happen in the domain creation with P2M pages already in
> use. To properly free the P2M for this case, firstly support the
> optionally preemption of p2m_teardown(), then call p2m_teardown() and
> p2m_set_allocation(d, 0, NULL) non-preemptively in p2m_final_teardown().
> As non-preemptive p2m_teardown() should only return 0, use a
> BUG_ON to confirm that.
>
> Since p2m_final_teardown() is called either after
> domain_relinquish_resources() where relinquish_p2m_mapping() has been
> called, or from failure path of domain_create()/arch_domain_create()
> where mappings that require p2m_put_l3_page() should never be created,
> relinquish_p2m_mapping() is not added in p2m_final_teardown(), add
> in-code comments to refer this.
>
> Fixes: cbea5a1149ca ("xen/arm: Allocate and free P2M pages from the P2M pool")
> Suggested-by: Julien Grall <jgrall@xxxxxxxxxx>
> Signed-off-by: Henry Wang <Henry.Wang@xxxxxxx>
Reviewed-by: Bertrand Marquis <bertrand.marquis@xxxxxxx>
Cheers
Bertrand
> ---
> This should also be backported to 4.13, 4.14, 4.15 and 4.16.
> v5 changes:
> - Rebase on top of Andrew's patch, update commit message accordingly.
> v4 changes:
> - Move the initial population of 16 default pages to the end of
> p2m_init(), add if(rc) return rc; after p2m_alloc_table()
> v3 changes:
> - Move the population of default pages to p2m_init().
> - Use a loop over p2m_teardown_allocation() to implement the
> non-preemptive p2m_teardown_allocation() and avoid open-coding.
> - Reorder assertions in p2m_final_teardown().
> - Add p2m_teardown() will always return 0 if called non-preemptively in
> doc, move the page_list_empty(&p2m->pages) check to p2m_teardown()
> and use a BUG_ON to confirm p2m_teardown() will return 0 in
> p2m_final_teardown().
> - Add a comment in p2m_final_teardown() to mention relinquish_p2m_mapping()
> does not need to be called, also update commit message.
> v2 changes:
> - Move the p2m_set_allocation(d, 0, NULL); to p2m_final_teardown().
> - Support optionally preemption of p2m_teardown(), and make the calling of
> p2m_teardown() preemptively when relinquish the resources, non-preemptively
> in p2m_final_teardown().
> - Refactor the error handling to make the code use less spin_unlock.
> - Explain the worst case of page tables and the unconditional population
> of pages in commit message.
> - Mention the unconditional population of pages in in-code comment.
> ---
> xen/arch/arm/domain.c | 2 +-
> xen/arch/arm/include/asm/p2m.h | 14 ++++++++++----
> xen/arch/arm/p2m.c | 34 ++++++++++++++++++++++++++++++++--
> 3 files changed, 43 insertions(+), 7 deletions(-)
>
> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> index 2c84e6dbbb..38e22f12af 100644
> --- a/xen/arch/arm/domain.c
> +++ b/xen/arch/arm/domain.c
> @@ -1064,7 +1064,7 @@ int domain_relinquish_resources(struct domain *d)
> return ret;
>
> PROGRESS(p2m):
> - ret = p2m_teardown(d);
> + ret = p2m_teardown(d, true);
> if ( ret )
> return ret;
>
> diff --git a/xen/arch/arm/include/asm/p2m.h b/xen/arch/arm/include/asm/p2m.h
> index 42bfd548c4..c8f14d13c2 100644
> --- a/xen/arch/arm/include/asm/p2m.h
> +++ b/xen/arch/arm/include/asm/p2m.h
> @@ -194,14 +194,18 @@ int p2m_init(struct domain *d);
>
> /*
> * The P2M resources are freed in two parts:
> - * - p2m_teardown() will be called when relinquish the resources. It
> - * will free large resources (e.g. intermediate page-tables) that
> - * requires preemption.
> + * - p2m_teardown() will be called preemptively when relinquish the
> + * resources, in which case it will free large resources (e.g.
> intermediate
> + * page-tables) that requires preemption.
> * - p2m_final_teardown() will be called when domain struct is been
> * freed. This *cannot* be preempted and therefore one small
> * resources should be freed here.
> + * Note that p2m_final_teardown() will also call p2m_teardown(), to properly
> + * free the P2M when failures happen in the domain creation with P2M pages
> + * already in use. In this case p2m_teardown() is called non-preemptively
> and
> + * p2m_teardown() will always return 0.
> */
> -int p2m_teardown(struct domain *d);
> +int p2m_teardown(struct domain *d, bool allow_preemption);
> void p2m_final_teardown(struct domain *d);
>
> /*
> @@ -266,6 +270,8 @@ mfn_t p2m_get_entry(struct p2m_domain *p2m, gfn_t gfn,
> /*
> * Direct set a p2m entry: only for use by the P2M code.
> * The P2M write lock should be taken.
> + * TODO: Add a check in __p2m_set_entry() to avoid creating a mapping in
> + * arch_domain_create() that requires p2m_put_l3_page() to be called.
> */
> int p2m_set_entry(struct p2m_domain *p2m,
> gfn_t sgfn,
> diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
> index 6826f63150..00d05bb708 100644
> --- a/xen/arch/arm/p2m.c
> +++ b/xen/arch/arm/p2m.c
> @@ -1685,7 +1685,7 @@ static void p2m_free_vmid(struct domain *d)
> spin_unlock(&vmid_alloc_lock);
> }
>
> -int p2m_teardown(struct domain *d)
> +int p2m_teardown(struct domain *d, bool allow_preemption)
> {
> struct p2m_domain *p2m = p2m_get_hostp2m(d);
> unsigned long count = 0;
> @@ -1693,6 +1693,9 @@ int p2m_teardown(struct domain *d)
> unsigned int i;
> int rc = 0;
>
> + if ( page_list_empty(&p2m->pages) )
> + return 0;
> +
> p2m_write_lock(p2m);
>
> /*
> @@ -1716,7 +1719,7 @@ int p2m_teardown(struct domain *d)
> p2m_free_page(p2m->domain, pg);
> count++;
> /* Arbitrarily preempt every 512 iterations */
> - if ( !(count % 512) && hypercall_preempt_check() )
> + if ( allow_preemption && !(count % 512) && hypercall_preempt_check()
> )
> {
> rc = -ERESTART;
> break;
> @@ -1736,7 +1739,20 @@ void p2m_final_teardown(struct domain *d)
> if ( !p2m->domain )
> return;
>
> + /*
> + * No need to call relinquish_p2m_mapping() here because
> + * p2m_final_teardown() is called either after
> domain_relinquish_resources()
> + * where relinquish_p2m_mapping() has been called, or from failure path
> of
> + * domain_create()/arch_domain_create() where mappings that require
> + * p2m_put_l3_page() should never be created. For the latter case, also
> see
> + * comment on top of the p2m_set_entry() for more info.
> + */
> +
> + BUG_ON(p2m_teardown(d, false));
> ASSERT(page_list_empty(&p2m->pages));
> +
> + while ( p2m_teardown_allocation(d) == -ERESTART )
> + continue; /* No preemption support here */
> ASSERT(page_list_empty(&d->arch.paging.p2m_freelist));
>
> if ( p2m->root )
> @@ -1803,6 +1819,20 @@ int p2m_init(struct domain *d)
> if ( rc )
> return rc;
>
> + /*
> + * Hardware using GICv2 needs to create a P2M mapping of 8KB GICv2 area
> + * when the domain is created. Considering the worst case for page
> + * tables and keep a buffer, populate 16 pages to the P2M pages pool
> here.
> + * For GICv3, the above-mentioned P2M mapping is not necessary, but since
> + * the allocated 16 pages here would not be lost, hence populate these
> + * pages unconditionally.
> + */
> + spin_lock(&d->arch.paging.lock);
> + rc = p2m_set_allocation(d, 16, NULL);
> + spin_unlock(&d->arch.paging.lock);
> + if ( rc )
> + return rc;
> +
> return 0;
> }
>
> --
> 2.17.1
>
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |