ia64/xen-unstable
changeset 18732:4413d53a8320
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>
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>
author | Keir Fraser <keir.fraser@citrix.com> |
---|---|
date | Mon Oct 27 13:29:35 2008 +0000 (2008-10-27) |
parents | 9bbb54fd9181 |
children | 2a022ee37392 |
files | xen/arch/x86/mm.c xen/arch/x86/x86_64/compat/mm.c xen/common/kernel.c xen/include/public/features.h xen/include/public/xen.h |
line diff
1.1 --- a/xen/arch/x86/mm.c Mon Oct 27 13:27:33 2008 +0000 1.2 +++ b/xen/arch/x86/mm.c Mon Oct 27 13:29:35 2008 +0000 1.3 @@ -2431,6 +2431,29 @@ static inline cpumask_t vcpumask_to_pcpu 1.4 return pmask; 1.5 } 1.6 1.7 +#ifdef __i386__ 1.8 +static inline void *fixmap_domain_page(unsigned long mfn) 1.9 +{ 1.10 + unsigned int cpu = smp_processor_id(); 1.11 + void *ptr = (void *)fix_to_virt(FIX_PAE_HIGHMEM_0 + cpu); 1.12 + 1.13 + l1e_write(fix_pae_highmem_pl1e - cpu, 1.14 + l1e_from_pfn(mfn, __PAGE_HYPERVISOR)); 1.15 + flush_tlb_one_local(ptr); 1.16 + return ptr; 1.17 +} 1.18 +static inline void fixunmap_domain_page(const void *ptr) 1.19 +{ 1.20 + unsigned int cpu = virt_to_fix((unsigned long)ptr) - FIX_PAE_HIGHMEM_0; 1.21 + 1.22 + l1e_write(fix_pae_highmem_pl1e - cpu, l1e_empty()); 1.23 + this_cpu(make_cr3_timestamp) = this_cpu(tlbflush_time); 1.24 +} 1.25 +#else 1.26 +#define fixmap_domain_page(mfn) mfn_to_virt(mfn) 1.27 +#define fixunmap_domain_page(ptr) ((void)(ptr)) 1.28 +#endif 1.29 + 1.30 int do_mmuext_op( 1.31 XEN_GUEST_HANDLE(mmuext_op_t) uops, 1.32 unsigned int count, 1.33 @@ -2700,6 +2723,66 @@ int do_mmuext_op( 1.34 break; 1.35 } 1.36 1.37 + case MMUEXT_CLEAR_PAGE: 1.38 + { 1.39 + unsigned char *ptr; 1.40 + 1.41 + okay = !get_page_and_type_from_pagenr(mfn, PGT_writable_page, 1.42 + FOREIGNDOM, 0); 1.43 + if ( unlikely(!okay) ) 1.44 + { 1.45 + MEM_LOG("Error while clearing mfn %lx", mfn); 1.46 + break; 1.47 + } 1.48 + 1.49 + /* A page is dirtied when it's being cleared. */ 1.50 + paging_mark_dirty(d, mfn); 1.51 + 1.52 + ptr = fixmap_domain_page(mfn); 1.53 + clear_page(ptr); 1.54 + fixunmap_domain_page(ptr); 1.55 + 1.56 + put_page_and_type(page); 1.57 + break; 1.58 + } 1.59 + 1.60 + case MMUEXT_COPY_PAGE: 1.61 + { 1.62 + const unsigned char *src; 1.63 + unsigned char *dst; 1.64 + unsigned long src_mfn; 1.65 + 1.66 + src_mfn = gmfn_to_mfn(FOREIGNDOM, op.arg2.src_mfn); 1.67 + okay = get_page_from_pagenr(src_mfn, FOREIGNDOM); 1.68 + if ( unlikely(!okay) ) 1.69 + { 1.70 + MEM_LOG("Error while copying from mfn %lx", src_mfn); 1.71 + break; 1.72 + } 1.73 + 1.74 + okay = !get_page_and_type_from_pagenr(mfn, PGT_writable_page, 1.75 + FOREIGNDOM, 0); 1.76 + if ( unlikely(!okay) ) 1.77 + { 1.78 + put_page(mfn_to_page(src_mfn)); 1.79 + MEM_LOG("Error while copying to mfn %lx", mfn); 1.80 + break; 1.81 + } 1.82 + 1.83 + /* A page is dirtied when it's being copied to. */ 1.84 + paging_mark_dirty(d, mfn); 1.85 + 1.86 + src = map_domain_page(src_mfn); 1.87 + dst = fixmap_domain_page(mfn); 1.88 + copy_page(dst, src); 1.89 + fixunmap_domain_page(dst); 1.90 + unmap_domain_page(src); 1.91 + 1.92 + put_page_and_type(page); 1.93 + put_page(mfn_to_page(src_mfn)); 1.94 + break; 1.95 + } 1.96 + 1.97 default: 1.98 MEM_LOG("Invalid extended pt command 0x%x", op.cmd); 1.99 rc = -ENOSYS;
2.1 --- a/xen/arch/x86/x86_64/compat/mm.c Mon Oct 27 13:27:33 2008 +0000 2.2 +++ b/xen/arch/x86/x86_64/compat/mm.c Mon Oct 27 13:29:35 2008 +0000 2.3 @@ -231,6 +231,8 @@ int compat_mmuext_op(XEN_GUEST_HANDLE(mm 2.4 case MMUEXT_PIN_L4_TABLE: 2.5 case MMUEXT_UNPIN_TABLE: 2.6 case MMUEXT_NEW_BASEPTR: 2.7 + case MMUEXT_CLEAR_PAGE: 2.8 + case MMUEXT_COPY_PAGE: 2.9 arg1 = XLAT_mmuext_op_arg1_mfn; 2.10 break; 2.11 default: 2.12 @@ -258,6 +260,9 @@ int compat_mmuext_op(XEN_GUEST_HANDLE(mm 2.13 case MMUEXT_INVLPG_MULTI: 2.14 arg2 = XLAT_mmuext_op_arg2_vcpumask; 2.15 break; 2.16 + case MMUEXT_COPY_PAGE: 2.17 + arg2 = XLAT_mmuext_op_arg2_src_mfn; 2.18 + break; 2.19 default: 2.20 arg2 = -1; 2.21 break;
3.1 --- a/xen/common/kernel.c Mon Oct 27 13:27:33 2008 +0000 3.2 +++ b/xen/common/kernel.c Mon Oct 27 13:29:35 2008 +0000 3.3 @@ -221,7 +221,8 @@ DO(xen_version)(int cmd, XEN_GUEST_HANDL 3.4 fi.submap |= 1U << XENFEAT_supervisor_mode_kernel; 3.5 #ifdef CONFIG_X86 3.6 if ( !is_hvm_vcpu(current) ) 3.7 - fi.submap |= 1U << XENFEAT_mmu_pt_update_preserve_ad; 3.8 + fi.submap |= (1U << XENFEAT_mmu_pt_update_preserve_ad) | 3.9 + (1U << XENFEAT_highmem_assist); 3.10 #endif 3.11 break; 3.12 default:
4.1 --- a/xen/include/public/features.h Mon Oct 27 13:27:33 2008 +0000 4.2 +++ b/xen/include/public/features.h Mon Oct 27 13:29:35 2008 +0000 4.3 @@ -59,6 +59,9 @@ 4.4 /* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */ 4.5 #define XENFEAT_mmu_pt_update_preserve_ad 5 4.6 4.7 +/* x86: Does this Xen host support the MMU_{CLEAR,COPY}_PAGE hypercall? */ 4.8 +#define XENFEAT_highmem_assist 6 4.9 + 4.10 #define XENFEAT_NR_SUBMAPS 1 4.11 4.12 #endif /* __XEN_PUBLIC_FEATURES_H__ */
5.1 --- a/xen/include/public/xen.h Mon Oct 27 13:27:33 2008 +0000 5.2 +++ b/xen/include/public/xen.h Mon Oct 27 13:29:35 2008 +0000 5.3 @@ -231,6 +231,13 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); 5.4 * cmd: MMUEXT_SET_LDT 5.5 * linear_addr: Linear address of LDT base (NB. must be page-aligned). 5.6 * nr_ents: Number of entries in LDT. 5.7 + * 5.8 + * cmd: MMUEXT_CLEAR_PAGE 5.9 + * mfn: Machine frame number to be cleared. 5.10 + * 5.11 + * cmd: MMUEXT_COPY_PAGE 5.12 + * mfn: Machine frame number of the destination page. 5.13 + * src_mfn: Machine frame number of the source page. 5.14 */ 5.15 #define MMUEXT_PIN_L1_TABLE 0 5.16 #define MMUEXT_PIN_L2_TABLE 1 5.17 @@ -247,12 +254,15 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); 5.18 #define MMUEXT_FLUSH_CACHE 12 5.19 #define MMUEXT_SET_LDT 13 5.20 #define MMUEXT_NEW_USER_BASEPTR 15 5.21 +#define MMUEXT_CLEAR_PAGE 16 5.22 +#define MMUEXT_COPY_PAGE 17 5.23 5.24 #ifndef __ASSEMBLY__ 5.25 struct mmuext_op { 5.26 unsigned int cmd; 5.27 union { 5.28 - /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR */ 5.29 + /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR 5.30 + * CLEAR_PAGE, COPY_PAGE */ 5.31 xen_pfn_t mfn; 5.32 /* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */ 5.33 unsigned long linear_addr; 5.34 @@ -266,6 +276,8 @@ struct mmuext_op { 5.35 #else 5.36 void *vcpumask; 5.37 #endif 5.38 + /* COPY_PAGE */ 5.39 + xen_pfn_t src_mfn; 5.40 } arg2; 5.41 }; 5.42 typedef struct mmuext_op mmuext_op_t;