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

[Xen-devel] [PATCH 4/4] xen: enable EPT dirty bit for guest live migration



When p2m type is p2m_ram_logdirty, page should be read/write/execute(d) with EPT
dirty bit support.

When guest live migration with EPT dirty bit support, it does not trigger EPT
violation any longer, we flush dirty bitmap in ept_change_entry_type_page()
function, by walking the EPT page table.

Signed-off-by: Haitao Shan<haitao.shan@xxxxxxxxx>
Signed-off-by: Xudong Hao <xudong.hao@xxxxxxxxx>
---
 xen/arch/x86/mm/p2m-ept.c |   50 ++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c
index f373905..e07004d 100644
--- a/xen/arch/x86/mm/p2m-ept.c
+++ b/xen/arch/x86/mm/p2m-ept.c
@@ -24,6 +24,7 @@
 #include <asm/types.h>
 #include <asm/domain.h>
 #include <asm/p2m.h>
+#include <asm/hap.h>
 #include <asm/hvm/vmx/vmx.h>
 #include <asm/hvm/vmx/vmcs.h>
 #include <xen/iommu.h>
@@ -69,6 +70,11 @@ static void ept_p2m_type_to_flags(ept_entry_t *entry, 
p2m_type_t type, p2m_acces
                                                     entry->mfn);
             break;
         case p2m_ram_logdirty:
+            entry->w = hap_has_dirty_bit;
+            entry->r = entry->x = 1;
+            /* Not necessarily need to clear A bit, but it is safe anyway */
+            entry->a = entry->d = 0;
+            break;
         case p2m_ram_ro:
         case p2m_ram_shared:
             entry->r = entry->x = 1;
@@ -373,6 +379,9 @@ ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, 
mfn_t mfn,
                 need_modify_vtd_table = 0;
 
             ept_p2m_type_to_flags(&new_entry, p2mt, p2ma);
+
+            if ( old_entry.d && (old_entry.sa_p2mt == p2m_ram_logdirty) )
+                paging_mark_dirty(d, mfn_x(mfn));
         }
 
         atomic_write_ept_entry(ept_entry, new_entry);
@@ -749,7 +758,8 @@ void ept_change_entry_emt_with_range(struct domain *d,
  * quickly enable or diable log-dirty tracking
  */
 static void ept_change_entry_type_page(mfn_t ept_page_mfn, int ept_page_level,
-                                       p2m_type_t ot, p2m_type_t nt)
+                                       p2m_type_t ot, p2m_type_t nt,
+                                       struct domain *d, int mask)
 {
     ept_entry_t e, *epte = map_domain_page(mfn_x(ept_page_mfn));
 
@@ -760,15 +770,33 @@ static void ept_change_entry_type_page(mfn_t 
ept_page_mfn, int ept_page_level,
 
         if ( (ept_page_level > 0) && !is_epte_superpage(epte + i) )
             ept_change_entry_type_page(_mfn(epte[i].mfn),
-                                       ept_page_level - 1, ot, nt);
+                                       ept_page_level - 1, ot, nt, d, mask);
         else
         {
             e = atomic_read_ept_entry(&epte[i]);
             if ( e.sa_p2mt != ot )
                 continue;
 
+            if ( e.d && (e.sa_p2mt == p2m_ram_logdirty) )
+            {
+                int j, nr_pages;
+                struct p2m_domain *p2m = p2m_get_hostp2m(d);
+                for ( j = 0, nr_pages = 1; j < ept_page_level;
+                      j++, nr_pages *= 512 ) {}
+                for ( j = 0; j < nr_pages; j++ )
+                    paging_mark_dirty(d, e.mfn + j);
+
+                /* split super page to 4k page, so that dirty bitmap can 
+                 * map the dirty page
+                 */
+                if ( !ept_split_super_page(p2m, &e, ept_page_level, 0) )
+                    continue;
+                atomic_write_ept_entry(&epte[i], e);
+            }
             e.sa_p2mt = nt;
             ept_p2m_type_to_flags(&e, nt, e.access);
+            if (!mask)
+                e.a = e.d = 0;
             atomic_write_ept_entry(&epte[i], e);
         }
     }
@@ -786,7 +814,22 @@ static void ept_change_entry_type_global(struct p2m_domain 
*p2m,
     BUG_ON(p2m_is_grant(ot) || p2m_is_grant(nt));
     BUG_ON(ot != nt && (ot == p2m_mmio_direct || nt == p2m_mmio_direct));
 
-    ept_change_entry_type_page(_mfn(ept_get_asr(d)), ept_get_wl(d), ot, nt);
+    ept_change_entry_type_page(_mfn(ept_get_asr(d)), ept_get_wl(d),
+                               ot, nt, p2m->domain, WALK_EPT_UNUSED);
+
+    ept_sync_domain(d);
+}
+
+static void ept_query_entry_global(struct p2m_domain *p2m, int mask)
+{
+    struct domain *d = p2m->domain;
+    p2m_type_t ot = p2m_ram_logdirty;
+    p2m_type_t nt = p2m_ram_logdirty;
+    if ( ept_get_asr(d) == 0 )
+        return;
+
+    ept_change_entry_type_page(_mfn(ept_get_asr(d)), ept_get_wl(d),
+                               ot, nt, p2m->domain, mask);
 
     ept_sync_domain(d);
 }
@@ -796,6 +839,7 @@ void ept_p2m_init(struct p2m_domain *p2m)
     p2m->set_entry = ept_set_entry;
     p2m->get_entry = ept_get_entry;
     p2m->change_entry_type_global = ept_change_entry_type_global;
+    p2m->query_entry_global = ept_query_entry_global;
     p2m->audit_p2m = NULL;
 }
 
-- 
1.5.5


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.