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

[Xen-changelog] [xen-unstable] [IA64] Make P2M semantics match x86



# HG changeset patch
# User awilliam@xxxxxxxxxxxx
# Date 1174922117 21600
# Node ID fa77ec03afd609b095ce5813a776123b176c8b67
# Parent  be1017157768e8d6d5d5552cf0008d81d611b1bb
[IA64] Make P2M semantics match x86

So far the ia64 p2m has the semantic similar to
(the x86 p2m) + (page reference count).
But the differece from the x86 p2m have caused the breakage and work around.
This patch make the ia64 p2m semantic same as x86 to solve it.
- get_page() only for grant table page mapping and foreign domain page
  mapping.
- put_page() only for those pages.
- guest_physmap_remove_page() doesn't touch PGC_allocated bit.

Signed-off-by: Isaku Yamahata <yamahata@xxxxxxxxxxxxx>
---
 xen/arch/ia64/xen/mm.c    |  175 ++++++++++++++++++----------------------------
 xen/include/asm-ia64/mm.h |    2 
 2 files changed, 73 insertions(+), 104 deletions(-)

diff -r be1017157768 -r fa77ec03afd6 xen/arch/ia64/xen/mm.c
--- a/xen/arch/ia64/xen/mm.c    Thu Mar 22 09:30:54 2007 -0600
+++ b/xen/arch/ia64/xen/mm.c    Mon Mar 26 09:15:17 2007 -0600
@@ -208,46 +208,6 @@ alloc_dom_xen_and_dom_io(void)
     BUG_ON(dom_io == NULL);
 }
 
-// heavily depends on the struct page_info layout.
-// if (page_get_owner(page) == d &&
-//     test_and_clear_bit(_PGC_allocated, &page->count_info)) {
-//     put_page(page);
-// }
-static void
-try_to_clear_PGC_allocate(struct domain* d, struct page_info* page)
-{
-    u32 _d, _nd;
-    u64 x, nx, y;
-
-    _d = pickle_domptr(d);
-    y = *((u64*)&page->count_info);
-    do {
-        x = y;
-        _nd = x >> 32;
-        nx = x - 1;
-        __clear_bit(_PGC_allocated, &nx);
-
-        if (unlikely(!(x & PGC_allocated)) || unlikely(_nd != _d)) {
-            struct domain* nd = unpickle_domptr(_nd);
-            if (nd == NULL) {
-                gdprintk(XENLOG_INFO, "gnttab_transfer: "
-                        "Bad page %p: ed=%p(%u) 0x%x, "
-                        "sd=%p 0x%x,"
-                        " caf=%016lx, taf=%" PRtype_info "\n",
-                        (void *) page_to_mfn(page),
-                        d, d->domain_id, _d,
-                        nd, _nd,
-                        x,
-                        page->u.inuse.type_info);
-            }
-            break;
-        }
-
-        BUG_ON((nx & PGC_count_mask) < 1);
-        y = cmpxchg((u64*)&page->count_info, x, nx);
-    } while (unlikely(y != x));
-}
-
 static void
 mm_teardown_pte(struct domain* d, volatile pte_t* pte, unsigned long offset)
 {
@@ -267,22 +227,25 @@ mm_teardown_pte(struct domain* d, volati
     if (!mfn_valid(mfn))
         return;
     page = mfn_to_page(mfn);
-    // struct page_info corresponding to mfn may exist or not depending
-    // on CONFIG_VIRTUAL_FRAME_TABLE.
-    // This check is too easy.
-    // The right way is to check whether this page is of io area or acpi pages
+    // page might be pte page for p2m exposing. check it.
     if (page_get_owner(page) == NULL) {
         BUG_ON(page->count_info != 0);
         return;
     }
+    // struct page_info corresponding to mfn may exist or not depending
+    // on CONFIG_VIRTUAL_FRAME_TABLE.
+    // The above check is too easy.
+    // The right way is to check whether this page is of io area or acpi pages
 
     if (pte_pgc_allocated(old_pte)) {
         BUG_ON(page_get_owner(page) != d);
         BUG_ON(get_gpfn_from_mfn(mfn) == INVALID_M2P_ENTRY);
         set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY);
-        try_to_clear_PGC_allocate(d, page);
-    }
-    put_page(page);
+        if (test_and_clear_bit(_PGC_allocated, &page->count_info))
+            put_page(page);
+    } else {
+        put_page(page);
+    }
 }
 
 static void
@@ -770,7 +733,6 @@ __assign_new_domain_page(struct domain *
 {
     struct page_info *p;
     unsigned long maddr;
-    int ret;
 
     BUG_ON(!pte_none(*pte));
 
@@ -791,8 +753,6 @@ __assign_new_domain_page(struct domain *
                maddr);
     }
 
-    ret = get_page(p, d);
-    BUG_ON(ret == 0);
     set_gpfn_from_mfn(page_to_mfn(p), mpaddr >> PAGE_SHIFT);
     // clear_page() and set_gpfn_from_mfn() become visible before set_pte_rel()
     // because set_pte_rel() has release semantics
@@ -893,11 +853,9 @@ assign_domain_page(struct domain *d,
                    unsigned long mpaddr, unsigned long physaddr)
 {
     struct page_info* page = mfn_to_page(physaddr >> PAGE_SHIFT);
-    int ret;
 
     BUG_ON((physaddr & GPFN_IO_MASK) != GPFN_MEM);
-    ret = get_page(page, d);
-    BUG_ON(ret == 0);
+    BUG_ON(page->count_info != (PGC_allocated | 1));
     set_gpfn_from_mfn(physaddr >> PAGE_SHIFT, mpaddr >> PAGE_SHIFT);
     // because __assign_domain_page() uses set_pte_rel() which has
     // release semantics, smp_mb() isn't needed.
@@ -1086,6 +1044,29 @@ assign_domain_mach_page(struct domain *d
 }
 
 static void
+adjust_page_count_info(struct page_info* page)
+{
+    struct domain* d = page_get_owner(page);
+    BUG_ON((page->count_info & PGC_count_mask) != 1);
+    if (d != NULL) {
+        int ret = get_page(page, d);
+        BUG_ON(ret == 0);
+    } else {
+        u64 x, nx, y;
+
+        y = *((u64*)&page->count_info);
+        do {
+            x = y;
+            nx = x + 1;
+
+            BUG_ON((x >> 32) != 0);
+            BUG_ON((nx & PGC_count_mask) != 2);
+            y = cmpxchg((u64*)&page->count_info, x, nx);
+        } while (unlikely(y != x));
+    }
+}
+
+static void
 domain_put_page(struct domain* d, unsigned long mpaddr,
                 volatile pte_t* ptep, pte_t old_pte, int clear_PGC_allocate)
 {
@@ -1100,8 +1081,19 @@ domain_put_page(struct domain* d, unsign
             BUG();
         }
 
-       if (clear_PGC_allocate)
-            try_to_clear_PGC_allocate(d, page);
+        if (likely(clear_PGC_allocate)) {
+            if (!test_and_clear_bit(_PGC_allocated, &page->count_info))
+                BUG();
+            /* put_page() is done by domain_page_flush_and_put() */
+        } else {
+            // In this case, page reference count mustn't touched.
+            // domain_page_flush_and_put() decrements it, we increment
+            // it in advence. This patch is slow path.
+            //
+            // guest_remove_page(): owner = d, count_info = 1
+            // memory_exchange(): owner = NULL, count_info = 1
+            adjust_page_count_info(page);
+        }
     }
     domain_page_flush_and_put(d, mpaddr, ptep, old_pte, page);
 }
@@ -1148,7 +1140,7 @@ assign_domain_page_cmpxchg_rel(struct do
 assign_domain_page_cmpxchg_rel(struct domain* d, unsigned long mpaddr,
                                struct page_info* old_page,
                                struct page_info* new_page,
-                               unsigned long flags)
+                               unsigned long flags, int clear_PGC_allocate)
 {
     struct mm_struct *mm = &d->arch.mm;
     volatile pte_t* pte;
@@ -1160,6 +1152,7 @@ assign_domain_page_cmpxchg_rel(struct do
     pte_t new_pte;
     pte_t ret_pte;
 
+    BUG_ON((flags & ASSIGN_pgc_allocated) == 0);
     pte = lookup_alloc_domain_pte(d, mpaddr);
 
  again:
@@ -1200,6 +1193,18 @@ assign_domain_page_cmpxchg_rel(struct do
     BUG_ON(old_mfn == new_mfn);
 
     set_gpfn_from_mfn(old_mfn, INVALID_M2P_ENTRY);
+    if (likely(clear_PGC_allocate)) {
+        if (!test_and_clear_bit(_PGC_allocated, &old_page->count_info))
+            BUG();
+    } else {
+        int ret;
+        // adjust for count_info for domain_page_flush_and_put()
+        // This is slow path.
+        BUG_ON(!test_bit(_PGC_allocated, &old_page->count_info));
+        BUG_ON(d == NULL);
+        ret = get_page(old_page, d);
+        BUG_ON(ret == 0);
+    }
 
     domain_page_flush_and_put(d, mpaddr, pte, old_pte, old_page);
     perfc_incrc(assign_domain_pge_cmpxchg_rel);
@@ -1207,7 +1212,8 @@ assign_domain_page_cmpxchg_rel(struct do
 }
 
 static void
-zap_domain_page_one(struct domain *d, unsigned long mpaddr, unsigned long mfn)
+zap_domain_page_one(struct domain *d, unsigned long mpaddr,
+                    int clear_PGC_allocate, unsigned long mfn)
 {
     struct mm_struct *mm = &d->arch.mm;
     volatile pte_t *pte;
@@ -1258,12 +1264,8 @@ zap_domain_page_one(struct domain *d, un
     page = mfn_to_page(mfn);
     BUG_ON((page->count_info & PGC_count_mask) == 0);
 
-    // exchange_memory() calls
-    //   steal_page()
-    //     page owner is set to NULL
-    //   guest_physmap_remove_page()
-    //     zap_domain_page_one()
-    domain_put_page(d, mpaddr, pte, old_pte, (page_get_owner(page) != NULL));
+    BUG_ON(clear_PGC_allocate && (page_get_owner(page) == NULL));
+    domain_put_page(d, mpaddr, pte, old_pte, clear_PGC_allocate);
     perfc_incrc(zap_dcomain_page_one);
 }
 
@@ -1276,7 +1278,7 @@ dom0vp_zap_physmap(struct domain *d, uns
         return -ENOSYS;
     }
 
-    zap_domain_page_one(d, gpfn << PAGE_SHIFT, INVALID_MFN);
+    zap_domain_page_one(d, gpfn << PAGE_SHIFT, 1, INVALID_MFN);
     perfc_incrc(dom0vp_zap_physmap);
     return 0;
 }
@@ -1563,6 +1565,7 @@ destroy_grant_host_mapping(unsigned long
     /* try_to_clear_PGC_allocate(d, page) is not needed. */
     BUG_ON(page_get_owner(page) == d &&
            get_gpfn_from_mfn(mfn) == gpfn);
+    BUG_ON(pte_pgc_allocated(old_pte));
     domain_page_flush_and_put(d, gpaddr, pte, old_pte, page);
 
     perfc_incrc(destroy_grant_host_mapping);
@@ -1606,9 +1609,6 @@ steal_page(struct domain *d, struct page
         // assign_domain_page_cmpxchg_rel() has release semantics
         // so smp_mb() isn't needed.
 
-        ret = get_page(new, d);
-        BUG_ON(ret == 0);
-
         gpfn = get_gpfn_from_mfn(page_to_mfn(page));
         if (gpfn == INVALID_M2P_ENTRY) {
             free_domheap_page(new);
@@ -1621,7 +1621,7 @@ steal_page(struct domain *d, struct page
 
         ret = assign_domain_page_cmpxchg_rel(d, gpfn << PAGE_SHIFT, page, new,
                                              ASSIGN_writable |
-                                             ASSIGN_pgc_allocated);
+                                             ASSIGN_pgc_allocated, 0);
         if (ret < 0) {
             gdprintk(XENLOG_INFO, "assign_domain_page_cmpxchg_rel failed %d\n",
                     ret);
@@ -1648,18 +1648,8 @@ steal_page(struct domain *d, struct page
         // page->u.inused._domain = 0;
         _nd = x >> 32;
 
-        if (
-            // when !MEMF_no_refcount, page might be put_page()'d or
-            // it will be put_page()'d later depending on queued.
-            unlikely(!(memflags & MEMF_no_refcount) &&
-                     ((x & (PGC_count_mask | PGC_allocated)) !=
+        if (unlikely(((x & (PGC_count_mask | PGC_allocated)) !=
                       (1 | PGC_allocated))) ||
-            // when MEMF_no_refcount, page isn't de-assigned from
-            // this domain yet. So count_info = 2
-            unlikely((memflags & MEMF_no_refcount) &&
-                     ((x & (PGC_count_mask | PGC_allocated)) !=
-                      (2 | PGC_allocated))) ||
-
             unlikely(_nd != _d)) {
             struct domain* nd = unpickle_domptr(_nd);
             if (nd == NULL) {
@@ -1711,11 +1701,8 @@ guest_physmap_add_page(struct domain *d,
 guest_physmap_add_page(struct domain *d, unsigned long gpfn,
                        unsigned long mfn)
 {
-    int ret;
-
     BUG_ON(!mfn_valid(mfn));
-    ret = get_page(mfn_to_page(mfn), d);
-    BUG_ON(ret == 0);
+    BUG_ON(mfn_to_page(mfn)->count_info != (PGC_allocated | 1));
     set_gpfn_from_mfn(mfn, gpfn);
     smp_mb();
     assign_domain_page_replace(d, gpfn << PAGE_SHIFT, mfn,
@@ -1731,7 +1718,7 @@ guest_physmap_remove_page(struct domain 
                           unsigned long mfn)
 {
     BUG_ON(mfn == 0);//XXX
-    zap_domain_page_one(d, gpfn << PAGE_SHIFT, mfn);
+    zap_domain_page_one(d, gpfn << PAGE_SHIFT, 0, mfn);
     perfc_incrc(guest_physmap_remove_page);
 }
 
@@ -2142,26 +2129,8 @@ arch_memory_op(int op, XEN_GUEST_HANDLE(
 
         /* Unmap from old location, if any. */
         gpfn = get_gpfn_from_mfn(mfn);
-        if (gpfn != INVALID_M2P_ENTRY) {
-            /*
-             * guest_physmap_remove_page() (for IPF) descrements page
-             * counter and unset PGC_allocated flag,
-             * so pre-increment page counter and post-set flag inserted
-             */
-            /* pre-increment page counter */
-            if (!get_page(mfn_to_page(mfn), d))
-                goto out;
-
+        if (gpfn != INVALID_M2P_ENTRY)
             guest_physmap_remove_page(d, gpfn, mfn);
-
-            /* post-set PGC_allocated flag */
-            if ((mfn_to_page(mfn)->count_info & PGC_count_mask) != 1) {
-                /* no one but us is using this page */
-                put_page(mfn_to_page(mfn));
-                goto out;
-            }
-            set_bit(_PGC_allocated, &mfn_to_page(mfn)->count_info);
-        }
 
         /* Map at new location. */
         guest_physmap_add_page(d, xatp.gpfn, mfn);
diff -r be1017157768 -r fa77ec03afd6 xen/include/asm-ia64/mm.h
--- a/xen/include/asm-ia64/mm.h Thu Mar 22 09:30:54 2007 -0600
+++ b/xen/include/asm-ia64/mm.h Mon Mar 26 09:15:17 2007 -0600
@@ -212,7 +212,7 @@ static inline int get_page_and_type(stru
 
 static inline int page_is_removable(struct page_info *page)
 {
-    return ((page->count_info & PGC_count_mask) == 2);
+    return ((page->count_info & PGC_count_mask) == 1);
 }
 
 #define        set_machinetophys(_mfn, _pfn) do { } while(0);

_______________________________________________
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®.