diff mbox series

[1/5] mm: Add vma_alloc_zeroed_movable_folio()

Message ID 20230116191813.2145215-2-willy@infradead.org (mailing list archive)
State New
Headers show
Series Convert various functions in memory.c to use folios | expand

Commit Message

Matthew Wilcox Jan. 16, 2023, 7:18 p.m. UTC
Replace alloc_zeroed_user_highpage_movable().  The main difference is
returning a folio containing a single page instead of returning the
page, but take the opportunity to rename the function to match other
allocation functions a little better and rewrite the documentation
to place more emphasis on the zeroing rather than the highmem aspect.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
 arch/alpha/include/asm/page.h   |  5 ++---
 arch/arm64/include/asm/page.h   |  4 ++--
 arch/arm64/mm/fault.c           |  4 ++--
 arch/ia64/include/asm/page.h    | 14 ++++++--------
 arch/m68k/include/asm/page_no.h |  5 ++---
 arch/s390/include/asm/page.h    |  5 ++---
 arch/x86/include/asm/page.h     |  5 ++---
 include/linux/highmem.h         | 33 ++++++++++++++++-----------------
 mm/memory.c                     | 16 ++++++++++------
 9 files changed, 44 insertions(+), 47 deletions(-)

Comments

Mike Rapoport Jan. 19, 2023, 10:16 a.m. UTC | #1
On Mon, Jan 16, 2023 at 07:18:09PM +0000, Matthew Wilcox (Oracle) wrote:
> Replace alloc_zeroed_user_highpage_movable().  The main difference is
> returning a folio containing a single page instead of returning the
> page, but take the opportunity to rename the function to match other
> allocation functions a little better and rewrite the documentation
> to place more emphasis on the zeroing rather than the highmem aspect.
> 
> Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> ---
>  arch/alpha/include/asm/page.h   |  5 ++---
>  arch/arm64/include/asm/page.h   |  4 ++--
>  arch/arm64/mm/fault.c           |  4 ++--
>  arch/ia64/include/asm/page.h    | 14 ++++++--------
>  arch/m68k/include/asm/page_no.h |  5 ++---
>  arch/s390/include/asm/page.h    |  5 ++---
>  arch/x86/include/asm/page.h     |  5 ++---
>  include/linux/highmem.h         | 33 ++++++++++++++++-----------------
>  mm/memory.c                     | 16 ++++++++++------
>  9 files changed, 44 insertions(+), 47 deletions(-)

...

> diff --git a/include/linux/highmem.h b/include/linux/highmem.h
> index 56703082f803..9fa462561e05 100644
> --- a/include/linux/highmem.h
> +++ b/include/linux/highmem.h
> @@ -208,31 +208,30 @@ static inline void clear_user_highpage(struct page *page, unsigned long vaddr)
>  }
>  #endif
>  
> -#ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
> +#ifndef vma_alloc_zeroed_movable_folio
>  /**
> - * alloc_zeroed_user_highpage_movable - Allocate a zeroed HIGHMEM page for a VMA that the caller knows can move
> - * @vma: The VMA the page is to be allocated for
> - * @vaddr: The virtual address the page will be inserted into
> + * vma_alloc_zeroed_movable_folio - Allocate a zeroed page for a VMA.
> + * @vma: The VMA the page is to be allocated for.
> + * @vaddr: The virtual address the page will be inserted into.
>   *
> - * Returns: The allocated and zeroed HIGHMEM page
> + * This function will allocate a page suitable for inserting into this
> + * VMA at this virtual address.  It may be allocated from highmem or
> + * the movable zone.  An architecture may provide its own implementation.
>   *
> - * This function will allocate a page for a VMA that the caller knows will
> - * be able to migrate in the future using move_pages() or reclaimed
> - *
> - * An architecture may override this function by defining
> - * __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE and providing their own
> - * implementation.
> + * Return: A folio containing one allocated and zeroed page or NULL if
> + * we are out of memory.
>   */
> -static inline struct page *
> -alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
> +static inline
> +struct folio *vma_alloc_zeroed_movable_folio(struct vm_area_struct *vma,
>  				   unsigned long vaddr)
>  {
> -	struct page *page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr);
> +	struct folio *folio;
>  
> -	if (page)
> -		clear_user_highpage(page, vaddr);
> +	folio = vma_alloc_folio(GFP_HIGHUSER_MOVABLE, 0, vma, vaddr, false);

Add __GFP_ZERO and simply return vma_alloc_folio(...)?

> +	if (folio)
> +		clear_user_highpage(&folio->page, vaddr);
>  
> -	return page;
> +	return folio;
>  }
>  #endif
Matthew Wilcox Jan. 19, 2023, 1:57 p.m. UTC | #2
On Thu, Jan 19, 2023 at 12:16:12PM +0200, Mike Rapoport wrote:
> > +static inline
> > +struct folio *vma_alloc_zeroed_movable_folio(struct vm_area_struct *vma,
> >  				   unsigned long vaddr)
> >  {
> > -	struct page *page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr);
> > +	struct folio *folio;
> >  
> > -	if (page)
> > -		clear_user_highpage(page, vaddr);
> > +	folio = vma_alloc_folio(GFP_HIGHUSER_MOVABLE, 0, vma, vaddr, false);
> 
> Add __GFP_ZERO and simply return vma_alloc_folio(...)?
> 
> > +	if (folio)
> > +		clear_user_highpage(&folio->page, vaddr);

This page is about to be mapped into userspace; the kernel isn't going
to touch the data in it.  So we don't care if the kernel's view of this
page contains zeroes, only that the userspace view of this page contains
zeroes.  The architectures that override this do exactly what you
suggest, but they know they have a physical cache and so that works for
them.  For virtually indexed caches, this is more efficient.
Zi Yan Jan. 19, 2023, 6:22 p.m. UTC | #3
On 16 Jan 2023, at 14:18, Matthew Wilcox (Oracle) wrote:

> Replace alloc_zeroed_user_highpage_movable().  The main difference is
> returning a folio containing a single page instead of returning the
> page, but take the opportunity to rename the function to match other
> allocation functions a little better and rewrite the documentation
> to place more emphasis on the zeroing rather than the highmem aspect.
>
> Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> ---
>  arch/alpha/include/asm/page.h   |  5 ++---
>  arch/arm64/include/asm/page.h   |  4 ++--
>  arch/arm64/mm/fault.c           |  4 ++--
>  arch/ia64/include/asm/page.h    | 14 ++++++--------
>  arch/m68k/include/asm/page_no.h |  5 ++---
>  arch/s390/include/asm/page.h    |  5 ++---
>  arch/x86/include/asm/page.h     |  5 ++---
>  include/linux/highmem.h         | 33 ++++++++++++++++-----------------
>  mm/memory.c                     | 16 ++++++++++------
>  9 files changed, 44 insertions(+), 47 deletions(-)
>
LGTM. Reviewed-by: Zi Yan <ziy@nvidia.com>

--
Best Regards,
Yan, Zi
diff mbox series

Patch

diff --git a/arch/alpha/include/asm/page.h b/arch/alpha/include/asm/page.h
index 8f3f5eecba28..bc5256fba8f0 100644
--- a/arch/alpha/include/asm/page.h
+++ b/arch/alpha/include/asm/page.h
@@ -17,9 +17,8 @@ 
 extern void clear_page(void *page);
 #define clear_user_page(page, vaddr, pg)	clear_page(page)
 
-#define alloc_zeroed_user_highpage_movable(vma, vaddr) \
-	alloc_page_vma(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, vma, vaddr)
-#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
+#define vma_alloc_zeroed_movable_folio(vma, vaddr) \
+	vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr, false)
 
 extern void copy_page(void * _to, void * _from);
 #define copy_user_page(to, from, vaddr, pg)	copy_page(to, from)
diff --git a/arch/arm64/include/asm/page.h b/arch/arm64/include/asm/page.h
index 993a27ea6f54..2312e6ee595f 100644
--- a/arch/arm64/include/asm/page.h
+++ b/arch/arm64/include/asm/page.h
@@ -29,9 +29,9 @@  void copy_user_highpage(struct page *to, struct page *from,
 void copy_highpage(struct page *to, struct page *from);
 #define __HAVE_ARCH_COPY_HIGHPAGE
 
-struct page *alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
+struct folio *vma_alloc_zeroed_movable_folio(struct vm_area_struct *vma,
 						unsigned long vaddr);
-#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
+#define vma_alloc_zeroed_movable_folio vma_alloc_zeroed_movable_folio
 
 void tag_clear_highpage(struct page *to);
 #define __HAVE_ARCH_TAG_CLEAR_HIGHPAGE
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 596f46dabe4e..f4cb0f85ccf4 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -925,7 +925,7 @@  NOKPROBE_SYMBOL(do_debug_exception);
 /*
  * Used during anonymous page fault handling.
  */
-struct page *alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
+struct folio *vma_alloc_zeroed_movable_folio(struct vm_area_struct *vma,
 						unsigned long vaddr)
 {
 	gfp_t flags = GFP_HIGHUSER_MOVABLE | __GFP_ZERO;
@@ -938,7 +938,7 @@  struct page *alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
 	if (vma->vm_flags & VM_MTE)
 		flags |= __GFP_ZEROTAGS;
 
-	return alloc_page_vma(flags, vma, vaddr);
+	return vma_alloc_folio(flags, 0, vma, vaddr, false);
 }
 
 void tag_clear_highpage(struct page *page)
diff --git a/arch/ia64/include/asm/page.h b/arch/ia64/include/asm/page.h
index 1b990466d540..ba0b365cf2b2 100644
--- a/arch/ia64/include/asm/page.h
+++ b/arch/ia64/include/asm/page.h
@@ -82,17 +82,15 @@  do {						\
 } while (0)
 
 
-#define alloc_zeroed_user_highpage_movable(vma, vaddr)			\
+#define vma_alloc_zeroed_movable_folio(vma, vaddr)			\
 ({									\
-	struct page *page = alloc_page_vma(				\
-		GFP_HIGHUSER_MOVABLE | __GFP_ZERO, vma, vaddr);		\
-	if (page)							\
- 		flush_dcache_page(page);				\
-	page;								\
+	struct folio *folio = vma_alloc_folio(				\
+		GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr, false); \
+	if (folio)							\
+		flush_dcache_folio(folio);				\
+	folio;								\
 })
 
-#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
-
 #define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
 #include <asm-generic/memory_model.h>
diff --git a/arch/m68k/include/asm/page_no.h b/arch/m68k/include/asm/page_no.h
index c9d0d84158a4..abd2c3aeb015 100644
--- a/arch/m68k/include/asm/page_no.h
+++ b/arch/m68k/include/asm/page_no.h
@@ -13,9 +13,8 @@  extern unsigned long memory_end;
 #define clear_user_page(page, vaddr, pg)	clear_page(page)
 #define copy_user_page(to, from, vaddr, pg)	copy_page(to, from)
 
-#define alloc_zeroed_user_highpage_movable(vma, vaddr) \
-	alloc_page_vma(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, vma, vaddr)
-#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
+#define vma_alloc_zeroed_movable_folio(vma, vaddr) \
+	vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr, false)
 
 #define __pa(vaddr)		((unsigned long)(vaddr))
 #define __va(paddr)		((void *)((unsigned long)(paddr)))
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index 61dea67bb9c7..8a2a3b5d1e29 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -73,9 +73,8 @@  static inline void copy_page(void *to, void *from)
 #define clear_user_page(page, vaddr, pg)	clear_page(page)
 #define copy_user_page(to, from, vaddr, pg)	copy_page(to, from)
 
-#define alloc_zeroed_user_highpage_movable(vma, vaddr) \
-	alloc_page_vma(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, vma, vaddr)
-#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
+#define vma_alloc_zeroed_movable_folio(vma, vaddr) \
+	vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr, false)
 
 /*
  * These are used to make use of C type-checking..
diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h
index 9cc82f305f4b..d18e5c332cb9 100644
--- a/arch/x86/include/asm/page.h
+++ b/arch/x86/include/asm/page.h
@@ -34,9 +34,8 @@  static inline void copy_user_page(void *to, void *from, unsigned long vaddr,
 	copy_page(to, from);
 }
 
-#define alloc_zeroed_user_highpage_movable(vma, vaddr) \
-	alloc_page_vma(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, vma, vaddr)
-#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
+#define vma_alloc_zeroed_movable_folio(vma, vaddr) \
+	vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr, false)
 
 #ifndef __pa
 #define __pa(x)		__phys_addr((unsigned long)(x))
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 56703082f803..9fa462561e05 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -208,31 +208,30 @@  static inline void clear_user_highpage(struct page *page, unsigned long vaddr)
 }
 #endif
 
-#ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
+#ifndef vma_alloc_zeroed_movable_folio
 /**
- * alloc_zeroed_user_highpage_movable - Allocate a zeroed HIGHMEM page for a VMA that the caller knows can move
- * @vma: The VMA the page is to be allocated for
- * @vaddr: The virtual address the page will be inserted into
+ * vma_alloc_zeroed_movable_folio - Allocate a zeroed page for a VMA.
+ * @vma: The VMA the page is to be allocated for.
+ * @vaddr: The virtual address the page will be inserted into.
  *
- * Returns: The allocated and zeroed HIGHMEM page
+ * This function will allocate a page suitable for inserting into this
+ * VMA at this virtual address.  It may be allocated from highmem or
+ * the movable zone.  An architecture may provide its own implementation.
  *
- * This function will allocate a page for a VMA that the caller knows will
- * be able to migrate in the future using move_pages() or reclaimed
- *
- * An architecture may override this function by defining
- * __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE and providing their own
- * implementation.
+ * Return: A folio containing one allocated and zeroed page or NULL if
+ * we are out of memory.
  */
-static inline struct page *
-alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
+static inline
+struct folio *vma_alloc_zeroed_movable_folio(struct vm_area_struct *vma,
 				   unsigned long vaddr)
 {
-	struct page *page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr);
+	struct folio *folio;
 
-	if (page)
-		clear_user_highpage(page, vaddr);
+	folio = vma_alloc_folio(GFP_HIGHUSER_MOVABLE, 0, vma, vaddr, false);
+	if (folio)
+		clear_user_highpage(&folio->page, vaddr);
 
-	return page;
+	return folio;
 }
 #endif
 
diff --git a/mm/memory.c b/mm/memory.c
index f7613650efd4..4cb2cd809b18 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3056,10 +3056,12 @@  static vm_fault_t wp_page_copy(struct vm_fault *vmf)
 		goto oom;
 
 	if (is_zero_pfn(pte_pfn(vmf->orig_pte))) {
-		new_page = alloc_zeroed_user_highpage_movable(vma,
-							      vmf->address);
-		if (!new_page)
+		struct folio *new_folio;
+
+		new_folio = vma_alloc_zeroed_movable_folio(vma, vmf->address);
+		if (!new_folio)
 			goto oom;
+		new_page = &new_folio->page;
 	} else {
 		new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma,
 				vmf->address);
@@ -3998,6 +4000,7 @@  static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
 {
 	struct vm_area_struct *vma = vmf->vma;
 	struct page *page;
+	struct folio *folio;
 	vm_fault_t ret = 0;
 	pte_t entry;
 
@@ -4047,11 +4050,12 @@  static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
 	/* Allocate our own private page. */
 	if (unlikely(anon_vma_prepare(vma)))
 		goto oom;
-	page = alloc_zeroed_user_highpage_movable(vma, vmf->address);
-	if (!page)
+	folio = vma_alloc_zeroed_movable_folio(vma, vmf->address);
+	if (!folio)
 		goto oom;
 
-	if (mem_cgroup_charge(page_folio(page), vma->vm_mm, GFP_KERNEL))
+	page = &folio->page;
+	if (mem_cgroup_charge(folio, vma->vm_mm, GFP_KERNEL))
 		goto oom_free_page;
 	cgroup_throttle_swaprate(page, GFP_KERNEL);