Subject: Utilize hypervisor highmem handling helpers This is against 2.6.26, it does not apply to the 2.6.18 tree (I'd make this effort only if the patch is desired into that tree). Signed-off-by: Jan Beulich Index: head-2008-07-21/arch/x86/mm/highmem_32-xen.c =================================================================== --- head-2008-07-21.orig/arch/x86/mm/highmem_32-xen.c 2008-07-21 17:42:48.000000000 +0200 +++ head-2008-07-21/arch/x86/mm/highmem_32-xen.c 2008-07-22 16:44:59.000000000 +0200 @@ -151,7 +151,63 @@ struct page *kmap_atomic_to_page(void *p return pte_page(*pte); } +static int highmem_assist __read_mostly = 1; + +void clear_highpage(struct page *page) +{ + void *kaddr; + + if (highmem_assist && PageHighMem(page)) { + struct mmuext_op meo; + + meo.cmd = MMUEXT_CLEAR_PAGE; + meo.arg1.mfn = pfn_to_mfn(page_to_pfn(page)); + switch (HYPERVISOR_mmuext_op(&meo, 1, NULL, DOMID_SELF)) { + case 0: + return; + case -ENOSYS: + highmem_assist = 0; + } + } + + kaddr = kmap_atomic(page, KM_USER0); + clear_page(kaddr); + kunmap_atomic(kaddr, KM_USER0); +} + +void copy_highpage(struct page *to, struct page *from) +{ + void *vfrom, *vto; + + if (highmem_assist && (PageHighMem(from) || PageHighMem(to))) { + unsigned long from_pfn = page_to_pfn(from); + unsigned long to_pfn = page_to_pfn(to); + struct mmuext_op meo; + + meo.arg1.mfn = pfn_to_mfn(to_pfn); + meo.arg2.src_mfn = pfn_to_mfn(from_pfn); + if (mfn_to_pfn(meo.arg2.src_mfn) == from_pfn + && mfn_to_pfn(meo.arg1.mfn) == to_pfn) { + meo.cmd = MMUEXT_COPY_PAGE; + switch (HYPERVISOR_mmuext_op(&meo, 1, NULL, DOMID_SELF)) { + case 0: + return; + case -ENOSYS: + highmem_assist = 0; + } + } + } + + vfrom = kmap_atomic(from, KM_USER0); + vto = kmap_atomic(to, KM_USER1); + copy_page(vto, vfrom); + kunmap_atomic(vfrom, KM_USER0); + kunmap_atomic(vto, KM_USER1); +} + EXPORT_SYMBOL(kmap); EXPORT_SYMBOL(kunmap); EXPORT_SYMBOL(kmap_atomic); EXPORT_SYMBOL(kunmap_atomic); +EXPORT_SYMBOL(clear_highpage); +EXPORT_SYMBOL(copy_highpage); Index: head-2008-07-21/include/asm-x86/mach-xen/asm/highmem.h =================================================================== --- head-2008-07-21.orig/include/asm-x86/mach-xen/asm/highmem.h 2008-07-21 17:42:48.000000000 +0200 +++ head-2008-07-21/include/asm-x86/mach-xen/asm/highmem.h 2008-07-22 16:42:58.000000000 +0200 @@ -74,6 +74,23 @@ struct page *kmap_atomic_to_page(void *p #define flush_cache_kmaps() do { } while (0) +void clear_highpage(struct page *); +static inline void clear_user_highpage(struct page *page, unsigned long vaddr) +{ + clear_highpage(page); +} +#define __HAVE_ARCH_CLEAR_HIGHPAGE +#define __HAVE_ARCH_CLEAR_USER_HIGHPAGE + +void copy_highpage(struct page *to, struct page *from); +static inline void copy_user_highpage(struct page *to, struct page *from, + unsigned long vaddr, struct vm_area_struct *vma) +{ + copy_highpage(to, from); +} +#define __HAVE_ARCH_COPY_HIGHPAGE +#define __HAVE_ARCH_COPY_USER_HIGHPAGE + #endif /* __KERNEL__ */ #endif /* _ASM_HIGHMEM_H */ Index: head-2008-07-21/include/linux/highmem.h =================================================================== --- head-2008-07-21.orig/include/linux/highmem.h 2008-04-17 04:49:44.000000000 +0200 +++ head-2008-07-21/include/linux/highmem.h 2008-07-22 16:42:58.000000000 +0200 @@ -62,6 +62,7 @@ static inline void *kmap_atomic(struct p #endif /* CONFIG_HIGHMEM */ +#ifndef __HAVE_ARCH_CLEAR_USER_HIGHPAGE /* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */ static inline void clear_user_highpage(struct page *page, unsigned long vaddr) { @@ -69,6 +70,7 @@ static inline void clear_user_highpage(s clear_user_page(addr, vaddr, page); kunmap_atomic(addr, KM_USER0); } +#endif #ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE /** @@ -115,12 +117,14 @@ alloc_zeroed_user_highpage_movable(struc return __alloc_zeroed_user_highpage(__GFP_MOVABLE, vma, vaddr); } +#ifndef __HAVE_ARCH_CLEAR_HIGHPAGE static inline void clear_highpage(struct page *page) { void *kaddr = kmap_atomic(page, KM_USER0); clear_page(kaddr); kunmap_atomic(kaddr, KM_USER0); } +#endif static inline void zero_user_segments(struct page *page, unsigned start1, unsigned end1, @@ -174,6 +178,8 @@ static inline void copy_user_highpage(st #endif +#ifndef __HAVE_ARCH_COPY_HIGHPAGE + static inline void copy_highpage(struct page *to, struct page *from) { char *vfrom, *vto; @@ -185,4 +191,6 @@ static inline void copy_highpage(struct kunmap_atomic(vto, KM_USER1); } +#endif + #endif /* _LINUX_HIGHMEM_H */ Index: head-2008-07-21/include/xen/interface/xen.h =================================================================== --- head-2008-07-21.orig/include/xen/interface/xen.h 2008-07-21 17:22:56.000000000 +0200 +++ head-2008-07-21/include/xen/interface/xen.h 2008-07-22 16:42:58.000000000 +0200 @@ -236,6 +236,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 @@ -252,12 +259,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 0x1000 +#define MMUEXT_COPY_PAGE 0x1001 #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; @@ -271,6 +281,8 @@ struct mmuext_op { #else void *vcpumask; #endif + /* COPY_PAGE */ + xen_pfn_t src_mfn; } arg2; }; DEFINE_XEN_GUEST_HANDLE_STRUCT(mmuext_op);