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

[Xen-changelog] [xen-unstable] x86/mm/sharing: Clean ups for relinquishing shared pages on destroy



# HG changeset patch
# User Andres Lagar-Cavilla <andres@xxxxxxxxxxxxxxxx>
# Date 1334752727 -3600
# Node ID e1989df606e908f1ff34c2be5a1bb3b63047d6af
# Parent  b595d2f08d1bae7df7705b87cb95951877a4c3b8
x86/mm/sharing: Clean ups for relinquishing shared pages on destroy

When a domain is destroyed, its pages are freed in relinquish_resources in a
preemptible mode, in the context of a synchronous domctl.

P2m entries pointing to shared pages are, however, released during p2m cleanup
in an RCU callback, and in non-preemptible mode.

This is an O(n) operation for a very large n, which may include actually
freeing shared pages for which the domain is the last holder.

To improve responsiveness, move this operation to the preemtible portion of
domain destruction, during the synchronous domain_kill hypercall. And remove
the bulk of the work from the RCU callback.

Signed-off-by: Andres Lagar-Cavilla <andres@xxxxxxxxxxxxxxxx>
Acked-by: Tim Deegan <tim@xxxxxxx>
Committed-by: Tim Deegan <tim@xxxxxxx>
---


diff -r b595d2f08d1b -r e1989df606e9 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Wed Apr 18 13:38:47 2012 +0100
+++ b/xen/arch/x86/domain.c     Wed Apr 18 13:38:47 2012 +0100
@@ -2132,10 +2132,22 @@ int domain_relinquish_resources(struct d
             }
         }
 
-        d->arch.relmem = RELMEM_xen;
+        d->arch.relmem = RELMEM_shared;
         /* fallthrough */
 
-        /* Relinquish every page of memory. */
+    case RELMEM_shared:
+
+        if ( is_hvm_domain(d) )
+        {
+            /* If the domain has shared pages, relinquish them allowing
+             * for preemption. */
+            ret = relinquish_shared_pages(d);
+            if ( ret )
+                return ret;
+        }
+
+        d->arch.relmem = RELMEM_xen;
+        /* Fallthrough. Relinquish every page of memory. */
     case RELMEM_xen:
         ret = relinquish_memory(d, &d->xenpage_list, ~0UL);
         if ( ret )
diff -r b595d2f08d1b -r e1989df606e9 xen/arch/x86/mm/mem_sharing.c
--- a/xen/arch/x86/mm/mem_sharing.c     Wed Apr 18 13:38:47 2012 +0100
+++ b/xen/arch/x86/mm/mem_sharing.c     Wed Apr 18 13:38:47 2012 +0100
@@ -33,6 +33,7 @@
 #include <asm/mem_event.h>
 #include <asm/atomic.h>
 #include <xen/rcupdate.h>
+#include <asm/event.h>
 
 #include "mm-locks.h"
 
@@ -1034,6 +1035,50 @@ private_page_found:
     return 0;
 }
 
+int relinquish_shared_pages(struct domain *d)
+{
+    int rc = 0;
+    struct p2m_domain *p2m = p2m_get_hostp2m(d);
+    unsigned long gfn, count = 0;
+
+    if ( p2m == NULL )
+        return 0;
+
+    p2m_lock(p2m);
+    for (gfn = p2m->next_shared_gfn_to_relinquish; 
+         gfn < p2m->max_mapped_pfn; gfn++ )
+    {
+        p2m_access_t a;
+        p2m_type_t t;
+        mfn_t mfn;
+        if ( atomic_read(&d->shr_pages) == 0 )
+            break;
+        mfn = p2m->get_entry(p2m, gfn, &t, &a, 0, NULL);
+        if ( mfn_valid(mfn) && (t == p2m_ram_shared) )
+        {
+            /* Does not fail with ENOMEM given the DESTROY flag */
+            BUG_ON(__mem_sharing_unshare_page(d, gfn, 
+                    MEM_SHARING_DESTROY_GFN));
+            /* Clear out the p2m entry so no one else may try to 
+             * unshare */
+            p2m->set_entry(p2m, gfn, _mfn(0), PAGE_ORDER_4K,
+                            p2m_invalid, p2m_access_rwx);
+            count++;
+        }
+
+        /* Preempt every 2MiB. Arbitrary */
+        if ( (count == 512) && hypercall_preempt_check() )
+        {
+            p2m->next_shared_gfn_to_relinquish = gfn + 1;
+            rc = -EAGAIN;
+            break;
+        }
+    }
+
+    p2m_unlock(p2m);
+    return rc;
+}
+
 int mem_sharing_memop(struct domain *d, xen_mem_sharing_op_t *mec)
 {
     int rc = 0;
diff -r b595d2f08d1b -r e1989df606e9 xen/arch/x86/mm/p2m.c
--- a/xen/arch/x86/mm/p2m.c     Wed Apr 18 13:38:47 2012 +0100
+++ b/xen/arch/x86/mm/p2m.c     Wed Apr 18 13:38:47 2012 +0100
@@ -371,9 +371,13 @@ void p2m_teardown(struct p2m_domain *p2m
     p2m_lock(p2m);
 
 #ifdef __x86_64__
+    /* Try to unshare any remaining shared p2m entries. Safeguard
+     * Since relinquish_shared_pages should have done the work. */ 
     for ( gfn=0; gfn < p2m->max_mapped_pfn; gfn++ )
     {
         p2m_access_t a;
+        if ( atomic_read(&d->shr_pages) == 0 )
+            break;
         mfn = p2m->get_entry(p2m, gfn, &t, &a, 0, NULL);
         if ( mfn_valid(mfn) && (t == p2m_ram_shared) )
         {
diff -r b595d2f08d1b -r e1989df606e9 xen/include/asm-arm/mm.h
--- a/xen/include/asm-arm/mm.h  Wed Apr 18 13:38:47 2012 +0100
+++ b/xen/include/asm-arm/mm.h  Wed Apr 18 13:38:47 2012 +0100
@@ -251,6 +251,10 @@ int  get_page(struct page_info *page, st
 
 static inline void put_gfn(struct domain *d, unsigned long gfn) {}
 static inline void mem_event_cleanup(struct domain *d) {}
+static inline int relinquish_shared_pages(struct domain *d)
+{
+    return 0;
+}
 
 #define INVALID_MFN             (~0UL)
 
diff -r b595d2f08d1b -r e1989df606e9 xen/include/asm-x86/domain.h
--- a/xen/include/asm-x86/domain.h      Wed Apr 18 13:38:47 2012 +0100
+++ b/xen/include/asm-x86/domain.h      Wed Apr 18 13:38:47 2012 +0100
@@ -296,6 +296,7 @@ struct arch_domain
     /* Continuable domain_relinquish_resources(). */
     enum {
         RELMEM_not_started,
+        RELMEM_shared,
         RELMEM_xen,
         RELMEM_l4,
         RELMEM_l3,
diff -r b595d2f08d1b -r e1989df606e9 xen/include/asm-x86/mem_sharing.h
--- a/xen/include/asm-x86/mem_sharing.h Wed Apr 18 13:38:47 2012 +0100
+++ b/xen/include/asm-x86/mem_sharing.h Wed Apr 18 13:38:47 2012 +0100
@@ -89,9 +89,19 @@ int mem_sharing_domctl(struct domain *d,
 int mem_sharing_audit(void);
 void mem_sharing_init(void);
 
+/* Scans the p2m and relinquishes any shared pages, destroying 
+ * those for which this domain holds the final reference.
+ * Preemptible.
+ */
+int relinquish_shared_pages(struct domain *d);
+
 #else 
 
 #define mem_sharing_init()  do { } while (0)
+static inline int relinquish_shared_pages(struct domain *d)
+{
+    return 0;
+}
 
 #endif /* __x86_64__ */
 
diff -r b595d2f08d1b -r e1989df606e9 xen/include/asm-x86/p2m.h
--- a/xen/include/asm-x86/p2m.h Wed Apr 18 13:38:47 2012 +0100
+++ b/xen/include/asm-x86/p2m.h Wed Apr 18 13:38:47 2012 +0100
@@ -260,6 +260,10 @@ struct p2m_domain {
     /* Highest guest frame that's ever been mapped in the p2m */
     unsigned long max_mapped_pfn;
 
+    /* When releasing shared gfn's in a preemptible manner, recall where
+     * to resume the search */
+    unsigned long next_shared_gfn_to_relinquish;
+
     /* Populate-on-demand variables
      * All variables are protected with the pod lock. We cannot rely on
      * the p2m lock if it's turned into a fine-grained lock.

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
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®.