aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm/kvm_main.c
diff options
context:
space:
mode:
authorIzik Eidus <avi@qumranet.com>2007-10-18 05:09:33 -0400
committerAvi Kivity <avi@qumranet.com>2008-01-30 10:52:54 -0500
commit8a7ae055f3533b520401c170ac55e30628b34df5 (patch)
treef9654746dc92fa18ef66e49e12537dc6cb1d32e6 /drivers/kvm/kvm_main.c
parentcea7bb21280e3a825e64b54740edc5d3e6e4193c (diff)
KVM: MMU: Partial swapping of guest memory
This allows guest memory to be swapped. Pages which are currently mapped via shadow page tables are pinned into memory, but all other pages can be freely swapped. The patch makes gfn_to_page() elevate the page's reference count, and introduces kvm_release_page() that pairs with it. Signed-off-by: Izik Eidus <izike@qumranet.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/kvm_main.c')
-rw-r--r--drivers/kvm/kvm_main.c83
1 files changed, 46 insertions, 37 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 47000be25479..f86a47c2f255 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -300,19 +300,6 @@ static struct kvm *kvm_create_vm(void)
300 return kvm; 300 return kvm;
301} 301}
302 302
303static void kvm_free_userspace_physmem(struct kvm_memory_slot *free)
304{
305 int i;
306
307 for (i = 0; i < free->npages; ++i) {
308 if (free->phys_mem[i]) {
309 if (!PageReserved(free->phys_mem[i]))
310 SetPageDirty(free->phys_mem[i]);
311 page_cache_release(free->phys_mem[i]);
312 }
313 }
314}
315
316static void kvm_free_kernel_physmem(struct kvm_memory_slot *free) 303static void kvm_free_kernel_physmem(struct kvm_memory_slot *free)
317{ 304{
318 int i; 305 int i;
@@ -330,9 +317,7 @@ static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
330{ 317{
331 if (!dont || free->phys_mem != dont->phys_mem) 318 if (!dont || free->phys_mem != dont->phys_mem)
332 if (free->phys_mem) { 319 if (free->phys_mem) {
333 if (free->user_alloc) 320 if (!free->user_alloc)
334 kvm_free_userspace_physmem(free);
335 else
336 kvm_free_kernel_physmem(free); 321 kvm_free_kernel_physmem(free);
337 vfree(free->phys_mem); 322 vfree(free->phys_mem);
338 } 323 }
@@ -361,7 +346,7 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
361 346
362 for (i = 0; i < ARRAY_SIZE(vcpu->pio.guest_pages); ++i) 347 for (i = 0; i < ARRAY_SIZE(vcpu->pio.guest_pages); ++i)
363 if (vcpu->pio.guest_pages[i]) { 348 if (vcpu->pio.guest_pages[i]) {
364 __free_page(vcpu->pio.guest_pages[i]); 349 kvm_release_page(vcpu->pio.guest_pages[i]);
365 vcpu->pio.guest_pages[i] = NULL; 350 vcpu->pio.guest_pages[i] = NULL;
366 } 351 }
367} 352}
@@ -752,19 +737,8 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
752 memset(new.phys_mem, 0, npages * sizeof(struct page *)); 737 memset(new.phys_mem, 0, npages * sizeof(struct page *));
753 memset(new.rmap, 0, npages * sizeof(*new.rmap)); 738 memset(new.rmap, 0, npages * sizeof(*new.rmap));
754 if (user_alloc) { 739 if (user_alloc) {
755 unsigned long pages_num;
756
757 new.user_alloc = 1; 740 new.user_alloc = 1;
758 down_read(&current->mm->mmap_sem); 741 new.userspace_addr = mem->userspace_addr;
759
760 pages_num = get_user_pages(current, current->mm,
761 mem->userspace_addr,
762 npages, 1, 1, new.phys_mem,
763 NULL);
764
765 up_read(&current->mm->mmap_sem);
766 if (pages_num != npages)
767 goto out_unlock;
768 } else { 742 } else {
769 for (i = 0; i < npages; ++i) { 743 for (i = 0; i < npages; ++i) {
770 new.phys_mem[i] = alloc_page(GFP_HIGHUSER 744 new.phys_mem[i] = alloc_page(GFP_HIGHUSER
@@ -1039,12 +1013,39 @@ struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
1039 1013
1040 gfn = unalias_gfn(kvm, gfn); 1014 gfn = unalias_gfn(kvm, gfn);
1041 slot = __gfn_to_memslot(kvm, gfn); 1015 slot = __gfn_to_memslot(kvm, gfn);
1042 if (!slot) 1016 if (!slot) {
1017 get_page(bad_page);
1043 return bad_page; 1018 return bad_page;
1019 }
1020 if (slot->user_alloc) {
1021 struct page *page[1];
1022 int npages;
1023
1024 down_read(&current->mm->mmap_sem);
1025 npages = get_user_pages(current, current->mm,
1026 slot->userspace_addr
1027 + (gfn - slot->base_gfn) * PAGE_SIZE, 1,
1028 1, 1, page, NULL);
1029 up_read(&current->mm->mmap_sem);
1030 if (npages != 1) {
1031 get_page(bad_page);
1032 return bad_page;
1033 }
1034 return page[0];
1035 }
1036 get_page(slot->phys_mem[gfn - slot->base_gfn]);
1044 return slot->phys_mem[gfn - slot->base_gfn]; 1037 return slot->phys_mem[gfn - slot->base_gfn];
1045} 1038}
1046EXPORT_SYMBOL_GPL(gfn_to_page); 1039EXPORT_SYMBOL_GPL(gfn_to_page);
1047 1040
1041void kvm_release_page(struct page *page)
1042{
1043 if (!PageReserved(page))
1044 SetPageDirty(page);
1045 put_page(page);
1046}
1047EXPORT_SYMBOL_GPL(kvm_release_page);
1048
1048static int next_segment(unsigned long len, int offset) 1049static int next_segment(unsigned long len, int offset)
1049{ 1050{
1050 if (len > PAGE_SIZE - offset) 1051 if (len > PAGE_SIZE - offset)
@@ -1060,13 +1061,16 @@ int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset,
1060 struct page *page; 1061 struct page *page;
1061 1062
1062 page = gfn_to_page(kvm, gfn); 1063 page = gfn_to_page(kvm, gfn);
1063 if (is_error_page(page)) 1064 if (is_error_page(page)) {
1065 kvm_release_page(page);
1064 return -EFAULT; 1066 return -EFAULT;
1067 }
1065 page_virt = kmap_atomic(page, KM_USER0); 1068 page_virt = kmap_atomic(page, KM_USER0);
1066 1069
1067 memcpy(data, page_virt + offset, len); 1070 memcpy(data, page_virt + offset, len);
1068 1071
1069 kunmap_atomic(page_virt, KM_USER0); 1072 kunmap_atomic(page_virt, KM_USER0);
1073 kvm_release_page(page);
1070 return 0; 1074 return 0;
1071} 1075}
1072EXPORT_SYMBOL_GPL(kvm_read_guest_page); 1076EXPORT_SYMBOL_GPL(kvm_read_guest_page);
@@ -1098,14 +1102,17 @@ int kvm_write_guest_page(struct kvm *kvm, gfn_t gfn, const void *data,
1098 struct page *page; 1102 struct page *page;
1099 1103
1100 page = gfn_to_page(kvm, gfn); 1104 page = gfn_to_page(kvm, gfn);
1101 if (is_error_page(page)) 1105 if (is_error_page(page)) {
1106 kvm_release_page(page);
1102 return -EFAULT; 1107 return -EFAULT;
1108 }
1103 page_virt = kmap_atomic(page, KM_USER0); 1109 page_virt = kmap_atomic(page, KM_USER0);
1104 1110
1105 memcpy(page_virt + offset, data, len); 1111 memcpy(page_virt + offset, data, len);
1106 1112
1107 kunmap_atomic(page_virt, KM_USER0); 1113 kunmap_atomic(page_virt, KM_USER0);
1108 mark_page_dirty(kvm, gfn); 1114 mark_page_dirty(kvm, gfn);
1115 kvm_release_page(page);
1109 return 0; 1116 return 0;
1110} 1117}
1111EXPORT_SYMBOL_GPL(kvm_write_guest_page); 1118EXPORT_SYMBOL_GPL(kvm_write_guest_page);
@@ -1136,13 +1143,16 @@ int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len)
1136 struct page *page; 1143 struct page *page;
1137 1144
1138 page = gfn_to_page(kvm, gfn); 1145 page = gfn_to_page(kvm, gfn);
1139 if (is_error_page(page)) 1146 if (is_error_page(page)) {
1147 kvm_release_page(page);
1140 return -EFAULT; 1148 return -EFAULT;
1149 }
1141 page_virt = kmap_atomic(page, KM_USER0); 1150 page_virt = kmap_atomic(page, KM_USER0);
1142 1151
1143 memset(page_virt + offset, 0, len); 1152 memset(page_virt + offset, 0, len);
1144 1153
1145 kunmap_atomic(page_virt, KM_USER0); 1154 kunmap_atomic(page_virt, KM_USER0);
1155 kvm_release_page(page);
1146 return 0; 1156 return 0;
1147} 1157}
1148EXPORT_SYMBOL_GPL(kvm_clear_guest_page); 1158EXPORT_SYMBOL_GPL(kvm_clear_guest_page);
@@ -2070,8 +2080,6 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
2070 for (i = 0; i < nr_pages; ++i) { 2080 for (i = 0; i < nr_pages; ++i) {
2071 mutex_lock(&vcpu->kvm->lock); 2081 mutex_lock(&vcpu->kvm->lock);
2072 page = gva_to_page(vcpu, address + i * PAGE_SIZE); 2082 page = gva_to_page(vcpu, address + i * PAGE_SIZE);
2073 if (page)
2074 get_page(page);
2075 vcpu->pio.guest_pages[i] = page; 2083 vcpu->pio.guest_pages[i] = page;
2076 mutex_unlock(&vcpu->kvm->lock); 2084 mutex_unlock(&vcpu->kvm->lock);
2077 if (!page) { 2085 if (!page) {
@@ -3074,9 +3082,10 @@ static struct page *kvm_vm_nopage(struct vm_area_struct *vma,
3074 3082
3075 pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; 3083 pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
3076 page = gfn_to_page(kvm, pgoff); 3084 page = gfn_to_page(kvm, pgoff);
3077 if (is_error_page(page)) 3085 if (is_error_page(page)) {
3086 kvm_release_page(page);
3078 return NOPAGE_SIGBUS; 3087 return NOPAGE_SIGBUS;
3079 get_page(page); 3088 }
3080 if (type != NULL) 3089 if (type != NULL)
3081 *type = VM_FAULT_MINOR; 3090 *type = VM_FAULT_MINOR;
3082 3091