diff mbox series

[v14,084/138] mm/page_alloc: Add folio allocation functions

Message ID 20210715033704.692967-85-willy@infradead.org (mailing list archive)
State New
Headers show
Series Memory folios | expand

Commit Message

Matthew Wilcox July 15, 2021, 3:36 a.m. UTC
The __folio_alloc(), __folio_alloc_node() and folio_alloc() functions
are mostly for type safety, but they also ensure that the page allocator
allocates a compound page and initialises the deferred list if the page
is large enough to have one.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 include/linux/gfp.h | 16 ++++++++++++++++
 mm/mempolicy.c      | 10 ++++++++++
 mm/page_alloc.c     | 12 ++++++++++++
 3 files changed, 38 insertions(+)

Comments

David Howells Aug. 10, 2021, 9:51 p.m. UTC | #1
Matthew Wilcox (Oracle) <willy@infradead.org> wrote:

> +struct folio *folio_alloc(gfp_t gfp, unsigned order)
> +{
> +	struct page *page = alloc_pages(gfp | __GFP_COMP, order);
> +
> +	if (page && order > 1)
> +		prep_transhuge_page(page);

Ummm...  Shouldn't order==1 pages (two page folios) be prep'd also?

> +	return (struct folio *)page;
> +}

Would it be better to just jump to alloc_pages() if order <= 1?  E.g.:

struct folio *folio_alloc(gfp_t gfp, unsigned order)
{
	struct page *page;

	if (order <= 1)
		return (struct folio *)alloc_pages(gfp | __GFP_COMP, order);

	page = alloc_pages(gfp | __GFP_COMP, order);
	if (page)
		prep_transhuge_page(page);
	return (struct folio *)page;
}

David
Vlastimil Babka Aug. 12, 2021, 5:25 p.m. UTC | #2
On 7/15/21 5:36 AM, Matthew Wilcox (Oracle) wrote:
> The __folio_alloc(), __folio_alloc_node() and folio_alloc() functions
> are mostly for type safety, but they also ensure that the page allocator
> allocates a compound page and initialises the deferred list if the page
> is large enough to have one.
> 
> Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> Reviewed-by: Christoph Hellwig <hch@lst.de>

Acked-by: Vlastimil Babka <vbabka@suse.cz>
Matthew Wilcox Aug. 16, 2021, 2:35 a.m. UTC | #3
On Tue, Aug 10, 2021 at 10:51:23PM +0100, David Howells wrote:
> Matthew Wilcox (Oracle) <willy@infradead.org> wrote:
> 
> > +struct folio *folio_alloc(gfp_t gfp, unsigned order)
> > +{
> > +	struct page *page = alloc_pages(gfp | __GFP_COMP, order);
> > +
> > +	if (page && order > 1)
> > +		prep_transhuge_page(page);
> 
> Ummm...  Shouldn't order==1 pages (two page folios) be prep'd also?

No.  The deferred list is stored in the second tail page, so there's
nowhere to store one if there are only two pages.

The free_transhuge_page() dtor only handles the deferred list, so
it's fine to skip setting the DTOR in the page too.

> Would it be better to just jump to alloc_pages() if order <= 1?  E.g.:
> 
> struct folio *folio_alloc(gfp_t gfp, unsigned order)
> {
> 	struct page *page;
> 
> 	if (order <= 1)
> 		return (struct folio *)alloc_pages(gfp | __GFP_COMP, order);
> 
> 	page = alloc_pages(gfp | __GFP_COMP, order);
> 	if (page)
> 		prep_transhuge_page(page);
> 	return (struct folio *)page;
> }

That doesn't look simpler to me?
diff mbox series

Patch

diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index dc5ff40608ce..3745efd21cf6 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -523,6 +523,8 @@  static inline void arch_alloc_page(struct page *page, int order) { }
 
 struct page *__alloc_pages(gfp_t gfp, unsigned int order, int preferred_nid,
 		nodemask_t *nodemask);
+struct folio *__folio_alloc(gfp_t gfp, unsigned int order, int preferred_nid,
+		nodemask_t *nodemask);
 
 unsigned long __alloc_pages_bulk(gfp_t gfp, int preferred_nid,
 				nodemask_t *nodemask, int nr_pages,
@@ -564,6 +566,15 @@  __alloc_pages_node(int nid, gfp_t gfp_mask, unsigned int order)
 	return __alloc_pages(gfp_mask, order, nid, NULL);
 }
 
+static inline
+struct folio *__folio_alloc_node(gfp_t gfp, unsigned int order, int nid)
+{
+	VM_BUG_ON(nid < 0 || nid >= MAX_NUMNODES);
+	VM_WARN_ON((gfp & __GFP_THISNODE) && !node_online(nid));
+
+	return __folio_alloc(gfp, order, nid, NULL);
+}
+
 /*
  * Allocate pages, preferring the node given as nid. When nid == NUMA_NO_NODE,
  * prefer the current CPU's closest node. Otherwise node must be valid and
@@ -580,6 +591,7 @@  static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,
 
 #ifdef CONFIG_NUMA
 struct page *alloc_pages(gfp_t gfp, unsigned int order);
+struct folio *folio_alloc(gfp_t gfp, unsigned order);
 extern struct page *alloc_pages_vma(gfp_t gfp_mask, int order,
 			struct vm_area_struct *vma, unsigned long addr,
 			int node, bool hugepage);
@@ -590,6 +602,10 @@  static inline struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)
 {
 	return alloc_pages_node(numa_node_id(), gfp_mask, order);
 }
+static inline struct folio *folio_alloc(gfp_t gfp, unsigned int order)
+{
+	return __folio_alloc_node(gfp, order, numa_node_id());
+}
 #define alloc_pages_vma(gfp_mask, order, vma, addr, node, false)\
 	alloc_pages(gfp_mask, order)
 #define alloc_hugepage_vma(gfp_mask, vma, addr, order) \
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index e32360e90274..95d0cf05f7ca 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -2249,6 +2249,16 @@  struct page *alloc_pages(gfp_t gfp, unsigned order)
 }
 EXPORT_SYMBOL(alloc_pages);
 
+struct folio *folio_alloc(gfp_t gfp, unsigned order)
+{
+	struct page *page = alloc_pages(gfp | __GFP_COMP, order);
+
+	if (page && order > 1)
+		prep_transhuge_page(page);
+	return (struct folio *)page;
+}
+EXPORT_SYMBOL(folio_alloc);
+
 int vma_dup_policy(struct vm_area_struct *src, struct vm_area_struct *dst)
 {
 	struct mempolicy *pol = mpol_dup(vma_policy(src));
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d72a0d9d4184..d03145671934 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -5399,6 +5399,18 @@  struct page *__alloc_pages(gfp_t gfp, unsigned int order, int preferred_nid,
 }
 EXPORT_SYMBOL(__alloc_pages);
 
+struct folio *__folio_alloc(gfp_t gfp, unsigned int order, int preferred_nid,
+		nodemask_t *nodemask)
+{
+	struct page *page = __alloc_pages(gfp | __GFP_COMP, order,
+			preferred_nid, nodemask);
+
+	if (page && order > 1)
+		prep_transhuge_page(page);
+	return (struct folio *)page;
+}
+EXPORT_SYMBOL(__folio_alloc);
+
 /*
  * Common helper functions. Never use with __GFP_HIGHMEM because the returned
  * address cannot represent highmem pages. Use alloc_pages and then kmap if