[PATCH v3 13/21] clear_page: add generic clear_user_pages_incoherent()
From: Ankur Arora
Date: Mon Jun 06 2022 - 16:47:00 EST
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@xxxxxxxxxx>
---
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(+)
diff --git a/include/asm-generic/clear_page.h b/include/asm-generic/clear_page.h
index f827d661519c..0ebff70a60a9 100644
--- a/include/asm-generic/clear_page.h
+++ b/include/asm-generic/clear_page.h
@@ -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 */
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 08781d7693e7..90179f623c3b 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.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
--
2.31.1