Skip to content

Commit

Permalink
mm, compaction: fix wrong pfn handling in __reset_isolation_pfn()
Browse files Browse the repository at this point in the history
Florian and Dave reported [1] a NULL pointer dereference in
__reset_isolation_pfn().  While the exact cause is unclear, staring at
the code revealed two bugs, which might be related.

One bug is that if zone starts in the middle of pageblock, block_page
might correspond to different pfn than block_pfn, and then the
pfn_valid_within() checks will check different pfn's than those accessed
via struct page.  This might result in acessing an unitialized page in
CONFIG_HOLES_IN_ZONE configs.

The other bug is that end_page refers to the first page of next
pageblock and not last page of current pageblock.  The online and valid
check is then wrong and with sections, the while (page < end_page) loop
might wander off actual struct page arrays.

[1] https://lore.kernel.org/linux-xfs/[email protected]/

Link: http://lkml.kernel.org/r/[email protected]
Fixes: 6b0868c ("mm/compaction.c: correct zone boundary handling when resetting pageblock skip hints")
Signed-off-by: Vlastimil Babka <[email protected]>
Reported-by: Florian Weimer <[email protected]>
Reported-by: Dave Chinner <[email protected]>
Acked-by: Mel Gorman <[email protected]>
Cc: <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
tehcaster authored and torvalds committed Oct 14, 2019
1 parent 3f36d86 commit a2e9a5a
Showing 1 changed file with 4 additions and 3 deletions.
7 changes: 4 additions & 3 deletions mm/compaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,14 +270,15 @@ __reset_isolation_pfn(struct zone *zone, unsigned long pfn, bool check_source,

/* Ensure the start of the pageblock or zone is online and valid */
block_pfn = pageblock_start_pfn(pfn);
block_page = pfn_to_online_page(max(block_pfn, zone->zone_start_pfn));
block_pfn = max(block_pfn, zone->zone_start_pfn);
block_page = pfn_to_online_page(block_pfn);
if (block_page) {
page = block_page;
pfn = block_pfn;
}

/* Ensure the end of the pageblock or zone is online and valid */
block_pfn += pageblock_nr_pages;
block_pfn = pageblock_end_pfn(pfn) - 1;
block_pfn = min(block_pfn, zone_end_pfn(zone) - 1);
end_page = pfn_to_online_page(block_pfn);
if (!end_page)
Expand All @@ -303,7 +304,7 @@ __reset_isolation_pfn(struct zone *zone, unsigned long pfn, bool check_source,

page += (1 << PAGE_ALLOC_COSTLY_ORDER);
pfn += (1 << PAGE_ALLOC_COSTLY_ORDER);
} while (page < end_page);
} while (page <= end_page);

return false;
}
Expand Down

0 comments on commit a2e9a5a

Please sign in to comment.