This commit is contained in:
committed by
Git OBS Bridge
parent
6eb384a263
commit
1c73c9b461
206
18724-i386-highmem-assist.patch
Normal file
206
18724-i386-highmem-assist.patch
Normal file
@@ -0,0 +1,206 @@
|
||||
# HG changeset patch
|
||||
# User Keir Fraser <keir.fraser@citrix.com>
|
||||
# Date 1225114175 0
|
||||
# Node ID 4413d53a8320809e93142ed599a81e1bfe5ae900
|
||||
# Parent 9bbb54fd9181644d2bdd3c7f93c2cba1dac1b719
|
||||
x86: highmem handling assistance hypercalls
|
||||
|
||||
While looking at the origin of very frequently executed hypercalls I
|
||||
realized that the high page accessor functions in Linux would be good
|
||||
candidates to handle in the hypervisor - clearing or copying to/from
|
||||
a high page is a pretty frequent operation (provided there's enough
|
||||
memory in the domain). While prior to the first submission I only
|
||||
measured kernel builds (where the results are not hinting at a
|
||||
meaningful improvement), I now found time to do a more specific
|
||||
analysis: page clearing is being improved by about 20%, page copying
|
||||
doesn't seem to significantly benefit (though that may be an effect of
|
||||
the simplistic copy_page() implementation Xen currently uses) -
|
||||
nevertheless I would think that if one function is supported by the
|
||||
hypervisor, then the other should also be.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@novell.com>
|
||||
|
||||
--- a/xen/arch/x86/mm.c
|
||||
+++ b/xen/arch/x86/mm.c
|
||||
@@ -2431,6 +2431,29 @@ static inline cpumask_t vcpumask_to_pcpu
|
||||
return pmask;
|
||||
}
|
||||
|
||||
+#ifdef __i386__
|
||||
+static inline void *fixmap_domain_page(unsigned long mfn)
|
||||
+{
|
||||
+ unsigned int cpu = smp_processor_id();
|
||||
+ void *ptr = (void *)fix_to_virt(FIX_PAE_HIGHMEM_0 + cpu);
|
||||
+
|
||||
+ l1e_write(fix_pae_highmem_pl1e - cpu,
|
||||
+ l1e_from_pfn(mfn, __PAGE_HYPERVISOR));
|
||||
+ flush_tlb_one_local(ptr);
|
||||
+ return ptr;
|
||||
+}
|
||||
+static inline void fixunmap_domain_page(const void *ptr)
|
||||
+{
|
||||
+ unsigned int cpu = virt_to_fix((unsigned long)ptr) - FIX_PAE_HIGHMEM_0;
|
||||
+
|
||||
+ l1e_write(fix_pae_highmem_pl1e - cpu, l1e_empty());
|
||||
+ this_cpu(make_cr3_timestamp) = this_cpu(tlbflush_time);
|
||||
+}
|
||||
+#else
|
||||
+#define fixmap_domain_page(mfn) mfn_to_virt(mfn)
|
||||
+#define fixunmap_domain_page(ptr) ((void)(ptr))
|
||||
+#endif
|
||||
+
|
||||
int do_mmuext_op(
|
||||
XEN_GUEST_HANDLE(mmuext_op_t) uops,
|
||||
unsigned int count,
|
||||
@@ -2700,6 +2723,66 @@ int do_mmuext_op(
|
||||
break;
|
||||
}
|
||||
|
||||
+ case MMUEXT_CLEAR_PAGE:
|
||||
+ {
|
||||
+ unsigned char *ptr;
|
||||
+
|
||||
+ okay = !get_page_and_type_from_pagenr(mfn, PGT_writable_page,
|
||||
+ FOREIGNDOM, 0);
|
||||
+ if ( unlikely(!okay) )
|
||||
+ {
|
||||
+ MEM_LOG("Error while clearing mfn %lx", mfn);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* A page is dirtied when it's being cleared. */
|
||||
+ paging_mark_dirty(d, mfn);
|
||||
+
|
||||
+ ptr = fixmap_domain_page(mfn);
|
||||
+ clear_page(ptr);
|
||||
+ fixunmap_domain_page(ptr);
|
||||
+
|
||||
+ put_page_and_type(page);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ case MMUEXT_COPY_PAGE:
|
||||
+ {
|
||||
+ const unsigned char *src;
|
||||
+ unsigned char *dst;
|
||||
+ unsigned long src_mfn;
|
||||
+
|
||||
+ src_mfn = gmfn_to_mfn(FOREIGNDOM, op.arg2.src_mfn);
|
||||
+ okay = get_page_from_pagenr(src_mfn, FOREIGNDOM);
|
||||
+ if ( unlikely(!okay) )
|
||||
+ {
|
||||
+ MEM_LOG("Error while copying from mfn %lx", src_mfn);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ okay = !get_page_and_type_from_pagenr(mfn, PGT_writable_page,
|
||||
+ FOREIGNDOM, 0);
|
||||
+ if ( unlikely(!okay) )
|
||||
+ {
|
||||
+ put_page(mfn_to_page(src_mfn));
|
||||
+ MEM_LOG("Error while copying to mfn %lx", mfn);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* A page is dirtied when it's being copied to. */
|
||||
+ paging_mark_dirty(d, mfn);
|
||||
+
|
||||
+ src = map_domain_page(src_mfn);
|
||||
+ dst = fixmap_domain_page(mfn);
|
||||
+ copy_page(dst, src);
|
||||
+ fixunmap_domain_page(dst);
|
||||
+ unmap_domain_page(src);
|
||||
+
|
||||
+ put_page_and_type(page);
|
||||
+ put_page(mfn_to_page(src_mfn));
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
default:
|
||||
MEM_LOG("Invalid extended pt command 0x%x", op.cmd);
|
||||
rc = -ENOSYS;
|
||||
--- a/xen/arch/x86/x86_64/compat/mm.c
|
||||
+++ b/xen/arch/x86/x86_64/compat/mm.c
|
||||
@@ -217,6 +217,8 @@ int compat_mmuext_op(XEN_GUEST_HANDLE(mm
|
||||
case MMUEXT_PIN_L4_TABLE:
|
||||
case MMUEXT_UNPIN_TABLE:
|
||||
case MMUEXT_NEW_BASEPTR:
|
||||
+ case MMUEXT_CLEAR_PAGE:
|
||||
+ case MMUEXT_COPY_PAGE:
|
||||
arg1 = XLAT_mmuext_op_arg1_mfn;
|
||||
break;
|
||||
default:
|
||||
@@ -244,6 +246,9 @@ int compat_mmuext_op(XEN_GUEST_HANDLE(mm
|
||||
case MMUEXT_INVLPG_MULTI:
|
||||
arg2 = XLAT_mmuext_op_arg2_vcpumask;
|
||||
break;
|
||||
+ case MMUEXT_COPY_PAGE:
|
||||
+ arg2 = XLAT_mmuext_op_arg2_src_mfn;
|
||||
+ break;
|
||||
default:
|
||||
arg2 = -1;
|
||||
break;
|
||||
--- a/xen/common/kernel.c
|
||||
+++ b/xen/common/kernel.c
|
||||
@@ -222,6 +222,7 @@ DO(xen_version)(int cmd, XEN_GUEST_HANDL
|
||||
#ifdef CONFIG_X86
|
||||
if ( !is_hvm_vcpu(current) )
|
||||
fi.submap |= (1U << XENFEAT_mmu_pt_update_preserve_ad) |
|
||||
+ (1U << XENFEAT_highmem_assist) |
|
||||
(1U << XENFEAT_gnttab_map_avail_bits);
|
||||
#endif
|
||||
break;
|
||||
--- a/xen/include/public/features.h
|
||||
+++ b/xen/include/public/features.h
|
||||
@@ -59,6 +59,9 @@
|
||||
/* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */
|
||||
#define XENFEAT_mmu_pt_update_preserve_ad 5
|
||||
|
||||
+/* x86: Does this Xen host support the MMU_{CLEAR,COPY}_PAGE hypercall? */
|
||||
+#define XENFEAT_highmem_assist 6
|
||||
+
|
||||
/*
|
||||
* If set, GNTTABOP_map_grant_ref honors flags to be placed into guest kernel
|
||||
* available pte bits.
|
||||
--- a/xen/include/public/xen.h
|
||||
+++ b/xen/include/public/xen.h
|
||||
@@ -231,6 +231,13 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
|
||||
* cmd: MMUEXT_SET_LDT
|
||||
* linear_addr: Linear address of LDT base (NB. must be page-aligned).
|
||||
* nr_ents: Number of entries in LDT.
|
||||
+ *
|
||||
+ * cmd: MMUEXT_CLEAR_PAGE
|
||||
+ * mfn: Machine frame number to be cleared.
|
||||
+ *
|
||||
+ * cmd: MMUEXT_COPY_PAGE
|
||||
+ * mfn: Machine frame number of the destination page.
|
||||
+ * src_mfn: Machine frame number of the source page.
|
||||
*/
|
||||
#define MMUEXT_PIN_L1_TABLE 0
|
||||
#define MMUEXT_PIN_L2_TABLE 1
|
||||
@@ -247,12 +254,15 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
|
||||
#define MMUEXT_FLUSH_CACHE 12
|
||||
#define MMUEXT_SET_LDT 13
|
||||
#define MMUEXT_NEW_USER_BASEPTR 15
|
||||
+#define MMUEXT_CLEAR_PAGE 16
|
||||
+#define MMUEXT_COPY_PAGE 17
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
struct mmuext_op {
|
||||
unsigned int cmd;
|
||||
union {
|
||||
- /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR */
|
||||
+ /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR
|
||||
+ * CLEAR_PAGE, COPY_PAGE */
|
||||
xen_pfn_t mfn;
|
||||
/* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */
|
||||
unsigned long linear_addr;
|
||||
@@ -266,6 +276,8 @@ struct mmuext_op {
|
||||
#else
|
||||
void *vcpumask;
|
||||
#endif
|
||||
+ /* COPY_PAGE */
|
||||
+ xen_pfn_t src_mfn;
|
||||
} arg2;
|
||||
};
|
||||
typedef struct mmuext_op mmuext_op_t;
|
Reference in New Issue
Block a user