replace the slots lock from the mmap_sem to private kvm lock
PATCH 1/1 replace the slots lock from the mmap_sem to private kvm lock
right now kvm take the down_read(mmap_sem) lock to make sure that no slots will be removed while trying to get them / make the dirty log safe,
but in some cases when the down_read(mmap_sem) is called and after that kvm_read_guest() is called copy_from_user can result in a page fault that will lead to recursivly taking the mmap_sem,
this patch remove the mmap_sem, with new kvm private lock.
Signature · 1 line
woof.
Quoted 1 line
From
17ab59f76968731a1dc1067fc07d637b5c52e3daMon Sep 17 00:00:00 2001
From: Izik Eidus <[email protected]>
Date: Sun, 10 Feb 2008 18:04:15 +0200
Subject: [PATCH] KVM: remove the usage of the mmap_sem for the protection of the memory slots.
this patch replace the mmap_sem lock for the memory slots with a new kvm private lock,
it is needed beacuse untill now there were cases where the down_read for the mmap_sem can be called recursivly.
(for example when doing copy_to_user() unpresent memory that will result in pagefault)
--- arch/x86/kvm/mmu.c | 24 +++++++++++++--- arch/x86/kvm/paging_tmpl.h | 13 ++++++--- arch/x86/kvm/vmx.c | 7 +++- arch/x86/kvm/x86.c | 65 +++++++++++++++++++++++++------------------- include/linux/kvm_host.h | 1 + virt/kvm/kvm_main.c | 7 +++- 6 files changed, 76 insertions(+), 41 deletions(-)
arch/x86/kvm/mmu.c +19 -5
@@ -868,11 +868,18 @@ static void page_header_update_slot(struct kvm *kvm, void *pte, gfn_t gfn)struct page *gva_to_page (struct kvm_vcpu *vcpu,gva_t gva) { +struct page *page; +gpa_t gpa = vcpu->arch.mmu.gva_to_gpa (vcpu, gva);if (gpa ==UNMAPPED_GVA )return NULL ; -return gfn_to_page (vcpu->kvm, gpa >>PAGE_SHIFT ); + +down_read (¤t->mm->mmap_sem); + page =gfn_to_page (vcpu->kvm, gpa >>PAGE_SHIFT ); +up_read (¤t->mm->mmap_sem); + +return page; } static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
@@ -1005,13 +1012,16 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn)struct page *page; +down_read (&vcpu->kvm->slots_lock); +down_read (¤t->mm->mmap_sem); page =gfn_to_page (vcpu->kvm, gfn); +up_read (¤t->mm->mmap_sem);/* mmio */ if (is_error_page (page)) {kvm_release_page_clean (page); -up_read (¤t->mm->mmap_sem); +up_read (&vcpu->kvm->slots_lock);return 1 ; }
@@ -1020,7 +1030,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn) r =__nonpaging_map (vcpu, v, write, gfn, page);spin_unlock (&vcpu->kvm->mmu_lock); -up_read (¤t->mm->mmap_sem); +up_read (&vcpu->kvm->slots_lock);return r; }
@@ -1381,7 +1391,11 @@ static void mmu_guess_page_from_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,if (!is_present_pte (gpte))return ; gfn = (gpte &PT64_BASE_ADDR_MASK ) >>PAGE_SHIFT ; + +down_read (¤t->mm->mmap_sem); page =gfn_to_page (vcpu->kvm, gfn); +up_read (¤t->mm->mmap_sem); +if (is_error_page (page)) {kvm_release_page_clean (page);return ;
@@ -1503,9 +1517,9 @@ int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva)gpa_t gpa;int r; -down_read (¤t->mm->mmap_sem); +down_read (&vcpu->kvm->slots_lock); gpa = vcpu->arch.mmu.gva_to_gpa (vcpu, gva); -up_read (¤t->mm->mmap_sem); +up_read (&vcpu->kvm->slots_lock);spin_lock (&vcpu->kvm->mmu_lock); r =kvm_mmu_unprotect_page (vcpu->kvm, gpa >>PAGE_SHIFT );
arch/x86/kvm/paging_tmpl.h +9 -4
@@ -91,7 +91,10 @@ static bool FNAME(cmpxchg_gpte)(struct kvm *kvm,pt_element_t *table;struct page *page; +down_read (¤t->mm->mmap_sem); page =gfn_to_page (kvm, table_gfn); +up_read (¤t->mm->mmap_sem); + table =kmap_atomic (page,KM_USER0 ); ret =CMPXCHG (&table[index], orig_pte, new_pte);
@@ -375,7 +378,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,if (r)return r; -down_read (¤t->mm->mmap_sem); +down_read (&vcpu->kvm->slots_lock);/* * Look up the shadow pte for the faulting address. */
@@ -389,17 +392,19 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,pgprintk ("%s: guest page fault\n" , __FUNCTION__);inject_page_fault (vcpu, addr, walker.error_code); vcpu->arch.last_pt_write_count =0 ;/* reset fork detector */ -up_read (¤t->mm->mmap_sem); +up_read (&vcpu->kvm->slots_lock);return 0 ; } +down_read (¤t->mm->mmap_sem); page =gfn_to_page (vcpu->kvm, walker.gfn); +up_read (¤t->mm->mmap_sem);/* mmio */ if (is_error_page (page)) {pgprintk ("gfn %x is mmio\n" , walker.gfn);kvm_release_page_clean (page); -up_read (¤t->mm->mmap_sem); +up_read (&vcpu->kvm->slots_lock);return 1 ; }
@@ -416,7 +421,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, ++vcpu->stat.pf_fixed;kvm_mmu_audit (vcpu,"post page fault (fixed)" );spin_unlock (&vcpu->kvm->mmu_lock); -up_read (¤t->mm->mmap_sem); +up_read (&vcpu->kvm->slots_lock);return write_pt; }
arch/x86/kvm/vmx.c +5 -2
@@ -1519,7 +1519,7 @@ static int alloc_apic_access_page(struct kvm *kvm)struct kvm_userspace_memory_region kvm_userspace_mem;int r =0 ; -down_write (¤t->mm->mmap_sem); +down_write (&kvm->slots_lock);if (kvm->arch.apic_access_page) goto out; kvm_userspace_mem.slot =APIC_ACCESS_PAGE_PRIVATE_MEMSLOT ;
@@ -1529,9 +1529,12 @@ static int alloc_apic_access_page(struct kvm *kvm) r =__kvm_set_memory_region (kvm, &kvm_userspace_mem,0 );if (r) goto out; + +down_read (¤t->mm->mmap_sem); kvm->arch.apic_access_page =gfn_to_page (kvm,0xfee00 ); +up_read (¤t->mm->mmap_sem); out: -up_write (¤t->mm->mmap_sem); +up_write (&kvm->slots_lock);return r; }
arch/x86/kvm/x86.c +37 -28
230 lines not on this page · raw message
include/linux/kvm_host.h +1 -0
@@ -109,6 +109,7 @@ struct kvm_memory_slot {struct kvm {struct mutex lock;/* protects the vcpus array and APIC accesses */ spinlock_t mmu_lock; +struct rw_semaphore slots_lock;struct mm_struct *mm;/* userspace tied to this vm */ int nmemslots; struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS +
virt/kvm/kvm_main.c +5 -2
@@ -169,6 +169,7 @@ static struct kvm *kvm_create_vm(void)kvm_io_bus_init (&kvm->pio_bus);mutex_init (&kvm->lock);kvm_io_bus_init (&kvm->mmio_bus); +init_rwsem (&kvm->slots_lock);spin_lock (&kvm_lock);list_add (&kvm->vm_list, &vm_list);spin_unlock (&kvm_lock);
@@ -339,9 +340,9 @@ int kvm_set_memory_region(struct kvm *kvm, {int r; -down_write (¤t->mm->mmap_sem); +down_write (&kvm->slots_lock); r =__kvm_set_memory_region (kvm, mem, user_alloc); -up_write (¤t->mm->mmap_sem); +up_write (&kvm->slots_lock);return r; }EXPORT_SYMBOL_GPL (kvm_set_memory_region);
@@ -989,7 +990,9 @@ static int kvm_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)if (!kvm_is_visible_gfn (kvm, vmf->pgoff))return VM_FAULT_SIGBUS ; + page =gfn_to_page (kvm, vmf->pgoff); +if (is_error_page (page)) {kvm_release_page_clean (page);return VM_FAULT_SIGBUS ;
Signature · 1 line
1.5.3.6
-------------------------------------------------------------------------
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel
Quoted 9 lines · Izik Eidus
right now kvm take the
down_read(mmap_sem)lock to make sure that no slots will be
removed while trying to get them / make the dirty log safe, but in some cases when thedown_read(mmap_sem)is called and after thatkvm_read_guest()is calledcopy_from_usercan result in a page fault that will lead to recursivly taking themmap_sem,this patch remove the
mmap_sem, with new kvm private lock.
Hi Izik,
do_mmap/do_munmap requires the mmap_sem in write-mode.
I couldnt find any sequence which grabs mmap_sem and then slots_lock, but it would be nice to verify again that can't happen.
Other than that looks good.
-------------------------------------------------------------------------
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/
Quoted 10 lines · Marcelo Tosatti
Quoted 8 lines · Izik Eidus
right now kvm take the
down_read(mmap_sem)lock to make sure that no slots will be
removed while trying to get them / make the dirty log safe, but in some cases when thedown_read(mmap_sem)is called and after thatkvm_read_guest()is calledcopy_from_usercan result in a page fault that will lead to recursivly taking themmap_sem,
Quoted 7 lines
Quoted 2 lines
this patch remove the
mmap_sem, with new kvm private lock.Hi Izik,
do_mmap/do_munmap requires the
mmap_semin write-mode.
right, i missed it
Quoted 3 lines
I couldnt find any sequence which grabs
mmap_semand thenslots_lock, but it would be nice to verify again that can't happen.
sure
Quoted 3 lines
Other than that looks good.
thanks
Signature · 7 lines
woof. ------------------------------------------------------------------------- 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/