]> Git Repo - linux.git/commitdiff
mm, page_alloc: fix has_unmovable_pages for HugePages
authorOscar Salvador <[email protected]>
Fri, 21 Dec 2018 22:31:00 +0000 (14:31 -0800)
committerLinus Torvalds <[email protected]>
Fri, 21 Dec 2018 22:51:18 +0000 (14:51 -0800)
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 1.0.0-prebuilt.qemu-project.org 04/01/2014
  RIP: 0010:has_unmovable_pages+0x154/0x210
  Call Trace:
   is_mem_section_removable+0x7d/0x100
   removable_show+0x90/0xb0
   dev_attr_show+0x1c/0x50
   sysfs_kf_seq_show+0xca/0x1b0
   seq_read+0x133/0x380
   __vfs_read+0x26/0x180
   vfs_read+0x89/0x140
   ksys_read+0x42/0x90
   do_syscall_64+0x5b/0x180
   entry_SYSCALL_64_after_hwframe+0x44/0xa9

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
round_up().

[[email protected]: remove round_up(), adjust skip pages logic per Michal]
Link: http://lkml.kernel.org/r/[email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Oscar Salvador <[email protected]>
Acked-by: Michal Hocko <[email protected]>
Reviewed-by: David Hildenbrand <[email protected]>
Cc: Vlastimil Babka <[email protected]>
Cc: Pavel Tatashin <[email protected]>
Cc: Mike Rapoport <[email protected]>
Cc: <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
mm/page_alloc.c

index e2afdb2dc2c548ad618f0ba634fd0e37b2e320b1..e95b5b7c9c3d637efe29d07d86c75975acbfc500 100644 (file)
@@ -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;
                        continue;
                }
 
This page took 0.08184 seconds and 4 git commands to generate.