x86 mm: free p2m pages to the shadow/hap pool.
authorTim Deegan <Tim.Deegan@citrix.com>
Fri, 1 Oct 2010 10:57:53 +0000 (11:57 +0100)
committerTim Deegan <Tim.Deegan@citrix.com>
Fri, 1 Oct 2010 10:57:53 +0000 (11:57 +0100)
This allows the p2m code to dynamically free and reallocate memory
rather than just freeing everything once at domain teardown.
The previous mechanism (allocating p2m pages from shadow/hap
memory but freeing them directly to the domheap) was a relic
of the original shadow2's rather complex pool code.

Signed-off-by: Tim Deegan <Tim.Deegan@citrix.com>
xen/arch/x86/mm/hap/hap.c
xen/arch/x86/mm/shadow/common.c

index be4fc1e1659ea86ca25c21ca10977fdf49c52011..683f31632b137368bb1b237c9443e727c197feac 100644 (file)
@@ -329,8 +329,9 @@ static void hap_free_p2m_page(struct p2m_domain *p2m, struct page_info *pg)
     /* Free should not decrement domain's total allocation, since
      * these pages were allocated without an owner. */
     page_set_owner(pg, NULL);
-    free_domheap_page(pg);
     d->arch.paging.hap.p2m_pages--;
+    d->arch.paging.hap.total_pages++;
+    hap_free(d, page_to_mfn(pg));
     ASSERT(d->arch.paging.hap.p2m_pages >= 0);
     hap_unlock(d);
 }
@@ -618,7 +619,11 @@ void hap_final_teardown(struct domain *d)
         hap_teardown(d);
 
     p2m_teardown(p2m_get_hostp2m(d));
+    /* Free any memory that the p2m teardown released */
+    hap_lock(d);
+    hap_set_allocation(d, 0, NULL);
     ASSERT(d->arch.paging.hap.p2m_pages == 0);
+    hap_unlock(d);
 }
 
 void hap_teardown(struct domain *d)
index ca623f255351954d7d87426f2035198ae8694511..b91e6c2a4a98a8bcae1f461eb4ab1775693e4712 100644 (file)
@@ -1577,7 +1577,6 @@ void shadow_free(struct domain *d, mfn_t smfn)
 
     shadow_type = sp->u.sh.type;
     ASSERT(shadow_type != SH_type_none);
-    ASSERT(shadow_type != SH_type_p2m_table);
     ASSERT(sp->u.sh.head || (shadow_type > SH_type_max_shadow));
     pages = shadow_size(shadow_type);
 
@@ -1637,6 +1636,8 @@ shadow_alloc_p2m_page(struct p2m_domain *p2m)
  
     shadow_prealloc(d, SH_type_p2m_table, 1);
     pg = mfn_to_page(shadow_alloc(d, SH_type_p2m_table, 0));
+    d->arch.paging.shadow.p2m_pages++;
+    d->arch.paging.shadow.total_pages--;
 
     shadow_unlock(d);
 
@@ -1647,8 +1648,6 @@ shadow_alloc_p2m_page(struct p2m_domain *p2m)
      * believed to be a concern. */
     page_set_owner(pg, d);
     pg->count_info |= 1;
-    d->arch.paging.shadow.p2m_pages++;
-    d->arch.paging.shadow.total_pages--;
     return pg;
 }
 
@@ -1664,12 +1663,14 @@ shadow_free_p2m_page(struct p2m_domain *p2m, struct page_info *pg)
                      pg->count_info, pg->u.inuse.type_info);
     }
     pg->count_info &= ~PGC_count_mask;
-    /* Free should not decrement domain's total allocation, since 
-     * these pages were allocated without an owner. */
+    pg->u.sh.type = SH_type_p2m_table; /* p2m code reuses type-info */
     page_set_owner(pg, NULL); 
-    free_domheap_pages(pg, 0);
+
+    shadow_lock(d);
+    shadow_free(d, page_to_mfn(pg));
     d->arch.paging.shadow.p2m_pages--;
-    perfc_decr(shadow_alloc_count);
+    d->arch.paging.shadow.total_pages++;
+    shadow_unlock(d);
 }
 
 #if CONFIG_PAGING_LEVELS == 3
@@ -3114,7 +3115,7 @@ void shadow_teardown(struct domain *d)
 {
     struct vcpu *v;
     mfn_t mfn;
-    struct p2m_domain *p2m = p2m_get_hostp2m(d);
+    struct page_info *unpaged_pagetable = NULL;
 
     ASSERT(d->is_dying);
     ASSERT(d != current->domain);
@@ -3200,8 +3201,8 @@ void shadow_teardown(struct domain *d)
             if ( !hvm_paging_enabled(v) )
                 v->arch.guest_table = pagetable_null();
         }
-        shadow_free_p2m_page(p2m, 
-            pagetable_get_page(d->arch.paging.shadow.unpaged_pagetable));
+        unpaged_pagetable = 
+            pagetable_get_page(d->arch.paging.shadow.unpaged_pagetable);
         d->arch.paging.shadow.unpaged_pagetable = pagetable_null();
     }
 
@@ -3218,6 +3219,10 @@ void shadow_teardown(struct domain *d)
     }
 
     shadow_unlock(d);
+
+    /* Must be called outside the lock */
+    if ( unpaged_pagetable ) 
+        shadow_free_p2m_page(p2m_get_hostp2m(d), unpaged_pagetable);
 }
 
 void shadow_final_teardown(struct domain *d)
@@ -3238,13 +3243,16 @@ void shadow_final_teardown(struct domain *d)
 
     /* It is now safe to pull down the p2m map. */
     p2m_teardown(p2m_get_hostp2m(d));
-
+    /* Free any shadow memory that the p2m teardown released */
+    shadow_lock(d);
+    sh_set_allocation(d, 0, NULL);
     SHADOW_PRINTK("dom %u final teardown done."
                    "  Shadow pages total = %u, free = %u, p2m=%u\n",
                    d->domain_id,
                    d->arch.paging.shadow.total_pages, 
                    d->arch.paging.shadow.free_pages, 
                    d->arch.paging.shadow.p2m_pages);
+    shadow_unlock(d);
 }
 
 static int shadow_one_bit_enable(struct domain *d, u32 mode)