All of lore.kernel.org
 help / color / mirror / Atom feed
* [merged mm-hotfixes-stable] x86-mm-fix-pmd_modify-dropping-the-dirty-bit.patch removed from -mm tree
@ 2026-09-18  5:43 Andrew Morton
  2026-09-18 11:40 ` Pedro Falcato
  0 siblings, 1 reply; 3+ messages in thread
From: Andrew Morton @ 2026-09-18  5:43 UTC (permalink / raw)
  To: mm-commits, yu-cheng.yu, vbabka, tglx, stable, rppt,
	rick.p.edgecombe, pfalcato, orsonpeters, ljs, liam, jannh, david,
	dave.hansen, yanglincheng, akpm


The quilt patch titled
     Subject: x86/mm: fix pmd_modify() dropping the dirty bit
has been removed from the -mm tree.  Its filename was
     x86-mm-fix-pmd_modify-dropping-the-dirty-bit.patch

This patch was dropped because it was merged into the mm-hotfixes-stable branch
of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

------------------------------------------------------
From: Vernon Yang <yanglincheng@kylinos.cn>
Subject: x86/mm: fix pmd_modify() dropping the dirty bit
Date: Thu, 3 Sep 2026 11:16:08 +0800

pmd_modify() masks the old value with (_HPAGE_CHG_MASK & ~_PAGE_DIRTY),
silently discarding the hardware dirty bit.  The subsequent
pmd_mksaveddirty() call is supposed to transfer _PAGE_DIRTY into
_PAGE_SAVED_DIRTY when write-protecting, but the dirty bit was already
stripped from the value, so there is nothing left to transfer.

Contrast with pte_modify(), which keeps _PAGE_DIRTY_BITS in its mask, and
pud_modify(), which keeps _HPAGE_CHG_MASK untouched: pmd_modify() is the
odd one out.  Any pmd_modify() on a writable, dirty PMD loses the dirty
state.

One visible consequence is data loss with MADV_FREE on PMD-mapped THP:

    memset(buf, 0x5A, size);          // PMD-mapped THP, PMD dirty
    madvise(buf, size, MADV_FREE);    // PMD cleaned but left writable,
                                      // folio marked lazyfree
    memset(buf, 0x5A, size);          // hardware sets _PAGE_DIRTY again
    mprotect(buf, size, PROT_READ);   // pmd_modify() drops the dirty bit
    mprotect(buf, size, PROT_READ|PROT_WRITE);
    // ... memory pressure ...

Reclaim (e.g.  under memcg pressure) then finds the lazyfree folio with no
dirty bit set anywhere and frees it in __discard_anon_folio_pmd_locked(),
even though the data was rewritten after MADV_FREE; subsequent reads fault
in fresh zero pages.  NUMA hinting alone can trigger the same loss, as
do_huge_pmd_numa_page() restores the PMD through pmd_modify() as well.

PMD-mapped file THPs are affected too: mprotect()/NUMA hinting dropping
the dirty bit means rewritten data is never written back.

Fix it by keeping _PAGE_DIRTY in the preserved mask, exactly like
pte_modify() and pud_modify() do.  The existing
pmd_mksaveddirty()/pmd_clear_saveddirty() pair then performs the
hardware-dirty <-> saved-dirty transition based on the write bit,
preserving the shadow-stack encoding rules.

(Pedro [1]: "FYI we just had a customer case for our downstream kernel
for this exact same issue.  This fixed it beautifully".)

Link: https://lore.kernel.org/20260903031608.1194238-1-vernon2gm@gmail.com
Link: https://lore.kernel.org/ap6IYeTM8PMinxo-@pedro-suse.tail5790ac.ts.net [1]
Fixes: bb3aadf7d446 ("x86/mm: Start actually marking _PAGE_SAVED_DIRTY")
Signed-off-by: Vernon Yang <yanglincheng@kylinos.cn>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reported-by: Orson Peters <orsonpeters@gmail.com>
Closes: https://lore.kernel.org/r/CAJxLxMUGu1-L+O_nAONOwOXnS=cNbNApCWqdthRjd76LThtSPg@mail.gmail.com/
Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Tested-by: Pedro Falcato <pfalcato@suse.de>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: David Hildenbrand <david@kernel.org>
Cc: Jann Horn <jannh@google.com>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Yu-cheng Yu <yu-cheng.yu@intel.com>
Cc: <stable@vger.kernel.org>
---

 arch/x86/include/asm/pgtable.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/arch/x86/include/asm/pgtable.h~x86-mm-fix-pmd_modify-dropping-the-dirty-bit
+++ a/arch/x86/include/asm/pgtable.h
@@ -806,7 +806,7 @@ static inline pmd_t pmd_modify(pmd_t pmd
 	pmdval_t val = pmd_val(pmd), oldval = val;
 	pmd_t pmd_result;
 
-	val &= (_HPAGE_CHG_MASK & ~_PAGE_DIRTY);
+	val &= _HPAGE_CHG_MASK;
 	val |= check_pgprot(newprot) & ~_HPAGE_CHG_MASK;
 	val = flip_protnone_guard(oldval, val, PHYSICAL_PMD_PAGE_MASK);
 
_

Patches currently in -mm which might be from yanglincheng@kylinos.cn are

mm-khugepaged-fix-swap-entry-value-to-folio_pfn.patch
mm-khugepaged-fix-folio-is-used-after-pte_unmap_unlock.patch
mm-khugepaged-fix-folio-is-used-after-folio_put-unlock.patch


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-09-18 15:21 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-18  5:43 [merged mm-hotfixes-stable] x86-mm-fix-pmd_modify-dropping-the-dirty-bit.patch removed from -mm tree Andrew Morton
2026-09-18 11:40 ` Pedro Falcato
2026-09-18 15:21   ` Andrew Morton

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.