x86: perform mem_sharing teardown before paging teardown

An assert failure has been observed in p2m_teardown when performing vm
forking and then destroying the forked VM (p2m-basic.c:173). The assert
checks whether the domain's shared pages counter is 0. According to the
patch that originally added the assert (7bedbbb5c3) the p2m_teardown
should only happen after mem_sharing already relinquished all shared pages.

In this patch we flip the order in which relinquish ops are called to avoid
tripping the assert. Conceptually sharing being torn down makes sense to
happen before paging is torn down.

Fixes: e7aa55c0aa ("x86/p2m: free the paging memory pool preemptively")
Signed-off-by: Tamas K Lengyel <tamas@tklengyel.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
master commit: 2869349f0c
master date: 2023-02-23 12:35:48 +0100
This commit is contained in:
Tamas K Lengyel authored and Jan Beulich committed 2023-03-03 08:14:25 +01:00
1 parent d1c6934b41
commit 700320a792
1 file changed
+29 -27
+29 -27
View File
@@ -2343,9 +2343,9 @@ int domain_relinquish_resources(struct domain *d)
enum {
PROG_iommu_pagetables = 1,
PROG_shared,
PROG_paging,
PROG_vcpu_pagetables,
PROG_shared,
PROG_xen,
PROG_l4,
PROG_l3,
@@ -2364,6 +2364,34 @@ int domain_relinquish_resources(struct domain *d)
if ( ret )
return ret;
#ifdef CONFIG_MEM_SHARING
PROGRESS(shared):
if ( is_hvm_domain(d) )
{
/*
* If the domain has shared pages, relinquish them allowing
* for preemption.
*/
ret = relinquish_shared_pages(d);
if ( ret )
return ret;
/*
* If the domain is forked, decrement the parent's pause count
* and release the domain.
*/
if ( mem_sharing_is_fork(d) )
{
struct domain *parent = d->parent;
d->parent = NULL;
domain_unpause(parent);
put_domain(parent);
}
}
#endif
PROGRESS(paging):
/* Tear down paging-assistance stuff. */
@@ -2404,32 +2432,6 @@ int domain_relinquish_resources(struct domain *d)
d->arch.auto_unmask = 0;
}
#ifdef CONFIG_MEM_SHARING
PROGRESS(shared):
if ( is_hvm_domain(d) )
{
/* If the domain has shared pages, relinquish them allowing
* for preemption. */
ret = relinquish_shared_pages(d);
if ( ret )
return ret;
/*
* If the domain is forked, decrement the parent's pause count
* and release the domain.
*/
if ( mem_sharing_is_fork(d) )
{
struct domain *parent = d->parent;
d->parent = NULL;
domain_unpause(parent);
put_domain(parent);
}
}
#endif
spin_lock(&d->page_alloc_lock);
page_list_splice(&d->arch.relmem_list, &d->page_list);
INIT_PAGE_LIST_HEAD(&d->arch.relmem_list);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.