diff options
Diffstat (limited to 'virt')
| -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;  static bool largepages_enabled = true; +struct page *hwpoison_page; +pfn_t hwpoison_pfn; +  inline int kvm_is_mmio_pfn(pfn_t pfn)  {  	if (pfn_valid(pfn)) { @@ -810,16 +813,22 @@ EXPORT_SYMBOL_GPL(kvm_disable_largepages);  int is_error_page(struct page *page)  { -	return page == bad_page; +	return page == bad_page || page == hwpoison_page;  }  EXPORT_SYMBOL_GPL(is_error_page);  int is_error_pfn(pfn_t pfn)  { -	return pfn == bad_pfn; +	return pfn == bad_pfn || pfn == hwpoison_pfn;  }  EXPORT_SYMBOL_GPL(is_error_pfn); +int is_hwpoison_pfn(pfn_t pfn) +{ +	return pfn == hwpoison_pfn; +} +EXPORT_SYMBOL_GPL(is_hwpoison_pfn); +  static inline unsigned long bad_hva(void)  {  	return PAGE_OFFSET; @@ -945,6 +954,11 @@ static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr)  	if (unlikely(npages != 1)) {  		struct vm_area_struct *vma; +		if (is_hwpoison_address(addr)) { +			get_page(hwpoison_page); +			return page_to_pfn(hwpoison_page); +		} +  		down_read(¤t->mm->mmap_sem);  		vma = find_vma(current->mm, addr); @@ -2197,6 +2211,15 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,  	bad_pfn = page_to_pfn(bad_page); +	hwpoison_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + +	if (hwpoison_page == NULL) { +		r = -ENOMEM; +		goto out_free_0; +	} + +	hwpoison_pfn = page_to_pfn(hwpoison_page); +  	if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) {  		r = -ENOMEM;  		goto out_free_0; @@ -2269,6 +2292,8 @@ out_free_1:  out_free_0a:  	free_cpumask_var(cpus_hardware_enabled);  out_free_0: +	if (hwpoison_page) +		__free_page(hwpoison_page);  	__free_page(bad_page);  out:  	kvm_arch_exit(); @@ -2290,6 +2315,7 @@ void kvm_exit(void)  	kvm_arch_hardware_unsetup();  	kvm_arch_exit();  	free_cpumask_var(cpus_hardware_enabled); +	__free_page(hwpoison_page);  	__free_page(bad_page);  }  EXPORT_SYMBOL_GPL(kvm_exit);  |