Skip to content

Commit

Permalink
mm, compaction: make fast_isolate_freepages() stay within zone
Browse files Browse the repository at this point in the history
Compaction always operates on pages from a single given zone when
isolating both pages to migrate and freepages.  Pageblock boundaries are
intersected with zone boundaries to be safe in case zone starts or ends in
the middle of pageblock.  The use of pageblock_pfn_to_page() protects
against non-contiguous pageblocks.

The functions fast_isolate_freepages() and fast_isolate_around() don't
currently protect the fast freepage isolation thoroughly enough against
these corner cases, and can result in freepage isolation operate outside
of zone boundaries:

 - in fast_isolate_freepages() if we get a pfn from the first pageblock
   of a zone that starts in the middle of that pageblock, 'highest' can
   be a pfn outside of the zone.

   If we fail to isolate anything in this function, we may then call
   fast_isolate_around() on a pfn outside of the zone and there
   effectively do a set_pageblock_skip(page_to_pfn(highest)) which may
   currently hit a VM_BUG_ON() in some configurations

 - fast_isolate_around() checks only the zone end boundary and not
   beginning, nor that the pageblock is contiguous (with
   pageblock_pfn_to_page()) so it's possible that we end up calling
   isolate_freepages_block() on a range of pfn's from two different
   zones and end up e.g. isolating freepages under the wrong zone's
   lock.

This patch should fix the above issues.

Link: https://lkml.kernel.org/r/[email protected]
Fixes: 5a81188 ("mm, compaction: use free lists to quickly locate a migration target")
Signed-off-by: Vlastimil Babka <[email protected]>
Acked-by: David Rientjes <[email protected]>
Acked-by: Mel Gorman <[email protected]>
Cc: Andrea Arcangeli <[email protected]>
Cc: David Hildenbrand <[email protected]>
Cc: Michal Hocko <[email protected]>
Cc: Mike Rapoport <[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 Feb 24, 2021
1 parent 15d28d0 commit 6e2b704
Showing 1 changed file with 11 additions and 5 deletions.
16 changes: 11 additions & 5 deletions mm/compaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -1284,7 +1284,7 @@ static void
fast_isolate_around(struct compact_control *cc, unsigned long pfn, unsigned long nr_isolated)
{
unsigned long start_pfn, end_pfn;
struct page *page = pfn_to_page(pfn);
struct page *page;

/* Do not search around if there are enough pages already */
if (cc->nr_freepages >= cc->nr_migratepages)
Expand All @@ -1295,8 +1295,12 @@ fast_isolate_around(struct compact_control *cc, unsigned long pfn, unsigned long
return;

/* Pageblock boundaries */
start_pfn = pageblock_start_pfn(pfn);
end_pfn = min(pageblock_end_pfn(pfn), zone_end_pfn(cc->zone)) - 1;
start_pfn = max(pageblock_start_pfn(pfn), cc->zone->zone_start_pfn);
end_pfn = min(pageblock_end_pfn(pfn), zone_end_pfn(cc->zone));

page = pageblock_pfn_to_page(start_pfn, end_pfn, cc->zone);
if (!page)
return;

/* Scan before */
if (start_pfn != pfn) {
Expand Down Expand Up @@ -1398,7 +1402,8 @@ fast_isolate_freepages(struct compact_control *cc)
pfn = page_to_pfn(freepage);

if (pfn >= highest)
highest = pageblock_start_pfn(pfn);
highest = max(pageblock_start_pfn(pfn),
cc->zone->zone_start_pfn);

if (pfn >= low_pfn) {
cc->fast_search_fail = 0;
Expand Down Expand Up @@ -1468,7 +1473,8 @@ fast_isolate_freepages(struct compact_control *cc)
} else {
if (cc->direct_compaction && pfn_valid(min_pfn)) {
page = pageblock_pfn_to_page(min_pfn,
pageblock_end_pfn(min_pfn),
min(pageblock_end_pfn(min_pfn),
zone_end_pfn(cc->zone)),
cc->zone);
cc->free_pfn = min_pfn;
}
Expand Down

0 comments on commit 6e2b704

Please sign in to comment.