lkml.org 
[lkml]   [2021]   [Mar]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 601/663] mm, compaction: make fast_isolate_freepages() stay within zone
    Date
    From: Vlastimil Babka <vbabka@suse.cz>

    commit 6e2b7044c199229a3d20cefbd3184968238c4184 upstream.

    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/20210217173300.6394-1-vbabka@suse.cz
    Fixes: 5a811889de10 ("mm, compaction: use free lists to quickly locate a migration target")
    Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
    Acked-by: David Rientjes <rientjes@google.com>
    Acked-by: Mel Gorman <mgorman@techsingularity.net>
    Cc: Andrea Arcangeli <aarcange@redhat.com>
    Cc: David Hildenbrand <david@redhat.com>
    Cc: Michal Hocko <mhocko@kernel.org>
    Cc: Mike Rapoport <rppt@kernel.org>
    Cc: <stable@vger.kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    mm/compaction.c | 16 +++++++++++-----
    1 file changed, 11 insertions(+), 5 deletions(-)

    --- a/mm/compaction.c
    +++ b/mm/compaction.c
    @@ -1248,7 +1248,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)
    @@ -1259,8 +1259,12 @@ fast_isolate_around(struct compact_contr
    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) {
    @@ -1362,7 +1366,8 @@ fast_isolate_freepages(struct compact_co
    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;
    @@ -1432,7 +1437,8 @@ fast_isolate_freepages(struct compact_co
    } 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;
    }

    \
     
     \ /
      Last update: 2021-03-02 00:36    [W:2.068 / U:0.032 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site