diff mbox series

[v3,13/21] clear_page: add generic clear_user_pages_incoherent()

Message ID 20220606203725.1313715-9-ankur.a.arora@oracle.com (mailing list archive)
State New
Headers show
Series huge page clearing optimizations | expand

Commit Message

Ankur Arora June 6, 2022, 8:37 p.m. UTC
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(+)

Comments

Luc Van Oostenryck June 8, 2022, 12:01 a.m. UTC | #1
On Mon, Jun 06, 2022 at 08:37:17PM +0000, Ankur Arora wrote:
> +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);
> +}

Hi,

Please use 'void __incoherent *' and 'void __force *', as it's done
elsewhere for __force and address spaces.

-- Luc
Ankur Arora June 12, 2022, 11:19 a.m. UTC | #2
Luc Van Oostenryck <luc.vanoostenryck@gmail.com> writes:

> On Mon, Jun 06, 2022 at 08:37:17PM +0000, Ankur Arora wrote:
>> +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);
>> +}
>
> Hi,
>
> Please use 'void __incoherent *' and 'void __force *', as it's done
> elsewhere for __force and address spaces.

Thanks Luc. Will fix.

--
ankur
diff mbox series

Patch

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