[RFC 5/8]KVM: rmap readonly pages

From: Shaohua Li
Date: Mon Jul 23 2007 - 02:59:51 EST


Make shadow page table rmap readonly pages.

Signed-off-by: Shaohua Li <shaohua.li@xxxxxxxxx>
---
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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/