[PATCH 13/46] mm/huge_memory: fix truncate racing with PMD zapping

Zi Yan ziy at nvidia.com
Tue Oct 27 19:54:27 PDT 2026


On Mon Oct 26, 2026 at 7:17 PM EDT, David Hildenbrand (Arm) wrote:
> From: Chris Mason <mason at kernel.org>
>
> zap_huge_pmd_folio() removes the rmap before calling folio_mark_dirty().
> If this was the last mapping, truncation can skip unmapping the folio
> and proceed without waiting for the PMD lock, racing with dirtying.
>
> ifs_set_range_dirty() can oops if MADV_DONTNEED races with
> ftruncate() on XFS, when we get the folio set dirty after it was found
> to not be mapped anymore.
>
> Move folio_mark_dirty() and folio_mark_accessed() before rmap removal,
> matching the PTE zap path. This keeps the folio mapped while updating
> its state, so truncation must wait for the page table lock.
>
> Fix generated by an LLM and sent by Chris Mason in private.
>
> Fixes: fe6cf984939d ("mm/huge_memory: transfer the pmd dirty bit to the folio on zap")
> Cc: stable at vger.kernel.org
> Signed-off-by: Chris Mason <mason at kernel.org>
> [ david: simplify comment and description ]
> Signed-off-by: David Hildenbrand (Arm) <david at kernel.org>
> ---
>  mm/huge_memory.c | 14 ++++++++------
>  1 file changed, 8 insertions(+), 6 deletions(-)
>

It seems to me that moving the rmap removal code after folio_mark_*()
matches zap_present_folio_ptes() closer. Feel free to use it or ignore
it.

Anyway,

Reviewed-by: Zi Yan <ziy at nvidia.com>


diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index bd44d58e86845..192f7969e3648 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2484,10 +2484,6 @@ static void zap_huge_pmd_folio(struct mm_struct *mm, struct vm_area_struct *vma,
 {
 	const bool is_device_private = folio_is_device_private(folio);
 
-	/* Present and device private folios are rmappable. */
-	if (is_present || is_device_private)
-		folio_remove_rmap_pmd(folio, &folio->page, vma);
-
 	if (folio_test_anon(folio)) {
 		add_mm_counter(mm, MM_ANONPAGES, -HPAGE_PMD_NR);
 	} else {
@@ -2501,6 +2497,13 @@ static void zap_huge_pmd_folio(struct mm_struct *mm, struct vm_area_struct *vma,
 			folio_mark_accessed(folio);
 	}
 
+	/*
+	 * Present and device private folios are rmappable. Only remove the rmap
+	 * after transferring young+dirty to the folio.
+	 */
+	if (is_present || is_device_private)
+		folio_remove_rmap_pmd(folio, &folio->page, vma);
+
 	/* Device private folios are pinned. */
 	if (is_device_private)
 		folio_put(folio);


-- 
Best Regards,
Yan, Zi




More information about the kexec mailing list