]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob
5e0efe4a16ea86d6c1d57ce2e966588b39559d6b
[thirdparty/kernel/stable-queue.git] /
1 From 9658d698a8a83540bf6a6c80d13c9a61590ee985 Mon Sep 17 00:00:00 2001
2 From: Lance Yang <lance.yang@linux.dev>
3 Date: Tue, 30 Sep 2025 16:10:40 +0800
4 Subject: mm/rmap: fix soft-dirty and uffd-wp bit loss when remapping zero-filled mTHP subpage to shared zeropage
5
6 From: Lance Yang <lance.yang@linux.dev>
7
8 commit 9658d698a8a83540bf6a6c80d13c9a61590ee985 upstream.
9
10 When splitting an mTHP and replacing a zero-filled subpage with the shared
11 zeropage, try_to_map_unused_to_zeropage() currently drops several
12 important PTE bits.
13
14 For userspace tools like CRIU, which rely on the soft-dirty mechanism for
15 incremental snapshots, losing the soft-dirty bit means modified pages are
16 missed, leading to inconsistent memory state after restore.
17
18 As pointed out by David, the more critical uffd-wp bit is also dropped.
19 This breaks the userfaultfd write-protection mechanism, causing writes to
20 be silently missed by monitoring applications, which can lead to data
21 corruption.
22
23 Preserve both the soft-dirty and uffd-wp bits from the old PTE when
24 creating the new zeropage mapping to ensure they are correctly tracked.
25
26 Link: https://lkml.kernel.org/r/20250930081040.80926-1-lance.yang@linux.dev
27 Fixes: b1f202060afe ("mm: remap unused subpages to shared zeropage when splitting isolated thp")
28 Signed-off-by: Lance Yang <lance.yang@linux.dev>
29 Suggested-by: David Hildenbrand <david@redhat.com>
30 Suggested-by: Dev Jain <dev.jain@arm.com>
31 Acked-by: David Hildenbrand <david@redhat.com>
32 Reviewed-by: Dev Jain <dev.jain@arm.com>
33 Acked-by: Zi Yan <ziy@nvidia.com>
34 Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
35 Reviewed-by: Harry Yoo <harry.yoo@oracle.com>
36 Cc: Alistair Popple <apopple@nvidia.com>
37 Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
38 Cc: Barry Song <baohua@kernel.org>
39 Cc: Byungchul Park <byungchul@sk.com>
40 Cc: Gregory Price <gourry@gourry.net>
41 Cc: "Huang, Ying" <ying.huang@linux.alibaba.com>
42 Cc: Jann Horn <jannh@google.com>
43 Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
44 Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
45 Cc: Mariano Pache <npache@redhat.com>
46 Cc: Mathew Brost <matthew.brost@intel.com>
47 Cc: Peter Xu <peterx@redhat.com>
48 Cc: Rakie Kim <rakie.kim@sk.com>
49 Cc: Rik van Riel <riel@surriel.com>
50 Cc: Ryan Roberts <ryan.roberts@arm.com>
51 Cc: Usama Arif <usamaarif642@gmail.com>
52 Cc: Vlastimil Babka <vbabka@suse.cz>
53 Cc: Yu Zhao <yuzhao@google.com>
54 Cc: <stable@vger.kernel.org>
55 Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
56 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
57 ---
58 mm/migrate.c | 15 ++++++++++-----
59 1 file changed, 10 insertions(+), 5 deletions(-)
60
61 --- a/mm/migrate.c
62 +++ b/mm/migrate.c
63 @@ -198,8 +198,7 @@ bool isolate_folio_to_list(struct folio
64 }
65
66 static bool try_to_map_unused_to_zeropage(struct page_vma_mapped_walk *pvmw,
67 - struct folio *folio,
68 - unsigned long idx)
69 + struct folio *folio, pte_t old_pte, unsigned long idx)
70 {
71 struct page *page = folio_page(folio, idx);
72 pte_t newpte;
73 @@ -208,7 +207,7 @@ static bool try_to_map_unused_to_zeropag
74 return false;
75 VM_BUG_ON_PAGE(!PageAnon(page), page);
76 VM_BUG_ON_PAGE(!PageLocked(page), page);
77 - VM_BUG_ON_PAGE(pte_present(*pvmw->pte), page);
78 + VM_BUG_ON_PAGE(pte_present(old_pte), page);
79
80 if (folio_test_mlocked(folio) || (pvmw->vma->vm_flags & VM_LOCKED) ||
81 mm_forbids_zeropage(pvmw->vma->vm_mm))
82 @@ -224,6 +223,12 @@ static bool try_to_map_unused_to_zeropag
83
84 newpte = pte_mkspecial(pfn_pte(my_zero_pfn(pvmw->address),
85 pvmw->vma->vm_page_prot));
86 +
87 + if (pte_swp_soft_dirty(old_pte))
88 + newpte = pte_mksoft_dirty(newpte);
89 + if (pte_swp_uffd_wp(old_pte))
90 + newpte = pte_mkuffd_wp(newpte);
91 +
92 set_pte_at(pvmw->vma->vm_mm, pvmw->address, pvmw->pte, newpte);
93
94 dec_mm_counter(pvmw->vma->vm_mm, mm_counter(folio));
95 @@ -266,13 +271,13 @@ static bool remove_migration_pte(struct
96 continue;
97 }
98 #endif
99 + old_pte = ptep_get(pvmw.pte);
100 if (rmap_walk_arg->map_unused_to_zeropage &&
101 - try_to_map_unused_to_zeropage(&pvmw, folio, idx))
102 + try_to_map_unused_to_zeropage(&pvmw, folio, old_pte, idx))
103 continue;
104
105 folio_get(folio);
106 pte = mk_pte(new, READ_ONCE(vma->vm_page_prot));
107 - old_pte = ptep_get(pvmw.pte);
108
109 entry = pte_to_swp_entry(old_pte);
110 if (!is_migration_entry_young(entry))