diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c index be46d6e01f..406c237eed 100644 --- a/xen/arch/x86/mm/hap/hap.c +++ b/xen/arch/x86/mm/hap/hap.c @@ -547,17 +547,17 @@ void hap_final_teardown(struct domain *d) if ( hvm_altp2m_supported() ) for ( i = 0; i < MAX_ALTP2M; i++ ) - p2m_teardown(d->arch.altp2m_p2m[i], true); + p2m_teardown(d->arch.altp2m_p2m[i], true, NULL); /* Destroy nestedp2m's first */ for (i = 0; i < MAX_NESTEDP2M; i++) { - p2m_teardown(d->arch.nested_p2m[i], true); + p2m_teardown(d->arch.nested_p2m[i], true, NULL); } if ( d->arch.paging.hap.total_pages != 0 ) hap_teardown(d, NULL); - p2m_teardown(p2m_get_hostp2m(d), true); + p2m_teardown(p2m_get_hostp2m(d), true, NULL); /* Free any memory that the p2m teardown released */ paging_lock(d); hap_set_allocation(d, 0, NULL); @@ -608,14 +608,24 @@ void hap_teardown(struct domain *d, bool *preempted) FREE_XENHEAP_PAGE(d->arch.altp2m_visible_eptp); for ( i = 0; i < MAX_ALTP2M; i++ ) - p2m_teardown(d->arch.altp2m_p2m[i], false); + { + p2m_teardown(d->arch.altp2m_p2m[i], false, preempted); + if ( preempted && *preempted ) + return; + } } /* Destroy nestedp2m's after altp2m. */ for ( i = 0; i < MAX_NESTEDP2M; i++ ) - p2m_teardown(d->arch.nested_p2m[i], false); + { + p2m_teardown(d->arch.nested_p2m[i], false, preempted); + if ( preempted && *preempted ) + return; + } - p2m_teardown(p2m_get_hostp2m(d), false); + p2m_teardown(p2m_get_hostp2m(d), false, preempted); + if ( preempted && *preempted ) + return; paging_lock(d); diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index 7ec6466922..39cfce47a3 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -737,12 +737,13 @@ int p2m_alloc_table(struct p2m_domain *p2m) * hvm fixme: when adding support for pvh non-hardware domains, this path must * cleanup any foreign p2m types (release refcnts on them). */ -void p2m_teardown(struct p2m_domain *p2m, bool remove_root) +void p2m_teardown(struct p2m_domain *p2m, bool remove_root, bool *preempted) /* Return all the p2m pages to Xen. * We know we don't have any extra mappings to these pages */ { struct page_info *pg, *root_pg = NULL; struct domain *d; + unsigned int i = 0; if (p2m == NULL) return; @@ -761,8 +762,19 @@ void p2m_teardown(struct p2m_domain *p2m, bool remove_root) } while ( (pg = page_list_remove_head(&p2m->pages)) ) - if ( pg != root_pg ) - d->arch.paging.free_page(d, pg); + { + if ( pg == root_pg ) + continue; + + d->arch.paging.free_page(d, pg); + + /* Arbitrarily check preemption every 1024 iterations */ + if ( preempted && !(++i % 1024) && general_preempt_check() ) + { + *preempted = true; + break; + } + } if ( root_pg ) page_list_add(root_pg, &p2m->pages); diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index bedb779ca4..ba2ef80778 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -2749,8 +2749,12 @@ int shadow_enable(struct domain *d, u32 mode) out_locked: paging_unlock(d); out_unlocked: + /* + * This is fine to ignore the preemption here because only the root + * will be allocated by p2m_alloc_table(). + */ if ( rv != 0 && !pagetable_is_null(p2m_get_pagetable(p2m)) ) - p2m_teardown(p2m, true); + p2m_teardown(p2m, true, NULL); if ( rv != 0 && pg != NULL ) { pg->count_info &= ~PGC_count_mask; @@ -2797,7 +2801,9 @@ void shadow_teardown(struct domain *d, bool *preempted) paging_unlock(d); - p2m_teardown(p2m_get_hostp2m(d), false); + p2m_teardown(p2m_get_hostp2m(d), false, preempted); + if ( preempted && *preempted ) + return; paging_lock(d); @@ -2916,7 +2922,7 @@ void shadow_final_teardown(struct domain *d) shadow_teardown(d, NULL); /* It is now safe to pull down the p2m map. */ - p2m_teardown(p2m_get_hostp2m(d), true); + p2m_teardown(p2m_get_hostp2m(d), true, NULL); /* Free any shadow memory that the p2m teardown released */ paging_lock(d); shadow_set_allocation(d, 0, NULL); diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h index cfe2e55fcf..3136fcb040 100644 --- a/xen/include/asm-x86/p2m.h +++ b/xen/include/asm-x86/p2m.h @@ -595,7 +595,7 @@ int p2m_init(struct domain *d); int p2m_alloc_table(struct p2m_domain *p2m); /* Return all the p2m resources to Xen. */ -void p2m_teardown(struct p2m_domain *p2m, bool remove_root); +void p2m_teardown(struct p2m_domain *p2m, bool remove_root, bool *preempted); void p2m_final_teardown(struct domain *d); /* Add a page to a domain's p2m table */