Commit 17e2e7d7 authored by Oscar Salvador's avatar Oscar Salvador Committed by Linus Torvalds

mm, page_alloc: fix has_unmovable_pages for HugePages

While playing with gigantic hugepages and memory_hotplug, I triggered
the following #PF when "cat memoryX/removable":

  BUG: unable to handle kernel NULL pointer dereference at 0000000000000008
  #PF error: [normal kernel read fault]
  PGD 0 P4D 0
  Oops: 0000 [#1] SMP PTI
  CPU: 1 PID: 1481 Comm: cat Tainted: G            E     4.20.0-rc6-mm1-1-default+ #18
  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 04/01/2014
  RIP: 0010:has_unmovable_pages+0x154/0x210
  Call Trace:

The reason is we do not pass the Head to page_hstate(), and so, the call
to compound_order() in page_hstate() returns 0, so we end up checking
all hstates's size to match PAGE_SIZE.

Obviously, we do not find any hstate matching that size, and we return
NULL.  Then, we dereference that NULL pointer in
hugepage_migration_supported() and we got the #PF from above.

Fix that by getting the head page before calling page_hstate().

Also, since gigantic pages span several pageblocks, re-adjust the logic
for skipping pages.  While are it, we can also get rid of the

[ remove round_up(), adjust skip pages logic per Michal]
Link: default avatarOscar Salvador <>
Acked-by: default avatarMichal Hocko <>
Reviewed-by: default avatarDavid Hildenbrand <>
Cc: Vlastimil Babka <>
Cc: Pavel Tatashin <>
Cc: Mike Rapoport <>
Cc: <>
Signed-off-by: default avatarAndrew Morton <>
Signed-off-by: default avatarLinus Torvalds <>
parent 5eed6f1d
......@@ -7814,11 +7814,14 @@ bool has_unmovable_pages(struct zone *zone, struct page *page, int count,
* handle each tail page individually in migration.
if (PageHuge(page)) {
struct page *head = compound_head(page);
unsigned int skip_pages;
if (!hugepage_migration_supported(page_hstate(page)))
if (!hugepage_migration_supported(page_hstate(head)))
goto unmovable;
iter = round_up(iter + 1, 1<<compound_order(page)) - 1;
skip_pages = (1 << compound_order(head)) - (page - head);
iter += skip_pages - 1;
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