From mboxrd@z Thu Jan 1 00:00:00 1970 From: Marcelo Tosatti Subject: KVM: MMU: add KVM_ZAP_GFN ioctl Date: Wed, 12 Mar 2008 19:29:41 -0300 Message-ID: <20080312222941.GA30457@dmt> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Cc: kvm-devel To: Avi Kivity Return-path: Content-Disposition: inline List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: kvm-devel-bounces@lists.sourceforge.net Errors-To: kvm-devel-bounces@lists.sourceforge.net List-Id: kvm.vger.kernel.org Add an ioctl to zap all mappings to a given gfn. This allows userspace remove the QEMU process mappings and the page without causing inconsistency. Signed-off-by: Marcelo Tosatti diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index f0cdfba..c41464f 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -642,6 +642,67 @@ static void rmap_write_protect(struct kvm *kvm, u64 gfn) account_shadowed(kvm, gfn); } +static void rmap_nuke(struct kvm *kvm, u64 gfn) +{ + unsigned long *rmapp; + u64 *spte; + int nuked = 0; + + gfn = unalias_gfn(kvm, gfn); + rmapp = gfn_to_rmap(kvm, gfn, 0); + + spte = rmap_next(kvm, rmapp, NULL); + while (spte) { + BUG_ON(!spte); + BUG_ON(!(*spte & PT_PRESENT_MASK)); + rmap_printk("rmap_nuke: spte %p %llx\n", spte, *spte); + rmap_remove(kvm, spte); + set_shadow_pte(spte, shadow_trap_nonpresent_pte); + nuked = 1; + spte = rmap_next(kvm, rmapp, spte); + } + /* check for huge page mappings */ + rmapp = gfn_to_rmap(kvm, gfn, 1); + spte = rmap_next(kvm, rmapp, NULL); + while (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_nuke(large): spte %p %llx %lld\n", spte, *spte, gfn); + rmap_remove(kvm, spte); + --kvm->stat.lpages; + set_shadow_pte(spte, shadow_trap_nonpresent_pte); + nuked = 1; + spte = rmap_next(kvm, rmapp, spte); + } + + if (nuked) + kvm_flush_remote_tlbs(kvm); +} + +int kvm_zap_single_gfn(struct kvm *kvm, gfn_t gfn) +{ + unsigned long addr; + int have_mmu_notifiers = 0; + + down_read(&kvm->slots_lock); + addr = gfn_to_hva(kvm, gfn); + + if (kvm_is_error_hva(addr)) { + up_read(&kvm->slots_lock); + return -EINVAL; + } + + if (!have_mmu_notifiers) { + spin_lock(&kvm->mmu_lock); + rmap_nuke(kvm, gfn); + spin_unlock(&kvm->mmu_lock); + } + up_read(&kvm->slots_lock); + + return 0; +} + #ifdef MMU_DEBUG static int is_empty_shadow_page(u64 *spt) { diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index e65a9d6..d982ca1 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -816,6 +816,9 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_NR_MEMSLOTS: r = KVM_MEMORY_SLOTS; break; + case KVM_CAP_ZAP_GFN: + r = 1; + break; default: r = 0; break; @@ -1636,6 +1639,15 @@ long kvm_arch_vm_ioctl(struct file *filp, r = 0; break; } + case KVM_ZAP_GFN: { + gfn_t gfn; + + r = -EFAULT; + if (copy_from_user(&gfn, argp, sizeof gfn)) + goto out; + r = kvm_zap_single_gfn(kvm, gfn); + break; + } default: ; } diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h index 024b57c..4e45bd2 100644 --- a/include/asm-x86/kvm_host.h +++ b/include/asm-x86/kvm_host.h @@ -425,6 +425,7 @@ void kvm_mmu_set_nonpresent_ptes(u64 trap_pte, u64 notrap_pte); int kvm_mmu_reset_context(struct kvm_vcpu *vcpu); void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot); void kvm_mmu_zap_all(struct kvm *kvm); +int kvm_zap_single_gfn(struct kvm *kvm, gfn_t gfn); unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm); void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages); diff --git a/include/linux/kvm.h b/include/linux/kvm.h index e92e703..9ea714f 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -236,6 +236,7 @@ struct kvm_vapic_addr { #define KVM_CAP_CLOCKSOURCE 8 #define KVM_CAP_NR_VCPUS 9 /* returns max vcpus per vm */ #define KVM_CAP_NR_MEMSLOTS 10 /* returns max memory slots per vm */ +#define KVM_CAP_ZAP_GFN 11 /* * ioctls for VM fds @@ -258,6 +259,7 @@ struct kvm_vapic_addr { #define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level) #define KVM_GET_IRQCHIP _IOWR(KVMIO, 0x62, struct kvm_irqchip) #define KVM_SET_IRQCHIP _IOR(KVMIO, 0x63, struct kvm_irqchip) +#define KVM_ZAP_GFN _IOR(KVMIO, 0x64, unsigned long) /* * ioctls for vcpu fds ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/