Define fallback versions of clear_pages(), clear_user_pages().
In absence of architectural primitives, these just do straight clearing
sequentially.
Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
---
include/linux/mm.h | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 1ae97a0b8ec7..b8c3f265b497 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -3768,6 +3768,38 @@ static inline void clear_page_guard(struct zone *zone, struct page *page,
unsigned int order) {}
#endif /* CONFIG_DEBUG_PAGEALLOC */
+#ifndef ARCH_PAGE_CONTIG_NR
+#define PAGE_CONTIG_NR 1
+#else
+#define PAGE_CONTIG_NR ARCH_PAGE_CONTIG_NR
+#endif
+
+#ifndef clear_pages
+/*
+ * clear_pages() - clear kernel page range.
+ * @addr: start address of page range
+ * @npages: number of pages
+ *
+ * Assumes that (@addr, +@npages) references a kernel region.
+ * Like clear_page(), this does absolutely no exception handling.
+ */
+static inline void clear_pages(void *addr, unsigned int npages)
+{
+ for (int i = 0; i < npages; i++)
+ clear_page(addr + i * PAGE_SIZE);
+}
+#endif
+
+#ifndef clear_user_pages
+static inline void clear_user_pages(void *addr, unsigned long vaddr,
+ struct page *pg, unsigned int npages)
+{
+ for (int i = 0; i < npages; i++)
+ clear_user_page(addr + i * PAGE_SIZE,
+ vaddr + i * PAGE_SIZE, pg + i);
+}
+#endif
+
#ifdef __HAVE_ARCH_GATE_AREA
extern struct vm_area_struct *get_gate_vma(struct mm_struct *mm);
extern int in_gate_area_no_mm(unsigned long addr);
--
2.31.1
On 02.09.25 10:08, Ankur Arora wrote: > Define fallback versions of clear_pages(), clear_user_pages(). > > In absence of architectural primitives, these just do straight clearing > sequentially. > > Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com> > --- > include/linux/mm.h | 32 ++++++++++++++++++++++++++++++++ > 1 file changed, 32 insertions(+) > > diff --git a/include/linux/mm.h b/include/linux/mm.h > index 1ae97a0b8ec7..b8c3f265b497 100644 > --- a/include/linux/mm.h > +++ b/include/linux/mm.h > @@ -3768,6 +3768,38 @@ static inline void clear_page_guard(struct zone *zone, struct page *page, > unsigned int order) {} > #endif /* CONFIG_DEBUG_PAGEALLOC */ > > +#ifndef ARCH_PAGE_CONTIG_NR > +#define PAGE_CONTIG_NR 1 > +#else > +#define PAGE_CONTIG_NR ARCH_PAGE_CONTIG_NR > +#endif > + These likely don't belong into this aptch :) > +#ifndef clear_pages > +/* /** for proper kernel doc > + * clear_pages() - clear kernel page range. > + * @addr: start address of page range > + * @npages: number of pages > + * > + * Assumes that (@addr, +@npages) references a kernel region. > + * Like clear_page(), this does absolutely no exception handling. > + */ > +static inline void clear_pages(void *addr, unsigned int npages) > +{ > + for (int i = 0; i < npages; i++) > + clear_page(addr + i * PAGE_SIZE); If we know that we will clear at least one page (which we can document) do { clear_page(addr); addr += PAGE_SIZE; } while (--npages); Similarly for the case below. > +} > +#endif > + > +#ifndef clear_user_pages Can we add kernel doc here as well? > +static inline void clear_user_pages(void *addr, unsigned long vaddr, > + struct page *pg, unsigned int npages) > +{ > + for (int i = 0; i < npages; i++) > + clear_user_page(addr + i * PAGE_SIZE, > + vaddr + i * PAGE_SIZE, pg + i); > +} > +#endif > + > #ifdef __HAVE_ARCH_GATE_AREA > extern struct vm_area_struct *get_gate_vma(struct mm_struct *mm); > extern int in_gate_area_no_mm(unsigned long addr); -- Cheers David / dhildenb
David Hildenbrand <david@redhat.com> writes: > On 02.09.25 10:08, Ankur Arora wrote: >> Define fallback versions of clear_pages(), clear_user_pages(). >> In absence of architectural primitives, these just do straight clearing >> sequentially. >> Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com> >> --- >> include/linux/mm.h | 32 ++++++++++++++++++++++++++++++++ >> 1 file changed, 32 insertions(+) >> diff --git a/include/linux/mm.h b/include/linux/mm.h >> index 1ae97a0b8ec7..b8c3f265b497 100644 >> --- a/include/linux/mm.h >> +++ b/include/linux/mm.h >> @@ -3768,6 +3768,38 @@ static inline void clear_page_guard(struct zone *zone, struct page *page, >> unsigned int order) {} >> #endif /* CONFIG_DEBUG_PAGEALLOC */ >> +#ifndef ARCH_PAGE_CONTIG_NR >> +#define PAGE_CONTIG_NR 1 >> +#else >> +#define PAGE_CONTIG_NR ARCH_PAGE_CONTIG_NR >> +#endif >> + > > These likely don't belong into this aptch :) Yeah :). >> +#ifndef clear_pages >> +/* > > /** > > for proper kernel doc > >> + * clear_pages() - clear kernel page range. >> + * @addr: start address of page range >> + * @npages: number of pages >> + * >> + * Assumes that (@addr, +@npages) references a kernel region. >> + * Like clear_page(), this does absolutely no exception handling. >> + */ >> +static inline void clear_pages(void *addr, unsigned int npages) >> +{ >> + for (int i = 0; i < npages; i++) >> + clear_page(addr + i * PAGE_SIZE); > > If we know that we will clear at least one page (which we can document) > > do { > clear_page(addr); > addr += PAGE_SIZE; > } while (--npages); > > Similarly for the case below. Ack. Though how about the following instead? Slightly less clear but probably better suited for caching the likely access pattern. addr += (npages - 1) * PAGE_SIZE; do { clear_page(addr); addr -= PAGE_SIZE; } while (--npages); >> +} >> +#endif >> + >> +#ifndef clear_user_pages > > Can we add kernel doc here as well? Will do. Thanks for the quick reviews. -- ankur
Ankur Arora <ankur.a.arora@oracle.com> writes: > David Hildenbrand <david@redhat.com> writes: > >> On 02.09.25 10:08, Ankur Arora wrote: [ ... ] >>> + * clear_pages() - clear kernel page range. >>> + * @addr: start address of page range >>> + * @npages: number of pages >>> + * >>> + * Assumes that (@addr, +@npages) references a kernel region. >>> + * Like clear_page(), this does absolutely no exception handling. >>> + */ >>> +static inline void clear_pages(void *addr, unsigned int npages) >>> +{ >>> + for (int i = 0; i < npages; i++) >>> + clear_page(addr + i * PAGE_SIZE); >> >> If we know that we will clear at least one page (which we can document) >> >> do { >> clear_page(addr); >> addr += PAGE_SIZE; >> } while (--npages); >> >> Similarly for the case below. > > Ack. Though how about the following instead? Slightly less clear but > probably better suited for caching the likely access pattern. > > addr += (npages - 1) * PAGE_SIZE; > do { > clear_page(addr); > addr -= PAGE_SIZE; > } while (--npages); Decided against using this reverse access pattern. I would need to replicate it at three places (clear_pages(), clear_user_pages() and clear_highpages()) and this kind of policy should probably be dictated from folio_zero_user() or clear_contig_pages() etc. -- ankur
Hi Ankur, kernel test robot noticed the following build warnings: [auto build test WARNING on akpm-mm/mm-everything] url: https://github.com/intel-lab-lkp/linux/commits/Ankur-Arora/perf-bench-mem-Remove-repetition-around-time-measurement/20250902-161417 base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything patch link: https://lore.kernel.org/r/20250902080816.3715913-12-ankur.a.arora%40oracle.com patch subject: [PATCH v6 11/15] mm: define clear_pages(), clear_user_pages() config: sparc-defconfig (https://download.01.org/0day-ci/archive/20250903/202509030338.DlQJTxIk-lkp@intel.com/config) compiler: sparc-linux-gcc (GCC) 15.1.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250903/202509030338.DlQJTxIk-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202509030338.DlQJTxIk-lkp@intel.com/ All warnings (new ones prefixed by >>): In file included from arch/sparc/include/asm/page.h:8, from arch/sparc/include/asm/string_32.h:13, from arch/sparc/include/asm/string.h:7, from include/linux/string.h:65, from include/linux/bitmap.h:13, from include/linux/cpumask.h:12, from arch/sparc/include/asm/smp_32.h:15, from arch/sparc/include/asm/smp.h:7, from arch/sparc/include/asm/switch_to_32.h:5, from arch/sparc/include/asm/switch_to.h:7, from arch/sparc/include/asm/ptrace.h:120, from arch/sparc/include/asm/thread_info_32.h:19, from arch/sparc/include/asm/thread_info.h:7, from include/linux/thread_info.h:60, from include/asm-generic/preempt.h:5, from ./arch/sparc/include/generated/asm/preempt.h:1, from include/linux/preempt.h:79, from include/linux/spinlock.h:56, from include/linux/mmzone.h:8, from include/linux/gfp.h:7, from include/linux/umh.h:4, from include/linux/kmod.h:9, from include/linux/module.h:18, from init/main.c:18: include/linux/mm.h: In function 'clear_user_pages': arch/sparc/include/asm/page_32.h:22:17: error: implicit declaration of function 'sparc_flush_page_to_ram' [-Wimplicit-function-declaration] 22 | sparc_flush_page_to_ram(page); \ | ^~~~~~~~~~~~~~~~~~~~~~~ include/linux/mm.h:3886:17: note: in expansion of macro 'clear_user_page' 3886 | clear_user_page(addr + i * PAGE_SIZE, | ^~~~~~~~~~~~~~~ In file included from arch/sparc/include/asm/cacheflush.h:11, from include/linux/cacheflush.h:5, from include/linux/highmem.h:8, from include/linux/bvec.h:10, from include/linux/blk_types.h:10, from include/linux/writeback.h:13, from include/linux/memcontrol.h:23, from include/linux/bpf.h:31, from include/linux/security.h:35, from include/linux/perf_event.h:53, from include/linux/trace_events.h:10, from include/trace/syscall.h:7, from include/linux/syscalls.h:95, from init/main.c:22: arch/sparc/include/asm/cacheflush_32.h: At top level: >> arch/sparc/include/asm/cacheflush_32.h:38:6: warning: conflicting types for 'sparc_flush_page_to_ram'; have 'void(struct page *)' 38 | void sparc_flush_page_to_ram(struct page *page); | ^~~~~~~~~~~~~~~~~~~~~~~ arch/sparc/include/asm/page_32.h:22:17: note: previous implicit declaration of 'sparc_flush_page_to_ram' with type 'void(struct page *)' 22 | sparc_flush_page_to_ram(page); \ | ^~~~~~~~~~~~~~~~~~~~~~~ include/linux/mm.h:3886:17: note: in expansion of macro 'clear_user_page' 3886 | clear_user_page(addr + i * PAGE_SIZE, | ^~~~~~~~~~~~~~~ vim +38 arch/sparc/include/asm/cacheflush_32.h f5e706ad886b6a include/asm-sparc/cacheflush_32.h Sam Ravnborg 2008-07-17 19 f5e706ad886b6a include/asm-sparc/cacheflush_32.h Sam Ravnborg 2008-07-17 20 #define copy_to_user_page(vma, page, vaddr, dst, src, len) \ f5e706ad886b6a include/asm-sparc/cacheflush_32.h Sam Ravnborg 2008-07-17 21 do { \ f5e706ad886b6a include/asm-sparc/cacheflush_32.h Sam Ravnborg 2008-07-17 22 flush_cache_page(vma, vaddr, page_to_pfn(page));\ f5e706ad886b6a include/asm-sparc/cacheflush_32.h Sam Ravnborg 2008-07-17 23 memcpy(dst, src, len); \ f5e706ad886b6a include/asm-sparc/cacheflush_32.h Sam Ravnborg 2008-07-17 24 } while (0) f5e706ad886b6a include/asm-sparc/cacheflush_32.h Sam Ravnborg 2008-07-17 25 #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ f5e706ad886b6a include/asm-sparc/cacheflush_32.h Sam Ravnborg 2008-07-17 26 do { \ f5e706ad886b6a include/asm-sparc/cacheflush_32.h Sam Ravnborg 2008-07-17 27 flush_cache_page(vma, vaddr, page_to_pfn(page));\ f5e706ad886b6a include/asm-sparc/cacheflush_32.h Sam Ravnborg 2008-07-17 28 memcpy(dst, src, len); \ f5e706ad886b6a include/asm-sparc/cacheflush_32.h Sam Ravnborg 2008-07-17 29 } while (0) f5e706ad886b6a include/asm-sparc/cacheflush_32.h Sam Ravnborg 2008-07-17 30 5d83d66635bb16 arch/sparc/include/asm/cacheflush_32.h David S. Miller 2012-05-13 31 #define __flush_page_to_ram(addr) \ 5d83d66635bb16 arch/sparc/include/asm/cacheflush_32.h David S. Miller 2012-05-13 32 sparc32_cachetlb_ops->page_to_ram(addr) 5d83d66635bb16 arch/sparc/include/asm/cacheflush_32.h David S. Miller 2012-05-13 33 #define flush_sig_insns(mm,insn_addr) \ 5d83d66635bb16 arch/sparc/include/asm/cacheflush_32.h David S. Miller 2012-05-13 34 sparc32_cachetlb_ops->sig_insns(mm, insn_addr) 5d83d66635bb16 arch/sparc/include/asm/cacheflush_32.h David S. Miller 2012-05-13 35 #define flush_page_for_dma(addr) \ 5d83d66635bb16 arch/sparc/include/asm/cacheflush_32.h David S. Miller 2012-05-13 36 sparc32_cachetlb_ops->page_for_dma(addr) f5e706ad886b6a include/asm-sparc/cacheflush_32.h Sam Ravnborg 2008-07-17 37 f05a68653e56ca arch/sparc/include/asm/cacheflush_32.h Sam Ravnborg 2014-05-16 @38 void sparc_flush_page_to_ram(struct page *page); 665f640294540a arch/sparc/include/asm/cacheflush_32.h Matthew Wilcox (Oracle 2023-08-02 39) void sparc_flush_folio_to_ram(struct folio *folio); f5e706ad886b6a include/asm-sparc/cacheflush_32.h Sam Ravnborg 2008-07-17 40 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
Hi Ankur, kernel test robot noticed the following build errors: [auto build test ERROR on akpm-mm/mm-everything] url: https://github.com/intel-lab-lkp/linux/commits/Ankur-Arora/perf-bench-mem-Remove-repetition-around-time-measurement/20250902-161417 base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything patch link: https://lore.kernel.org/r/20250902080816.3715913-12-ankur.a.arora%40oracle.com patch subject: [PATCH v6 11/15] mm: define clear_pages(), clear_user_pages() config: arm-randconfig-002-20250903 (https://download.01.org/0day-ci/archive/20250903/202509030341.jBuh7Fma-lkp@intel.com/config) compiler: clang version 16.0.6 (https://github.com/llvm/llvm-project 7cbf1a2591520c2491aa35339f227775f4d3adf6) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250903/202509030341.jBuh7Fma-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202509030341.jBuh7Fma-lkp@intel.com/ All errors (new ones prefixed by >>): In file included from arch/arm/kernel/asm-offsets.c:12: >> include/linux/mm.h:3886:3: error: call to undeclared function 'clear_user_page'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] clear_user_page(addr + i * PAGE_SIZE, ^ include/linux/mm.h:3886:3: note: did you mean 'clear_user_pages'? include/linux/mm.h:3882:20: note: 'clear_user_pages' declared here static inline void clear_user_pages(void *addr, unsigned long vaddr, ^ 1 error generated. make[3]: *** [scripts/Makefile.build:182: arch/arm/kernel/asm-offsets.s] Error 1 shuffle=1003087465 make[3]: Target 'prepare' not remade because of errors. make[2]: *** [Makefile:1282: prepare0] Error 2 shuffle=1003087465 make[2]: Target 'prepare' not remade because of errors. make[1]: *** [Makefile:248: __sub-make] Error 2 shuffle=1003087465 make[1]: Target 'prepare' not remade because of errors. make: *** [Makefile:248: __sub-make] Error 2 shuffle=1003087465 make: Target 'prepare' not remade because of errors. vim +/clear_user_page +3886 include/linux/mm.h 3880 3881 #ifndef clear_user_pages 3882 static inline void clear_user_pages(void *addr, unsigned long vaddr, 3883 struct page *pg, unsigned int npages) 3884 { 3885 for (int i = 0; i < npages; i++) > 3886 clear_user_page(addr + i * PAGE_SIZE, 3887 vaddr + i * PAGE_SIZE, pg + i); 3888 } 3889 #endif 3890 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
© 2016 - 2025 Red Hat, Inc.