Make shadow page table rmap readonly pages.

Signed-off-by: Shaohua Li <[EMAIL PROTECTED]>
---
 drivers/kvm/mmu.c         |   66 ++++++++++++++++++++++++++--------------------
 drivers/kvm/paging_tmpl.h |    2 -
 2 files changed, 39 insertions(+), 29 deletions(-)

Index: linux/drivers/kvm/mmu.c
===================================================================
--- linux.orig/drivers/kvm/mmu.c        2007-07-20 14:19:16.000000000 +0800
+++ linux/drivers/kvm/mmu.c     2007-07-20 14:25:25.000000000 +0800
@@ -23,6 +23,7 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/pagemap.h>
 #include <linux/highmem.h>
 #include <linux/module.h>
 
@@ -187,12 +188,6 @@ static int is_io_pte(unsigned long pte)
        return pte & PT_SHADOW_IO_MARK;
 }
 
-static int is_rmap_pte(u64 pte)
-{
-       return (pte & (PT_WRITABLE_MASK | PT_PRESENT_MASK))
-               == (PT_WRITABLE_MASK | PT_PRESENT_MASK);
-}
-
 static void set_shadow_pte(u64 *sptep, u64 spte)
 {
 #ifdef CONFIG_X86_64
@@ -326,12 +321,12 @@ static void rmap_add(struct kvm_vcpu *vc
        struct kvm_rmap_desc *desc;
        int i;
 
-       if (!is_rmap_pte(*spte))
-               return;
        page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT);
        if (!page_private(page)) {
                rmap_printk("rmap_add: %p %llx 0->1\n", spte, *spte);
                set_page_private(page,(unsigned long)spte);
+               SetPagePrivate(page);
+               page_cache_get(page);
        } else if (!(page_private(page) & 1)) {
                rmap_printk("rmap_add: %p %llx 1->many\n", spte, *spte);
                desc = mmu_alloc_rmap_desc(vcpu);
@@ -367,9 +362,13 @@ static void rmap_desc_remove_entry(struc
        desc->shadow_ptes[j] = NULL;
        if (j != 0)
                return;
-       if (!prev_desc && !desc->more)
+       if (!prev_desc && !desc->more) {
                set_page_private(page,(unsigned long)desc->shadow_ptes[0]);
-       else
+               if (page_private(page) == 0) {
+                       ClearPagePrivate(page);
+                       page_cache_release(page);
+               }
+       } else
                if (prev_desc)
                        prev_desc->more = desc->more;
                else
@@ -384,8 +383,6 @@ static void rmap_remove(struct kvm_vcpu 
        struct kvm_rmap_desc *prev_desc;
        int i;
 
-       if (!is_rmap_pte(*spte))
-               return;
        page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT);
        if (!page_private(page)) {
                printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte);
@@ -398,6 +395,8 @@ static void rmap_remove(struct kvm_vcpu 
                        BUG();
                }
                set_page_private(page,0);
+               ClearPagePrivate(page);
+               page_cache_release(page);
        } else {
                rmap_printk("rmap_remove:  %p %llx many->many\n", spte, *spte);
                desc = (struct kvm_rmap_desc *)(page_private(page) & ~1ul);
@@ -417,32 +416,44 @@ static void rmap_remove(struct kvm_vcpu 
        }
 }
 
+static void rmap_write_protect_one(struct kvm_vcpu *vcpu, u64 *spte,
+       struct page *page)
+{
+               BUG_ON(!spte);
+               BUG_ON((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT
+                      != page_to_pfn(page));
+               BUG_ON(!(*spte & PT_PRESENT_MASK));
+               rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
+               set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK);
+               kvm_flush_remote_tlbs(vcpu->kvm);
+}
+
 static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
 {
        struct kvm *kvm = vcpu->kvm;
        struct page *page;
        struct kvm_rmap_desc *desc;
        u64 *spte;
+       int i;
 
        page = gfn_to_page(kvm, gfn);
        BUG_ON(!page);
 
-       while (page_private(page)) {
-               if (!(page_private(page) & 1))
-                       spte = (u64 *)page_private(page);
-               else {
-                       desc = (struct kvm_rmap_desc *)(page_private(page) & 
~1ul);
-                       spte = desc->shadow_ptes[0];
+       if (!page_private(page))
+               return;
+
+       if (!(page_private(page) & 1)) {
+               spte = (u64 *)page_private(page);
+               rmap_write_protect_one(vcpu, spte, page);
+               return;
+       }
+       desc = (struct kvm_rmap_desc *)(page_private(page) & ~1ul);
+       while (desc) {
+               for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; i++) {
+                       spte = desc->shadow_ptes[i];
+                       rmap_write_protect_one(vcpu, spte, page);
                }
-               BUG_ON(!spte);
-               BUG_ON((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT
-                      != page_to_pfn(page));
-               BUG_ON(!(*spte & PT_PRESENT_MASK));
-               BUG_ON(!(*spte & PT_WRITABLE_MASK));
-               rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
-               rmap_remove(vcpu, spte);
-               set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK);
-               kvm_flush_remote_tlbs(vcpu->kvm);
+               desc = desc->more;
        }
 }
 
@@ -1291,7 +1302,6 @@ void kvm_mmu_slot_remove_write_access(st
                for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
                        /* avoid RMW */
                        if (pt[i] & PT_WRITABLE_MASK) {
-                               rmap_remove(vcpu, &pt[i]);
                                pt[i] &= ~PT_WRITABLE_MASK;
                        }
        }
Index: linux/drivers/kvm/paging_tmpl.h
===================================================================
--- linux.orig/drivers/kvm/paging_tmpl.h        2007-07-20 14:20:50.000000000 
+0800
+++ linux/drivers/kvm/paging_tmpl.h     2007-07-20 14:23:55.000000000 +0800
@@ -212,7 +212,7 @@ static void FNAME(set_pte_common)(struct
        hpa_t paddr;
        int dirty = gpte & PT_DIRTY_MASK;
        u64 spte = *shadow_pte;
-       int was_rmapped = is_rmap_pte(spte);
+       int was_rmapped = spte & PT_PRESENT_MASK;
 
        pgprintk("%s: spte %llx gpte %llx access %llx write_fault %d"
                 " user_fault %d gfn %lx\n",
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to