KVM: MMU: rmap_write_protect() hugepage iteration bug

Marcelo Tosatti
2008-06-08T00:28:08Z

rmap_next() expects the "spte" argument to be NULL whenever there's only
one remaining entry in the descriptor. That is, it was not designed to
handle changes in the chain while iterating.

This bug cripples rmap_write_protect() so that it won't nuke all
writable large mappings to a particular gfn.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>

diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index aaccc40..e11ff17 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -632,17 +632,19 @@ static void rmap_write_protect(struct kvm *kvm, u64 gfn)
rmapp = gfn_to_rmap(kvm, gfn, 1);
spte = rmap_next(kvm, rmapp, NULL);
while (spte) {
+ u64 *next_spte;
BUG_ON(!spte);
BUG_ON(!(*spte & PT_PRESENT_MASK));
BUG_ON((*spte & (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK)) != (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK));
pgprintk("rmap_write_protect(large): spte %p %llx %lld\n", spte, *spte, gfn);
+ next_spte = rmap_next(kvm, rmapp, spte);
if (is_writeble_pte(*spte)) {
rmap_remove(kvm, spte);
--kvm->stat.lpages;
set_shadow_pte(spte, shadow_trap_nonpresent_pte);
write_protected = 1;
}
- spte = rmap_next(kvm, rmapp, spte);
+ spte = next_spte;
}

if (write_protected)