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

[Xen-changelog] [xen-unstable] x86/mm: make log-dirty code do all its allocations outside the lock



# HG changeset patch
# User Tim Deegan <Tim.Deegan@xxxxxxxxxx>
# Date 1297337272 0
# Node ID 21df67ee70406aa5a0dd452322de5601696efcda
# Parent  0df1b42910b10055721d37a88233e5f140169197
x86/mm: make log-dirty code do all its allocations outside the lock
to avoid taking the shadow/EPT lock with the lgd lock held.

Signed-off-by: Tim Deegan <Tim.Deegan@xxxxxxxxxx>
---
 xen/arch/x86/mm/paging.c |  105 +++++++++++++++++++++++++++++++----------------
 1 files changed, 71 insertions(+), 34 deletions(-)

diff -r 0df1b42910b1 -r 21df67ee7040 xen/arch/x86/mm/paging.c
--- a/xen/arch/x86/mm/paging.c  Thu Feb 10 11:27:51 2011 +0000
+++ b/xen/arch/x86/mm/paging.c  Thu Feb 10 11:27:52 2011 +0000
@@ -95,7 +95,7 @@
         spin_unlock(&(_d)->arch.paging.log_dirty.lock);                   \
     } while (0)
 
-static mfn_t paging_new_log_dirty_page(struct domain *d, void **mapping_p)
+static mfn_t paging_new_log_dirty_page(struct domain *d)
 {
     struct page_info *page;
 
@@ -103,33 +103,38 @@ static mfn_t paging_new_log_dirty_page(s
     if ( unlikely(page == NULL) )
     {
         d->arch.paging.log_dirty.failed_allocs++;
-        *mapping_p = NULL;
         return _mfn(INVALID_MFN);
     }
 
     d->arch.paging.log_dirty.allocs++;
-    *mapping_p = __map_domain_page(page);
 
     return page_to_mfn(page);
 }
 
-static mfn_t paging_new_log_dirty_leaf(
-    struct domain *d, unsigned long **leaf_p)
-{
-    mfn_t mfn = paging_new_log_dirty_page(d, (void **)leaf_p);
+/* Init a new leaf node; returns a mapping or NULL */
+static unsigned long *paging_new_log_dirty_leaf(mfn_t mfn)
+{
+    unsigned long *leaf = NULL;
     if ( mfn_valid(mfn) )
-        clear_page(*leaf_p);
-    return mfn;
-}
-
-static mfn_t paging_new_log_dirty_node(struct domain *d, mfn_t **node_p)
+    {
+        leaf = map_domain_page(mfn_x(mfn));
+        clear_page(leaf);
+    }
+    return leaf;
+}
+
+/* Init a new non-leaf node; returns a mapping or NULL */
+static mfn_t *paging_new_log_dirty_node(mfn_t mfn)
 {
     int i;
-    mfn_t mfn = paging_new_log_dirty_page(d, (void **)node_p);
+    mfn_t *node = NULL;
     if ( mfn_valid(mfn) )
+    {
+        node = map_domain_page(mfn_x(mfn));
         for ( i = 0; i < LOGDIRTY_NODE_ENTRIES; i++ )
-            (*node_p)[i] = _mfn(INVALID_MFN);
-    return mfn;
+            node[i] = _mfn(INVALID_MFN);
+    }
+    return node;
 }
 
 /* get the top of the log-dirty bitmap trie */
@@ -224,7 +229,7 @@ void paging_mark_dirty(struct domain *d,
 void paging_mark_dirty(struct domain *d, unsigned long guest_mfn)
 {
     unsigned long pfn;
-    mfn_t gmfn;
+    mfn_t gmfn, new_mfn;
     int changed;
     mfn_t mfn, *l4, *l3, *l2;
     unsigned long *l1;
@@ -235,8 +240,6 @@ void paging_mark_dirty(struct domain *d,
     if ( !paging_mode_log_dirty(d) || !mfn_valid(gmfn) ||
          page_get_owner(mfn_to_page(gmfn)) != d )
         return;
-
-    log_dirty_lock(d);
 
     /* We /really/ mean PFN here, even for non-translated guests. */
     pfn = get_gpfn_from_mfn(mfn_x(gmfn));
@@ -249,46 +252,70 @@ void paging_mark_dirty(struct domain *d,
      * Nothing to do here...
      */
     if ( unlikely(!VALID_M2P(pfn)) )
-        goto out;
+        return;
 
     i1 = L1_LOGDIRTY_IDX(pfn);
     i2 = L2_LOGDIRTY_IDX(pfn);
     i3 = L3_LOGDIRTY_IDX(pfn);
     i4 = L4_LOGDIRTY_IDX(pfn);
 
+    /* We can't call paging.alloc_page() with the log-dirty lock held
+     * and we almost never need to call it anyway, so assume that we
+     * won't.  If we do hit a missing page, we'll unlock, allocate one
+     * and start again. */
+    new_mfn = _mfn(INVALID_MFN);
+
+again:
+    log_dirty_lock(d);
+
     l4 = paging_map_log_dirty_bitmap(d);
     if ( unlikely(!l4) )
     {
-        d->arch.paging.log_dirty.top = paging_new_log_dirty_node(d, &l4);
-        if ( !l4 )
-            goto out;
-    }
+        l4 = paging_new_log_dirty_node(new_mfn);
+        d->arch.paging.log_dirty.top = new_mfn;
+        new_mfn = _mfn(INVALID_MFN);
+    }
+    if ( unlikely(!l4) )
+        goto oom;
+
     mfn = l4[i4];
     if ( !mfn_valid(mfn) )
-        mfn = l4[i4] = paging_new_log_dirty_node(d, &l3);
+    {
+        l3 = paging_new_log_dirty_node(new_mfn);
+        mfn = l4[i4] = new_mfn;
+        new_mfn = _mfn(INVALID_MFN);
+    }
     else
         l3 = map_domain_page(mfn_x(mfn));
     unmap_domain_page(l4);
-    if ( unlikely(!mfn_valid(mfn)) )
-        goto out;
+    if ( unlikely(!l3) )
+        goto oom;
 
     mfn = l3[i3];
     if ( !mfn_valid(mfn) )
-        mfn = l3[i3] = paging_new_log_dirty_node(d, &l2);
+    {
+        l2 = paging_new_log_dirty_node(new_mfn);
+        mfn = l3[i3] = new_mfn;
+        new_mfn = _mfn(INVALID_MFN);
+    }
     else
         l2 = map_domain_page(mfn_x(mfn));
     unmap_domain_page(l3);
-    if ( unlikely(!mfn_valid(mfn)) )
-        goto out;
+    if ( unlikely(!l2) )
+        goto oom;
 
     mfn = l2[i2];
     if ( !mfn_valid(mfn) )
-        mfn = l2[i2] = paging_new_log_dirty_leaf(d, &l1);
+    {
+        l1 = paging_new_log_dirty_leaf(new_mfn);
+        mfn = l2[i2] = new_mfn;
+        new_mfn = _mfn(INVALID_MFN);
+    }
     else
         l1 = map_domain_page(mfn_x(mfn));
     unmap_domain_page(l2);
-    if ( unlikely(!mfn_valid(mfn)) )
-        goto out;
+    if ( unlikely(!l1) )
+        goto oom;
 
     changed = !__test_and_set_bit(i1, l1);
     unmap_domain_page(l1);
@@ -300,8 +327,18 @@ void paging_mark_dirty(struct domain *d,
         d->arch.paging.log_dirty.dirty_count++;
     }
 
- out:
-    log_dirty_unlock(d);
+    log_dirty_unlock(d);
+    if ( mfn_valid(new_mfn) )
+        paging_free_log_dirty_page(d, mfn);
+    return;
+
+oom:
+    log_dirty_unlock(d);
+    new_mfn = paging_new_log_dirty_page(d);
+    if ( !mfn_valid(new_mfn) )
+        /* we've already recorded the failed allocation */
+        return;
+    goto again;
 }
 
 

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