mm/compaction: fix bug in hugetlb handling pathway
commit a84edd52f0a0fa193f0f685769939cf84510755b upstream. 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 commit66fe1cf7f5("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:369fa227c2("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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
c45ba83935
commit
4f34d6f979
@@ -980,13 +980,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;
|
||||
@@ -1010,8 +1010,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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user