Introduce clear_pages(), to be overridden by architectures that support more efficient clearing of consecutive pages. Also introduce clear_user_pages(), however, we will not expect this function to be overridden anytime soon. We have to place the clear_user_pages() variant that uses clear_user_page() into mm/util.c for now to work around macro magic on sparc and m68k. Signed-off-by: Ankur Arora --- include/linux/mm.h | 41 +++++++++++++++++++++++++++++++++++++++++ mm/util.c | 13 +++++++++++++ 2 files changed, 54 insertions(+) diff --git a/include/linux/mm.h b/include/linux/mm.h index 683168b522b3..ecbcb76df9de 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -3872,6 +3872,26 @@ static inline void clear_page_guard(struct zone *zone, struct page *page, unsigned int order) {} #endif /* CONFIG_DEBUG_PAGEALLOC */ +#ifndef __HAVE_ARCH_CLEAR_PAGES +/** + * clear_pages() - clear a page range for kernel-internal use. + * @addr: start address + * @npages: number of pages + * + * Use clear_user_pages() instead when clearing a page range to be + * mapped to user space. + * + * Does absolutely no exception handling. + */ +static inline void clear_pages(void *addr, unsigned int npages) +{ + do { + clear_page(addr); + addr += PAGE_SIZE; + } while (--npages); +} +#endif + #ifndef __HAVE_ARCH_CLEAR_USER_PAGE /** * clear_user_page() - clear a page to be mapped to user space @@ -3894,6 +3914,27 @@ static inline void clear_user_page(void *addr, unsigned long vaddr, struct page } #endif +/** + * clear_user_pages() - clear a page range to be mapped to user space + * @addr: start address + * @vaddr: start address of the user mapping + * @page: start page + * @npages: number of pages + * + * Assumes that the region (@addr, +@npages) has been validated + * already so this does no exception handling. + */ +#ifdef __HAVE_ARCH_CLEAR_USER_PAGE +void clear_user_pages(void *addr, unsigned long vaddr, + struct page *page, unsigned int npages); +#else /* !__HAVE_ARCH_CLEAR_USER_PAGE */ +static inline void clear_user_pages(void *addr, unsigned long vaddr, + struct page *page, unsigned int npages) +{ + clear_pages(addr, npages); +} +#endif /* __HAVE_ARCH_CLEAR_USER_PAGE */ + #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); diff --git a/mm/util.c b/mm/util.c index 8989d5767528..d3b662b71f33 100644 --- a/mm/util.c +++ b/mm/util.c @@ -1344,3 +1344,16 @@ bool page_range_contiguous(const struct page *page, unsigned long nr_pages) } EXPORT_SYMBOL(page_range_contiguous); #endif + +#ifdef __HAVE_ARCH_CLEAR_USER_PAGE +void clear_user_pages(void *addr, unsigned long vaddr, + struct page *page, unsigned int npages) +{ + do { + clear_user_page(addr, vaddr, page); + addr += PAGE_SIZE; + vaddr += PAGE_SIZE; + page++; + } while (--npages); +} +#endif /* __HAVE_ARCH_CLEAR_USER_PAGE */ -- 2.43.5