@@ -385,6 +385,7 @@ extern struct page *bad_page;
int is_error_page(struct page *page);
int is_error_pfn(pfn_t pfn);
int is_hwpoison_pfn(pfn_t pfn);
+int is_readonly_fault_pfn(pfn_t pfn);
int is_noslot_pfn(pfn_t pfn);
int is_invalid_pfn(pfn_t pfn);
int kvm_is_error_hva(unsigned long addr);
@@ -109,6 +109,9 @@ static pfn_t hwpoison_pfn;
static struct page *fault_page;
static pfn_t fault_pfn;
+static struct page *readonly_fault_page;
+static pfn_t readonly_fault_pfn;
+
inline int kvm_is_mmio_pfn(pfn_t pfn)
{
if (pfn_valid(pfn)) {
@@ -949,13 +952,15 @@ EXPORT_SYMBOL_GPL(kvm_disable_largepages);
int is_error_page(struct page *page)
{
- return page == bad_page || page == hwpoison_page || page == fault_page;
+ return page == bad_page || page == hwpoison_page || page == fault_page
+ || page == readonly_fault_page;
}
EXPORT_SYMBOL_GPL(is_error_page);
int is_error_pfn(pfn_t pfn)
{
- return pfn == bad_pfn || pfn == hwpoison_pfn || pfn == fault_pfn;
+ return pfn == bad_pfn || pfn == hwpoison_pfn || pfn == fault_pfn
+ || pfn == readonly_fault_pfn;
}
EXPORT_SYMBOL_GPL(is_error_pfn);
@@ -965,6 +970,12 @@ int is_hwpoison_pfn(pfn_t pfn)
}
EXPORT_SYMBOL_GPL(is_hwpoison_pfn);
+int is_readonly_fault_pfn(pfn_t pfn)
+{
+ return pfn == readonly_fault_pfn;
+}
+EXPORT_SYMBOL_GPL(is_readonly_fault_pfn);
+
int is_noslot_pfn(pfn_t pfn)
{
return pfn == bad_pfn;
@@ -973,7 +984,8 @@ EXPORT_SYMBOL_GPL(is_noslot_pfn);
int is_invalid_pfn(pfn_t pfn)
{
- return pfn == hwpoison_pfn || pfn == fault_pfn;
+ return pfn == hwpoison_pfn || pfn == fault_pfn ||
+ pfn == readonly_fault_pfn;
}
EXPORT_SYMBOL_GPL(is_invalid_pfn);
@@ -1076,6 +1088,12 @@ pfn_t get_fault_pfn(void)
}
EXPORT_SYMBOL_GPL(get_fault_pfn);
+static pfn_t get_readonly_fault_pfn(void)
+{
+ get_page(readonly_fault_page);
+ return readonly_fault_pfn;
+}
+
int get_user_page_nowait(struct task_struct *tsk, struct mm_struct *mm,
unsigned long start, int write, struct page **page)
{
@@ -2809,42 +2827,49 @@ static void kvm_sched_out(struct preempt_notifier *pn,
kvm_arch_vcpu_put(vcpu);
}
-int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
- struct module *module)
+static void kvm_uninit_dummy_pages(void)
{
- int r;
- int cpu;
-
- r = kvm_arch_init(opaque);
- if (r)
- goto out_fail;
+ if (fault_page)
+ __free_page(fault_page);
+ if (readonly_fault_page)
+ __free_page(readonly_fault_page);
+ if (hwpoison_page)
+ __free_page(hwpoison_page);
+ if (bad_page)
+ __free_page(bad_page);
+}
+static int kvm_init_dummy_pages(void)
+{
bad_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ hwpoison_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ fault_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ readonly_fault_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- if (bad_page == NULL) {
- r = -ENOMEM;
- goto out;
- }
+ if (!bad_page || !hwpoison_page || !fault_page || !readonly_fault_page)
+ return -ENOMEM;
bad_pfn = page_to_pfn(bad_page);
+ hwpoison_pfn = page_to_pfn(hwpoison_page);
+ fault_pfn = page_to_pfn(fault_page);
+ readonly_fault_pfn = page_to_pfn(readonly_fault_page);
- hwpoison_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-
- if (hwpoison_page == NULL) {
- r = -ENOMEM;
- goto out_free_0;
- }
+ return 0;
+}
- hwpoison_pfn = page_to_pfn(hwpoison_page);
+int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
+ struct module *module)
+{
+ int r;
+ int cpu;
- fault_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ r = kvm_arch_init(opaque);
+ if (r)
+ goto out_fail;
- if (fault_page == NULL) {
- r = -ENOMEM;
+ r = kvm_init_dummy_pages();
+ if (r)
goto out_free_0;
- }
-
- fault_pfn = page_to_pfn(fault_page);
if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) {
r = -ENOMEM;
@@ -2920,12 +2945,7 @@ out_free_1:
out_free_0a:
free_cpumask_var(cpus_hardware_enabled);
out_free_0:
- if (fault_page)
- __free_page(fault_page);
- if (hwpoison_page)
- __free_page(hwpoison_page);
- __free_page(bad_page);
-out:
+ kvm_uninit_dummy_pages();
kvm_arch_exit();
out_fail:
return r;
@@ -2945,8 +2965,6 @@ void kvm_exit(void)
kvm_arch_hardware_unsetup();
kvm_arch_exit();
free_cpumask_var(cpus_hardware_enabled);
- __free_page(fault_page);
- __free_page(hwpoison_page);
- __free_page(bad_page);
+ kvm_uninit_dummy_pages();
}
EXPORT_SYMBOL_GPL(kvm_exit);
Introduce readonly_fault_pfn, in the later patch, it indicates failure when we try to get a writable pfn from the readonly memslot Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> --- include/linux/kvm_host.h | 1 + virt/kvm/kvm_main.c | 92 +++++++++++++++++++++++++++------------------ 2 files changed, 56 insertions(+), 37 deletions(-)