Marcelo Tosatti wrote: > 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. > >
I'm thinking of comitting rmap_nuke() to kvm.git, and the rest to the external module, since this is only needed on kernels without mmu notifiers. Andrea, is rmap_nuke() suitable for the mmu notifiers pte clear callback? Oh, and a single gfn may have multiple hvas, so we need to iterate over something here. > Signed-off-by: Marcelo Tosatti <[EMAIL PROTECTED]> > > > 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/ > _______________________________________________ > kvm-devel mailing list > kvm-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/kvm-devel > -- error compiling committee.c: too many arguments to function ------------------------------------------------------------------------- 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/ _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel