diff options
Diffstat (limited to 'virt/kvm/kvm_main.c')
-rw-r--r-- | virt/kvm/kvm_main.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index f032806a212f..187aa8d984a7 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -92,6 +92,9 @@ static bool kvm_rebooting; | |||
92 | 92 | ||
93 | static bool largepages_enabled = true; | 93 | static bool largepages_enabled = true; |
94 | 94 | ||
95 | struct page *hwpoison_page; | ||
96 | pfn_t hwpoison_pfn; | ||
97 | |||
95 | inline int kvm_is_mmio_pfn(pfn_t pfn) | 98 | inline int kvm_is_mmio_pfn(pfn_t pfn) |
96 | { | 99 | { |
97 | if (pfn_valid(pfn)) { | 100 | if (pfn_valid(pfn)) { |
@@ -810,16 +813,22 @@ EXPORT_SYMBOL_GPL(kvm_disable_largepages); | |||
810 | 813 | ||
811 | int is_error_page(struct page *page) | 814 | int is_error_page(struct page *page) |
812 | { | 815 | { |
813 | return page == bad_page; | 816 | return page == bad_page || page == hwpoison_page; |
814 | } | 817 | } |
815 | EXPORT_SYMBOL_GPL(is_error_page); | 818 | EXPORT_SYMBOL_GPL(is_error_page); |
816 | 819 | ||
817 | int is_error_pfn(pfn_t pfn) | 820 | int is_error_pfn(pfn_t pfn) |
818 | { | 821 | { |
819 | return pfn == bad_pfn; | 822 | return pfn == bad_pfn || pfn == hwpoison_pfn; |
820 | } | 823 | } |
821 | EXPORT_SYMBOL_GPL(is_error_pfn); | 824 | EXPORT_SYMBOL_GPL(is_error_pfn); |
822 | 825 | ||
826 | int is_hwpoison_pfn(pfn_t pfn) | ||
827 | { | ||
828 | return pfn == hwpoison_pfn; | ||
829 | } | ||
830 | EXPORT_SYMBOL_GPL(is_hwpoison_pfn); | ||
831 | |||
823 | static inline unsigned long bad_hva(void) | 832 | static inline unsigned long bad_hva(void) |
824 | { | 833 | { |
825 | return PAGE_OFFSET; | 834 | return PAGE_OFFSET; |
@@ -945,6 +954,11 @@ static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr) | |||
945 | if (unlikely(npages != 1)) { | 954 | if (unlikely(npages != 1)) { |
946 | struct vm_area_struct *vma; | 955 | struct vm_area_struct *vma; |
947 | 956 | ||
957 | if (is_hwpoison_address(addr)) { | ||
958 | get_page(hwpoison_page); | ||
959 | return page_to_pfn(hwpoison_page); | ||
960 | } | ||
961 | |||
948 | down_read(¤t->mm->mmap_sem); | 962 | down_read(¤t->mm->mmap_sem); |
949 | vma = find_vma(current->mm, addr); | 963 | vma = find_vma(current->mm, addr); |
950 | 964 | ||
@@ -2197,6 +2211,15 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, | |||
2197 | 2211 | ||
2198 | bad_pfn = page_to_pfn(bad_page); | 2212 | bad_pfn = page_to_pfn(bad_page); |
2199 | 2213 | ||
2214 | hwpoison_page = alloc_page(GFP_KERNEL | __GFP_ZERO); | ||
2215 | |||
2216 | if (hwpoison_page == NULL) { | ||
2217 | r = -ENOMEM; | ||
2218 | goto out_free_0; | ||
2219 | } | ||
2220 | |||
2221 | hwpoison_pfn = page_to_pfn(hwpoison_page); | ||
2222 | |||
2200 | if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) { | 2223 | if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) { |
2201 | r = -ENOMEM; | 2224 | r = -ENOMEM; |
2202 | goto out_free_0; | 2225 | goto out_free_0; |
@@ -2269,6 +2292,8 @@ out_free_1: | |||
2269 | out_free_0a: | 2292 | out_free_0a: |
2270 | free_cpumask_var(cpus_hardware_enabled); | 2293 | free_cpumask_var(cpus_hardware_enabled); |
2271 | out_free_0: | 2294 | out_free_0: |
2295 | if (hwpoison_page) | ||
2296 | __free_page(hwpoison_page); | ||
2272 | __free_page(bad_page); | 2297 | __free_page(bad_page); |
2273 | out: | 2298 | out: |
2274 | kvm_arch_exit(); | 2299 | kvm_arch_exit(); |
@@ -2290,6 +2315,7 @@ void kvm_exit(void) | |||
2290 | kvm_arch_hardware_unsetup(); | 2315 | kvm_arch_hardware_unsetup(); |
2291 | kvm_arch_exit(); | 2316 | kvm_arch_exit(); |
2292 | free_cpumask_var(cpus_hardware_enabled); | 2317 | free_cpumask_var(cpus_hardware_enabled); |
2318 | __free_page(hwpoison_page); | ||
2293 | __free_page(bad_page); | 2319 | __free_page(bad_page); |
2294 | } | 2320 | } |
2295 | EXPORT_SYMBOL_GPL(kvm_exit); | 2321 | EXPORT_SYMBOL_GPL(kvm_exit); |