diff options
author | Izik Eidus <izike@qumranet.com> | 2008-02-10 11:04:15 -0500 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-03-04 08:19:40 -0500 |
commit | 72dc67a69690288538142df73a7e3ac66fea68dc (patch) | |
tree | f40cc5ef0c66686a469977fd438e5b6786f16280 /arch/x86/kvm/x86.c | |
parent | c7ac679c160db864810920df61a6ed14275011aa (diff) |
KVM: remove the usage of the mmap_sem for the protection of the memory slots.
This patch replaces the mmap_sem lock for the memory slots with a new
kvm private lock, it is needed beacuse untill now there were cases where
kvm accesses user memory while holding the mmap semaphore.
Signed-off-by: Izik Eidus <izike@qumranet.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'arch/x86/kvm/x86.c')
-rw-r--r-- | arch/x86/kvm/x86.c | 65 |
1 files changed, 37 insertions, 28 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 338764fa5391..6b01552bd1f1 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -184,7 +184,7 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) | |||
184 | int ret; | 184 | int ret; |
185 | u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)]; | 185 | u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)]; |
186 | 186 | ||
187 | down_read(¤t->mm->mmap_sem); | 187 | down_read(&vcpu->kvm->slots_lock); |
188 | ret = kvm_read_guest_page(vcpu->kvm, pdpt_gfn, pdpte, | 188 | ret = kvm_read_guest_page(vcpu->kvm, pdpt_gfn, pdpte, |
189 | offset * sizeof(u64), sizeof(pdpte)); | 189 | offset * sizeof(u64), sizeof(pdpte)); |
190 | if (ret < 0) { | 190 | if (ret < 0) { |
@@ -201,7 +201,7 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) | |||
201 | 201 | ||
202 | memcpy(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs)); | 202 | memcpy(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs)); |
203 | out: | 203 | out: |
204 | up_read(¤t->mm->mmap_sem); | 204 | up_read(&vcpu->kvm->slots_lock); |
205 | 205 | ||
206 | return ret; | 206 | return ret; |
207 | } | 207 | } |
@@ -215,13 +215,13 @@ static bool pdptrs_changed(struct kvm_vcpu *vcpu) | |||
215 | if (is_long_mode(vcpu) || !is_pae(vcpu)) | 215 | if (is_long_mode(vcpu) || !is_pae(vcpu)) |
216 | return false; | 216 | return false; |
217 | 217 | ||
218 | down_read(¤t->mm->mmap_sem); | 218 | down_read(&vcpu->kvm->slots_lock); |
219 | r = kvm_read_guest(vcpu->kvm, vcpu->arch.cr3 & ~31u, pdpte, sizeof(pdpte)); | 219 | r = kvm_read_guest(vcpu->kvm, vcpu->arch.cr3 & ~31u, pdpte, sizeof(pdpte)); |
220 | if (r < 0) | 220 | if (r < 0) |
221 | goto out; | 221 | goto out; |
222 | changed = memcmp(pdpte, vcpu->arch.pdptrs, sizeof(pdpte)) != 0; | 222 | changed = memcmp(pdpte, vcpu->arch.pdptrs, sizeof(pdpte)) != 0; |
223 | out: | 223 | out: |
224 | up_read(¤t->mm->mmap_sem); | 224 | up_read(&vcpu->kvm->slots_lock); |
225 | 225 | ||
226 | return changed; | 226 | return changed; |
227 | } | 227 | } |
@@ -359,7 +359,7 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) | |||
359 | */ | 359 | */ |
360 | } | 360 | } |
361 | 361 | ||
362 | down_read(¤t->mm->mmap_sem); | 362 | down_read(&vcpu->kvm->slots_lock); |
363 | /* | 363 | /* |
364 | * Does the new cr3 value map to physical memory? (Note, we | 364 | * Does the new cr3 value map to physical memory? (Note, we |
365 | * catch an invalid cr3 even in real-mode, because it would | 365 | * catch an invalid cr3 even in real-mode, because it would |
@@ -375,7 +375,7 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) | |||
375 | vcpu->arch.cr3 = cr3; | 375 | vcpu->arch.cr3 = cr3; |
376 | vcpu->arch.mmu.new_cr3(vcpu); | 376 | vcpu->arch.mmu.new_cr3(vcpu); |
377 | } | 377 | } |
378 | up_read(¤t->mm->mmap_sem); | 378 | up_read(&vcpu->kvm->slots_lock); |
379 | } | 379 | } |
380 | EXPORT_SYMBOL_GPL(set_cr3); | 380 | EXPORT_SYMBOL_GPL(set_cr3); |
381 | 381 | ||
@@ -1232,12 +1232,12 @@ static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm, | |||
1232 | if (kvm_nr_mmu_pages < KVM_MIN_ALLOC_MMU_PAGES) | 1232 | if (kvm_nr_mmu_pages < KVM_MIN_ALLOC_MMU_PAGES) |
1233 | return -EINVAL; | 1233 | return -EINVAL; |
1234 | 1234 | ||
1235 | down_write(¤t->mm->mmap_sem); | 1235 | down_write(&kvm->slots_lock); |
1236 | 1236 | ||
1237 | kvm_mmu_change_mmu_pages(kvm, kvm_nr_mmu_pages); | 1237 | kvm_mmu_change_mmu_pages(kvm, kvm_nr_mmu_pages); |
1238 | kvm->arch.n_requested_mmu_pages = kvm_nr_mmu_pages; | 1238 | kvm->arch.n_requested_mmu_pages = kvm_nr_mmu_pages; |
1239 | 1239 | ||
1240 | up_write(¤t->mm->mmap_sem); | 1240 | up_write(&kvm->slots_lock); |
1241 | return 0; | 1241 | return 0; |
1242 | } | 1242 | } |
1243 | 1243 | ||
@@ -1286,7 +1286,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm, | |||
1286 | < alias->target_phys_addr) | 1286 | < alias->target_phys_addr) |
1287 | goto out; | 1287 | goto out; |
1288 | 1288 | ||
1289 | down_write(¤t->mm->mmap_sem); | 1289 | down_write(&kvm->slots_lock); |
1290 | 1290 | ||
1291 | p = &kvm->arch.aliases[alias->slot]; | 1291 | p = &kvm->arch.aliases[alias->slot]; |
1292 | p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT; | 1292 | p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT; |
@@ -1300,7 +1300,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm, | |||
1300 | 1300 | ||
1301 | kvm_mmu_zap_all(kvm); | 1301 | kvm_mmu_zap_all(kvm); |
1302 | 1302 | ||
1303 | up_write(¤t->mm->mmap_sem); | 1303 | up_write(&kvm->slots_lock); |
1304 | 1304 | ||
1305 | return 0; | 1305 | return 0; |
1306 | 1306 | ||
@@ -1376,7 +1376,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, | |||
1376 | struct kvm_memory_slot *memslot; | 1376 | struct kvm_memory_slot *memslot; |
1377 | int is_dirty = 0; | 1377 | int is_dirty = 0; |
1378 | 1378 | ||
1379 | down_write(¤t->mm->mmap_sem); | 1379 | down_write(&kvm->slots_lock); |
1380 | 1380 | ||
1381 | r = kvm_get_dirty_log(kvm, log, &is_dirty); | 1381 | r = kvm_get_dirty_log(kvm, log, &is_dirty); |
1382 | if (r) | 1382 | if (r) |
@@ -1392,7 +1392,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, | |||
1392 | } | 1392 | } |
1393 | r = 0; | 1393 | r = 0; |
1394 | out: | 1394 | out: |
1395 | up_write(¤t->mm->mmap_sem); | 1395 | up_write(&kvm->slots_lock); |
1396 | return r; | 1396 | return r; |
1397 | } | 1397 | } |
1398 | 1398 | ||
@@ -1570,7 +1570,7 @@ int emulator_read_std(unsigned long addr, | |||
1570 | void *data = val; | 1570 | void *data = val; |
1571 | int r = X86EMUL_CONTINUE; | 1571 | int r = X86EMUL_CONTINUE; |
1572 | 1572 | ||
1573 | down_read(¤t->mm->mmap_sem); | 1573 | down_read(&vcpu->kvm->slots_lock); |
1574 | while (bytes) { | 1574 | while (bytes) { |
1575 | gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); | 1575 | gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); |
1576 | unsigned offset = addr & (PAGE_SIZE-1); | 1576 | unsigned offset = addr & (PAGE_SIZE-1); |
@@ -1592,7 +1592,7 @@ int emulator_read_std(unsigned long addr, | |||
1592 | addr += tocopy; | 1592 | addr += tocopy; |
1593 | } | 1593 | } |
1594 | out: | 1594 | out: |
1595 | up_read(¤t->mm->mmap_sem); | 1595 | up_read(&vcpu->kvm->slots_lock); |
1596 | return r; | 1596 | return r; |
1597 | } | 1597 | } |
1598 | EXPORT_SYMBOL_GPL(emulator_read_std); | 1598 | EXPORT_SYMBOL_GPL(emulator_read_std); |
@@ -1611,9 +1611,9 @@ static int emulator_read_emulated(unsigned long addr, | |||
1611 | return X86EMUL_CONTINUE; | 1611 | return X86EMUL_CONTINUE; |
1612 | } | 1612 | } |
1613 | 1613 | ||
1614 | down_read(¤t->mm->mmap_sem); | 1614 | down_read(&vcpu->kvm->slots_lock); |
1615 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); | 1615 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); |
1616 | up_read(¤t->mm->mmap_sem); | 1616 | up_read(&vcpu->kvm->slots_lock); |
1617 | 1617 | ||
1618 | /* For APIC access vmexit */ | 1618 | /* For APIC access vmexit */ |
1619 | if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) | 1619 | if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) |
@@ -1651,14 +1651,14 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
1651 | { | 1651 | { |
1652 | int ret; | 1652 | int ret; |
1653 | 1653 | ||
1654 | down_read(¤t->mm->mmap_sem); | 1654 | down_read(&vcpu->kvm->slots_lock); |
1655 | ret = kvm_write_guest(vcpu->kvm, gpa, val, bytes); | 1655 | ret = kvm_write_guest(vcpu->kvm, gpa, val, bytes); |
1656 | if (ret < 0) { | 1656 | if (ret < 0) { |
1657 | up_read(¤t->mm->mmap_sem); | 1657 | up_read(&vcpu->kvm->slots_lock); |
1658 | return 0; | 1658 | return 0; |
1659 | } | 1659 | } |
1660 | kvm_mmu_pte_write(vcpu, gpa, val, bytes); | 1660 | kvm_mmu_pte_write(vcpu, gpa, val, bytes); |
1661 | up_read(¤t->mm->mmap_sem); | 1661 | up_read(&vcpu->kvm->slots_lock); |
1662 | return 1; | 1662 | return 1; |
1663 | } | 1663 | } |
1664 | 1664 | ||
@@ -1670,9 +1670,9 @@ static int emulator_write_emulated_onepage(unsigned long addr, | |||
1670 | struct kvm_io_device *mmio_dev; | 1670 | struct kvm_io_device *mmio_dev; |
1671 | gpa_t gpa; | 1671 | gpa_t gpa; |
1672 | 1672 | ||
1673 | down_read(¤t->mm->mmap_sem); | 1673 | down_read(&vcpu->kvm->slots_lock); |
1674 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); | 1674 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); |
1675 | up_read(¤t->mm->mmap_sem); | 1675 | up_read(&vcpu->kvm->slots_lock); |
1676 | 1676 | ||
1677 | if (gpa == UNMAPPED_GVA) { | 1677 | if (gpa == UNMAPPED_GVA) { |
1678 | kvm_inject_page_fault(vcpu, addr, 2); | 1678 | kvm_inject_page_fault(vcpu, addr, 2); |
@@ -1749,7 +1749,7 @@ static int emulator_cmpxchg_emulated(unsigned long addr, | |||
1749 | char *kaddr; | 1749 | char *kaddr; |
1750 | u64 val; | 1750 | u64 val; |
1751 | 1751 | ||
1752 | down_read(¤t->mm->mmap_sem); | 1752 | down_read(&vcpu->kvm->slots_lock); |
1753 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); | 1753 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); |
1754 | 1754 | ||
1755 | if (gpa == UNMAPPED_GVA || | 1755 | if (gpa == UNMAPPED_GVA || |
@@ -1760,13 +1760,17 @@ static int emulator_cmpxchg_emulated(unsigned long addr, | |||
1760 | goto emul_write; | 1760 | goto emul_write; |
1761 | 1761 | ||
1762 | val = *(u64 *)new; | 1762 | val = *(u64 *)new; |
1763 | |||
1764 | down_read(¤t->mm->mmap_sem); | ||
1763 | page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); | 1765 | page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); |
1766 | up_read(¤t->mm->mmap_sem); | ||
1767 | |||
1764 | kaddr = kmap_atomic(page, KM_USER0); | 1768 | kaddr = kmap_atomic(page, KM_USER0); |
1765 | set_64bit((u64 *)(kaddr + offset_in_page(gpa)), val); | 1769 | set_64bit((u64 *)(kaddr + offset_in_page(gpa)), val); |
1766 | kunmap_atomic(kaddr, KM_USER0); | 1770 | kunmap_atomic(kaddr, KM_USER0); |
1767 | kvm_release_page_dirty(page); | 1771 | kvm_release_page_dirty(page); |
1768 | emul_write: | 1772 | emul_write: |
1769 | up_read(¤t->mm->mmap_sem); | 1773 | up_read(&vcpu->kvm->slots_lock); |
1770 | } | 1774 | } |
1771 | #endif | 1775 | #endif |
1772 | 1776 | ||
@@ -2159,10 +2163,10 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | |||
2159 | kvm_x86_ops->skip_emulated_instruction(vcpu); | 2163 | kvm_x86_ops->skip_emulated_instruction(vcpu); |
2160 | 2164 | ||
2161 | for (i = 0; i < nr_pages; ++i) { | 2165 | for (i = 0; i < nr_pages; ++i) { |
2162 | down_read(¤t->mm->mmap_sem); | 2166 | down_read(&vcpu->kvm->slots_lock); |
2163 | page = gva_to_page(vcpu, address + i * PAGE_SIZE); | 2167 | page = gva_to_page(vcpu, address + i * PAGE_SIZE); |
2164 | vcpu->arch.pio.guest_pages[i] = page; | 2168 | vcpu->arch.pio.guest_pages[i] = page; |
2165 | up_read(¤t->mm->mmap_sem); | 2169 | up_read(&vcpu->kvm->slots_lock); |
2166 | if (!page) { | 2170 | if (!page) { |
2167 | kvm_inject_gp(vcpu, 0); | 2171 | kvm_inject_gp(vcpu, 0); |
2168 | free_pio_guest_pages(vcpu); | 2172 | free_pio_guest_pages(vcpu); |
@@ -2485,8 +2489,9 @@ static void vapic_enter(struct kvm_vcpu *vcpu) | |||
2485 | 2489 | ||
2486 | down_read(¤t->mm->mmap_sem); | 2490 | down_read(¤t->mm->mmap_sem); |
2487 | page = gfn_to_page(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT); | 2491 | page = gfn_to_page(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT); |
2488 | vcpu->arch.apic->vapic_page = page; | ||
2489 | up_read(¤t->mm->mmap_sem); | 2492 | up_read(¤t->mm->mmap_sem); |
2493 | |||
2494 | vcpu->arch.apic->vapic_page = page; | ||
2490 | } | 2495 | } |
2491 | 2496 | ||
2492 | static void vapic_exit(struct kvm_vcpu *vcpu) | 2497 | static void vapic_exit(struct kvm_vcpu *vcpu) |
@@ -2959,9 +2964,9 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, | |||
2959 | gpa_t gpa; | 2964 | gpa_t gpa; |
2960 | 2965 | ||
2961 | vcpu_load(vcpu); | 2966 | vcpu_load(vcpu); |
2962 | down_read(¤t->mm->mmap_sem); | 2967 | down_read(&vcpu->kvm->slots_lock); |
2963 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, vaddr); | 2968 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, vaddr); |
2964 | up_read(¤t->mm->mmap_sem); | 2969 | up_read(&vcpu->kvm->slots_lock); |
2965 | tr->physical_address = gpa; | 2970 | tr->physical_address = gpa; |
2966 | tr->valid = gpa != UNMAPPED_GVA; | 2971 | tr->valid = gpa != UNMAPPED_GVA; |
2967 | tr->writeable = 1; | 2972 | tr->writeable = 1; |
@@ -3234,11 +3239,13 @@ int kvm_arch_set_memory_region(struct kvm *kvm, | |||
3234 | */ | 3239 | */ |
3235 | if (!user_alloc) { | 3240 | if (!user_alloc) { |
3236 | if (npages && !old.rmap) { | 3241 | if (npages && !old.rmap) { |
3242 | down_write(¤t->mm->mmap_sem); | ||
3237 | memslot->userspace_addr = do_mmap(NULL, 0, | 3243 | memslot->userspace_addr = do_mmap(NULL, 0, |
3238 | npages * PAGE_SIZE, | 3244 | npages * PAGE_SIZE, |
3239 | PROT_READ | PROT_WRITE, | 3245 | PROT_READ | PROT_WRITE, |
3240 | MAP_SHARED | MAP_ANONYMOUS, | 3246 | MAP_SHARED | MAP_ANONYMOUS, |
3241 | 0); | 3247 | 0); |
3248 | up_write(¤t->mm->mmap_sem); | ||
3242 | 3249 | ||
3243 | if (IS_ERR((void *)memslot->userspace_addr)) | 3250 | if (IS_ERR((void *)memslot->userspace_addr)) |
3244 | return PTR_ERR((void *)memslot->userspace_addr); | 3251 | return PTR_ERR((void *)memslot->userspace_addr); |
@@ -3246,8 +3253,10 @@ int kvm_arch_set_memory_region(struct kvm *kvm, | |||
3246 | if (!old.user_alloc && old.rmap) { | 3253 | if (!old.user_alloc && old.rmap) { |
3247 | int ret; | 3254 | int ret; |
3248 | 3255 | ||
3256 | down_write(¤t->mm->mmap_sem); | ||
3249 | ret = do_munmap(current->mm, old.userspace_addr, | 3257 | ret = do_munmap(current->mm, old.userspace_addr, |
3250 | old.npages * PAGE_SIZE); | 3258 | old.npages * PAGE_SIZE); |
3259 | up_write(¤t->mm->mmap_sem); | ||
3251 | if (ret < 0) | 3260 | if (ret < 0) |
3252 | printk(KERN_WARNING | 3261 | printk(KERN_WARNING |
3253 | "kvm_vm_ioctl_set_memory_region: " | 3262 | "kvm_vm_ioctl_set_memory_region: " |