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

[Xen-changelog] [xen-unstable] Domctls defined for all relevant memory sharing operations.



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1261031276 0
# Node ID 68e964ec2c7bdb3b4f8997b3c027cedfaa2c7bb2
# Parent  8cf5bffd9663fc541be4d4a1b63630787739fd0d
Domctls defined for all relevant memory sharing operations.

Signed-off-by: Grzegorz Milos <Grzegorz.Milos@xxxxxxxxxx>
---
 xen/arch/x86/domain.c             |    1 
 xen/arch/x86/domctl.c             |   16 ++
 xen/arch/x86/mm.c                 |    3 
 xen/arch/x86/mm/mem_sharing.c     |  223 ++++++++++++++++++++++++++++++++++----
 xen/common/domctl.c               |    1 
 xen/include/asm-x86/hvm/domain.h  |    1 
 xen/include/asm-x86/mem_sharing.h |    3 
 xen/include/public/domctl.h       |   49 ++++++++
 xen/include/public/memory.h       |    7 +
 xen/include/xen/sched.h           |    1 
 10 files changed, 283 insertions(+), 22 deletions(-)

diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Thu Dec 17 06:27:56 2009 +0000
+++ b/xen/arch/x86/domain.c     Thu Dec 17 06:27:56 2009 +0000
@@ -404,6 +404,7 @@ int arch_domain_create(struct domain *d,
         is_hvm_domain(d) &&
         hvm_funcs.hap_supported &&
         (domcr_flags & DOMCRF_hap);
+    d->arch.hvm_domain.mem_sharing_enabled = 0;
 
     d->arch.s3_integrity = !!(domcr_flags & DOMCRF_s3_integrity);
 
diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/arch/x86/domctl.c
--- a/xen/arch/x86/domctl.c     Thu Dec 17 06:27:56 2009 +0000
+++ b/xen/arch/x86/domctl.c     Thu Dec 17 06:27:56 2009 +0000
@@ -32,6 +32,7 @@
 #include <xen/iommu.h>
 #include <asm/mem_event.h>
 #include <public/mem_event.h>
+#include <asm/mem_sharing.h>
 
 #ifdef XEN_GDBSX_CONFIG                    
 #ifdef XEN_KDB_CONFIG
@@ -1317,6 +1318,21 @@ long arch_do_domctl(
     }
     break;
 
+    case XEN_DOMCTL_mem_sharing_op:
+    {
+        struct domain *d;
+
+        ret = -ESRCH;
+        d = rcu_lock_domain_by_id(domctl->domain);
+        if ( d != NULL )
+        {
+            ret = mem_sharing_domctl(d, &domctl->u.mem_sharing_op);
+            rcu_unlock_domain(d);
+            copy_to_guest(u_domctl, domctl, 1);
+        } 
+    }
+    break;
+
     default:
         ret = -ENOSYS;
         break;
diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Thu Dec 17 06:27:56 2009 +0000
+++ b/xen/arch/x86/mm.c Thu Dec 17 06:27:56 2009 +0000
@@ -4503,6 +4503,9 @@ long arch_memory_op(int op, XEN_GUEST_HA
         return rc;
     }
 
+    case XENMEM_get_sharing_freed_pages:
+        return mem_sharing_get_nr_saved_mfns();
+
     default:
         return subarch_memory_op(op, arg);
     }
diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/arch/x86/mm/mem_sharing.c
--- a/xen/arch/x86/mm/mem_sharing.c     Thu Dec 17 06:27:56 2009 +0000
+++ b/xen/arch/x86/mm/mem_sharing.c     Thu Dec 17 06:27:56 2009 +0000
@@ -24,11 +24,18 @@
 #include <asm/string.h>
 #include <asm/p2m.h>
 #include <asm/mem_event.h>
+#include <asm/atomic.h>
 #include <xen/domain_page.h>
 #include <xen/types.h>
 #include <xen/spinlock.h>
 #include <xen/mm.h>
 #include <xen/sched.h>
+
+
+#define hap_enabled(d) \
+    (is_hvm_domain(d) && (d)->arch.hvm_domain.hap_enabled)
+#define mem_sharing_enabled(d) \
+    (is_hvm_domain(d) && (d)->arch.hvm_domain.mem_sharing_enabled)
  
 #undef mfn_to_page
 #define mfn_to_page(_m) __mfn_to_page(mfn_x(_m))
@@ -38,6 +45,7 @@
 #define page_to_mfn(_pg) _mfn(__page_to_mfn(_pg))
 
 static shr_handle_t next_handle = 1;
+static atomic_t nr_saved_mfns = ATOMIC_INIT(0); 
 
 typedef struct shr_hash_entry 
 {
@@ -64,6 +72,17 @@ typedef struct shr_lock
     const char *locker_function; /* func that took it */
 } shr_lock_t;
 static shr_lock_t shr_lock;
+
+/* Returns true if list has only one entry. O(1) complexity. */
+static inline int list_has_one_entry(struct list_head *head)
+{
+    return (head->next != head) && (head->next->next == head);
+}
+
+static inline struct gfn_info* gfn_get_info(struct list_head *list)
+{
+    return list_entry(list->next, struct gfn_info, list);
+}
 
 #define shr_lock_init(_i)                      \
     do {                                       \
@@ -97,8 +116,6 @@ static shr_lock_t shr_lock;
         spin_unlock(&shr_lock.lock);                      \
     } while (0)
 
-
-
 static void mem_sharing_hash_init(void)
 {
     int i;
@@ -123,9 +140,21 @@ static gfn_info_t *mem_sharing_gfn_alloc
     return xmalloc(gfn_info_t); 
 }
 
-static void mem_sharing_gfn_destroy(gfn_info_t *gfn_info)
-{
-    xfree(gfn_info);
+static void mem_sharing_gfn_destroy(gfn_info_t *gfn, int was_shared)
+{
+    /* Decrement the number of pages, if the gfn was shared before */
+    if(was_shared)
+    {
+        struct domain *d = get_domain_by_id(gfn->domain);
+        /* Domain may have been destroyed by now, if we are called from
+         * p2m_teardown */
+        if(d)
+        {
+            atomic_dec(&d->shr_pages);
+            put_domain(d);
+        }
+    }
+    xfree(gfn);
 }
 
 static shr_hash_entry_t* mem_sharing_hash_lookup(shr_handle_t handle)
@@ -219,6 +248,11 @@ static struct page_info* mem_sharing_all
     return page;
 }
 
+unsigned int mem_sharing_get_nr_saved_mfns(void)
+{
+    return (unsigned int)atomic_read(&nr_saved_mfns);
+}
+
 int mem_sharing_sharing_resume(struct domain *d)
 {
     mem_event_response_t rsp;
@@ -290,6 +324,61 @@ shared_entry_header(struct grant_table *
         return &shared_entry_v2(t, ref).hdr;
 }
 
+static int mem_sharing_gref_to_gfn(struct domain *d, 
+                                   grant_ref_t ref, 
+                                   unsigned long *gfn)
+{
+    if(d->grant_table->gt_version < 1)
+        return -1;
+
+    if (d->grant_table->gt_version == 1) 
+    {
+        grant_entry_v1_t *sha1;
+        sha1 = &shared_entry_v1(d->grant_table, ref);
+        *gfn = sha1->frame;
+        return 0;
+    } 
+    else 
+    {
+        grant_entry_v2_t *sha2;
+        sha2 = &shared_entry_v2(d->grant_table, ref);
+        *gfn = sha2->full_page.frame;
+        return 0;
+    }
+ 
+    return -2;
+}
+
+/* Account for a GFN being shared/unshared.
+ * When sharing this function needs to be called _before_ gfn lists are merged
+ * together, but _after_ gfn is removed from the list when unsharing.
+ */
+static int mem_sharing_gfn_account(struct gfn_info *gfn, int sharing)
+{
+    struct domain *d;
+
+    /* A) When sharing:
+     * if the gfn being shared is in > 1 long list, its already been 
+     * accounted for
+     * B) When unsharing:
+     * if the list is longer than > 1, we don't have to account yet. 
+     */
+    if(list_has_one_entry(&gfn->list))
+    {
+        d = get_domain_by_id(gfn->domain);
+        BUG_ON(!d);
+        if(sharing) 
+            atomic_inc(&d->shr_pages);
+        else
+            atomic_dec(&d->shr_pages);
+        put_domain(d);
+
+        return 1;
+    }
+
+    return 0;
+}
+
 int mem_sharing_debug_gref(struct domain *d, grant_ref_t ref)
 {
     grant_entry_header_t *shah;
@@ -302,21 +391,12 @@ int mem_sharing_debug_gref(struct domain
                 d->domain_id, ref);
         return -1;
     }
+    mem_sharing_gref_to_gfn(d, ref, &gfn); 
     shah = shared_entry_header(d->grant_table, ref);
     if (d->grant_table->gt_version == 1) 
-    {
-        grant_entry_v1_t *sha1;
-        sha1 = &shared_entry_v1(d->grant_table, ref);
         status = shah->flags;
-        gfn = sha1->frame;
-    } 
     else 
-    {
-        grant_entry_v2_t *sha2;
-        sha2 = &shared_entry_v2(d->grant_table, ref);
         status = status_entry(d->grant_table, ref);
-        gfn = sha2->full_page.frame;
-    }
     
     printk("==> Grant [dom=%d,ref=%d], status=%x. ", 
             d->domain_id, ref, status);
@@ -381,7 +461,7 @@ int mem_sharing_nominate_page(struct dom
          * since no-one knew that the mfn was temporarily sharable */
         ASSERT(page_make_private(d, page) == 0);
         mem_sharing_hash_destroy(hash_entry);
-        mem_sharing_gfn_destroy(gfn_info);
+        mem_sharing_gfn_destroy(gfn_info, 0);
         shr_unlock();
         goto out;
     }
@@ -415,14 +495,17 @@ int mem_sharing_share_pages(shr_handle_t
 
     shr_lock();
 
-    ret = -1;
+    ret = XEN_DOMCTL_MEM_SHARING_S_HANDLE_INVALID;
     se = mem_sharing_hash_lookup(sh);
     if(se == NULL) goto err_out;
-    ret = -2;
+    ret = XEN_DOMCTL_MEM_SHARING_C_HANDLE_INVALID;
     ce = mem_sharing_hash_lookup(ch);
     if(ce == NULL) goto err_out;
     spage = mfn_to_page(se->mfn); 
     cpage = mfn_to_page(ce->mfn); 
+    /* gfn lists always have at least one entry => save to call list_entry */
+    mem_sharing_gfn_account(gfn_get_info(&ce->gfns), 1);
+    mem_sharing_gfn_account(gfn_get_info(&se->gfns), 1);
     list_for_each_safe(le, te, &ce->gfns)
     {
         gfn = list_entry(le, struct gfn_info, list);
@@ -440,6 +523,7 @@ int mem_sharing_share_pages(shr_handle_t
     } 
     ASSERT(list_empty(&ce->gfns));
     mem_sharing_hash_delete(ch);
+    atomic_inc(&nr_saved_mfns);
     /* Free the client page */
     if(test_and_clear_bit(_PGC_allocated, &cpage->count_info))
         put_page(cpage);
@@ -491,8 +575,13 @@ gfn_found:
      * (possibly freeing the page), and exit early */
     if(flags & MEM_SHARING_DESTROY_GFN)
     {
-        mem_sharing_gfn_destroy(gfn_info);
-        if(last_gfn) mem_sharing_hash_delete(handle);
+        mem_sharing_gfn_destroy(gfn_info, !last_gfn);
+        if(last_gfn) 
+            mem_sharing_hash_delete(handle);
+        else 
+            /* Even though we don't allocate a private page, we have to account
+             * for the MFN that originally backed this PFN. */
+            atomic_dec(&nr_saved_mfns);
         shr_unlock();
         put_page_and_type(page);
         if(last_gfn && 
@@ -528,8 +617,11 @@ gfn_found:
 
 private_page_found:    
     /* We've got a private page, we can commit the gfn destruction */
-    mem_sharing_gfn_destroy(gfn_info);
-    if(last_gfn) mem_sharing_hash_delete(handle);
+    mem_sharing_gfn_destroy(gfn_info, !last_gfn);
+    if(last_gfn) 
+        mem_sharing_hash_delete(handle);
+    else
+        atomic_dec(&nr_saved_mfns);
     shr_unlock();
 
     if(p2m_change_type(d, gfn, p2m_ram_shared, p2m_ram_rw) != 
@@ -544,6 +636,93 @@ private_page_found:
     return 0;
 }
 
+int mem_sharing_domctl(struct domain *d, xen_domctl_mem_sharing_op_t *mec)
+{
+    int rc;
+
+    switch(mec->op)
+    {
+        case XEN_DOMCTL_MEM_SHARING_OP_CONTROL:
+        {
+            rc = 0;
+            if(!hap_enabled(d))
+                return -EINVAL;
+            d->arch.hvm_domain.mem_sharing_enabled = mec->enable;
+            return 0; 
+        }
+        break;
+
+        case XEN_DOMCTL_MEM_SHARING_OP_NOMINATE_GFN:
+        {
+            unsigned long gfn = mec->nominate.gfn;
+            shr_handle_t handle;
+            if(!mem_sharing_enabled(d))
+                return -EINVAL;
+            rc = mem_sharing_nominate_page(d, gfn, 0, &handle);
+            mec->nominate.handle = handle;
+        }
+        break;
+
+        case XEN_DOMCTL_MEM_SHARING_OP_NOMINATE_GREF:
+        {
+            grant_ref_t gref = mec->nominate.grant_ref;
+            unsigned long gfn;
+            shr_handle_t handle;
+
+            if(!mem_sharing_enabled(d))
+                return -EINVAL;
+            if(mem_sharing_gref_to_gfn(d, gref, &gfn) < 0)
+                return -EINVAL;
+            rc = mem_sharing_nominate_page(d, gfn, 3, &handle);
+            mec->nominate.handle = handle;
+        }
+        break;
+
+        case XEN_DOMCTL_MEM_SHARING_OP_SHARE:
+        {
+            shr_handle_t sh = mec->share.source_handle;
+            shr_handle_t ch = mec->share.client_handle;
+            rc = mem_sharing_share_pages(sh, ch); 
+        }
+        break;
+
+        case XEN_DOMCTL_MEM_SHARING_OP_RESUME:
+        {
+            if(!mem_sharing_enabled(d))
+                return -EINVAL;
+            rc = mem_sharing_sharing_resume(d);
+        }
+        break;
+
+        case XEN_DOMCTL_MEM_SHARING_OP_DEBUG_GFN:
+        {
+            unsigned long gfn = mec->debug.gfn;
+            rc = mem_sharing_debug_gfn(d, gfn);
+        }
+        break;
+
+        case XEN_DOMCTL_MEM_SHARING_OP_DEBUG_MFN:
+        {
+            unsigned long mfn = mec->debug.mfn;
+            rc = mem_sharing_debug_mfn(mfn);
+        }
+        break;
+
+        case XEN_DOMCTL_MEM_SHARING_OP_DEBUG_GREF:
+        {
+            grant_ref_t gref = mec->debug.gref;
+            rc = mem_sharing_debug_gref(d, gref);
+        }
+        break;
+
+        default:
+            rc = -ENOSYS;
+            break;
+    }
+
+    return rc;
+}
+
 void mem_sharing_init(void)
 {
     printk("Initing memory sharing.\n");
diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/common/domctl.c
--- a/xen/common/domctl.c       Thu Dec 17 06:27:56 2009 +0000
+++ b/xen/common/domctl.c       Thu Dec 17 06:27:56 2009 +0000
@@ -136,6 +136,7 @@ void getdomaininfo(struct domain *d, str
 
     info->tot_pages         = d->tot_pages;
     info->max_pages         = d->max_pages;
+    info->shr_pages         = atomic_read(&d->shr_pages);
     info->shared_info_frame = mfn_to_gmfn(d, __pa(d->shared_info)>>PAGE_SHIFT);
     BUG_ON(SHARED_M2P(info->shared_info_frame));
 
diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/include/asm-x86/hvm/domain.h
--- a/xen/include/asm-x86/hvm/domain.h  Thu Dec 17 06:27:56 2009 +0000
+++ b/xen/include/asm-x86/hvm/domain.h  Thu Dec 17 06:27:56 2009 +0000
@@ -90,6 +90,7 @@ struct hvm_domain {
     struct viridian_domain viridian;
 
     bool_t                 hap_enabled;
+    bool_t                 mem_sharing_enabled;
     bool_t                 qemu_mapcache_invalidate;
     bool_t                 is_s3_suspended;
 
diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/include/asm-x86/mem_sharing.h
--- a/xen/include/asm-x86/mem_sharing.h Thu Dec 17 06:27:56 2009 +0000
+++ b/xen/include/asm-x86/mem_sharing.h Thu Dec 17 06:27:56 2009 +0000
@@ -27,6 +27,7 @@
 
 typedef uint64_t shr_handle_t; 
 
+unsigned int mem_sharing_get_nr_saved_mfns(void);
 int mem_sharing_nominate_page(struct domain *d, 
                               unsigned long gfn,
                               int expected_refcnt,
@@ -38,6 +39,8 @@ int mem_sharing_unshare_page(struct doma
                              uint16_t flags);
 int mem_sharing_sharing_resume(struct domain *d);
 int mem_sharing_cache_resize(struct domain *d, int new_size);
+int mem_sharing_domctl(struct domain *d, 
+                       xen_domctl_mem_sharing_op_t *mec);
 void mem_sharing_init(void);
 
 #endif /* __MEM_SHARING_H__ */
diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/include/public/domctl.h
--- a/xen/include/public/domctl.h       Thu Dec 17 06:27:56 2009 +0000
+++ b/xen/include/public/domctl.h       Thu Dec 17 06:27:56 2009 +0000
@@ -33,6 +33,7 @@
 #endif
 
 #include "xen.h"
+#include "grant_table.h"
 
 #define XEN_DOMCTL_INTERFACE_VERSION 0x00000005
 
@@ -103,6 +104,7 @@ struct xen_domctl_getdomaininfo {
     uint32_t flags;              /* XEN_DOMINF_* */
     uint64_aligned_t tot_pages;
     uint64_aligned_t max_pages;
+    uint64_aligned_t shr_pages;
     uint64_aligned_t shared_info_frame; /* GMFN of shared_info struct */
     uint64_aligned_t cpu_time;
     uint32_t nr_online_vcpus;    /* Number of VCPUs currently online. */
@@ -726,6 +728,52 @@ struct xen_domctl_mem_event_op {
 };
 typedef struct xen_domctl_mem_event_op xen_domctl_mem_event_op_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_mem_event_op_t);
+
+/*
+ * Memory sharing operations
+ */
+#define XEN_DOMCTL_mem_sharing_op  58
+
+#define XEN_DOMCTL_MEM_SHARING_OP_CONTROL        0
+#define XEN_DOMCTL_MEM_SHARING_OP_NOMINATE_GFN   1
+#define XEN_DOMCTL_MEM_SHARING_OP_NOMINATE_GREF  2
+#define XEN_DOMCTL_MEM_SHARING_OP_SHARE          3
+#define XEN_DOMCTL_MEM_SHARING_OP_RESUME         4
+#define XEN_DOMCTL_MEM_SHARING_OP_DEBUG_GFN      5
+#define XEN_DOMCTL_MEM_SHARING_OP_DEBUG_MFN      6
+#define XEN_DOMCTL_MEM_SHARING_OP_DEBUG_GREF     7
+
+#define XEN_DOMCTL_MEM_SHARING_S_HANDLE_INVALID  (-10)
+#define XEN_DOMCTL_MEM_SHARING_C_HANDLE_INVALID  (-9)
+
+struct xen_domctl_mem_sharing_op {
+    uint8_t       op;            /* XEN_DOMCTL_MEM_EVENT_OP_* */
+
+    union {
+        int enable;                       /* for OP_CONTROL            */
+
+        struct mem_sharing_op_nominate {  /* for OP_NOMINATE           */
+            union {
+                unsigned long gfn;        /* IN: gfn to nominate       */
+                uint32_t      grant_ref;  /* IN: grant ref to nominate */
+            };
+            uint64_t       handle;        /* OUT: the handle           */
+        } nominate;
+        struct mem_sharing_op_share {
+            uint64_t source_handle;       /* IN: handle to the source page */
+            uint64_t client_handle;       /* IN: handle to the client page */
+        } share; 
+        struct mem_sharing_op_debug {
+            union {
+                unsigned long  gfn;        /* IN: gfn to debug          */
+                unsigned long  mfn;        /* IN: mfn to debug          */
+                grant_ref_t    gref;       /* IN: gref to debug         */
+            };
+        } debug;
+    };
+};
+typedef struct xen_domctl_mem_sharing_op xen_domctl_mem_sharing_op_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_mem_sharing_op_t);
 
 
 struct xen_domctl {
@@ -772,6 +820,7 @@ struct xen_domctl {
         struct xen_domctl_subscribe         subscribe;
         struct xen_domctl_debug_op          debug_op;
         struct xen_domctl_mem_event_op      mem_event_op;
+        struct xen_domctl_mem_sharing_op    mem_sharing_op;
 #if defined(__i386__) || defined(__x86_64__)
         struct xen_domctl_cpuid             cpuid;
 #endif
diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/include/public/memory.h
--- a/xen/include/public/memory.h       Thu Dec 17 06:27:56 2009 +0000
+++ b/xen/include/public/memory.h       Thu Dec 17 06:27:56 2009 +0000
@@ -281,6 +281,13 @@ struct xen_pod_target {
     domid_t domid;
 };
 typedef struct xen_pod_target xen_pod_target_t;
+
+/*
+ * Get the number of MFNs saved through memory sharing.
+ * The call never fails. 
+ */
+#define XENMEM_get_sharing_freed_pages    18
+
 #endif /* __XEN_PUBLIC_MEMORY_H__ */
 
 /*
diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/include/xen/sched.h
--- a/xen/include/xen/sched.h   Thu Dec 17 06:27:56 2009 +0000
+++ b/xen/include/xen/sched.h   Thu Dec 17 06:27:56 2009 +0000
@@ -201,6 +201,7 @@ struct domain
     struct page_list_head xenpage_list; /* linked list (size xenheap_pages) */
     unsigned int     tot_pages;       /* number of pages currently possesed */
     unsigned int     max_pages;       /* maximum value for tot_pages        */
+    atomic_t         shr_pages;       /* number of shared pages             */
     unsigned int     xenheap_pages;   /* # pages allocated from Xen heap    */
 
     unsigned int     max_vcpus;

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