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

[Xen-changelog] [xen-unstable] shadow: drop guest VRAM write access after some idleness



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1210248945 -3600
# Node ID 0ac957f9d42e778565e745d7b6dc55bd527c8e90
# Parent  fe625fd796f8de4cf09cba6b7bd0c7e8438e2552
shadow: drop guest VRAM write access after some idleness

If the video RAM has been kept clean for at least 2 seconds, we can
afford taking the time to drop guest write access, which allows us to
save the dirty bit scanning entirely until we get a guest page handle.

From: Samuel Thibault <samuel.thibault@xxxxxxxxxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
 xen/arch/x86/mm/shadow/common.c  |   53 +++++++++++++++++++++++++++++----------
 xen/arch/x86/mm/shadow/multi.c   |   15 ++++++++++-
 xen/arch/x86/mm/shadow/private.h |    1 
 3 files changed, 55 insertions(+), 14 deletions(-)

diff -r fe625fd796f8 -r 0ac957f9d42e xen/arch/x86/mm/shadow/common.c
--- a/xen/arch/x86/mm/shadow/common.c   Thu May 08 13:14:27 2008 +0100
+++ b/xen/arch/x86/mm/shadow/common.c   Thu May 08 13:15:45 2008 +0100
@@ -2869,6 +2869,8 @@ int shadow_track_dirty_vram(struct domai
     unsigned long end_pfn = begin_pfn + nr;
     unsigned long dirty_size = (nr + 7) / 8;
     int flush_tlb = 0;
+    unsigned long i;
+    p2m_type_t t;
 
     if (end_pfn < begin_pfn
             || begin_pfn > d->arch.p2m->max_mapped_pfn
@@ -2879,7 +2881,8 @@ int shadow_track_dirty_vram(struct domai
 
     if ( d->dirty_vram && (!nr ||
              ( begin_pfn != d->dirty_vram->begin_pfn
-            || end_pfn   != d->dirty_vram->end_pfn )) ) {
+            || end_pfn   != d->dirty_vram->end_pfn )) )
+    {
         /* Different tracking, tear the previous down. */
         gdprintk(XENLOG_INFO, "stopping tracking VRAM %lx - %lx\n", 
d->dirty_vram->begin_pfn, d->dirty_vram->end_pfn);
         xfree(d->dirty_vram->sl1ma);
@@ -2888,17 +2891,16 @@ int shadow_track_dirty_vram(struct domai
         d->dirty_vram = NULL;
     }
 
-    if ( !nr ) {
+    if ( !nr )
+    {
         rc = 0;
         goto out;
     }
 
     /* This should happen seldomly (Video mode change),
      * no need to be careful. */
-    if ( !d->dirty_vram ) {
-        unsigned long i;
-        p2m_type_t t;
-
+    if ( !d->dirty_vram )
+    {
         /* Just recount from start. */
         for ( i = begin_pfn; i < end_pfn; i++ )
             flush_tlb |= sh_remove_all_mappings(d->vcpu[0], gfn_to_mfn(d, i, 
&t));
@@ -2919,10 +2921,20 @@ int shadow_track_dirty_vram(struct domai
             goto out_sl1ma;
         memset(d->dirty_vram->dirty_bitmap, 0, dirty_size);
 
+        d->dirty_vram->last_dirty = NOW();
+
         /* Tell the caller that this time we could not track dirty bits. */
         rc = -ENODATA;
-    } else {
-        int i;
+    }
+    else if (d->dirty_vram->last_dirty == -1)
+    {
+        /* still completely clean, just copy our empty bitmap */
+        rc = -EFAULT;
+        if ( copy_to_guest(dirty_bitmap, d->dirty_vram->dirty_bitmap, 
dirty_size) == 0 )
+            rc = 0;
+    }
+    else
+    {
 #ifdef __i386__
         unsigned long map_mfn = INVALID_MFN;
         void *map_sl1p = NULL;
@@ -2930,26 +2942,29 @@ int shadow_track_dirty_vram(struct domai
 
         /* Iterate over VRAM to track dirty bits. */
         for ( i = 0; i < nr; i++ ) {
-            p2m_type_t t;
             mfn_t mfn = gfn_to_mfn(d, begin_pfn + i, &t);
             struct page_info *page = mfn_to_page(mfn);
             u32 count_info = page->u.inuse.type_info & PGT_count_mask;
             int dirty = 0;
             paddr_t sl1ma = d->dirty_vram->sl1ma[i];
 
-            switch (count_info) {
+            switch (count_info)
+            {
             case 0:
                 /* No guest reference, nothing to track. */
                 break;
             case 1:
                 /* One guest reference. */
-                if ( sl1ma == INVALID_PADDR ) {
+                if ( sl1ma == INVALID_PADDR )
+                {
                     /* We don't know which sl1e points to this, too bad. */
                     dirty = 1;
                     /* TODO: Heuristics for finding the single mapping of
                      * this gmfn */
                     flush_tlb |= sh_remove_all_mappings(d->vcpu[0], 
gfn_to_mfn(d, begin_pfn + i, &t));
-                } else {
+                }
+                else
+                {
                     /* Hopefully the most common case: only one mapping,
                      * whose dirty bit we can use. */
                     l1_pgentry_t *sl1e;
@@ -2968,7 +2983,8 @@ int shadow_track_dirty_vram(struct domai
                     sl1e = maddr_to_virt(sl1ma);
 #endif
 
-                    if ( l1e_get_flags(*sl1e) & _PAGE_DIRTY ) {
+                    if ( l1e_get_flags(*sl1e) & _PAGE_DIRTY )
+                    {
                         dirty = 1;
                         /* Note: this is atomic, so we may clear a
                          * _PAGE_ACCESSED set by another processor. */
@@ -2985,7 +3001,10 @@ int shadow_track_dirty_vram(struct domai
             }
 
             if ( dirty )
+            {
                 d->dirty_vram->dirty_bitmap[i / 8] |= 1 << (i % 8);
+                d->dirty_vram->last_dirty = NOW();
+            }
         }
 
 #ifdef __i386__
@@ -2996,6 +3015,14 @@ int shadow_track_dirty_vram(struct domai
         rc = -EFAULT;
         if ( copy_to_guest(dirty_bitmap, d->dirty_vram->dirty_bitmap, 
dirty_size) == 0 ) {
             memset(d->dirty_vram->dirty_bitmap, 0, dirty_size);
+            if (d->dirty_vram->last_dirty + SECONDS(2) < NOW())
+            {
+                /* was clean for more than two seconds, try to disable guest
+                 * write access */
+                for ( i = begin_pfn; i < end_pfn; i++ )
+                    flush_tlb |= sh_remove_write_access(d->vcpu[0], 
gfn_to_mfn(d, i, &t), 1, 0);
+                d->dirty_vram->last_dirty = -1;
+            }
             rc = 0;
         }
     }
diff -r fe625fd796f8 -r 0ac957f9d42e xen/arch/x86/mm/shadow/multi.c
--- a/xen/arch/x86/mm/shadow/multi.c    Thu May 08 13:14:27 2008 +0100
+++ b/xen/arch/x86/mm/shadow/multi.c    Thu May 08 13:15:45 2008 +0100
@@ -870,6 +870,17 @@ _sh_propagate(struct vcpu *v,
         }
     }
 
+    if ( unlikely((level == 1) && d->dirty_vram
+            && d->dirty_vram->last_dirty == -1
+            && gfn_x(target_gfn) >= d->dirty_vram->begin_pfn
+            && gfn_x(target_gfn) < d->dirty_vram->end_pfn) )
+    {
+        if ( ft & FETCH_TYPE_WRITE )
+            d->dirty_vram->last_dirty = NOW();
+        else
+            sflags &= ~_PAGE_RW;
+    }
+
     /* Read-only memory */
     if ( p2mt == p2m_ram_ro ) 
         sflags &= ~_PAGE_RW;
@@ -1320,8 +1331,10 @@ static inline void shadow_vram_put_l1e(s
                  * just hope it will remain. */
             }
         }
-        if ( dirty )
+        if ( dirty ) {
             d->dirty_vram->dirty_bitmap[i / 8] |= 1 << (i % 8);
+            d->dirty_vram->last_dirty = NOW();
+        }
     }
 }
 
diff -r fe625fd796f8 -r 0ac957f9d42e xen/arch/x86/mm/shadow/private.h
--- a/xen/arch/x86/mm/shadow/private.h  Thu May 08 13:14:27 2008 +0100
+++ b/xen/arch/x86/mm/shadow/private.h  Thu May 08 13:15:45 2008 +0100
@@ -536,6 +536,7 @@ struct sh_dirty_vram {
     unsigned long end_pfn;
     paddr_t *sl1ma;
     uint8_t *dirty_bitmap;
+    s_time_t last_dirty;
 };
 
 /**************************************************************************/

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