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

[Xen-changelog] [xen-unstable] This patch defines a new PGT type called PGT_shared_page and a new synthetic



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1261031276 0
# Node ID 3a3be3938b2c71d179330b10fcb187db00c837b2
# Parent  9b344d919ee4c54e33d6f14c44a9fa1856aa6b7d
This patch defines a new PGT type called PGT_shared_page and a new synthetic
domain called 'dom_cow'. In order to share a page, the type needs to be changed
to PGT_shared_page and the owner to dom_dow. Only pages with PGT_none, and no
type count are allowed to become sharable. Conversly, sharable pages can only be
made 'private' if type count equals one. page_make_sharable() and
page_make_private() handle these transitions.

Signed-off-by: Grzegorz Milos <Grzegorz.Milos@xxxxxxxxxx>
---
 xen/arch/x86/mm.c        |   98 ++++++++++++++++++++++++++++++++++++++++++++++-
 xen/common/page_alloc.c  |    9 +++-
 xen/include/asm-x86/mm.h |   45 +++++++++++----------
 xen/include/public/xen.h |    4 +
 4 files changed, 134 insertions(+), 22 deletions(-)

diff -r 9b344d919ee4 -r 3a3be3938b2c xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Thu Dec 17 06:27:55 2009 +0000
+++ b/xen/arch/x86/mm.c Thu Dec 17 06:27:56 2009 +0000
@@ -138,7 +138,7 @@ int mem_hotplug = 0;
 int mem_hotplug = 0;
 
 /* Private domain structs for DOMID_XEN and DOMID_IO. */
-struct domain *dom_xen, *dom_io;
+struct domain *dom_xen, *dom_io, *dom_cow;
 
 /* Frame table size in pages. */
 unsigned long max_page;
@@ -250,6 +250,13 @@ void __init arch_init_memory(void)
      */
     dom_io = domain_create(DOMID_IO, DOMCRF_dummy, 0);
     BUG_ON(dom_io == NULL);
+    
+    /*
+     * Initialise our DOMID_IO domain.
+     * This domain owns sharable pages.
+     */
+    dom_cow = domain_create(DOMID_COW, DOMCRF_dummy, 0);
+    BUG_ON(dom_cow == NULL);
 
     /* First 1MB of RAM is historically marked as I/O. */
     for ( i = 0; i < 0x100; i++ )
@@ -3789,6 +3796,95 @@ int steal_page(
     return -1;
 }
 
+int page_make_sharable(struct domain *d, 
+                       struct page_info *page, 
+                       int expected_refcnt)
+{
+    unsigned long x, nx, y;
+
+    /* Acquire ref first, so that the page doesn't dissapear from us */
+    if(!get_page(page, d))
+        return -EINVAL;
+
+    spin_lock(&d->page_alloc_lock);
+
+    /* Change page type and count atomically */
+    y = page->u.inuse.type_info;
+    nx = PGT_shared_page | PGT_validated | 1; 
+    do {
+        x = y;
+        /* We can only change the type if count is zero, and 
+           type is PGT_none */
+        if((x & (PGT_type_mask | PGT_count_mask)) != PGT_none)
+        {
+            put_page(page);
+            spin_unlock(&d->page_alloc_lock);
+            return -EEXIST;
+        }
+        y = cmpxchg(&page->u.inuse.type_info, x, nx);
+    } while(x != y);
+
+    /* Check if the ref count is 2. The first from PGT_allocated, and the 
second
+     * from get_page at the top of this function */
+    if(page->count_info != (PGC_allocated | (2 + expected_refcnt)))
+    {
+        /* Return type count back to zero */
+        put_page_and_type(page);
+        spin_unlock(&d->page_alloc_lock);
+        return -E2BIG;
+    }
+
+    page_set_owner(page, dom_cow);
+    d->tot_pages--;
+    page_list_del(page, &d->page_list);
+    spin_unlock(&d->page_alloc_lock);
+
+    /* NOTE: We are not putting the page back. In effect this function acquires
+     * one ref and type ref for the caller */
+
+    return 0;
+}
+
+int page_make_private(struct domain *d, struct page_info *page)
+{
+    unsigned long x, y;
+
+    if(!get_page(page, dom_cow))
+        return -EINVAL;
+    
+    spin_lock(&d->page_alloc_lock);
+
+    /* Change page type and count atomically */
+    y = page->u.inuse.type_info;
+    do {
+        x = y;
+        /* We can only change the type if count is one */
+        if((x & (PGT_type_mask | PGT_count_mask)) != 
+                (PGT_shared_page | 1))
+        {
+            put_page(page);
+            spin_unlock(&d->page_alloc_lock);
+            return -EEXIST;
+        }
+        y = cmpxchg(&page->u.inuse.type_info, x, PGT_none);
+    } while(x != y);
+
+    /* We dropped type ref above, drop one ref count too */
+    put_page(page);
+
+    /* Change the owner */
+    ASSERT(page_get_owner(page) == dom_cow);
+    page_set_owner(page, d);
+
+    d->tot_pages++;
+    page_list_add_tail(page, &d->page_list);
+    spin_unlock(&d->page_alloc_lock);
+
+    put_page(page);
+
+    return 0;
+}
+
 static int __do_update_va_mapping(
     unsigned long va, u64 val64, unsigned long flags, struct domain *pg_owner)
 {
diff -r 9b344d919ee4 -r 3a3be3938b2c xen/common/page_alloc.c
--- a/xen/common/page_alloc.c   Thu Dec 17 06:27:55 2009 +0000
+++ b/xen/common/page_alloc.c   Thu Dec 17 06:27:56 2009 +0000
@@ -1145,7 +1145,7 @@ void free_domheap_pages(struct page_info
 
         spin_unlock_recursive(&d->page_alloc_lock);
     }
-    else if ( likely(d != NULL) )
+    else if ( likely(d != NULL) && likely(d != dom_cow) )
     {
         /* NB. May recursively lock from relinquish_memory(). */
         spin_lock_recursive(&d->page_alloc_lock);
@@ -1171,6 +1171,13 @@ void free_domheap_pages(struct page_info
                 scrub_one_page(&pg[i]);
 
         free_heap_pages(pg, order);
+    }
+    else if ( unlikely(d == dom_cow) )
+    {
+        ASSERT(order == 0); 
+        scrub_one_page(pg);
+        free_heap_pages(pg, 0);
+        drop_dom_ref = 0;
     }
     else
     {
diff -r 9b344d919ee4 -r 3a3be3938b2c xen/include/asm-x86/mm.h
--- a/xen/include/asm-x86/mm.h  Thu Dec 17 06:27:55 2009 +0000
+++ b/xen/include/asm-x86/mm.h  Thu Dec 17 06:27:56 2009 +0000
@@ -155,33 +155,34 @@ struct page_info
 #define PG_mask(x, idx) (x ## UL << PG_shift(idx))
 
  /* The following page types are MUTUALLY EXCLUSIVE. */
-#define PGT_none          PG_mask(0, 3) /* no special uses of this page */
-#define PGT_l1_page_table PG_mask(1, 3) /* using as an L1 page table? */
-#define PGT_l2_page_table PG_mask(2, 3) /* using as an L2 page table? */
-#define PGT_l3_page_table PG_mask(3, 3) /* using as an L3 page table? */
-#define PGT_l4_page_table PG_mask(4, 3) /* using as an L4 page table? */
-#define PGT_seg_desc_page PG_mask(5, 3) /* using this page in a GDT/LDT? */
-#define PGT_writable_page PG_mask(7, 3) /* has writable mappings? */
-#define PGT_type_mask     PG_mask(7, 3) /* Bits 29-31. */
+#define PGT_none          PG_mask(0, 4)  /* no special uses of this page   */
+#define PGT_l1_page_table PG_mask(1, 4)  /* using as an L1 page table?     */
+#define PGT_l2_page_table PG_mask(2, 4)  /* using as an L2 page table?     */
+#define PGT_l3_page_table PG_mask(3, 4)  /* using as an L3 page table?     */
+#define PGT_l4_page_table PG_mask(4, 4)  /* using as an L4 page table?     */
+#define PGT_seg_desc_page PG_mask(5, 4)  /* using this page in a GDT/LDT?  */
+#define PGT_writable_page PG_mask(7, 4)  /* has writable mappings?         */
+#define PGT_shared_page   PG_mask(8, 4)  /* CoW sharable page              */
+#define PGT_type_mask     PG_mask(15, 4) /* Bits 28-31 or 60-63.           */
 
  /* Owning guest has pinned this page to its current type? */
-#define _PGT_pinned       PG_shift(4)
-#define PGT_pinned        PG_mask(1, 4)
+#define _PGT_pinned       PG_shift(5)
+#define PGT_pinned        PG_mask(1, 5)
  /* Has this page been validated for use as its current type? */
-#define _PGT_validated    PG_shift(5)
-#define PGT_validated     PG_mask(1, 5)
+#define _PGT_validated    PG_shift(6)
+#define PGT_validated     PG_mask(1, 6)
  /* PAE only: is this an L2 page directory containing Xen-private mappings? */
-#define _PGT_pae_xen_l2   PG_shift(6)
-#define PGT_pae_xen_l2    PG_mask(1, 6)
+#define _PGT_pae_xen_l2   PG_shift(7)
+#define PGT_pae_xen_l2    PG_mask(1, 7)
 /* Has this page been *partially* validated for use as its current type? */
-#define _PGT_partial      PG_shift(7)
-#define PGT_partial       PG_mask(1, 7)
+#define _PGT_partial      PG_shift(8)
+#define PGT_partial       PG_mask(1, 8)
  /* Page is locked? */
-#define _PGT_locked       PG_shift(8)
-#define PGT_locked        PG_mask(1, 8)
+#define _PGT_locked       PG_shift(9)
+#define PGT_locked        PG_mask(1, 9)
 
  /* Count of uses of this frame as its current type. */
-#define PGT_count_width   PG_shift(8)
+#define PGT_count_width   PG_shift(9)
 #define PGT_count_mask    ((1UL<<PGT_count_width)-1)
 
  /* Cleared when the owning guest 'frees' this page. */
@@ -529,6 +530,10 @@ int steal_page(
     struct domain *d, struct page_info *page, unsigned int memflags);
 int donate_page(
     struct domain *d, struct page_info *page, unsigned int memflags);
+int page_make_sharable(struct domain *d, 
+                       struct page_info *page, 
+                       int expected_refcnt);
+int page_make_private(struct domain *d, struct page_info *page);
 
 int map_ldt_shadow_page(unsigned int);
 
@@ -551,6 +556,6 @@ unsigned int domain_clamp_alloc_bitsize(
 
 unsigned long domain_get_maximum_gpfn(struct domain *d);
 
-extern struct domain *dom_xen, *dom_io;        /* for vmcoreinfo */
+extern struct domain *dom_xen, *dom_io, *dom_cow;      /* for vmcoreinfo */
 
 #endif /* __ASM_X86_MM_H__ */
diff -r 9b344d919ee4 -r 3a3be3938b2c xen/include/public/xen.h
--- a/xen/include/public/xen.h  Thu Dec 17 06:27:55 2009 +0000
+++ b/xen/include/public/xen.h  Thu Dec 17 06:27:56 2009 +0000
@@ -366,6 +366,10 @@ typedef uint16_t domid_t;
  */
 #define DOMID_XEN  (0x7FF2U)
 
+/*
+ * DOMID_COW is used as the owner of sharable pages */
+#define DOMID_COW  (0x7FF3U)
+
 /* DOMID_INVALID is used to identity invalid domid */
 #define DOMID_INVALID (0x7FFFU)
 

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