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 - 2026 Red Hat, Inc.