diff --git a/mm/internal.h b/mm/internal.h index 566cbd2dce48..8b1263e81054 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -589,14 +589,16 @@ void free_pgtables(struct mmu_gather *tlb, struct unmap_desc *desc); void pmd_install(struct mm_struct *mm, pmd_t *pmd, pgtable_t *pte); /** - * sync_with_folio_pmd_zap - sync with concurrent zapping of a folio PMD + * sync_with_folio_pmd_zap - sync with concurrent zapping of folios * @mm: The mm_struct. * @pmdp: Pointer to the pmd that was found to be pmd_none(). * * When we find a pmd_none() while unmapping a folio without holding the PTL, - * zap_huge_pmd() may have cleared the PMD but not yet modified the folio to - * indicate that it's unmapped. Skipping the PMD without synchronization could - * make folio unmapping code assume that unmapping failed. + * zap_huge_pmd() may have cleared the PMD but not yet updated the folio + * mapcount, and zap_empty_pte_table() clears the PMD only after the rmaps + * for the table have been removed, but nothing orders the pmd_none() read + * against later mapcount reads. Skipping the PMD without synchronization + * could make folio unmapping code assume that unmapping failed. * * Wait for concurrent zapping to complete by grabbing the PTL. */ diff --git a/mm/memory.c b/mm/memory.c index 591592bc5a94..916637e8381d 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2036,17 +2036,6 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb, } } while (pte += nr, addr += PAGE_SIZE * nr, addr != end); - /* - * Fast path: try to hold the pmd lock and unmap the PTE page. - * - * If the pte lock was released midway (retry case), or if the attempt - * to hold the pmd lock failed, then we need to recheck all pte entries - * to ensure they are still none, thereby preventing the pte entries - * from being repopulated by another thread. - */ - if (can_reclaim_pt && direct_reclaim && addr == end) - direct_reclaim = zap_empty_pte_table(mm, pmd, ptl, &pmdval); - add_mm_rss_vec(mm, rss); lazy_mmu_mode_disable(); @@ -2055,6 +2044,20 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb, tlb_flush_mmu_tlbonly(tlb); tlb_flush_rmaps(tlb, vma); } + + /* + * Fast path: try to hold the pmd lock and unmap the PTE page. + * + * If the pte lock was released midway (retry case), or if the attempt + * to hold the pmd lock failed, then we need to recheck all pte entries + * to ensure they are still none, thereby preventing the pte entries + * from being repopulated by another thread. + * + * Clear the PMD after the rmaps for the table have been removed, in case + * an incorrect mapcount is observed after unmapping the folio. + */ + if (can_reclaim_pt && direct_reclaim && addr == end) + direct_reclaim = zap_empty_pte_table(mm, pmd, ptl, &pmdval); pte_unmap_unlock(start_pte, ptl); /* @@ -2101,13 +2104,15 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb, addr = next; continue; } + /* We already synchronized with concurrent zapping. */ + if (pmd_none(*pmd)) { + addr = next; + continue; + } /* fall through */ - } else if (details && details->single_folio && - folio_test_pmd_mappable(details->single_folio) && - next - addr == HPAGE_PMD_SIZE && pmd_none(*pmd)) { - sync_with_folio_pmd_zap(tlb->mm, pmd); - } - if (pmd_none(*pmd)) { + } else if (pmd_none(*pmd)) { + if (details && details->single_folio) + sync_with_folio_pmd_zap(tlb->mm, pmd); addr = next; continue; }