All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andres Lagar-Cavilla <andres@lagarcavilla.org>
To: xen-devel@lists.xen.org
Cc: andres@gridcentric.ca, keir.xen@gmail.com, tim@xen.org,
	adin@gridcentric.ca
Subject: [PATCH 1 of 3] x86/mm/sharing: Clean ups for relinquishing shared pages on destroy
Date: Thu, 12 Apr 2012 10:16:12 -0400	[thread overview]
Message-ID: <9cbdf6b230dc6d2d2964.1334240172@xdev.gridcentric.ca> (raw)
In-Reply-To: <patchbomb.1334240171@xdev.gridcentric.ca>

 xen/arch/x86/domain.c             |  16 ++++++++++++-
 xen/arch/x86/mm/mem_sharing.c     |  45 +++++++++++++++++++++++++++++++++++++++
 xen/arch/x86/mm/p2m.c             |   4 +++
 xen/include/asm-arm/mm.h          |   4 +++
 xen/include/asm-x86/domain.h      |   1 +
 xen/include/asm-x86/mem_sharing.h |  10 ++++++++
 xen/include/asm-x86/p2m.h         |   4 +++
 7 files changed, 82 insertions(+), 2 deletions(-)


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@lagarcavilla.org>

diff -r c74fe64aafeb -r 9cbdf6b230dc xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -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 c74fe64aafeb -r 9cbdf6b230dc xen/arch/x86/mm/mem_sharing.c
--- a/xen/arch/x86/mm/mem_sharing.c
+++ b/xen/arch/x86/mm/mem_sharing.c
@@ -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 c74fe64aafeb -r 9cbdf6b230dc xen/arch/x86/mm/p2m.c
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -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 c74fe64aafeb -r 9cbdf6b230dc xen/include/asm-arm/mm.h
--- a/xen/include/asm-arm/mm.h
+++ b/xen/include/asm-arm/mm.h
@@ -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 c74fe64aafeb -r 9cbdf6b230dc xen/include/asm-x86/domain.h
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -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 c74fe64aafeb -r 9cbdf6b230dc xen/include/asm-x86/mem_sharing.h
--- a/xen/include/asm-x86/mem_sharing.h
+++ b/xen/include/asm-x86/mem_sharing.h
@@ -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 c74fe64aafeb -r 9cbdf6b230dc xen/include/asm-x86/p2m.h
--- a/xen/include/asm-x86/p2m.h
+++ b/xen/include/asm-x86/p2m.h
@@ -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.

  reply	other threads:[~2012-04-12 14:16 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-04-12 14:16 [PATCH 0 of 3] RFC: x86 memory sharing performance improvements Andres Lagar-Cavilla
2012-04-12 14:16 ` Andres Lagar-Cavilla [this message]
2012-04-18 12:42   ` [PATCH 1 of 3] x86/mm/sharing: Clean ups for relinquishing shared pages on destroy Tim Deegan
2012-04-18 13:06     ` Andres Lagar-Cavilla
2012-04-12 14:16 ` [PATCH 2 of 3] x86/mem_sharing: modularize reverse map for shared frames Andres Lagar-Cavilla
2012-04-18 14:05   ` Tim Deegan
2012-04-18 14:19     ` Andres Lagar-Cavilla
2012-04-12 14:16 ` [PATCH 3 of 3] x86/mem_sharing: For shared pages with many references, use a hash table instead of a list Andres Lagar-Cavilla
2012-04-18 15:35   ` Tim Deegan
2012-04-18 16:18     ` Andres Lagar-Cavilla
2012-04-24 19:33       ` Andres Lagar-Cavilla

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9cbdf6b230dc6d2d2964.1334240172@xdev.gridcentric.ca \
    --to=andres@lagarcavilla.org \
    --cc=adin@gridcentric.ca \
    --cc=andres@gridcentric.ca \
    --cc=keir.xen@gmail.com \
    --cc=tim@xen.org \
    --cc=xen-devel@lists.xen.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.