@@ -16,6 +16,9 @@
#if defined(CONFIG_HIGHMEM) && defined(__HAVE_ARCH_CLEAR_USER_PAGES)
#error CONFIG_HIGHMEM is incompatible with __HAVE_ARCH_CLEAR_USER_PAGES
#endif
+#if defined(CONFIG_HIGHMEM) && defined(__HAVE_ARCH_CLEAR_USER_PAGES_INCOHERENT)
+#error CONFIG_HIGHMEM is incompatible with __HAVE_ARCH_CLEAR_USER_PAGES_INCOHERENT
+#endif
#ifndef __HAVE_ARCH_CLEAR_USER_PAGES
@@ -41,4 +44,22 @@ static inline void clear_user_pages(void *page, unsigned long vaddr,
#define ARCH_MAX_CLEAR_PAGES (1 << ARCH_MAX_CLEAR_PAGES_ORDER)
+#ifndef __HAVE_ARCH_CLEAR_USER_PAGES_INCOHERENT
+#ifndef __ASSEMBLY__
+/*
+ * Fallback path (via clear_user_pages()) if the architecture does not
+ * support incoherent clearing.
+ */
+static inline void clear_user_pages_incoherent(__incoherent void *page,
+ unsigned long vaddr,
+ struct page *pg,
+ unsigned int npages)
+{
+ clear_user_pages((__force void *)page, vaddr, pg, npages);
+}
+
+static inline void clear_page_make_coherent(void) { }
+#endif /* __ASSEMBLY__ */
+#endif /* __HAVE_ARCH_CLEAR_USER_PAGES_INCOHERENT */
+
#endif /* __ASM_GENERIC_CLEAR_PAGE_H */
@@ -231,6 +231,29 @@ static inline void clear_user_highpages(struct page *page, unsigned long vaddr,
}
#endif /* __HAVE_ARCH_CLEAR_USER_PAGES */
+#ifdef __HAVE_ARCH_CLEAR_USER_PAGES_INCOHERENT
+static inline void clear_user_highpages_incoherent(struct page *page,
+ unsigned long vaddr,
+ unsigned int npages)
+{
+ __incoherent void *addr = (__incoherent void *) page_address(page);
+
+ clear_user_pages_incoherent(addr, vaddr, page, npages);
+}
+#else
+static inline void clear_user_highpages_incoherent(struct page *page,
+ unsigned long vaddr,
+ unsigned int npages)
+{
+ /*
+ * We fallback to clear_user_highpages() for the CONFIG_HIGHMEM
+ * configs.
+ * For !CONFIG_HIGHMEM, this will get translated to clear_user_pages().
+ */
+ clear_user_highpages(page, vaddr, npages);
+}
+#endif /* __HAVE_ARCH_CLEAR_USER_PAGES_INCOHERENT */
+
#ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
/**
* alloc_zeroed_user_highpage_movable - Allocate a zeroed HIGHMEM page for a VMA that the caller knows can move
Add generic primitives for clear_user_pages_incoherent() and clear_page_make_coherent(). To ensure that callers don't mix accesses to different types of address_spaces, annotate clear_user_pages_incoherent() as taking an __incoherent pointer as argument. Also add clear_user_highpages_incoherent() which either calls clear_user_pages_incoherent() or falls back to clear_user_highpages() Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com> --- Notes: clear_user_highpages_incoherent() operates on an __incoherent region and expects the caller to call clear_page_make_coherent(). It should, however be taking an __incoherent * as argument -- this it does not do because I couldn't see a clean way of doing that with highmem. Suggestions? include/asm-generic/clear_page.h | 21 +++++++++++++++++++++ include/linux/highmem.h | 23 +++++++++++++++++++++++ 2 files changed, 44 insertions(+)