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

[Xen-changelog] [xen-unstable] [XEN] Make common log-dirty paging code and add HAP log-dirty support.



# HG changeset patch
# User Tim Deegan <Tim.Deegan@xxxxxxxxxxxxx>
# Date 1181568952 -3600
# Node ID 3d5f39c610ad8ccc5097abbd15ab329a57ef0b6d
# Parent  f1c6de438b83264891a7479ba5556c502e17a9a5
[XEN] Make common log-dirty paging code and add HAP log-dirty support.
Signed-off-by: Wei Huang <wei.huang2@xxxxxxx>
---
 xen/arch/x86/hvm/hvm.c            |    2 
 xen/arch/x86/hvm/io.c             |    2 
 xen/arch/x86/hvm/svm/svm.c        |    4 
 xen/arch/x86/mm.c                 |   12 -
 xen/arch/x86/mm/hap/hap.c         |   58 +++++-
 xen/arch/x86/mm/p2m.c             |  136 ++++++++++++++-
 xen/arch/x86/mm/paging.c          |  333 +++++++++++++++++++++++++++++++++++++-
 xen/arch/x86/mm/shadow/common.c   |  330 ++++++-------------------------------
 xen/arch/x86/mm/shadow/multi.c    |   12 -
 xen/arch/x86/mm/shadow/private.h  |    6 
 xen/include/asm-x86/domain.h      |   45 +++--
 xen/include/asm-x86/grant_table.h |    2 
 xen/include/asm-x86/p2m.h         |    5 
 xen/include/asm-x86/paging.h      |   26 ++
 xen/include/asm-x86/shadow.h      |   18 --
 15 files changed, 652 insertions(+), 339 deletions(-)

diff -r f1c6de438b83 -r 3d5f39c610ad xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Mon Jun 11 11:37:10 2007 +0100
+++ b/xen/arch/x86/hvm/hvm.c    Mon Jun 11 14:35:52 2007 +0100
@@ -568,7 +568,7 @@ static int __hvm_copy(void *buf, paddr_t
         if ( dir )
         {
             memcpy(p, buf, count); /* dir == TRUE:  *to* guest */
-            mark_dirty(current->domain, mfn);
+            paging_mark_dirty(current->domain, mfn);
         }
         else
             memcpy(buf, p, count); /* dir == FALSE: *from guest */
diff -r f1c6de438b83 -r 3d5f39c610ad xen/arch/x86/hvm/io.c
--- a/xen/arch/x86/hvm/io.c     Mon Jun 11 11:37:10 2007 +0100
+++ b/xen/arch/x86/hvm/io.c     Mon Jun 11 14:35:52 2007 +0100
@@ -865,7 +865,7 @@ void hvm_io_assist(void)
     if ( (p->dir == IOREQ_READ) && p->data_is_ptr )
     {
         gmfn = get_mfn_from_gpfn(paging_gva_to_gfn(v, p->data));
-        mark_dirty(d, gmfn);
+        paging_mark_dirty(d, gmfn);
     }
 
  out:
diff -r f1c6de438b83 -r 3d5f39c610ad xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Mon Jun 11 11:37:10 2007 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c        Mon Jun 11 14:35:52 2007 +0100
@@ -1027,8 +1027,8 @@ static int svm_do_nested_pgfault(paddr_t
         return 1;
     }
 
-    /* We should not reach here. Otherwise, P2M table is not correct.*/
-    return 0;
+    paging_mark_dirty(current->domain, get_mfn_from_gpfn(gpa >> PAGE_SHIFT));
+    return p2m_set_flags(current->domain, gpa, __PAGE_HYPERVISOR|_PAGE_USER);
 }
 
 static void svm_do_no_device_fault(struct vmcb_struct *vmcb)
diff -r f1c6de438b83 -r 3d5f39c610ad xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Mon Jun 11 11:37:10 2007 +0100
+++ b/xen/arch/x86/mm.c Mon Jun 11 14:35:52 2007 +0100
@@ -1556,7 +1556,7 @@ int alloc_page_type(struct page_info *pa
 
     /* A page table is dirtied when its type count becomes non-zero. */
     if ( likely(owner != NULL) )
-        mark_dirty(owner, page_to_mfn(page));
+        paging_mark_dirty(owner, page_to_mfn(page));
 
     switch ( type & PGT_type_mask )
     {
@@ -1602,7 +1602,7 @@ void free_page_type(struct page_info *pa
         if ( unlikely(paging_mode_enabled(owner)) )
         {
             /* A page table is dirtied when its type count becomes zero. */
-            mark_dirty(owner, page_to_mfn(page));
+            paging_mark_dirty(owner, page_to_mfn(page));
 
             if ( shadow_mode_refcounts(owner) )
                 return;
@@ -2057,7 +2057,7 @@ int do_mmuext_op(
             }
 
             /* A page is dirtied when its pin status is set. */
-            mark_dirty(d, mfn);
+            paging_mark_dirty(d, mfn);
            
             /* We can race domain destruction (domain_relinquish_resources). */
             if ( unlikely(this_cpu(percpu_mm_info).foreign != NULL) )
@@ -2089,7 +2089,7 @@ int do_mmuext_op(
                 put_page_and_type(page);
                 put_page(page);
                 /* A page is dirtied when its pin status is cleared. */
-                mark_dirty(d, mfn);
+                paging_mark_dirty(d, mfn);
             }
             else
             {
@@ -2424,7 +2424,7 @@ int do_mmu_update(
             set_gpfn_from_mfn(mfn, gpfn);
             okay = 1;
 
-            mark_dirty(FOREIGNDOM, mfn);
+            paging_mark_dirty(FOREIGNDOM, mfn);
 
             put_page(mfn_to_page(mfn));
             break;
@@ -3005,7 +3005,7 @@ long do_update_descriptor(u64 pa, u64 de
         break;
     }
 
-    mark_dirty(dom, mfn);
+    paging_mark_dirty(dom, mfn);
 
     /* All is good so make the update. */
     gdt_pent = map_domain_page(mfn);
diff -r f1c6de438b83 -r 3d5f39c610ad xen/arch/x86/mm/hap/hap.c
--- a/xen/arch/x86/mm/hap/hap.c Mon Jun 11 11:37:10 2007 +0100
+++ b/xen/arch/x86/mm/hap/hap.c Mon Jun 11 14:35:52 2007 +0100
@@ -49,6 +49,40 @@
 #undef page_to_mfn
 #define page_to_mfn(_pg) (_mfn((_pg) - frame_table))
 
+/************************************************/
+/*            HAP LOG DIRTY SUPPORT             */
+/************************************************/
+/* hap code to call when log_dirty is enable. return 0 if no problem found. */
+int hap_enable_log_dirty(struct domain *d)
+{
+    hap_lock(d);
+    /* turn on PG_log_dirty bit in paging mode */
+    d->arch.paging.mode |= PG_log_dirty;
+    /* set l1e entries of P2M table to NOT_WRITABLE. */
+    p2m_set_flags_global(d, (_PAGE_PRESENT|_PAGE_USER));
+    flush_tlb_all_pge();
+    hap_unlock(d);
+
+    return 0;
+}
+
+int hap_disable_log_dirty(struct domain *d)
+{
+    hap_lock(d);
+    d->arch.paging.mode &= ~PG_log_dirty;
+    /* set l1e entries of P2M table with normal mode */
+    p2m_set_flags_global(d, __PAGE_HYPERVISOR|_PAGE_USER);
+    hap_unlock(d);
+    
+    return 1;
+}
+
+void hap_clean_dirty_bitmap(struct domain *d)
+{
+    /* mark physical memory as NOT_WRITEABLE and flush the TLB */
+    p2m_set_flags_global(d, (_PAGE_PRESENT|_PAGE_USER));
+    flush_tlb_all_pge();
+}
 /************************************************/
 /*             HAP SUPPORT FUNCTIONS            */
 /************************************************/
@@ -421,6 +455,10 @@ int hap_enable(struct domain *d, u32 mod
         }
     }
 
+    /* initialize log dirty here */
+    paging_log_dirty_init(d, hap_enable_log_dirty, hap_disable_log_dirty,
+                          hap_clean_dirty_bitmap);
+
     /* allocate P2m table */
     if ( mode & PG_translate ) {
         rv = p2m_alloc_table(d, hap_alloc_p2m_page, hap_free_p2m_page);
@@ -498,11 +536,6 @@ int hap_domctl(struct domain *d, xen_dom
 
     HERE_I_AM;
 
-    if ( unlikely(d == current->domain) ) {
-        gdprintk(XENLOG_INFO, "Don't try to do a hap op on yourself!\n");
-        return -EINVAL;
-    }
-    
     switch ( sc->op ) {
     case XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION:
         hap_lock(d);
@@ -669,7 +702,16 @@ hap_write_p2m_entry(struct vcpu *v, unsi
 hap_write_p2m_entry(struct vcpu *v, unsigned long gfn, l1_pgentry_t *p,
                     l1_pgentry_t new, unsigned int level)
 {
-    hap_lock(v->domain);
+    int do_locking;
+
+    /* This function can be called from two directions (P2M and log dirty). We
+     *  need to make sure this lock has been held or not.
+     */
+    do_locking = !hap_locked_by_me(v->domain);
+
+    if ( do_locking )
+        hap_lock(v->domain);
+
     safe_write_pte(p, new);
 #if CONFIG_PAGING_LEVELS == 3
     /* install P2M in monitor table for PAE Xen */
@@ -680,7 +722,9 @@ hap_write_p2m_entry(struct vcpu *v, unsi
        
     }
 #endif
-    hap_unlock(v->domain);
+    
+    if ( do_locking )
+        hap_unlock(v->domain);
 }
 
 /* Entry points into this mode of the hap code. */
diff -r f1c6de438b83 -r 3d5f39c610ad xen/arch/x86/mm/p2m.c
--- a/xen/arch/x86/mm/p2m.c     Mon Jun 11 11:37:10 2007 +0100
+++ b/xen/arch/x86/mm/p2m.c     Mon Jun 11 14:35:52 2007 +0100
@@ -169,7 +169,7 @@ p2m_next_level(struct domain *d, mfn_t *
 
 // Returns 0 on error (out of memory)
 static int
-set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn)
+set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn, u32 l1e_flags)
 {
     // XXX -- this might be able to be faster iff current->domain == d
     mfn_t table_mfn = pagetable_get_mfn(d->arch.phys_table);
@@ -213,7 +213,7 @@ set_p2m_entry(struct domain *d, unsigned
         d->arch.p2m.max_mapped_pfn = gfn;
 
     if ( mfn_valid(mfn) )
-        entry_content = l1e_from_pfn(mfn_x(mfn), __PAGE_HYPERVISOR|_PAGE_USER);
+        entry_content = l1e_from_pfn(mfn_x(mfn), l1e_flags);
     else
         entry_content = l1e_empty();
 
@@ -278,7 +278,7 @@ int p2m_alloc_table(struct domain *d,
         p2m_unlock(d);
         return -ENOMEM;
     }
-list_add_tail(&p2m_top->list, &d->arch.p2m.pages);
+    list_add_tail(&p2m_top->list, &d->arch.p2m.pages);
 
     p2m_top->count_info = 1;
     p2m_top->u.inuse.type_info = 
@@ -297,8 +297,8 @@ list_add_tail(&p2m_top->list, &d->arch.p
  
     /* Initialise physmap tables for slot zero. Other code assumes this. */
     gfn = 0;
-mfn = _mfn(INVALID_MFN);
-    if ( !set_p2m_entry(d, gfn, mfn) )
+    mfn = _mfn(INVALID_MFN);
+    if ( !set_p2m_entry(d, gfn, mfn, __PAGE_HYPERVISOR|_PAGE_USER) )
         goto error;
 
     for ( entry = d->page_list.next;
@@ -316,7 +316,7 @@ mfn = _mfn(INVALID_MFN);
             (gfn != 0x55555555L)
 #endif
              && gfn != INVALID_M2P_ENTRY
-             && !set_p2m_entry(d, gfn, mfn) )
+             && !set_p2m_entry(d, gfn, mfn, __PAGE_HYPERVISOR|_PAGE_USER) )
             goto error;
     }
 
@@ -497,7 +497,7 @@ static void audit_p2m(struct domain *d)
             /* This m2p entry is stale: the domain has another frame in
              * this physical slot.  No great disaster, but for neatness,
              * blow away the m2p entry. */ 
-            set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY);
+            set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY, 
__PAGE_HYPERVISOR|_PAGE_USER);
         }
 
         if ( test_linear && (gfn <= d->arch.p2m.max_mapped_pfn) )
@@ -626,7 +626,7 @@ p2m_remove_page(struct domain *d, unsign
     ASSERT(mfn_x(gfn_to_mfn(d, gfn)) == mfn);
     //ASSERT(mfn_to_gfn(d, mfn) == gfn);
 
-    set_p2m_entry(d, gfn, _mfn(INVALID_MFN));
+    set_p2m_entry(d, gfn, _mfn(INVALID_MFN), __PAGE_HYPERVISOR|_PAGE_USER);
     set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY);
 }
 
@@ -659,7 +659,7 @@ guest_physmap_add_page(struct domain *d,
     omfn = gfn_to_mfn(d, gfn);
     if ( mfn_valid(omfn) )
     {
-        set_p2m_entry(d, gfn, _mfn(INVALID_MFN));
+        set_p2m_entry(d, gfn, _mfn(INVALID_MFN), __PAGE_HYPERVISOR|_PAGE_USER);
         set_gpfn_from_mfn(mfn_x(omfn), INVALID_M2P_ENTRY);
     }
 
@@ -685,13 +685,129 @@ guest_physmap_add_page(struct domain *d,
         }
     }
 
-    set_p2m_entry(d, gfn, _mfn(mfn));
+    set_p2m_entry(d, gfn, _mfn(mfn), __PAGE_HYPERVISOR|_PAGE_USER);
     set_gpfn_from_mfn(mfn, gfn);
 
     audit_p2m(d);
     p2m_unlock(d);
 }
 
+/* This function goes through P2M table and modify l1e flags of all pages. Note
+ * that physical base address of l1e is intact. This function can be used for
+ * special purpose, such as marking physical memory as NOT WRITABLE for
+ * tracking dirty pages during live migration.
+ */
+void p2m_set_flags_global(struct domain *d, u32 l1e_flags)
+{
+    unsigned long mfn, gfn;
+    l1_pgentry_t l1e_content;
+    l1_pgentry_t *l1e;
+    l2_pgentry_t *l2e;
+    int i1, i2;
+#if CONFIG_PAGING_LEVELS >= 3
+    l3_pgentry_t *l3e;
+    int i3;
+#if CONFIG_PAGING_LEVELS == 4
+    l4_pgentry_t *l4e;
+    int i4;
+#endif /* CONFIG_PAGING_LEVELS == 4 */
+#endif /* CONFIG_PAGING_LEVELS >= 3 */
+    
+    if ( !paging_mode_translate(d) )
+        return;
+ 
+    if ( pagetable_get_pfn(d->arch.phys_table) == 0 )
+        return;
+
+    p2m_lock(d);
+        
+#if CONFIG_PAGING_LEVELS == 4
+    l4e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table)));
+#elif CONFIG_PAGING_LEVELS == 3
+    l3e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table)));
+#else /* CONFIG_PAGING_LEVELS == 2 */
+    l2e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table)));
+#endif
+
+#if CONFIG_PAGING_LEVELS >= 3
+#if CONFIG_PAGING_LEVELS >= 4
+    for ( i4 = 0; i4 < L4_PAGETABLE_ENTRIES; i4++ ) 
+    {
+       if ( !(l4e_get_flags(l4e[i4]) & _PAGE_PRESENT) )
+       {
+           continue;
+       }
+       l3e = map_domain_page(mfn_x(_mfn(l4e_get_pfn(l4e[i4]))));
+#endif /* now at levels 3 or 4... */
+       for ( i3 = 0; 
+             i3 < ((CONFIG_PAGING_LEVELS==4) ? L3_PAGETABLE_ENTRIES : 8); 
+             i3++ )
+       {
+           if ( !(l3e_get_flags(l3e[i3]) & _PAGE_PRESENT) )
+           {
+               continue;
+           }
+           l2e = map_domain_page(mfn_x(_mfn(l3e_get_pfn(l3e[i3]))));
+#endif /* all levels... */
+           for ( i2 = 0; i2 < L2_PAGETABLE_ENTRIES; i2++ )
+           {
+               if ( !(l2e_get_flags(l2e[i2]) & _PAGE_PRESENT) )
+               {
+                   continue;
+               }
+               l1e = map_domain_page(mfn_x(_mfn(l2e_get_pfn(l2e[i2]))));
+               
+               for ( i1 = 0; i1 < L1_PAGETABLE_ENTRIES; i1++, gfn++ )
+               {
+                   if ( !(l1e_get_flags(l1e[i1]) & _PAGE_PRESENT) )
+                       continue;
+                   mfn = l1e_get_pfn(l1e[i1]);
+                   gfn = get_gpfn_from_mfn(mfn);
+                   /* create a new 1le entry using l1e_flags */
+                   l1e_content = l1e_from_pfn(mfn, l1e_flags);
+                   paging_write_p2m_entry(d, gfn, &l1e[i1], l1e_content, 1);
+               }
+               unmap_domain_page(l1e);
+           }
+#if CONFIG_PAGING_LEVELS >= 3
+           unmap_domain_page(l2e);
+       }
+#if CONFIG_PAGING_LEVELS >= 4
+       unmap_domain_page(l3e);
+    }
+#endif
+#endif
+
+#if CONFIG_PAGING_LEVELS == 4
+    unmap_domain_page(l4e);
+#elif CONFIG_PAGING_LEVELS == 3
+    unmap_domain_page(l3e);
+#else /* CONFIG_PAGING_LEVELS == 2 */
+    unmap_domain_page(l2e);
+#endif
+
+    p2m_unlock(d);
+}
+
+/* This function traces through P2M table and modifies l1e flags of a specific
+ * gpa.
+ */
+int p2m_set_flags(struct domain *d, paddr_t gpa, u32 l1e_flags)
+{
+    unsigned long gfn;
+    mfn_t mfn;
+
+    p2m_lock(d);
+
+    gfn = gpa >> PAGE_SHIFT;
+    mfn = gfn_to_mfn(d, gfn);
+    if ( mfn_valid(mfn) )
+        set_p2m_entry(d, gfn, mfn, l1e_flags);
+    
+    p2m_unlock(d);
+
+    return 1;
+}
 
 /*
  * Local variables:
diff -r f1c6de438b83 -r 3d5f39c610ad xen/arch/x86/mm/paging.c
--- a/xen/arch/x86/mm/paging.c  Mon Jun 11 11:37:10 2007 +0100
+++ b/xen/arch/x86/mm/paging.c  Mon Jun 11 14:35:52 2007 +0100
@@ -25,6 +25,7 @@
 #include <asm/shadow.h>
 #include <asm/p2m.h>
 #include <asm/hap.h>
+#include <asm/guest_access.h>
 
 /* Xen command-line option to enable hardware-assisted paging */
 int opt_hap_enabled;
@@ -41,7 +42,279 @@ boolean_param("hap", opt_hap_enabled);
             debugtrace_printk("pgdebug: %s(): " _f, __func__, ##_a); \
     } while (0)
 
-
+/************************************************/
+/*              LOG DIRTY SUPPORT               */
+/************************************************/
+/* Override macros from asm/page.h to make them work with mfn_t */
+#undef mfn_to_page
+#define mfn_to_page(_m) (frame_table + mfn_x(_m))
+#undef mfn_valid
+#define mfn_valid(_mfn) (mfn_x(_mfn) < max_page)
+#undef page_to_mfn
+#define page_to_mfn(_pg) (_mfn((_pg) - frame_table))
+
+#define log_dirty_lock_init(_d)                                   \
+    do {                                                          \
+        spin_lock_init(&(_d)->arch.paging.log_dirty.lock);        \
+        (_d)->arch.paging.log_dirty.locker = -1;                  \
+        (_d)->arch.paging.log_dirty.locker_function = "nobody";   \
+    } while (0)
+
+#define log_dirty_lock(_d)                                                   \
+    do {                                                                     \
+        if (unlikely((_d)->arch.paging.log_dirty.locker==current->processor))\
+        {                                                                    \
+            printk("Error: paging log dirty lock held by %s\n",              \
+                   (_d)->arch.paging.log_dirty.locker_function);             \
+            BUG();                                                           \
+        }                                                                    \
+        spin_lock(&(_d)->arch.paging.log_dirty.lock);                        \
+        ASSERT((_d)->arch.paging.log_dirty.locker == -1);                    \
+        (_d)->arch.paging.log_dirty.locker = current->processor;             \
+        (_d)->arch.paging.log_dirty.locker_function = __func__;              \
+    } while (0)
+
+#define log_dirty_unlock(_d)                                              \
+    do {                                                                  \
+        ASSERT((_d)->arch.paging.log_dirty.locker == current->processor); \
+        (_d)->arch.paging.log_dirty.locker = -1;                          \
+        (_d)->arch.paging.log_dirty.locker_function = "nobody";           \
+        spin_unlock(&(_d)->arch.paging.log_dirty.lock);                   \
+    } while (0)
+
+/* allocate bitmap resources for log dirty */
+int paging_alloc_log_dirty_bitmap(struct domain *d)
+{
+    ASSERT(d->arch.paging.log_dirty.bitmap == NULL);
+    d->arch.paging.log_dirty.bitmap_size =
+        (domain_get_maximum_gpfn(d) + BITS_PER_LONG) & ~(BITS_PER_LONG - 1);
+    d->arch.paging.log_dirty.bitmap = 
+        xmalloc_array(unsigned long,
+                      d->arch.paging.log_dirty.bitmap_size / BITS_PER_LONG);
+    if ( d->arch.paging.log_dirty.bitmap == NULL )
+    {
+        d->arch.paging.log_dirty.bitmap_size = 0;
+        return -ENOMEM;
+    }
+    memset(d->arch.paging.log_dirty.bitmap, 0,
+           d->arch.paging.log_dirty.bitmap_size/8);
+
+    return 0;
+}
+
+/* free bitmap resources */
+void paging_free_log_dirty_bitmap(struct domain *d)
+{
+    d->arch.paging.log_dirty.bitmap_size = 0;
+    if ( d->arch.paging.log_dirty.bitmap )
+    {
+        xfree(d->arch.paging.log_dirty.bitmap);
+        d->arch.paging.log_dirty.bitmap = NULL;
+    }
+}
+
+int paging_log_dirty_enable(struct domain *d)
+{
+    int ret;
+
+    domain_pause(d);
+    log_dirty_lock(d);
+
+    if ( paging_mode_log_dirty(d) )
+    {
+        ret = -EINVAL;
+        goto out;
+    }
+
+    ret = paging_alloc_log_dirty_bitmap(d);
+    if ( ret != 0 )
+    {
+        paging_free_log_dirty_bitmap(d);
+        goto out;
+    }
+
+    ret = d->arch.paging.log_dirty.enable_log_dirty(d);
+    if ( ret != 0 )
+        paging_free_log_dirty_bitmap(d);
+
+ out:
+    log_dirty_unlock(d);
+    domain_unpause(d);
+    return ret;
+}
+
+int paging_log_dirty_disable(struct domain *d)
+{
+    int ret;
+
+    domain_pause(d);
+    log_dirty_lock(d);
+    ret = d->arch.paging.log_dirty.disable_log_dirty(d);
+    if ( !paging_mode_log_dirty(d) )
+        paging_free_log_dirty_bitmap(d);
+    log_dirty_unlock(d);
+    domain_unpause(d);
+
+    return ret;
+}
+
+/* Mark a page as dirty */
+void paging_mark_dirty(struct domain *d, unsigned long guest_mfn)
+{
+    unsigned long pfn;
+    mfn_t gmfn;
+
+    gmfn = _mfn(guest_mfn);
+
+    if ( !paging_mode_log_dirty(d) || !mfn_valid(gmfn) )
+        return;
+
+    log_dirty_lock(d);
+
+    ASSERT(d->arch.paging.log_dirty.bitmap != NULL);
+
+    /* We /really/ mean PFN here, even for non-translated guests. */
+    pfn = get_gpfn_from_mfn(mfn_x(gmfn));
+
+    /*
+     * Values with the MSB set denote MFNs that aren't really part of the 
+     * domain's pseudo-physical memory map (e.g., the shared info frame).
+     * Nothing to do here...
+     */
+    if ( unlikely(!VALID_M2P(pfn)) )
+        return;
+
+    if ( likely(pfn < d->arch.paging.log_dirty.bitmap_size) ) 
+    { 
+        if ( !__test_and_set_bit(pfn, d->arch.paging.log_dirty.bitmap) )
+        {
+            PAGING_DEBUG(LOGDIRTY, 
+                         "marked mfn %" PRI_mfn " (pfn=%lx), dom %d\n",
+                         mfn_x(gmfn), pfn, d->domain_id);
+            d->arch.paging.log_dirty.dirty_count++;
+        }
+    }
+    else
+    {
+        PAGING_PRINTK("mark_dirty OOR! "
+                      "mfn=%" PRI_mfn " pfn=%lx max=%x (dom %d)\n"
+                      "owner=%d c=%08x t=%" PRtype_info "\n",
+                      mfn_x(gmfn), 
+                      pfn, 
+                      d->arch.paging.log_dirty.bitmap_size,
+                      d->domain_id,
+                      (page_get_owner(mfn_to_page(gmfn))
+                       ? page_get_owner(mfn_to_page(gmfn))->domain_id
+                       : -1),
+                      mfn_to_page(gmfn)->count_info, 
+                      mfn_to_page(gmfn)->u.inuse.type_info);
+    }
+    
+    log_dirty_unlock(d);
+}
+
+/* Read a domain's log-dirty bitmap and stats.  If the operation is a CLEAN, 
+ * clear the bitmap and stats as well. */
+int paging_log_dirty_op(struct domain *d, struct xen_domctl_shadow_op *sc)
+{
+    int i, rv = 0, clean = 0, peek = 1;
+
+    domain_pause(d);
+    log_dirty_lock(d);
+
+    clean = (sc->op == XEN_DOMCTL_SHADOW_OP_CLEAN);
+
+    PAGING_DEBUG(LOGDIRTY, "log-dirty %s: dom %u faults=%u dirty=%u\n", 
+                 (clean) ? "clean" : "peek",
+                 d->domain_id,
+                 d->arch.paging.log_dirty.fault_count, 
+                 d->arch.paging.log_dirty.dirty_count);
+
+    sc->stats.fault_count = d->arch.paging.log_dirty.fault_count;
+    sc->stats.dirty_count = d->arch.paging.log_dirty.dirty_count;
+    
+    if ( clean )
+    {
+        d->arch.paging.log_dirty.fault_count = 0;
+        d->arch.paging.log_dirty.dirty_count = 0;
+
+        /* We need to further call clean_dirty_bitmap() functions of specific
+         * paging modes (shadow or hap).
+         */
+        d->arch.paging.log_dirty.clean_dirty_bitmap(d);
+    }
+
+    if ( guest_handle_is_null(sc->dirty_bitmap) )
+        /* caller may have wanted just to clean the state or access stats. */
+        peek = 0;
+
+    if ( (peek || clean) && (d->arch.paging.log_dirty.bitmap == NULL) )
+    {
+        rv = -EINVAL; /* perhaps should be ENOMEM? */
+        goto out;
+    }
+ 
+    if ( sc->pages > d->arch.paging.log_dirty.bitmap_size )
+        sc->pages = d->arch.paging.log_dirty.bitmap_size;
+
+#define CHUNK (8*1024) /* Transfer and clear in 1kB chunks for L1 cache. */
+    for ( i = 0; i < sc->pages; i += CHUNK )
+    {
+        int bytes = ((((sc->pages - i) > CHUNK)
+                      ? CHUNK
+                      : (sc->pages - i)) + 7) / 8;
+
+        if ( likely(peek) )
+        {
+            if ( copy_to_guest_offset(
+                sc->dirty_bitmap, i/8,
+                (uint8_t *)d->arch.paging.log_dirty.bitmap + (i/8), bytes) )
+            {
+                rv = -EFAULT;
+                goto out;
+            }
+        }
+
+        if ( clean )
+            memset((uint8_t *)d->arch.paging.log_dirty.bitmap + (i/8), 0, 
bytes);
+    }
+#undef CHUNK
+
+ out:
+    log_dirty_unlock(d);
+    domain_unpause(d);
+    return rv;
+}
+
+
+/* Note that this function takes three function pointers. Callers must supply
+ * these functions for log dirty code to call. This function usually is 
+ * invoked when paging is enabled. Check shadow_enable() and hap_enable() for 
+ * reference.
+ */
+void paging_log_dirty_init(struct domain *d,
+                           int    (*enable_log_dirty)(struct domain *d),
+                           int    (*disable_log_dirty)(struct domain *d),
+                           void   (*clean_dirty_bitmap)(struct domain *d))
+{
+    /* We initialize log dirty lock first */
+    log_dirty_lock_init(d);
+    
+    d->arch.paging.log_dirty.enable_log_dirty = enable_log_dirty;
+    d->arch.paging.log_dirty.disable_log_dirty = disable_log_dirty;
+    d->arch.paging.log_dirty.clean_dirty_bitmap = clean_dirty_bitmap;
+}
+
+/* This function fress log dirty bitmap resources. */
+void paging_log_dirty_teardown(struct domain*d)
+{
+    log_dirty_lock(d);
+    paging_free_log_dirty_bitmap(d);
+    log_dirty_unlock(d);
+}
+/************************************************/
+/*           CODE FOR PAGING SUPPORT            */
+/************************************************/
 /* Domain paging struct initialization. */
 void paging_domain_init(struct domain *d)
 {
@@ -65,16 +338,68 @@ int paging_domctl(struct domain *d, xen_
 int paging_domctl(struct domain *d, xen_domctl_shadow_op_t *sc,
                   XEN_GUEST_HANDLE(void) u_domctl)
 {
+    int rc;
+
+    if ( unlikely(d == current->domain) )
+    {
+        gdprintk(XENLOG_INFO, "Dom %u tried to do a paging op on itself.\n",
+                 d->domain_id);
+        return -EINVAL;
+    }
+    
+    if ( unlikely(d->is_dying) )
+    {
+        gdprintk(XENLOG_INFO, "Ignoring paging op on dying domain %u\n",
+                 d->domain_id);
+        return 0;
+    }
+
+    if ( unlikely(d->vcpu[0] == NULL) )
+    {
+        PAGING_ERROR("Paging op on a domain (%u) with no vcpus\n",
+                     d->domain_id);
+        return -EINVAL;
+    }
+    
+    /* Code to handle log-dirty. Note that some log dirty operations
+     * piggy-back on shadow operations. For example, when 
+     * XEN_DOMCTL_SHADOW_OP_OFF is called, it first checks whether log dirty
+     * mode is enabled. If does, we disables log dirty and continues with 
+     * shadow code. For this reason, we need to further dispatch domctl 
+     * to next-level paging code (shadow or hap).
+     */
+    switch ( sc->op )
+    {
+    case XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY:
+        return paging_log_dirty_enable(d);     
+       
+    case XEN_DOMCTL_SHADOW_OP_ENABLE:  
+        if ( sc->mode & XEN_DOMCTL_SHADOW_ENABLE_LOG_DIRTY )
+            return paging_log_dirty_enable(d);
+
+    case XEN_DOMCTL_SHADOW_OP_OFF:
+        if ( paging_mode_log_dirty(d) )
+            if ( (rc = paging_log_dirty_disable(d)) != 0 ) 
+                return rc;
+
+    case XEN_DOMCTL_SHADOW_OP_CLEAN:
+    case XEN_DOMCTL_SHADOW_OP_PEEK:
+       return paging_log_dirty_op(d, sc);
+    }
+       
     /* Here, dispatch domctl to the appropriate paging code */
     if ( opt_hap_enabled && is_hvm_domain(d) )
-        return hap_domctl(d, sc, u_domctl);
-    else
-        return shadow_domctl(d, sc, u_domctl);
+       return hap_domctl(d, sc, u_domctl);
+    else
+       return shadow_domctl(d, sc, u_domctl);
 }
 
 /* Call when destroying a domain */
 void paging_teardown(struct domain *d)
 {
+    /* clean up log dirty resources. */
+    paging_log_dirty_teardown(d);
+    
     if ( opt_hap_enabled && is_hvm_domain(d) )
         hap_teardown(d);
     else
diff -r f1c6de438b83 -r 3d5f39c610ad xen/arch/x86/mm/shadow/common.c
--- a/xen/arch/x86/mm/shadow/common.c   Mon Jun 11 11:37:10 2007 +0100
+++ b/xen/arch/x86/mm/shadow/common.c   Mon Jun 11 14:35:52 2007 +0100
@@ -87,8 +87,6 @@ __initcall(shadow_audit_key_init);
 __initcall(shadow_audit_key_init);
 #endif /* SHADOW_AUDIT */
 
-static void sh_free_log_dirty_bitmap(struct domain *d);
-
 int _shadow_mode_refcounts(struct domain *d)
 {
     return shadow_mode_refcounts(d);
@@ -541,7 +539,7 @@ sh_validate_guest_entry(struct vcpu *v, 
     int result = 0;
     struct page_info *page = mfn_to_page(gmfn);
 
-    sh_mark_dirty(v->domain, gmfn);
+    paging_mark_dirty(v->domain, mfn_x(gmfn));
     
     // Determine which types of shadows are affected, and update each.
     //
@@ -2455,6 +2453,10 @@ int shadow_enable(struct domain *d, u32 
         }        
     }
 
+    /* initialize log dirty here */
+    paging_log_dirty_init(d, shadow_enable_log_dirty, 
+                          shadow_disable_log_dirty, shadow_clean_dirty_bitmap);
+
     /* Init the P2M table.  Must be done before we take the shadow lock 
      * to avoid possible deadlock. */
     if ( mode & PG_translate )
@@ -2463,6 +2465,7 @@ int shadow_enable(struct domain *d, u32 
         if (rv != 0)
             goto out_unlocked;
     }
+
 
     shadow_lock(d);
 
@@ -2564,8 +2567,6 @@ void shadow_teardown(struct domain *d)
         /* Release the hash table back to xenheap */
         if (d->arch.paging.shadow.hash_table) 
             shadow_hash_teardown(d);
-        /* Release the log-dirty bitmap of dirtied pages */
-        sh_free_log_dirty_bitmap(d);
         /* Should not have any more memory held */
         SHADOW_PRINTK("teardown done."
                        "  Shadow pages total = %u, free = %u, p2m=%u\n",
@@ -2718,98 +2719,6 @@ static int shadow_test_disable(struct do
     domain_pause(d);
     shadow_lock(d);
     ret = shadow_one_bit_disable(d, PG_SH_enable);
-    shadow_unlock(d);
-    domain_unpause(d);
-
-    return ret;
-}
-
-static int
-sh_alloc_log_dirty_bitmap(struct domain *d)
-{
-    ASSERT(d->arch.paging.shadow.dirty_bitmap == NULL);
-    d->arch.paging.shadow.dirty_bitmap_size =
-        (domain_get_maximum_gpfn(d) + BITS_PER_LONG) & ~(BITS_PER_LONG - 1);
-    d->arch.paging.shadow.dirty_bitmap =
-        xmalloc_array(unsigned long,
-                      d->arch.paging.shadow.dirty_bitmap_size / BITS_PER_LONG);
-    if ( d->arch.paging.shadow.dirty_bitmap == NULL )
-    {
-        d->arch.paging.shadow.dirty_bitmap_size = 0;
-        return -ENOMEM;
-    }
-    memset(d->arch.paging.shadow.dirty_bitmap, 0,
-           d->arch.paging.shadow.dirty_bitmap_size/8);
-
-    return 0;
-}
-
-static void
-sh_free_log_dirty_bitmap(struct domain *d)
-{
-    d->arch.paging.shadow.dirty_bitmap_size = 0;
-    if ( d->arch.paging.shadow.dirty_bitmap )
-    {
-        xfree(d->arch.paging.shadow.dirty_bitmap);
-        d->arch.paging.shadow.dirty_bitmap = NULL;
-    }
-}
-
-static int shadow_log_dirty_enable(struct domain *d)
-{
-    int ret;
-
-    domain_pause(d);
-    shadow_lock(d);
-
-    if ( shadow_mode_log_dirty(d) )
-    {
-        ret = -EINVAL;
-        goto out;
-    }
-
-    if ( shadow_mode_enabled(d) )
-    {
-        /* This domain already has some shadows: need to clear them out 
-         * of the way to make sure that all references to guest memory are 
-         * properly write-protected */
-        shadow_blow_tables(d);
-    }
-
-#if (SHADOW_OPTIMIZATIONS & SHOPT_LINUX_L3_TOPLEVEL)
-    /* 32bit PV guests on 64bit xen behave like older 64bit linux: they
-     * change an l4e instead of cr3 to switch tables.  Give them the
-     * same optimization */
-    if ( is_pv_32on64_domain(d) )
-        d->arch.paging.shadow.opt_flags = SHOPT_LINUX_L3_TOPLEVEL;
-#endif
-
-    ret = sh_alloc_log_dirty_bitmap(d);
-    if ( ret != 0 )
-    {
-        sh_free_log_dirty_bitmap(d);
-        goto out;
-    }
-
-    ret = shadow_one_bit_enable(d, PG_log_dirty);
-    if ( ret != 0 )
-        sh_free_log_dirty_bitmap(d);
-
- out:
-    shadow_unlock(d);
-    domain_unpause(d);
-    return ret;
-}
-
-static int shadow_log_dirty_disable(struct domain *d)
-{
-    int ret;
-
-    domain_pause(d);
-    shadow_lock(d);
-    ret = shadow_one_bit_disable(d, PG_log_dirty);
-    if ( !shadow_mode_log_dirty(d) )
-        sh_free_log_dirty_bitmap(d);
     shadow_unlock(d);
     domain_unpause(d);
 
@@ -2892,150 +2801,62 @@ void shadow_convert_to_log_dirty(struct 
     BUG();
 }
 
-
-/* Read a domain's log-dirty bitmap and stats.  
- * If the operation is a CLEAN, clear the bitmap and stats as well. */
-static int shadow_log_dirty_op(
-    struct domain *d, struct xen_domctl_shadow_op *sc)
-{
-    int i, rv = 0, clean = 0, peek = 1;
-
-    domain_pause(d);
+/* Shadow specific code which is called in paging_log_dirty_enable().
+ * Return 0 if no problem found.
+ */
+int shadow_enable_log_dirty(struct domain *d)
+{
+    int ret;
+
+    /* shadow lock is required here */
     shadow_lock(d);
-
-    clean = (sc->op == XEN_DOMCTL_SHADOW_OP_CLEAN);
-
-    SHADOW_DEBUG(LOGDIRTY, "log-dirty %s: dom %u faults=%u dirty=%u\n", 
-                  (clean) ? "clean" : "peek",
-                  d->domain_id,
-                  d->arch.paging.shadow.fault_count, 
-                  d->arch.paging.shadow.dirty_count);
-
-    sc->stats.fault_count = d->arch.paging.shadow.fault_count;
-    sc->stats.dirty_count = d->arch.paging.shadow.dirty_count;
-
-    if ( clean )
-    {
-        /* Need to revoke write access to the domain's pages again.
-         * In future, we'll have a less heavy-handed approach to this,
-         * but for now, we just unshadow everything except Xen. */
+    if ( shadow_mode_enabled(d) )
+    {
+        /* This domain already has some shadows: need to clear them out 
+         * of the way to make sure that all references to guest memory are 
+         * properly write-protected */
         shadow_blow_tables(d);
-
-        d->arch.paging.shadow.fault_count = 0;
-        d->arch.paging.shadow.dirty_count = 0;
-    }
-
-    if ( guest_handle_is_null(sc->dirty_bitmap) )
-        /* caller may have wanted just to clean the state or access stats. */
-        peek = 0;
-
-    if ( (peek || clean) && (d->arch.paging.shadow.dirty_bitmap == NULL) )
-    {
-        rv = -EINVAL; /* perhaps should be ENOMEM? */
-        goto out;
-    }
- 
-    if ( sc->pages > d->arch.paging.shadow.dirty_bitmap_size )
-        sc->pages = d->arch.paging.shadow.dirty_bitmap_size;
-
-#define CHUNK (8*1024) /* Transfer and clear in 1kB chunks for L1 cache. */
-    for ( i = 0; i < sc->pages; i += CHUNK )
-    {
-        int bytes = ((((sc->pages - i) > CHUNK)
-                      ? CHUNK
-                      : (sc->pages - i)) + 7) / 8;
-
-        if ( likely(peek) )
-        {
-            if ( copy_to_guest_offset(
-                sc->dirty_bitmap, i/8,
-                (uint8_t *)d->arch.paging.shadow.dirty_bitmap + (i/8), bytes) )
-            {
-                rv = -EFAULT;
-                goto out;
-            }
-        }
-
-        if ( clean )
-            memset((uint8_t *)d->arch.paging.shadow.dirty_bitmap + (i/8), 0, 
bytes);
-    }
-#undef CHUNK
-
- out:
+    }
+
+#if (SHADOW_OPTIMIZATIONS & SHOPT_LINUX_L3_TOPLEVEL)
+    /* 32bit PV guests on 64bit xen behave like older 64bit linux: they
+     * change an l4e instead of cr3 to switch tables.  Give them the
+     * same optimization */
+    if ( is_pv_32on64_domain(d) )
+        d->arch.paging.shadow.opt_flags = SHOPT_LINUX_L3_TOPLEVEL;
+#endif
+    
+    ret = shadow_one_bit_enable(d, PG_log_dirty);
     shadow_unlock(d);
-    domain_unpause(d);
-    return rv;
-}
-
-
-/* Mark a page as dirty */
-void sh_mark_dirty(struct domain *d, mfn_t gmfn)
-{
-    unsigned long pfn;
-    int do_locking;
-
-    if ( !shadow_mode_log_dirty(d) || !mfn_valid(gmfn) )
-        return;
-
-    /* Although this is an externally visible function, we do not know
-     * whether the shadow lock will be held when it is called (since it
-     * can be called from __hvm_copy during emulation).
-     * If the lock isn't held, take it for the duration of the call. */
-    do_locking = !shadow_locked_by_me(d);
-    if ( do_locking ) 
-    { 
-        shadow_lock(d);
-        /* Check the mode again with the lock held */ 
-        if ( unlikely(!shadow_mode_log_dirty(d)) )
-        {
-            shadow_unlock(d);
-            return;
-        }
-    }
-
-    ASSERT(d->arch.paging.shadow.dirty_bitmap != NULL);
-
-    /* We /really/ mean PFN here, even for non-translated guests. */
-    pfn = get_gpfn_from_mfn(mfn_x(gmfn));
-
-    /*
-     * Values with the MSB set denote MFNs that aren't really part of the 
-     * domain's pseudo-physical memory map (e.g., the shared info frame).
-     * Nothing to do here...
-     */
-    if ( unlikely(!VALID_M2P(pfn)) )
-        return;
-
-    /* N.B. Can use non-atomic TAS because protected by shadow_lock. */
-    if ( likely(pfn < d->arch.paging.shadow.dirty_bitmap_size) ) 
-    { 
-        if ( !__test_and_set_bit(pfn, d->arch.paging.shadow.dirty_bitmap) )
-        {
-            SHADOW_DEBUG(LOGDIRTY, 
-                          "marked mfn %" PRI_mfn " (pfn=%lx), dom %d\n",
-                          mfn_x(gmfn), pfn, d->domain_id);
-            d->arch.paging.shadow.dirty_count++;
-        }
-    }
-    else
-    {
-        SHADOW_PRINTK("mark_dirty OOR! "
-                       "mfn=%" PRI_mfn " pfn=%lx max=%x (dom %d)\n"
-                       "owner=%d c=%08x t=%" PRtype_info "\n",
-                       mfn_x(gmfn), 
-                       pfn, 
-                       d->arch.paging.shadow.dirty_bitmap_size,
-                       d->domain_id,
-                       (page_get_owner(mfn_to_page(gmfn))
-                        ? page_get_owner(mfn_to_page(gmfn))->domain_id
-                        : -1),
-                       mfn_to_page(gmfn)->count_info, 
-                       mfn_to_page(gmfn)->u.inuse.type_info);
-    }
-
-    if ( do_locking ) shadow_unlock(d);
-}
-
+
+    return ret;
+}
+
+/* shadow specfic code which is called in paging_log_dirty_disable() */
+int shadow_disable_log_dirty(struct domain *d)
+{
+    int ret;
+
+    /* shadow lock is required here */    
+    shadow_lock(d);
+    ret = shadow_one_bit_disable(d, PG_log_dirty);
+    shadow_unlock(d);
+    
+    return ret;
+}
+
+/* This function is called when we CLEAN log dirty bitmap. See 
+ * paging_log_dirty_op() for details. 
+ */
+void shadow_clean_dirty_bitmap(struct domain *d)
+{
+    shadow_lock(d);
+    /* Need to revoke write access to the domain's pages again.
+     * In future, we'll have a less heavy-handed approach to this,
+     * but for now, we just unshadow everything except Xen. */
+    shadow_blow_tables(d);
+    shadow_unlock(d);
+}
 /**************************************************************************/
 /* Shadow-control XEN_DOMCTL dispatcher */
 
@@ -3045,33 +2866,9 @@ int shadow_domctl(struct domain *d,
 {
     int rc, preempted = 0;
 
-    if ( unlikely(d == current->domain) )
-    {
-        gdprintk(XENLOG_INFO, "Dom %u tried to do a shadow op on itself.\n",
-                 d->domain_id);
-        return -EINVAL;
-    }
-
-    if ( unlikely(d->is_dying) )
-    {
-        gdprintk(XENLOG_INFO, "Ignoring shadow op on dying domain %u\n",
-                 d->domain_id);
-        return 0;
-    }
-
-    if ( unlikely(d->vcpu[0] == NULL) )
-    {
-        SHADOW_ERROR("Shadow op on a domain (%u) with no vcpus\n",
-                     d->domain_id);
-        return -EINVAL;
-    }
-
     switch ( sc->op )
     {
     case XEN_DOMCTL_SHADOW_OP_OFF:
-        if ( shadow_mode_log_dirty(d) )
-            if ( (rc = shadow_log_dirty_disable(d)) != 0 ) 
-                return rc;
         if ( d->arch.paging.mode == PG_SH_enable )
             if ( (rc = shadow_test_disable(d)) != 0 ) 
                 return rc;
@@ -3080,19 +2877,10 @@ int shadow_domctl(struct domain *d,
     case XEN_DOMCTL_SHADOW_OP_ENABLE_TEST:
         return shadow_test_enable(d);
 
-    case XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY:
-        return shadow_log_dirty_enable(d);
-
     case XEN_DOMCTL_SHADOW_OP_ENABLE_TRANSLATE:
         return shadow_enable(d, PG_refcounts|PG_translate);
 
-    case XEN_DOMCTL_SHADOW_OP_CLEAN:
-    case XEN_DOMCTL_SHADOW_OP_PEEK:
-        return shadow_log_dirty_op(d, sc);
-
     case XEN_DOMCTL_SHADOW_OP_ENABLE:
-        if ( sc->mode & XEN_DOMCTL_SHADOW_ENABLE_LOG_DIRTY )
-            return shadow_log_dirty_enable(d);
         return shadow_enable(d, sc->mode << PG_mode_shift);
 
     case XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION:
diff -r f1c6de438b83 -r 3d5f39c610ad xen/arch/x86/mm/shadow/multi.c
--- a/xen/arch/x86/mm/shadow/multi.c    Mon Jun 11 11:37:10 2007 +0100
+++ b/xen/arch/x86/mm/shadow/multi.c    Mon Jun 11 14:35:52 2007 +0100
@@ -457,7 +457,7 @@ static u32 guest_set_ad_bits(struct vcpu
     }
 
     /* Set the bit(s) */
-    sh_mark_dirty(v->domain, gmfn);
+    paging_mark_dirty(v->domain, mfn_x(gmfn));
     SHADOW_DEBUG(A_AND_D, "gfn = %" SH_PRI_gfn ", "
                  "old flags = %#x, new flags = %#x\n", 
                  gfn_x(guest_l1e_get_gfn(*ep)), guest_l1e_get_flags(*ep), 
@@ -717,7 +717,7 @@ _sh_propagate(struct vcpu *v,
     if ( unlikely((level == 1) && shadow_mode_log_dirty(d)) )
     {
         if ( ft & FETCH_TYPE_WRITE ) 
-            sh_mark_dirty(d, target_mfn);
+            paging_mark_dirty(d, mfn_x(target_mfn));
         else if ( !sh_mfn_is_dirty(d, target_mfn) )
             sflags &= ~_PAGE_RW;
     }
@@ -2856,7 +2856,7 @@ static int sh_page_fault(struct vcpu *v,
     }
 
     perfc_incr(shadow_fault_fixed);
-    d->arch.paging.shadow.fault_count++;
+    d->arch.paging.log_dirty.fault_count++;
     reset_early_unshadow(v);
 
  done:
@@ -4058,7 +4058,7 @@ sh_x86_emulate_write(struct vcpu *v, uns
     else
         reset_early_unshadow(v);
     
-    sh_mark_dirty(v->domain, mfn);
+    paging_mark_dirty(v->domain, mfn_x(mfn));
 
     sh_unmap_domain_page(addr);
     shadow_audit_tables(v);
@@ -4114,7 +4114,7 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, u
     else
         reset_early_unshadow(v);
 
-    sh_mark_dirty(v->domain, mfn);
+    paging_mark_dirty(v->domain, mfn_x(mfn));
 
     sh_unmap_domain_page(addr);
     shadow_audit_tables(v);
@@ -4158,7 +4158,7 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v,
     else
         reset_early_unshadow(v);
 
-    sh_mark_dirty(v->domain, mfn);
+    paging_mark_dirty(v->domain, mfn_x(mfn));
 
     sh_unmap_domain_page(addr);
     shadow_audit_tables(v);
diff -r f1c6de438b83 -r 3d5f39c610ad xen/arch/x86/mm/shadow/private.h
--- a/xen/arch/x86/mm/shadow/private.h  Mon Jun 11 11:37:10 2007 +0100
+++ b/xen/arch/x86/mm/shadow/private.h  Mon Jun 11 14:35:52 2007 +0100
@@ -496,13 +496,13 @@ sh_mfn_is_dirty(struct domain *d, mfn_t 
 {
     unsigned long pfn;
     ASSERT(shadow_mode_log_dirty(d));
-    ASSERT(d->arch.paging.shadow.dirty_bitmap != NULL);
+    ASSERT(d->arch.paging.log_dirty.bitmap != NULL);
 
     /* We /really/ mean PFN here, even for non-translated guests. */
     pfn = get_gpfn_from_mfn(mfn_x(gmfn));
     if ( likely(VALID_M2P(pfn))
-         && likely(pfn < d->arch.paging.shadow.dirty_bitmap_size) 
-         && test_bit(pfn, d->arch.paging.shadow.dirty_bitmap) )
+         && likely(pfn < d->arch.paging.log_dirty.bitmap_size) 
+         && test_bit(pfn, d->arch.paging.log_dirty.bitmap) )
         return 1;
 
     return 0;
diff -r f1c6de438b83 -r 3d5f39c610ad xen/include/asm-x86/domain.h
--- a/xen/include/asm-x86/domain.h      Mon Jun 11 11:37:10 2007 +0100
+++ b/xen/include/asm-x86/domain.h      Mon Jun 11 14:35:52 2007 +0100
@@ -92,14 +92,6 @@ struct shadow_domain {
 
     /* Fast MMIO path heuristic */
     int has_fast_mmio_entries;
-
-    /* Shadow log-dirty bitmap */
-    unsigned long *dirty_bitmap;
-    unsigned int dirty_bitmap_size;  /* in pages, bit per page */
-
-    /* Shadow log-dirty mode stats */
-    unsigned int fault_count;
-    unsigned int dirty_count;
 };
 
 struct shadow_vcpu {
@@ -134,7 +126,6 @@ struct hap_domain {
 /************************************************/
 /*       p2m handling                           */
 /************************************************/
-
 struct p2m_domain {
     /* Lock that protects updates to the p2m */
     spinlock_t         lock;
@@ -156,16 +147,36 @@ struct p2m_domain {
 /************************************************/
 /*       common paging data structure           */
 /************************************************/
+struct log_dirty_domain {
+    /* log-dirty lock */
+    spinlock_t     lock;
+    int            locker; /* processor that holds the lock */
+    const char    *locker_function; /* func that took it */
+
+    /* log-dirty bitmap to record dirty pages */
+    unsigned long *bitmap;
+    unsigned int   bitmap_size;  /* in pages, bit per page */
+
+    /* log-dirty mode stats */
+    unsigned int   fault_count;
+    unsigned int   dirty_count;
+
+    /* functions which are paging mode specific */
+    int            (*enable_log_dirty   )(struct domain *d);
+    int            (*disable_log_dirty  )(struct domain *d);
+    void           (*clean_dirty_bitmap )(struct domain *d);
+};
+
 struct paging_domain {
-    u32               mode;  /* flags to control paging operation */
-
+    /* flags to control paging operation */
+    u32                     mode;
     /* extension for shadow paging support */
-    struct shadow_domain shadow;
-
-    /* Other paging assistance code will have structs here */
-    struct hap_domain    hap;
-};
-
+    struct shadow_domain    shadow;
+    /* extension for hardware-assited paging */
+    struct hap_domain       hap;
+    /* log dirty support */
+    struct log_dirty_domain log_dirty;
+};
 struct paging_vcpu {
     /* Pointers to mode-specific entry points. */
     struct paging_mode *mode;
diff -r f1c6de438b83 -r 3d5f39c610ad xen/include/asm-x86/grant_table.h
--- a/xen/include/asm-x86/grant_table.h Mon Jun 11 11:37:10 2007 +0100
+++ b/xen/include/asm-x86/grant_table.h Mon Jun 11 14:35:52 2007 +0100
@@ -31,7 +31,7 @@ int replace_grant_host_mapping(
 #define gnttab_shared_gmfn(d, t, i)                     \
     (mfn_to_gmfn(d, gnttab_shared_mfn(d, t, i)))
 
-#define gnttab_mark_dirty(d, f) mark_dirty((d), (f))
+#define gnttab_mark_dirty(d, f) paging_mark_dirty((d), (f))
 
 static inline void gnttab_clear_flag(unsigned long nr, uint16_t *addr)
 {
diff -r f1c6de438b83 -r 3d5f39c610ad xen/include/asm-x86/p2m.h
--- a/xen/include/asm-x86/p2m.h Mon Jun 11 11:37:10 2007 +0100
+++ b/xen/include/asm-x86/p2m.h Mon Jun 11 14:35:52 2007 +0100
@@ -129,6 +129,11 @@ void guest_physmap_remove_page(struct do
 void guest_physmap_remove_page(struct domain *d, unsigned long gfn,
                                unsigned long mfn);
 
+/* set P2M table l1e flags */
+void p2m_set_flags_global(struct domain *d, u32 l1e_flags);
+
+/* set P2M table l1e flags for a gpa */
+int p2m_set_flags(struct domain *d, paddr_t gpa, u32 l1e_flags);
 
 #endif /* _XEN_P2M_H */
 
diff -r f1c6de438b83 -r 3d5f39c610ad xen/include/asm-x86/paging.h
--- a/xen/include/asm-x86/paging.h      Mon Jun 11 11:37:10 2007 +0100
+++ b/xen/include/asm-x86/paging.h      Mon Jun 11 14:35:52 2007 +0100
@@ -62,6 +62,9 @@
 #define paging_mode_log_dirty(_d) ((_d)->arch.paging.mode & PG_log_dirty)
 #define paging_mode_translate(_d) ((_d)->arch.paging.mode & PG_translate)
 #define paging_mode_external(_d)  ((_d)->arch.paging.mode & PG_external)
+
+/* flags used for paging debug */
+#define PAGING_DEBUG_LOGDIRTY 0
 
 /******************************************************************************
  * The equivalent for a particular vcpu of a shadowed domain. */
@@ -136,6 +139,29 @@ struct paging_mode {
     struct shadow_paging_mode shadow;
 };
 
+/*****************************************************************************
+ * Log dirty code */
+
+/* allocate log dirty bitmap resource for recording dirty pages */
+int paging_alloc_log_dirty_bitmap(struct domain *d);
+
+/* free log dirty bitmap resource */
+void paging_free_log_dirty_bitmap(struct domain *d);
+
+/* enable log dirty */
+int paging_log_dirty_enable(struct domain *d);
+
+/* disable log dirty */
+int paging_log_dirty_disable(struct domain *d);
+
+/* log dirty initialization */
+void paging_log_dirty_init(struct domain *d,
+                           int  (*enable_log_dirty)(struct domain *d),
+                           int  (*disable_log_dirty)(struct domain *d),
+                           void (*clean_dirty_bitmap)(struct domain *d));
+
+/* mark a page as dirty */
+void paging_mark_dirty(struct domain *d, unsigned long guest_mfn);
 
 /*****************************************************************************
  * Entry points into the paging-assistance code */
diff -r f1c6de438b83 -r 3d5f39c610ad xen/include/asm-x86/shadow.h
--- a/xen/include/asm-x86/shadow.h      Mon Jun 11 11:37:10 2007 +0100
+++ b/xen/include/asm-x86/shadow.h      Mon Jun 11 14:35:52 2007 +0100
@@ -75,16 +75,14 @@ void shadow_teardown(struct domain *d);
 /* Call once all of the references to the domain have gone away */
 void shadow_final_teardown(struct domain *d);
 
-/* Mark a page as dirty in the log-dirty bitmap: called when Xen 
- * makes changes to guest memory on its behalf. */
-void sh_mark_dirty(struct domain *d, mfn_t gmfn);
-/* Cleaner version so we don't pepper shadow_mode tests all over the place */
-static inline void mark_dirty(struct domain *d, unsigned long gmfn)
-{
-    if ( unlikely(shadow_mode_log_dirty(d)) )
-        /* See the comment about locking in sh_mark_dirty */
-        sh_mark_dirty(d, _mfn(gmfn));
-}
+/* shadow code to call when log dirty is enabled */
+int shadow_enable_log_dirty(struct domain *d);
+
+/* shadow code to call when log dirty is disabled */
+int shadow_disable_log_dirty(struct domain *d);
+
+/* shadow code to call when bitmap is being cleaned */
+void shadow_clean_dirty_bitmap(struct domain *d);
 
 /* Update all the things that are derived from the guest's CR0/CR3/CR4.
  * Called to initialize paging structures if the paging mode

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