diff options
-rw-r--r-- | arch/x86/kvm/mmu.c | 4 | ||||
-rw-r--r-- | include/linux/kvm_host.h | 1 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 28 |
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; | |||
269 | int is_error_page(struct page *page); | 269 | int is_error_page(struct page *page); |
270 | int is_error_pfn(pfn_t pfn); | 270 | int is_error_pfn(pfn_t pfn); |
271 | int is_hwpoison_pfn(pfn_t pfn); | 271 | int is_hwpoison_pfn(pfn_t pfn); |
272 | int is_fault_pfn(pfn_t pfn); | ||
272 | int kvm_is_error_hva(unsigned long addr); | 273 | int kvm_is_error_hva(unsigned long addr); |
273 | int kvm_set_memory_region(struct kvm *kvm, | 274 | int 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; | |||
96 | static struct page *hwpoison_page; | 96 | static struct page *hwpoison_page; |
97 | static pfn_t hwpoison_pfn; | 97 | static pfn_t hwpoison_pfn; |
98 | 98 | ||
99 | static struct page *fault_page; | ||
100 | static pfn_t fault_pfn; | ||
101 | |||
99 | inline int kvm_is_mmio_pfn(pfn_t pfn) | 102 | inline 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 | ||
816 | int is_error_page(struct page *page) | 819 | int 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 | } |
820 | EXPORT_SYMBOL_GPL(is_error_page); | 823 | EXPORT_SYMBOL_GPL(is_error_page); |
821 | 824 | ||
822 | int is_error_pfn(pfn_t pfn) | 825 | int 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 | } |
826 | EXPORT_SYMBOL_GPL(is_error_pfn); | 829 | EXPORT_SYMBOL_GPL(is_error_pfn); |
827 | 830 | ||
@@ -831,6 +834,12 @@ int is_hwpoison_pfn(pfn_t pfn) | |||
831 | } | 834 | } |
832 | EXPORT_SYMBOL_GPL(is_hwpoison_pfn); | 835 | EXPORT_SYMBOL_GPL(is_hwpoison_pfn); |
833 | 836 | ||
837 | int is_fault_pfn(pfn_t pfn) | ||
838 | { | ||
839 | return pfn == fault_pfn; | ||
840 | } | ||
841 | EXPORT_SYMBOL_GPL(is_fault_pfn); | ||
842 | |||
834 | static inline unsigned long bad_hva(void) | 843 | static 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(¤t->mm->mmap_sem); | 970 | up_read(¤t->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: | |||
2298 | out_free_0a: | 2316 | out_free_0a: |
2299 | free_cpumask_var(cpus_hardware_enabled); | 2317 | free_cpumask_var(cpus_hardware_enabled); |
2300 | out_free_0: | 2318 | out_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); |