Commit 63931eb9 authored by Vlastimil Babka's avatar Vlastimil Babka Committed by Linus Torvalds

mm, page_alloc: disallow __GFP_COMP in alloc_pages_exact()

alloc_pages_exact*() allocates a page of sufficient order and then splits
it to return only the number of pages requested.  That makes it
incompatible with __GFP_COMP, because compound pages cannot be split.

As shown by [1] things may silently work until the requested size
(possibly depending on user) stops being power of two.  Then for
CONFIG_DEBUG_VM, BUG_ON() triggers in split_page().  Without
CONFIG_DEBUG_VM, consequences are unclear.

There are several options here, none of them great:

1) Don't do the splitting when __GFP_COMP is passed, and return the
   whole compound page.  However if caller then returns it via
   free_pages_exact(), that will be unexpected and the freeing actions
   there will be wrong.

2) Warn and remove __GFP_COMP from the flags.  But the caller may have
   really wanted it, so things may break later somewhere.

3) Warn and return NULL.  However NULL may be unexpected, especially
   for small sizes.

This patch picks option 2, because as Michal Hocko put it: "callers wanted
it" is much less probable than "caller is simply confused and more gfp
flags is surely better than fewer".

[1] https://lore.kernel.org/lkml/20181126002805.GI18977@shao2-debian/T/#u

Link: http://lkml.kernel.org/r/0c6393eb-b28d-4607-c386-862a71f09de6@suse.czSigned-off-by: default avatarVlastimil Babka <vbabka@suse.cz>
Acked-by: default avatarMichal Hocko <mhocko@suse.com>
Acked-by: default avatarKirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: default avatarMel Gorman <mgorman@techsingularity.net>
Cc: Takashi Iwai <tiwai@suse.de>
Cc: Hugh Dickins <hughd@google.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 5fd4ca2d
...@@ -4821,7 +4821,7 @@ static void *make_alloc_exact(unsigned long addr, unsigned int order, ...@@ -4821,7 +4821,7 @@ static void *make_alloc_exact(unsigned long addr, unsigned int order,
/** /**
* alloc_pages_exact - allocate an exact number physically-contiguous pages. * alloc_pages_exact - allocate an exact number physically-contiguous pages.
* @size: the number of bytes to allocate * @size: the number of bytes to allocate
* @gfp_mask: GFP flags for the allocation * @gfp_mask: GFP flags for the allocation, must not contain __GFP_COMP
* *
* This function is similar to alloc_pages(), except that it allocates the * This function is similar to alloc_pages(), except that it allocates the
* minimum number of pages to satisfy the request. alloc_pages() can only * minimum number of pages to satisfy the request. alloc_pages() can only
...@@ -4838,6 +4838,9 @@ void *alloc_pages_exact(size_t size, gfp_t gfp_mask) ...@@ -4838,6 +4838,9 @@ void *alloc_pages_exact(size_t size, gfp_t gfp_mask)
unsigned int order = get_order(size); unsigned int order = get_order(size);
unsigned long addr; unsigned long addr;
if (WARN_ON_ONCE(gfp_mask & __GFP_COMP))
gfp_mask &= ~__GFP_COMP;
addr = __get_free_pages(gfp_mask, order); addr = __get_free_pages(gfp_mask, order);
return make_alloc_exact(addr, order, size); return make_alloc_exact(addr, order, size);
} }
...@@ -4848,7 +4851,7 @@ EXPORT_SYMBOL(alloc_pages_exact); ...@@ -4848,7 +4851,7 @@ EXPORT_SYMBOL(alloc_pages_exact);
* pages on a node. * pages on a node.
* @nid: the preferred node ID where memory should be allocated * @nid: the preferred node ID where memory should be allocated
* @size: the number of bytes to allocate * @size: the number of bytes to allocate
* @gfp_mask: GFP flags for the allocation * @gfp_mask: GFP flags for the allocation, must not contain __GFP_COMP
* *
* Like alloc_pages_exact(), but try to allocate on node nid first before falling * Like alloc_pages_exact(), but try to allocate on node nid first before falling
* back. * back.
...@@ -4858,7 +4861,12 @@ EXPORT_SYMBOL(alloc_pages_exact); ...@@ -4858,7 +4861,12 @@ EXPORT_SYMBOL(alloc_pages_exact);
void * __meminit alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask) void * __meminit alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask)
{ {
unsigned int order = get_order(size); unsigned int order = get_order(size);
struct page *p = alloc_pages_node(nid, gfp_mask, order); struct page *p;
if (WARN_ON_ONCE(gfp_mask & __GFP_COMP))
gfp_mask &= ~__GFP_COMP;
p = alloc_pages_node(nid, gfp_mask, order);
if (!p) if (!p)
return NULL; return NULL;
return make_alloc_exact((unsigned long)page_address(p), order, size); return make_alloc_exact((unsigned long)page_address(p), order, size);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment