Equivalent of -unstable c/s 18720, 18731, and 18735. --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -1687,6 +1687,8 @@ static int relinquish_memory( { if ( free_page_type(page, x, 0) != 0 ) BUG(); + if ( x & PGT_partial ) + page->u.inuse.type_info--; break; } } --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -1343,7 +1343,7 @@ static void free_l1_table(struct page_in static int free_l2_table(struct page_info *page, int preemptible) { -#ifdef CONFIG_COMPAT +#if defined(CONFIG_COMPAT) || defined(DOMAIN_DESTRUCT_AVOID_RECURSION) struct domain *d = page_get_owner(page); #endif unsigned long pfn = page_to_mfn(page); @@ -1351,6 +1351,11 @@ static int free_l2_table(struct page_inf unsigned int i = page->nr_validated_ptes - 1; int err = 0; +#ifdef DOMAIN_DESTRUCT_AVOID_RECURSION + if ( d->arch.relmem == RELMEM_l3 ) + return 0; +#endif + pl2e = map_domain_page(pfn); ASSERT(page->nr_validated_ptes); @@ -1381,7 +1386,7 @@ static int free_l3_table(struct page_inf int rc = 0; #ifdef DOMAIN_DESTRUCT_AVOID_RECURSION - if ( d->arch.relmem == RELMEM_l3 ) + if ( d->arch.relmem == RELMEM_l4 ) return 0; #endif @@ -1424,11 +1429,6 @@ static int free_l4_table(struct page_inf unsigned int i = page->nr_validated_ptes - !page->partial_pte; int rc = 0; -#ifdef DOMAIN_DESTRUCT_AVOID_RECURSION - if ( d->arch.relmem == RELMEM_l4 ) - return 0; -#endif - do { if ( is_guest_l4_slot(d, i) ) rc = put_page_from_l4e(pl4e[i], pfn, preemptible); @@ -1940,7 +1940,6 @@ int free_page_type(struct page_info *pag { struct domain *owner = page_get_owner(page); unsigned long gmfn; - int rc; if ( likely(owner != NULL) ) { @@ -1973,34 +1972,39 @@ int free_page_type(struct page_info *pag page->nr_validated_ptes = 1U << PAGETABLE_ORDER; page->partial_pte = 0; } + switch ( type & PGT_type_mask ) { case PGT_l1_page_table: free_l1_table(page); - rc = 0; - break; + return 0; case PGT_l2_page_table: - rc = free_l2_table(page, preemptible); - break; + return free_l2_table(page, preemptible); case PGT_l3_page_table: #if CONFIG_PAGING_LEVELS == 3 if ( !(type & PGT_partial) ) page->nr_validated_ptes = L3_PAGETABLE_ENTRIES; #endif - rc = free_l3_table(page, preemptible); - break; + return free_l3_table(page, preemptible); case PGT_l4_page_table: - rc = free_l4_table(page, preemptible); - break; - default: - MEM_LOG("type %lx pfn %lx\n", type, page_to_mfn(page)); - rc = -EINVAL; - BUG(); + return free_l4_table(page, preemptible); } + MEM_LOG("type %lx pfn %lx\n", type, page_to_mfn(page)); + BUG(); + return -EINVAL; +} + + +static int __put_page_type_final(struct page_info *page, unsigned long type, + int preemptible) +{ + int rc = free_page_type(page, type, preemptible); + /* No need for atomic update of type_info here: noone else updates it. */ - if ( rc == 0 ) + switch ( rc ) { + case 0: /* * Record TLB information for flush later. We do not stamp page tables * when running in shadow mode: @@ -2013,9 +2017,8 @@ int free_page_type(struct page_info *pag page->tlbflush_timestamp = tlbflush_current_time(); wmb(); page->u.inuse.type_info--; - } - else if ( rc == -EINTR ) - { + break; + case -EINTR: ASSERT(!(page->u.inuse.type_info & (PGT_count_mask|PGT_validated|PGT_partial))); if ( !(shadow_mode_enabled(page_get_owner(page)) && @@ -2023,12 +2026,13 @@ int free_page_type(struct page_info *pag page->tlbflush_timestamp = tlbflush_current_time(); wmb(); page->u.inuse.type_info |= PGT_validated; - } - else - { - BUG_ON(rc != -EAGAIN); + break; + case -EAGAIN: wmb(); page->u.inuse.type_info |= PGT_partial; + break; + default: + BUG(); } return rc; @@ -2062,7 +2066,7 @@ static int __put_page_type(struct page_i x, nx)) != x) ) continue; /* We cleared the 'valid bit' so we do the clean up. */ - return free_page_type(page, x, preemptible); + return __put_page_type_final(page, x, preemptible); } /*