diff --git a/mm/khugepaged.c b/mm/khugepaged.c index a6cb9e92f7c9..7a6acb5ba863 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -2763,13 +2763,9 @@ static enum scan_result collapse_scan_file(struct mm_struct *mm, else cc->progress += HPAGE_PMD_NR; - if (result == SCAN_SUCCEED) { - if (present < HPAGE_PMD_NR - max_ptes_none) { - result = SCAN_EXCEED_NONE_PTE; - count_vm_event(THP_SCAN_EXCEED_NONE_PTE); - } else { - result = collapse_file(mm, addr, file, start, cc); - } + if (result == SCAN_SUCCEED && present < HPAGE_PMD_NR - max_ptes_none) { + result = SCAN_EXCEED_NONE_PTE; + count_vm_event(THP_SCAN_EXCEED_NONE_PTE); } trace_mm_khugepaged_scan_file(mm, failed_pfn, file, present, swap, result); @@ -2800,8 +2796,16 @@ static enum scan_result collapse_single_pmd(unsigned long addr, mmap_read_unlock(mm); *lock_dropped = true; -retry: + + /* + * SCAN_PTE_MAPPED_HUGEPAGE is work too: the page cache already holds + * the PMD folio, and only the PTE table is left to retract. + */ result = collapse_scan_file(mm, addr, file, pgoff, cc); + if (result != SCAN_SUCCEED) + goto put; +retry: + result = collapse_file(mm, addr, file, pgoff, cc); /* Dirty pages are worth a writeback and one more try, if asked for */ if (cc->policy.file_writeback_dirty && result == SCAN_PAGE_DIRTY_OR_WRITEBACK && @@ -2813,6 +2817,7 @@ static enum scan_result collapse_single_pmd(unsigned long addr, triggered_wb = true; goto retry; } +put: fput(file); if (result == SCAN_PTE_MAPPED_HUGEPAGE) {