]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
mm/compaction: fix bug in hugetlb handling pathway
authorVishal Moola (Oracle) <vishal.moola@gmail.com>
Tue, 1 Apr 2025 02:10:24 +0000 (19:10 -0700)
committerAndrew Morton <akpm@linux-foundation.org>
Sat, 12 Apr 2025 00:32:36 +0000 (17:32 -0700)
The compaction code doesn't take references on pages until we're certain
we should attempt to handle it.

In the hugetlb case, isolate_or_dissolve_huge_page() may return -EBUSY
without taking a reference to the folio associated with our pfn.  If our
folio's refcount drops to 0, compound_nr() becomes unpredictable, making
low_pfn and nr_scanned unreliable.  The user-visible effect is minimal -
this should rarely happen (if ever).

Fix this by storing the folio statistics earlier on the stack (just like
the THP and Buddy cases).

Also revert commit 66fe1cf7f581 ("mm: compaction: use helper compound_nr
in isolate_migratepages_block") to make backporting easier.

Link: https://lkml.kernel.org/r/20250401021025.637333-1-vishal.moola@gmail.com
Fixes: 369fa227c219 ("mm: make alloc_contig_range handle free hugetlb pages")
Signed-off-by: Vishal Moola (Oracle) <vishal.moola@gmail.com>
Acked-by: Oscar Salvador <osalvador@suse.de>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/compaction.c

index 139f00c0308a3d43ae3ed445eeed899f95d0c353..ca71fd3c31815c2129c21b754a76e7d077880cd9 100644 (file)
@@ -981,13 +981,13 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                }
 
                if (PageHuge(page)) {
+                       const unsigned int order = compound_order(page);
                        /*
                         * skip hugetlbfs if we are not compacting for pages
                         * bigger than its order. THPs and other compound pages
                         * are handled below.
                         */
                        if (!cc->alloc_contig) {
-                               const unsigned int order = compound_order(page);
 
                                if (order <= MAX_PAGE_ORDER) {
                                        low_pfn += (1UL << order) - 1;
@@ -1011,8 +1011,8 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                                 /* Do not report -EBUSY down the chain */
                                if (ret == -EBUSY)
                                        ret = 0;
-                               low_pfn += compound_nr(page) - 1;
-                               nr_scanned += compound_nr(page) - 1;
+                               low_pfn += (1UL << order) - 1;
+                               nr_scanned += (1UL << order) - 1;
                                goto isolate_fail;
                        }