[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