unalias rework
PATCH 1/1 unalias rework
Quoted 1 line
From
476d23f08738de2396134f5ef41923ad54994972Mon Sep 17 00:00:00 2001
From: izike <izike@izike-laptop.(none)>
Date: Thu, 4 Sep 2008 17:10:04 +0300
Subject: [PATCH] KVM: unalias rework
beside make the code less complecated it actually fix bug related to aliased pages inside the shadow code that treated as not aliased.
--- arch/ia64/include/asm/kvm_host.h | 1 + arch/ia64/kvm/kvm-ia64.c | 5 -- arch/s390/include/asm/kvm_host.h | 1 + arch/s390/kvm/kvm-s390.c | 5 -- arch/x86/kvm/mmu.c | 5 +-- arch/x86/kvm/vmx.c | 2 +- arch/x86/kvm/vmx.h | 8 +++- arch/x86/kvm/x86.c | 69 ++++++++++++++++------------- include/asm-x86/kvm_host.h | 9 ---- include/linux/kvm_host.h | 4 +- virt/kvm/kvm_main.c | 87 +++++++++++++++++++++++++++++-------- 11 files changed, 118 insertions(+), 78 deletions(-)
arch/ia64/include/asm/kvm_host.h +1 -0
@@ -35,6 +35,7 @@#define KVM_MAX_VCPUS 4#define KVM_MEMORY_SLOTS 32 +#define KVM_ALIAS_SLOTS 0/* memory slots that does not exposed to userspace */ #define KVM_PRIVATE_MEM_SLOTS 4
arch/ia64/kvm/kvm-ia64.c +0 -5
@@ -1782,11 +1782,6 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)return 0 ; } -gfn_t unalias_gfn (struct kvm *kvm,gfn_t gfn) -{ -return gfn; -} -int kvm_arch_vcpu_runnable (struct kvm_vcpu *vcpu) {return vcpu->arch.mp_state ==KVM_MP_STATE_RUNNABLE ;
arch/s390/include/asm/kvm_host.h +1 -0
@@ -18,6 +18,7 @@#define KVM_MAX_VCPUS 64#define KVM_MEMORY_SLOTS 32 +#define KVM_ALIAS_SLOTS 0/* memory slots that does not exposed to userspace */ #define KVM_PRIVATE_MEM_SLOTS 4
arch/s390/kvm/kvm-s390.c +0 -5
@@ -684,11 +684,6 @@ void kvm_arch_flush_shadow(struct kvm *kvm) { } -gfn_t unalias_gfn (struct kvm *kvm,gfn_t gfn) -{ -return gfn; -} -static int __init kvm_s390_init (void ) {return kvm_init (NULL ,sizeof (struct kvm_vcpu ),THIS_MODULE );
arch/x86/kvm/mmu.c +1 -4
@@ -436,7 +436,6 @@ static int is_largepage_backed(struct kvm_vcpu *vcpu, gfn_t large_gfn)/* * Take gfn and return the reverse mapping to it. -* Note: gfn must be unaliased before this function get called */ static unsigned long *gfn_to_rmap (struct kvm *kvm,gfn_t gfn,int lpage)
@@ -472,7 +471,6 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn, int lpage)if (!is_rmap_pte (*spte))return ; - gfn =unalias_gfn (vcpu->kvm, gfn); sp =page_header (__pa (spte)); sp->gfns[spte - sp->spt] = gfn; rmapp =gfn_to_rmap (vcpu->kvm, gfn, lpage);
@@ -607,7 +605,6 @@ static void rmap_write_protect(struct kvm *kvm, u64 gfn)u64 *spte;int write_protected =0 ; - gfn =unalias_gfn (kvm, gfn); rmapp =gfn_to_rmap (kvm, gfn,0 ); spte =rmap_next (kvm, rmapp,NULL );
@@ -2505,7 +2502,7 @@ static void audit_write_protection(struct kvm_vcpu *vcpu)continue ; slot =gfn_to_memslot (vcpu->kvm, sp->gfn); - gfn =unalias_gfn (vcpu->kvm, sp->gfn); + gfn = sp->gfn; rmapp = &slot->rmap[gfn - slot->base_gfn];if (*rmapp) printk(KERN_ERR "%s: (%s) shadow page has writable"
arch/x86/kvm/vmx.c +1 -1
@@ -2407,7 +2407,7 @@ static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr) {int ret;struct kvm_userspace_memory_region tss_mem = { - .slot =8 , + .slot =TSS_PRIVATE_MEMSLOT , .guest_phys_addr = addr, .memory_size =PAGE_SIZE *3 , .flags =0 ,
arch/x86/kvm/vmx.h +6 -2
@@ -349,8 +349,12 @@ enum vmcs_field {#define IA32_FEATURE_CONTROL_LOCKED_BIT 0x1#define IA32_FEATURE_CONTROL_VMXON_ENABLED_BIT 0x4 -#define APIC_ACCESS_PAGE_PRIVATE_MEMSLOT 9 -#define IDENTITY_PAGETABLE_PRIVATE_MEMSLOT 10 +#define TSS_PRIVATE_MEMSLOT KVM_MEMORY_SLOTS + \ + KVM_ALIAS_SLOTS +#define APIC_ACCESS_PAGE_PRIVATE_MEMSLOT KVM_MEMORY_SLOTS + \ + KVM_ALIAS_SLOTS + 1 +#define IDENTITY_PAGETABLE_PRIVATE_MEMSLOT KVM_MEMORY_SLOTS + \ + KVM_ALIAS_SLOTS + 2#define VMX_NR_VPIDS (1 << 16)#define VMX_VPID_EXTENT_SINGLE_CONTEXT 1
arch/x86/kvm/x86.c +38 -31
109 lines not on this page · raw message
include/asm-x86/kvm_host.h +0 -9
@@ -325,12 +325,6 @@ struct kvm_vcpu_arch {u64 mtrr[0x100 ]; }; -struct kvm_mem_alias { -gfn_t base_gfn; -unsigned long npages; -gfn_t target_gfn; -}; -struct kvm_irq_ack_notifier {struct hlist_node link;unsigned gsi;
@@ -352,9 +346,6 @@ struct kvm_assigned_dev_kernel { };struct kvm_arch { -int naliases; -struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS ]; -unsigned int n_free_mmu_pages;unsigned int n_requested_mmu_pages;unsigned int n_alloc_mmu_pages;
include/linux/kvm_host.h +2 -2
@@ -109,7 +109,8 @@ struct kvm {struct mm_struct *mm;/* userspace tied to this vm */ int nmemslots;struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS + -KVM_PRIVATE_MEM_SLOTS ]; +KVM_PRIVATE_MEM_SLOTS + +KVM_ALIAS_SLOTS ];struct kvm_vcpu *vcpus[KVM_MAX_VCPUS ];struct list_head vm_list;struct kvm_io_bus mmio_bus;
@@ -175,7 +176,6 @@ int kvm_arch_set_memory_region(struct kvm *kvm,struct kvm_memory_slot old, int user_alloc);void kvm_arch_flush_shadow (struct kvm *kvm); -gfn_t unalias_gfn (struct kvm *kvm,gfn_t gfn);struct page *gfn_to_page (struct kvm *kvm,gfn_t gfn);unsigned long gfn_to_hva (struct kvm *kvm,gfn_t gfn);void kvm_release_page_clean (struct page *page);
virt/kvm/kvm_main.c +68 -19
161 lines not on this page · raw message
Signature · 1 line
1.5.4.3
Hi Izik,
Quoted 57 lines · izik eidus
virt/kvm/kvm_main.c +44
-2+struct kvm_memory_slot *alias_slot = &kvm->memslots[i]; + +if (alias_slot->base_gfn == slot->base_gfn) +return 1 ; + } +return 0 ; +} + +static void update_alias_slots (struct kvm *kvm,struct kvm_memory_slot *free) +{ +int i; + +if (is_aliased_slot (kvm, free)) +return ; + +for (i =KVM_MEMORY_SLOTS ; i <KVM_MEMORY_SLOTS +KVM_ALIAS_SLOTS ; + ++i) { +struct kvm_memory_slot *alias_memslot = &kvm->memslots[i]; +unsigned long size = free->npages <<PAGE_SHIFT ; + +if (alias_memslot->userspace_addr >= free->userspace_addr && + alias_memslot->userspace_addr < free->userspace_addr + + size) { + alias_memslot->flags = free->flags; +if (free->dirty_bitmap) { +unsigned long offset = + alias_memslot->userspace_addr - + free->userspace_addr; +unsigned dirty_offset; +unsigned long bitmap_addr; + + offset = offset >>PAGE_SHIFT ; + dirty_offset =ALIGN (offset,BITS_PER_LONG ) /8 ; + bitmap_addr = (unsigned long ) free->dirty_bitmap; + bitmap_addr += dirty_offset; + alias_memslot->dirty_bitmap = (unsigned long *) bitmap_addr; + }else + alias_memslot->dirty_bitmap =NULL ; + } + } +} +/* * Free any memory in @free but not in @dont. */ -static void kvm_free_physmem_slot (struct kvm_memory_slot *free, +static void kvm_free_physmem_slot (struct kvm *kvm, +struct kvm_memory_slot *free,struct kvm_memory_slot *dont) {if (!dont || free->rmap != dont->rmap)@@ -385,10 +433,16 @@ static void kvm_free_physmem_slot(struct kvm_memory_slot *free,if (!dont || free->lpage_info != dont->lpage_info)vfree (free->lpage_info); - free->npages =0 ;
virt/kvm/kvm_main.c static void kvm_free_physmem_slot(struct kvm_memory_slot *free, · line 445
Quoted 10 lines
virt/kvm/kvm_main.c +7
-0free->dirty_bitmap =NULL ; free->rmap =NULL ; free->lpage_info =NULL ; + +#ifdef CONFIG_X86 +update_alias_slots (kvm, free); +if (dont) +update_alias_slots (kvm, dont); +#endif + free->npages =0 ;
Why is this needed? I don't understand when would you free a memslot without freeing any aliases that map it first?
Quoted 59 lines · Marcelo Tosatti
Hi Izik,
Quoted 55 lines · izik eidus
virt/kvm/kvm_main.c +44
-1+struct kvm_memory_slot *alias_slot = &kvm->memslots[i]; + +if (alias_slot->base_gfn == slot->base_gfn) +return 1 ; + } +return 0 ; +} + +static void update_alias_slots (struct kvm *kvm,struct kvm_memory_slot *free) +{ +int i; + +if (is_aliased_slot (kvm, free)) +return ; + +for (i =KVM_MEMORY_SLOTS ; i <KVM_MEMORY_SLOTS +KVM_ALIAS_SLOTS ; + ++i) { +struct kvm_memory_slot *alias_memslot = &kvm->memslots[i]; +unsigned long size = free->npages <<PAGE_SHIFT ; + +if (alias_memslot->userspace_addr >= free->userspace_addr && + alias_memslot->userspace_addr < free->userspace_addr + + size) { + alias_memslot->flags = free->flags; +if (free->dirty_bitmap) { +unsigned long offset = + alias_memslot->userspace_addr - + free->userspace_addr; +unsigned dirty_offset; +unsigned long bitmap_addr; + + offset = offset >>PAGE_SHIFT ; + dirty_offset =ALIGN (offset,BITS_PER_LONG ) /8 ; + bitmap_addr = (unsigned long ) free->dirty_bitmap; + bitmap_addr += dirty_offset; + alias_memslot->dirty_bitmap = (unsigned long *) bitmap_addr; + }else + alias_memslot->dirty_bitmap =NULL ; + } + } +} +/* * Free any memory in @free but not in @dont. */ -static void kvm_free_physmem_slot (struct kvm_memory_slot *free, +static void kvm_free_physmem_slot (struct kvm *kvm, +struct kvm_memory_slot *free,struct kvm_memory_slot *dont) {if (!dont || free->rmap != dont->rmap)@@ -385,10 +433,16 @@ static void kvm_free_physmem_slot(struct kvm_memory_slot *free,if (!dont || free->lpage_info != dont->lpage_info)vfree (free->lpage_info);
Quoted 17 lines
virt/kvm/kvm_main.c static void kvm_free_physmem_slot(struct kvm_memory_slot *free, · line 447
Quoted 12 lines
virt/kvm/kvm_main.c +7
-1- free->npages =0 ; free->dirty_bitmap =NULL ; free->rmap =NULL ; free->lpage_info =NULL ; + +#ifdef CONFIG_X86 +update_alias_slots (kvm, free); +if (dont) +update_alias_slots (kvm, dont); +#endif + free->npages =0 ;Why is this needed? I don't understand when would you free a memslot without freeing any aliases that map it first?
beacuse in case of dont != NULL, we actually dont free the memslot...
Quoted 59 lines · Marcelo Tosatti
Hi Izik,
Quoted 55 lines · izik eidus
virt/kvm/kvm_main.c +44
-1+struct kvm_memory_slot *alias_slot = &kvm->memslots[i]; + +if (alias_slot->base_gfn == slot->base_gfn) +return 1 ; + } +return 0 ; +} + +static void update_alias_slots (struct kvm *kvm,struct kvm_memory_slot *free) +{ +int i; + +if (is_aliased_slot (kvm, free)) +return ; + +for (i =KVM_MEMORY_SLOTS ; i <KVM_MEMORY_SLOTS +KVM_ALIAS_SLOTS ; + ++i) { +struct kvm_memory_slot *alias_memslot = &kvm->memslots[i]; +unsigned long size = free->npages <<PAGE_SHIFT ; + +if (alias_memslot->userspace_addr >= free->userspace_addr && + alias_memslot->userspace_addr < free->userspace_addr + + size) { + alias_memslot->flags = free->flags; +if (free->dirty_bitmap) { +unsigned long offset = + alias_memslot->userspace_addr - + free->userspace_addr; +unsigned dirty_offset; +unsigned long bitmap_addr; + + offset = offset >>PAGE_SHIFT ; + dirty_offset =ALIGN (offset,BITS_PER_LONG ) /8 ; + bitmap_addr = (unsigned long ) free->dirty_bitmap; + bitmap_addr += dirty_offset; + alias_memslot->dirty_bitmap = (unsigned long *) bitmap_addr; + }else + alias_memslot->dirty_bitmap =NULL ; + } + } +} +/* * Free any memory in @free but not in @dont. */ -static void kvm_free_physmem_slot (struct kvm_memory_slot *free, +static void kvm_free_physmem_slot (struct kvm *kvm, +struct kvm_memory_slot *free,struct kvm_memory_slot *dont) {if (!dont || free->rmap != dont->rmap)@@ -385,10 +433,16 @@ static void kvm_free_physmem_slot(struct kvm_memory_slot *free,if (!dont || free->lpage_info != dont->lpage_info)vfree (free->lpage_info);
Quoted 17 lines
virt/kvm/kvm_main.c static void kvm_free_physmem_slot(struct kvm_memory_slot *free, · line 447
Quoted 12 lines
virt/kvm/kvm_main.c +7
-1- free->npages =0 ; free->dirty_bitmap =NULL ; free->rmap =NULL ; free->lpage_info =NULL ; + +#ifdef CONFIG_X86 +update_alias_slots (kvm, free); +if (dont) +update_alias_slots (kvm, dont); +#endif + free->npages =0 ;Why is this needed? I don't understand when would you free a memslot without freeing any aliases that map it first?
(sent it already, but for some reason it didnt reach to the mailing list) beacuse in case of dont != NULL, we actually dont free the memslot...