aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kvm/mmu.c4
-rw-r--r--include/linux/kvm_host.h1
-rw-r--r--virt/kvm/kvm_main.c28
3 files changed, 28 insertions, 5 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index d8d48329cb82..89d7a2cae53b 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -2078,7 +2078,9 @@ static int kvm_handle_bad_page(struct kvm *kvm, gfn_t gfn, pfn_t pfn)
2078 if (is_hwpoison_pfn(pfn)) { 2078 if (is_hwpoison_pfn(pfn)) {
2079 kvm_send_hwpoison_signal(kvm, gfn); 2079 kvm_send_hwpoison_signal(kvm, gfn);
2080 return 0; 2080 return 0;
2081 } 2081 } else if (is_fault_pfn(pfn))
2082 return -EFAULT;
2083
2082 return 1; 2084 return 1;
2083} 2085}
2084 2086
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index e796326f3646..8055067b6bec 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -269,6 +269,7 @@ extern pfn_t bad_pfn;
269int is_error_page(struct page *page); 269int is_error_page(struct page *page);
270int is_error_pfn(pfn_t pfn); 270int is_error_pfn(pfn_t pfn);
271int is_hwpoison_pfn(pfn_t pfn); 271int is_hwpoison_pfn(pfn_t pfn);
272int is_fault_pfn(pfn_t pfn);
272int kvm_is_error_hva(unsigned long addr); 273int kvm_is_error_hva(unsigned long addr);
273int kvm_set_memory_region(struct kvm *kvm, 274int kvm_set_memory_region(struct kvm *kvm,
274 struct kvm_userspace_memory_region *mem, 275 struct kvm_userspace_memory_region *mem,
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 630d1224f187..b78b794c1039 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -96,6 +96,9 @@ static bool largepages_enabled = true;
96static struct page *hwpoison_page; 96static struct page *hwpoison_page;
97static pfn_t hwpoison_pfn; 97static pfn_t hwpoison_pfn;
98 98
99static struct page *fault_page;
100static pfn_t fault_pfn;
101
99inline int kvm_is_mmio_pfn(pfn_t pfn) 102inline int kvm_is_mmio_pfn(pfn_t pfn)
100{ 103{
101 if (pfn_valid(pfn)) { 104 if (pfn_valid(pfn)) {
@@ -815,13 +818,13 @@ EXPORT_SYMBOL_GPL(kvm_disable_largepages);
815 818
816int is_error_page(struct page *page) 819int is_error_page(struct page *page)
817{ 820{
818 return page == bad_page || page == hwpoison_page; 821 return page == bad_page || page == hwpoison_page || page == fault_page;
819} 822}
820EXPORT_SYMBOL_GPL(is_error_page); 823EXPORT_SYMBOL_GPL(is_error_page);
821 824
822int is_error_pfn(pfn_t pfn) 825int is_error_pfn(pfn_t pfn)
823{ 826{
824 return pfn == bad_pfn || pfn == hwpoison_pfn; 827 return pfn == bad_pfn || pfn == hwpoison_pfn || pfn == fault_pfn;
825} 828}
826EXPORT_SYMBOL_GPL(is_error_pfn); 829EXPORT_SYMBOL_GPL(is_error_pfn);
827 830
@@ -831,6 +834,12 @@ int is_hwpoison_pfn(pfn_t pfn)
831} 834}
832EXPORT_SYMBOL_GPL(is_hwpoison_pfn); 835EXPORT_SYMBOL_GPL(is_hwpoison_pfn);
833 836
837int is_fault_pfn(pfn_t pfn)
838{
839 return pfn == fault_pfn;
840}
841EXPORT_SYMBOL_GPL(is_fault_pfn);
842
834static inline unsigned long bad_hva(void) 843static inline unsigned long bad_hva(void)
835{ 844{
836 return PAGE_OFFSET; 845 return PAGE_OFFSET;
@@ -959,8 +968,8 @@ static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr)
959 if (vma == NULL || addr < vma->vm_start || 968 if (vma == NULL || addr < vma->vm_start ||
960 !(vma->vm_flags & VM_PFNMAP)) { 969 !(vma->vm_flags & VM_PFNMAP)) {
961 up_read(&current->mm->mmap_sem); 970 up_read(&current->mm->mmap_sem);
962 get_page(bad_page); 971 get_page(fault_page);
963 return page_to_pfn(bad_page); 972 return page_to_pfn(fault_page);
964 } 973 }
965 974
966 pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; 975 pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
@@ -2226,6 +2235,15 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
2226 2235
2227 hwpoison_pfn = page_to_pfn(hwpoison_page); 2236 hwpoison_pfn = page_to_pfn(hwpoison_page);
2228 2237
2238 fault_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
2239
2240 if (fault_page == NULL) {
2241 r = -ENOMEM;
2242 goto out_free_0;
2243 }
2244
2245 fault_pfn = page_to_pfn(fault_page);
2246
2229 if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) { 2247 if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) {
2230 r = -ENOMEM; 2248 r = -ENOMEM;
2231 goto out_free_0; 2249 goto out_free_0;
@@ -2298,6 +2316,8 @@ out_free_1:
2298out_free_0a: 2316out_free_0a:
2299 free_cpumask_var(cpus_hardware_enabled); 2317 free_cpumask_var(cpus_hardware_enabled);
2300out_free_0: 2318out_free_0:
2319 if (fault_page)
2320 __free_page(fault_page);
2301 if (hwpoison_page) 2321 if (hwpoison_page)
2302 __free_page(hwpoison_page); 2322 __free_page(hwpoison_page);
2303 __free_page(bad_page); 2323 __free_page(bad_page);