[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [HVM] HAP: tidy up page allocation/tracking and monitor-table building.



# HG changeset patch
# User Tim Deegan <Tim.Deegan@xxxxxxxxxxxxx>
# Date 1184763360 -3600
# Node ID ad87a491287455e302a914ed17a2a00902136ec6
# Parent  4197a1aad70bc567278a80a2225c87950d910095
[HVM] HAP: tidy up page allocation/tracking and monitor-table building.
Signed-off-by: Tim Deegan <Tim.Deegan@xxxxxxxxxxxxx>
---
 xen/arch/x86/mm/hap/hap.c    |  246 ++++++++++++++++++++++---------------------
 xen/include/asm-x86/domain.h |    2 
 2 files changed, 129 insertions(+), 119 deletions(-)

diff -r 4197a1aad70b -r ad87a4912874 xen/arch/x86/mm/hap/hap.c
--- a/xen/arch/x86/mm/hap/hap.c Wed Jul 18 10:04:46 2007 +0100
+++ b/xen/arch/x86/mm/hap/hap.c Wed Jul 18 13:56:00 2007 +0100
@@ -87,83 +87,79 @@ void hap_clean_dirty_bitmap(struct domai
 /************************************************/
 /*             HAP SUPPORT FUNCTIONS            */
 /************************************************/
-mfn_t hap_alloc(struct domain *d)
-{
-    struct page_info *sp = NULL;
+static struct page_info *hap_alloc(struct domain *d)
+{
+    struct page_info *pg = NULL;
     void *p;
 
     ASSERT(hap_locked_by_me(d));
 
-    sp = list_entry(d->arch.paging.hap.freelists.next, struct page_info, list);
-    list_del(&sp->list);
-    d->arch.paging.hap.free_pages -= 1;
-
-    /* Now safe to clear the page for reuse */
-    p = hap_map_domain_page(page_to_mfn(sp));
+    if ( unlikely(list_empty(&d->arch.paging.hap.freelist)) )
+        return NULL;
+
+    pg = list_entry(d->arch.paging.hap.freelist.next, struct page_info, list);
+    list_del(&pg->list);
+    d->arch.paging.hap.free_pages--;
+
+    p = hap_map_domain_page(page_to_mfn(pg));
     ASSERT(p != NULL);
     clear_page(p);
     hap_unmap_domain_page(p);
 
-    return page_to_mfn(sp);
-}
-
-void hap_free(struct domain *d, mfn_t smfn)
-{
-    struct page_info *sp = mfn_to_page(smfn); 
+    return pg;
+}
+
+static void hap_free(struct domain *d, mfn_t mfn)
+{
+    struct page_info *pg = mfn_to_page(mfn); 
 
     ASSERT(hap_locked_by_me(d));
 
-    d->arch.paging.hap.free_pages += 1;
-    list_add_tail(&sp->list, &d->arch.paging.hap.freelists);
-}
-
-struct page_info * hap_alloc_p2m_page(struct domain *d)
+    d->arch.paging.hap.free_pages++;
+    list_add_tail(&pg->list, &d->arch.paging.hap.freelist);
+}
+
+static struct page_info *hap_alloc_p2m_page(struct domain *d)
 {
     struct page_info *pg;
-    mfn_t mfn;
-    void *p;
 
     hap_lock(d);
+    pg = hap_alloc(d);
 
 #if CONFIG_PAGING_LEVELS == 3
     /* Under PAE mode, top-level P2M table should be allocated below 4GB space
      * because the size of h_cr3 is only 32-bit. We use alloc_domheap_pages to 
-     * force this requirement. This page will be de-allocated in 
-     * hap_free_p2m_page(), like other P2M pages.
-    */
-    if ( d->arch.paging.hap.p2m_pages == 0 ) 
-    {
+     * force this requirement, and exchange the guaranteed 32-bit-clean
+     * page for the one we just hap_alloc()ed. */
+    if ( d->arch.paging.hap.p2m_pages == 0
+         && mfn_x(page_to_mfn(pg)) >= (1UL << (32 - PAGE_SHIFT)) )
+    {
+        free_domheap_page(pg);
         pg = alloc_domheap_pages(NULL, 0, MEMF_bits(32));
-        d->arch.paging.hap.p2m_pages += 1;
-    }
-    else
+        if ( likely(pg != NULL) )
+        {
+            void *p = hap_map_domain_page(page_to_mfn(pg));
+            clear_page(p);
+            hap_unmap_domain_page(p);
+        }
+    }
 #endif
-    {
-        pg = mfn_to_page(hap_alloc(d));
-        d->arch.paging.hap.p2m_pages += 1;
-        d->arch.paging.hap.total_pages -= 1;
-    }
-
-    if ( pg == NULL )
-    {
-        hap_unlock(d);
-        return NULL;
-    }   
+
+    if ( likely(pg != NULL) )
+    {
+        d->arch.paging.hap.total_pages--;
+        d->arch.paging.hap.p2m_pages++;
+        page_set_owner(pg, d);
+        pg->count_info = 1;
+    }
 
     hap_unlock(d);
-
-    page_set_owner(pg, d);
-    pg->count_info = 1;
-    mfn = page_to_mfn(pg);
-    p = hap_map_domain_page(mfn);
-    clear_page(p);
-    hap_unmap_domain_page(p);
-
     return pg;
 }
 
 void hap_free_p2m_page(struct domain *d, struct page_info *pg)
 {
+    hap_lock(d);
     ASSERT(page_get_owner(pg) == d);
     /* Should have just the one ref we gave it in alloc_p2m_page() */
     if ( (pg->count_info & PGC_count_mask) != 1 )
@@ -173,9 +169,10 @@ void hap_free_p2m_page(struct domain *d,
     /* Free should not decrement domain's total allocation, since 
      * these pages were allocated without an owner. */
     page_set_owner(pg, NULL); 
-    free_domheap_pages(pg, 0);
+    free_domheap_page(pg);
     d->arch.paging.hap.p2m_pages--;
     ASSERT(d->arch.paging.hap.p2m_pages >= 0);
+    hap_unlock(d);
 }
 
 /* Return the size of the pool, rounded up to the nearest MB */
@@ -193,7 +190,7 @@ static unsigned int
 static unsigned int
 hap_set_allocation(struct domain *d, unsigned int pages, int *preempted)
 {
-    struct page_info *sp;
+    struct page_info *pg;
 
     ASSERT(hap_locked_by_me(d));
 
@@ -202,27 +199,27 @@ hap_set_allocation(struct domain *d, uns
         if ( d->arch.paging.hap.total_pages < pages )
         {
             /* Need to allocate more memory from domheap */
-            sp = alloc_domheap_pages(NULL, 0, 0);
-            if ( sp == NULL )
+            pg = alloc_domheap_page(NULL);
+            if ( pg == NULL )
             {
                 HAP_PRINTK("failed to allocate hap pages.\n");
                 return -ENOMEM;
             }
-            d->arch.paging.hap.free_pages += 1;
-            d->arch.paging.hap.total_pages += 1;
-            list_add_tail(&sp->list, &d->arch.paging.hap.freelists);
+            d->arch.paging.hap.free_pages++;
+            d->arch.paging.hap.total_pages++;
+            list_add_tail(&pg->list, &d->arch.paging.hap.freelist);
         }
         else if ( d->arch.paging.hap.total_pages > pages )
         {
             /* Need to return memory to domheap */
-            ASSERT(!list_empty(&d->arch.paging.hap.freelists));
-            sp = list_entry(d->arch.paging.hap.freelists.next,
+            ASSERT(!list_empty(&d->arch.paging.hap.freelist));
+            pg = list_entry(d->arch.paging.hap.freelist.next,
                             struct page_info, list);
-            list_del(&sp->list);
-            d->arch.paging.hap.free_pages -= 1;
-            d->arch.paging.hap.total_pages -= 1;
-            sp->count_info = 0;
-            free_domheap_pages(sp, 0);
+            list_del(&pg->list);
+            d->arch.paging.hap.free_pages--;
+            d->arch.paging.hap.total_pages--;
+            pg->count_info = 0;
+            free_domheap_page(pg);
         }
         
         /* Check to see if we need to yield and try again */
@@ -237,62 +234,63 @@ hap_set_allocation(struct domain *d, uns
 }
 
 #if CONFIG_PAGING_LEVELS == 4
-void hap_install_xen_entries_in_l4(struct vcpu *v, mfn_t gl4mfn, mfn_t sl4mfn)
+static void hap_install_xen_entries_in_l4(struct vcpu *v, mfn_t l4mfn)
 {
     struct domain *d = v->domain;
-    l4_pgentry_t *sl4e;
-
-    sl4e = hap_map_domain_page(sl4mfn);
-    ASSERT(sl4e != NULL);
+    l4_pgentry_t *l4e;
+
+    l4e = hap_map_domain_page(l4mfn);
+    ASSERT(l4e != NULL);
 
     /* Copy the common Xen mappings from the idle domain */
-    memcpy(&sl4e[ROOT_PAGETABLE_FIRST_XEN_SLOT],
+    memcpy(&l4e[ROOT_PAGETABLE_FIRST_XEN_SLOT],
            &idle_pg_table[ROOT_PAGETABLE_FIRST_XEN_SLOT],
            ROOT_PAGETABLE_XEN_SLOTS * sizeof(l4_pgentry_t));
 
     /* Install the per-domain mappings for this domain */
-    sl4e[l4_table_offset(PERDOMAIN_VIRT_START)] =
+    l4e[l4_table_offset(PERDOMAIN_VIRT_START)] =
         l4e_from_pfn(mfn_x(page_to_mfn(virt_to_page(d->arch.mm_perdomain_l3))),
                      __PAGE_HYPERVISOR);
 
-    sl4e[l4_table_offset(LINEAR_PT_VIRT_START)] =
-        l4e_from_pfn(mfn_x(gl4mfn), __PAGE_HYPERVISOR);
-
-    /* install domain-specific P2M table */
-    sl4e[l4_table_offset(RO_MPT_VIRT_START)] =
+    /* Install a linear mapping */
+    l4e[l4_table_offset(LINEAR_PT_VIRT_START)] =
+        l4e_from_pfn(mfn_x(l4mfn), __PAGE_HYPERVISOR);
+
+    /* Install the domain-specific P2M table */
+    l4e[l4_table_offset(RO_MPT_VIRT_START)] =
         l4e_from_pfn(mfn_x(pagetable_get_mfn(d->arch.phys_table)),
                      __PAGE_HYPERVISOR);
 
-    hap_unmap_domain_page(sl4e);
+    hap_unmap_domain_page(l4e);
 }
 #endif /* CONFIG_PAGING_LEVELS == 4 */
 
 #if CONFIG_PAGING_LEVELS == 3
-void hap_install_xen_entries_in_l2h(struct vcpu *v, mfn_t sl2hmfn)
+static void hap_install_xen_entries_in_l2h(struct vcpu *v, mfn_t l2hmfn)
 {
     struct domain *d = v->domain;
-    l2_pgentry_t *sl2e;
+    l2_pgentry_t *l2e;
     l3_pgentry_t *p2m;
-
     int i;
 
-    sl2e = hap_map_domain_page(sl2hmfn);
-    ASSERT(sl2e != NULL);
+    l2e = hap_map_domain_page(l2hmfn);
+    ASSERT(l2e != NULL);
     
     /* Copy the common Xen mappings from the idle domain */
-    memcpy(&sl2e[L2_PAGETABLE_FIRST_XEN_SLOT & (L2_PAGETABLE_ENTRIES-1)],
+    memcpy(&l2e[L2_PAGETABLE_FIRST_XEN_SLOT & (L2_PAGETABLE_ENTRIES-1)],
            &idle_pg_table_l2[L2_PAGETABLE_FIRST_XEN_SLOT],
            L2_PAGETABLE_XEN_SLOTS * sizeof(l2_pgentry_t));
 
     /* Install the per-domain mappings for this domain */
     for ( i = 0; i < PDPT_L2_ENTRIES; i++ )
-        sl2e[l2_table_offset(PERDOMAIN_VIRT_START) + i] =
+        l2e[l2_table_offset(PERDOMAIN_VIRT_START) + i] =
             l2e_from_pfn(
                 mfn_x(page_to_mfn(virt_to_page(d->arch.mm_perdomain_pt) + i)),
                 __PAGE_HYPERVISOR);
 
+    /* No linear mapping; will be set up by monitor-table contructor. */
     for ( i = 0; i < 4; i++ )
-        sl2e[l2_table_offset(LINEAR_PT_VIRT_START) + i] =
+        l2e[l2_table_offset(LINEAR_PT_VIRT_START) + i] =
             l2e_empty();
 
     /* Install the domain-specific p2m table */
@@ -300,63 +298,66 @@ void hap_install_xen_entries_in_l2h(stru
     p2m = hap_map_domain_page(pagetable_get_mfn(d->arch.phys_table));
     for ( i = 0; i < MACHPHYS_MBYTES>>1; i++ )
     {
-        sl2e[l2_table_offset(RO_MPT_VIRT_START) + i] =
+        l2e[l2_table_offset(RO_MPT_VIRT_START) + i] =
             (l3e_get_flags(p2m[i]) & _PAGE_PRESENT)
             ? l2e_from_pfn(mfn_x(_mfn(l3e_get_pfn(p2m[i]))),
                            __PAGE_HYPERVISOR)
             : l2e_empty();
     }
     hap_unmap_domain_page(p2m);
-    hap_unmap_domain_page(sl2e);
+    hap_unmap_domain_page(l2e);
 }
 #endif
 
 #if CONFIG_PAGING_LEVELS == 2
-void hap_install_xen_entries_in_l2(struct vcpu *v, mfn_t gl2mfn, mfn_t sl2mfn)
+static void hap_install_xen_entries_in_l2(struct vcpu *v, mfn_t l2mfn)
 {
     struct domain *d = v->domain;
-    l2_pgentry_t *sl2e;
+    l2_pgentry_t *l2e;
     int i;
 
-    sl2e = hap_map_domain_page(sl2mfn);
-    ASSERT(sl2e != NULL);
+    l2e = hap_map_domain_page(l2mfn);
+    ASSERT(l2e != NULL);
     
     /* Copy the common Xen mappings from the idle domain */
-    memcpy(&sl2e[L2_PAGETABLE_FIRST_XEN_SLOT],
+    memcpy(&l2e[L2_PAGETABLE_FIRST_XEN_SLOT],
            &idle_pg_table[L2_PAGETABLE_FIRST_XEN_SLOT],
            L2_PAGETABLE_XEN_SLOTS * sizeof(l2_pgentry_t));
 
     /* Install the per-domain mappings for this domain */
     for ( i = 0; i < PDPT_L2_ENTRIES; i++ )
-        sl2e[l2_table_offset(PERDOMAIN_VIRT_START) + i] =
+        l2e[l2_table_offset(PERDOMAIN_VIRT_START) + i] =
             l2e_from_pfn(
                 mfn_x(page_to_mfn(virt_to_page(d->arch.mm_perdomain_pt) + i)),
                 __PAGE_HYPERVISOR);
 
-
-    sl2e[l2_table_offset(LINEAR_PT_VIRT_START)] =
-        l2e_from_pfn(mfn_x(gl2mfn), __PAGE_HYPERVISOR);
-
-    /* install domain-specific P2M table */
-    sl2e[l2_table_offset(RO_MPT_VIRT_START)] =
+    /* Install the linear mapping */
+    l2e[l2_table_offset(LINEAR_PT_VIRT_START)] =
+        l2e_from_pfn(mfn_x(l2mfn), __PAGE_HYPERVISOR);
+
+    /* Install the domain-specific P2M table */
+    l2e[l2_table_offset(RO_MPT_VIRT_START)] =
         l2e_from_pfn(mfn_x(pagetable_get_mfn(d->arch.phys_table)),
                             __PAGE_HYPERVISOR);
 
-    hap_unmap_domain_page(sl2e);
+    hap_unmap_domain_page(l2e);
 }
 #endif
 
-mfn_t hap_make_monitor_table(struct vcpu *v)
+static mfn_t hap_make_monitor_table(struct vcpu *v)
 {
     struct domain *d = v->domain;
+    struct page_info *pg;
 
     ASSERT(pagetable_get_pfn(v->arch.monitor_table) == 0);
 
 #if CONFIG_PAGING_LEVELS == 4
     {
         mfn_t m4mfn;
-        m4mfn = hap_alloc(d);
-        hap_install_xen_entries_in_l4(v, m4mfn, m4mfn);
+        if ( (pg = hap_alloc(d)) == NULL )
+            goto oom;
+        m4mfn = page_to_mfn(pg);
+        hap_install_xen_entries_in_l4(v, m4mfn);
         return m4mfn;
     }
 #elif CONFIG_PAGING_LEVELS == 3
@@ -366,12 +367,16 @@ mfn_t hap_make_monitor_table(struct vcpu
         l2_pgentry_t *l2e;
         int i;
 
-        m3mfn = hap_alloc(d);
+        if ( (pg = hap_alloc(d)) == NULL )
+            goto oom;
+        m3mfn = page_to_mfn(pg);
 
         /* Install a monitor l2 table in slot 3 of the l3 table.
          * This is used for all Xen entries, including linear maps
          */
-        m2mfn = hap_alloc(d);
+        if ( (pg = hap_alloc(d)) == NULL )
+            goto oom;
+        m2mfn = page_to_mfn(pg);
         l3e = hap_map_domain_page(m3mfn);
         l3e[3] = l3e_from_pfn(mfn_x(m2mfn), _PAGE_PRESENT);
         hap_install_xen_entries_in_l2h(v, m2mfn);
@@ -391,16 +396,21 @@ mfn_t hap_make_monitor_table(struct vcpu
 #else
     {
         mfn_t m2mfn;
-        
-        m2mfn = hap_alloc(d);
-        hap_install_xen_entries_in_l2(v, m2mfn, m2mfn);
-    
+        if ( (pg = hap_alloc(d)) == NULL )
+            goto oom;
+        m2mfn = page_to_mfn(pg);;
+        hap_install_xen_entries_in_l2(v, m2mfn);
         return m2mfn;
     }
 #endif
-}
-
-void hap_destroy_monitor_table(struct vcpu* v, mfn_t mmfn)
+
+ oom:
+    HAP_ERROR("out of memory building monitor pagetable\n");
+    domain_crash(d);
+    return _mfn(INVALID_MFN);
+}
+
+static void hap_destroy_monitor_table(struct vcpu* v, mfn_t mmfn)
 {
     struct domain *d = v->domain;
 
@@ -424,7 +434,7 @@ void hap_domain_init(struct domain *d)
 void hap_domain_init(struct domain *d)
 {
     hap_lock_init(d);
-    INIT_LIST_HEAD(&d->arch.paging.hap.freelists);
+    INIT_LIST_HEAD(&d->arch.paging.hap.freelist);
 
     /* This domain will use HAP for log-dirty mode */
     paging_log_dirty_init(d, hap_enable_log_dirty, hap_disable_log_dirty,
@@ -640,12 +650,12 @@ static void hap_update_paging_modes(stru
 
 #if CONFIG_PAGING_LEVELS == 3
 static void p2m_install_entry_in_monitors(struct domain *d, l3_pgentry_t *l3e) 
-/* Special case, only used for external-mode domains on PAE hosts:
- * update the mapping of the p2m table.  Once again, this is trivial in
- * other paging modes (one top-level entry points to the top-level p2m,
- * no maintenance needed), but PAE makes life difficult by needing a
- * copy l3es of the p2m table in eight l2h slots in the monitor table.  This 
- * function makes fresh copies when a p2m l3e changes. */
+/* Special case, only used for PAE hosts: update the mapping of the p2m
+ * table.  This is trivial in other paging modes (one top-level entry
+ * points to the top-level p2m, no maintenance needed), but PAE makes
+ * life difficult by needing a copy of the p2m table in eight l2h slots
+ * in the monitor table.  This function makes fresh copies when a p2m
+ * l3e changes. */
 {
     l2_pgentry_t *ml2e;
     struct vcpu *v;
diff -r 4197a1aad70b -r ad87a4912874 xen/include/asm-x86/domain.h
--- a/xen/include/asm-x86/domain.h      Wed Jul 18 10:04:46 2007 +0100
+++ b/xen/include/asm-x86/domain.h      Wed Jul 18 13:56:00 2007 +0100
@@ -117,7 +117,7 @@ struct hap_domain {
     int               locker;
     const char       *locker_function;
     
-    struct list_head  freelists;
+    struct list_head  freelist;
     unsigned int      total_pages;  /* number of pages allocated */
     unsigned int      free_pages;   /* number of pages on freelists */
     unsigned int      p2m_pages;    /* number of pages allocates to p2m */

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.