diff options
Diffstat (limited to 'drivers/kvm/kvm_main.c')
-rw-r--r-- | drivers/kvm/kvm_main.c | 81 |
1 files changed, 70 insertions, 11 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index a1983d2d5b8f..22b143feb66d 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/anon_inodes.h> | 40 | #include <linux/anon_inodes.h> |
41 | #include <linux/profile.h> | 41 | #include <linux/profile.h> |
42 | #include <linux/kvm_para.h> | 42 | #include <linux/kvm_para.h> |
43 | #include <linux/pagemap.h> | ||
43 | 44 | ||
44 | #include <asm/processor.h> | 45 | #include <asm/processor.h> |
45 | #include <asm/msr.h> | 46 | #include <asm/msr.h> |
@@ -300,19 +301,40 @@ static struct kvm *kvm_create_vm(void) | |||
300 | return kvm; | 301 | return kvm; |
301 | } | 302 | } |
302 | 303 | ||
304 | static void kvm_free_userspace_physmem(struct kvm_memory_slot *free) | ||
305 | { | ||
306 | int i; | ||
307 | |||
308 | for (i = 0; i < free->npages; ++i) { | ||
309 | if (free->phys_mem[i]) { | ||
310 | if (!PageReserved(free->phys_mem[i])) | ||
311 | SetPageDirty(free->phys_mem[i]); | ||
312 | page_cache_release(free->phys_mem[i]); | ||
313 | } | ||
314 | } | ||
315 | } | ||
316 | |||
317 | static void kvm_free_kernel_physmem(struct kvm_memory_slot *free) | ||
318 | { | ||
319 | int i; | ||
320 | |||
321 | for (i = 0; i < free->npages; ++i) | ||
322 | if (free->phys_mem[i]) | ||
323 | __free_page(free->phys_mem[i]); | ||
324 | } | ||
325 | |||
303 | /* | 326 | /* |
304 | * Free any memory in @free but not in @dont. | 327 | * Free any memory in @free but not in @dont. |
305 | */ | 328 | */ |
306 | static void kvm_free_physmem_slot(struct kvm_memory_slot *free, | 329 | static void kvm_free_physmem_slot(struct kvm_memory_slot *free, |
307 | struct kvm_memory_slot *dont) | 330 | struct kvm_memory_slot *dont) |
308 | { | 331 | { |
309 | int i; | ||
310 | |||
311 | if (!dont || free->phys_mem != dont->phys_mem) | 332 | if (!dont || free->phys_mem != dont->phys_mem) |
312 | if (free->phys_mem) { | 333 | if (free->phys_mem) { |
313 | for (i = 0; i < free->npages; ++i) | 334 | if (free->user_alloc) |
314 | if (free->phys_mem[i]) | 335 | kvm_free_userspace_physmem(free); |
315 | __free_page(free->phys_mem[i]); | 336 | else |
337 | kvm_free_kernel_physmem(free); | ||
316 | vfree(free->phys_mem); | 338 | vfree(free->phys_mem); |
317 | } | 339 | } |
318 | if (!dont || free->rmap != dont->rmap) | 340 | if (!dont || free->rmap != dont->rmap) |
@@ -652,7 +674,9 @@ EXPORT_SYMBOL_GPL(fx_init); | |||
652 | * Discontiguous memory is allowed, mostly for framebuffers. | 674 | * Discontiguous memory is allowed, mostly for framebuffers. |
653 | */ | 675 | */ |
654 | static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, | 676 | static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, |
655 | struct kvm_memory_region *mem) | 677 | struct |
678 | kvm_userspace_memory_region *mem, | ||
679 | int user_alloc) | ||
656 | { | 680 | { |
657 | int r; | 681 | int r; |
658 | gfn_t base_gfn; | 682 | gfn_t base_gfn; |
@@ -728,11 +752,27 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, | |||
728 | 752 | ||
729 | memset(new.phys_mem, 0, npages * sizeof(struct page *)); | 753 | memset(new.phys_mem, 0, npages * sizeof(struct page *)); |
730 | memset(new.rmap, 0, npages * sizeof(*new.rmap)); | 754 | memset(new.rmap, 0, npages * sizeof(*new.rmap)); |
731 | for (i = 0; i < npages; ++i) { | 755 | if (user_alloc) { |
732 | new.phys_mem[i] = alloc_page(GFP_HIGHUSER | 756 | unsigned long pages_num; |
733 | | __GFP_ZERO); | 757 | |
734 | if (!new.phys_mem[i]) | 758 | new.user_alloc = 1; |
759 | down_read(¤t->mm->mmap_sem); | ||
760 | |||
761 | pages_num = get_user_pages(current, current->mm, | ||
762 | mem->userspace_addr, | ||
763 | npages, 1, 1, new.phys_mem, | ||
764 | NULL); | ||
765 | |||
766 | up_read(¤t->mm->mmap_sem); | ||
767 | if (pages_num != npages) | ||
735 | goto out_unlock; | 768 | goto out_unlock; |
769 | } else { | ||
770 | for (i = 0; i < npages; ++i) { | ||
771 | new.phys_mem[i] = alloc_page(GFP_HIGHUSER | ||
772 | | __GFP_ZERO); | ||
773 | if (!new.phys_mem[i]) | ||
774 | goto out_unlock; | ||
775 | } | ||
736 | } | 776 | } |
737 | } | 777 | } |
738 | 778 | ||
@@ -3108,11 +3148,29 @@ static long kvm_vm_ioctl(struct file *filp, | |||
3108 | break; | 3148 | break; |
3109 | case KVM_SET_MEMORY_REGION: { | 3149 | case KVM_SET_MEMORY_REGION: { |
3110 | struct kvm_memory_region kvm_mem; | 3150 | struct kvm_memory_region kvm_mem; |
3151 | struct kvm_userspace_memory_region kvm_userspace_mem; | ||
3111 | 3152 | ||
3112 | r = -EFAULT; | 3153 | r = -EFAULT; |
3113 | if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem)) | 3154 | if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem)) |
3114 | goto out; | 3155 | goto out; |
3115 | r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_mem); | 3156 | kvm_userspace_mem.slot = kvm_mem.slot; |
3157 | kvm_userspace_mem.flags = kvm_mem.flags; | ||
3158 | kvm_userspace_mem.guest_phys_addr = kvm_mem.guest_phys_addr; | ||
3159 | kvm_userspace_mem.memory_size = kvm_mem.memory_size; | ||
3160 | r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 0); | ||
3161 | if (r) | ||
3162 | goto out; | ||
3163 | break; | ||
3164 | } | ||
3165 | case KVM_SET_USER_MEMORY_REGION: { | ||
3166 | struct kvm_userspace_memory_region kvm_userspace_mem; | ||
3167 | |||
3168 | r = -EFAULT; | ||
3169 | if (copy_from_user(&kvm_userspace_mem, argp, | ||
3170 | sizeof kvm_userspace_mem)) | ||
3171 | goto out; | ||
3172 | |||
3173 | r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 1); | ||
3116 | if (r) | 3174 | if (r) |
3117 | goto out; | 3175 | goto out; |
3118 | break; | 3176 | break; |
@@ -3332,6 +3390,7 @@ static long kvm_dev_ioctl(struct file *filp, | |||
3332 | case KVM_CAP_IRQCHIP: | 3390 | case KVM_CAP_IRQCHIP: |
3333 | case KVM_CAP_HLT: | 3391 | case KVM_CAP_HLT: |
3334 | case KVM_CAP_MMU_SHADOW_CACHE_CONTROL: | 3392 | case KVM_CAP_MMU_SHADOW_CACHE_CONTROL: |
3393 | case KVM_CAP_USER_MEMORY: | ||
3335 | r = 1; | 3394 | r = 1; |
3336 | break; | 3395 | break; |
3337 | default: | 3396 | default: |