* [PATCH v2] mm/ksm: keep soft-dirty and uffd-wp when merging a page
@ 2026-10-19 1:09 Samarth Narang
2026-10-19 2:07 ` Lance Yang
2026-10-19 13:24 ` David Hildenbrand (Arm)
0 siblings, 2 replies; 11+ messages in thread
From: Samarth Narang @ 2026-10-19 1:09 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand
Cc: Xu Xin, Chengming Zhou, Peter Xu, Kiryl Shutsemau, Mike Rapoport,
Lance Yang, linux-mm, linux-kernel, Samarth Narang, stable
replace_page() maps the KSM page with a PTE built from scratch, so the
soft-dirty and uffd bits of the PTE it replaces are lost. Due to this, a
write before the merge no longer shows as soft-dirty, the next write to
a uffd-wp page raises no write-protect fault, and because the page is
mapped with the VMA's normal permissions, on a uffd-rwp VMA the next
access raises no RWP fault.
Copy the soft-dirty and uffd bits from the original PTE to the new PTE,
and restore PAGE_NONE for RWP VMAs, as try_to_map_unused_to_zeropage()
does.
Fixes: 0f8975ec4db2 ("mm: soft-dirty bits for user memory changes tracking")
Fixes: 63b2d4174c4a ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl")
Fixes: 2d427bb01639 ("mm/userfaultfd: add RWP fault delivery and expose UFFDIO_REGISTER_MODE_RWP")
Cc: stable@vger.kernel.org
Tested-by: Lance Yang <lance.yang@linux.dev>
Assisted-by: LLM
Signed-off-by: Samarth Narang <samarth.colleges@gmail.com>
---
Notes:
v1: https://lore.kernel.org/all/20261018122957.526467-1-samarth.colleges@gmail.com/
Changes since v1 (thanks, Lance):
- Fixes: point the uffd-wp and RWP tags at the commits that make the
registration modes reachable (63b2d4174c4a, 2d427bb01639).
- Shorten the comment; the uffd bit carries RWP state too.
- Add Lance's Tested-by.
mm/ksm.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/mm/ksm.c b/mm/ksm.c
index dbfb8f98b189..de144fa07c49 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -34,6 +34,7 @@
#include <linux/memory.h>
#include <linux/mmu_notifier.h>
#include <linux/swap.h>
+#include <linux/userfaultfd_k.h>
#include <linux/ksm.h>
#include <linux/hashtable.h>
#include <linux/freezer.h>
@@ -1463,6 +1464,17 @@ static int replace_page(struct vm_area_struct *vma, struct page *page,
dec_mm_counter(mm, MM_ANONPAGES);
}
+ /*
+ * Preserve soft-dirty and uffd bits when replacing the page.
+ * Restore PAGE_NONE for RWP-protected PTEs.
+ */
+ if (pte_soft_dirty(orig_pte))
+ newpte = pte_mksoft_dirty(newpte);
+ if (pte_uffd(orig_pte))
+ newpte = pte_mkuffd(newpte);
+ if (pte_uffd(orig_pte) && userfaultfd_rwp(vma))
+ newpte = pte_modify(newpte, PAGE_NONE);
+
flush_cache_page(vma, addr, pte_pfn(ptep_get(ptep)));
/*
* No need to notify as we are replacing a read only page with another
base-commit: 48fe11c8d0f1e4e59426a3606f20ac1130b6d8dc
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH v2] mm/ksm: keep soft-dirty and uffd-wp when merging a page 2026-10-19 1:09 [PATCH v2] mm/ksm: keep soft-dirty and uffd-wp when merging a page Samarth Narang @ 2026-10-19 2:07 ` Lance Yang 2026-10-19 13:24 ` David Hildenbrand (Arm) 1 sibling, 0 replies; 11+ messages in thread From: Lance Yang @ 2026-10-19 2:07 UTC (permalink / raw) To: Samarth Narang Cc: Xu Xin, Chengming Zhou, Peter Xu, Kiryl Shutsemau, Mike Rapoport, linux-mm, linux-kernel, stable, David Hildenbrand, Andrew Morton On 2026/10/19 09:09, Samarth Narang wrote: > replace_page() maps the KSM page with a PTE built from scratch, so the > soft-dirty and uffd bits of the PTE it replaces are lost. Due to this, a > write before the merge no longer shows as soft-dirty, the next write to > a uffd-wp page raises no write-protect fault, and because the page is > mapped with the VMA's normal permissions, on a uffd-rwp VMA the next > access raises no RWP fault. > > Copy the soft-dirty and uffd bits from the original PTE to the new PTE, > and restore PAGE_NONE for RWP VMAs, as try_to_map_unused_to_zeropage() > does. > > Fixes: 0f8975ec4db2 ("mm: soft-dirty bits for user memory changes tracking") > Fixes: 63b2d4174c4a ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl") > Fixes: 2d427bb01639 ("mm/userfaultfd: add RWP fault delivery and expose UFFDIO_REGISTER_MODE_RWP") > Cc: stable@vger.kernel.org > Tested-by: Lance Yang <lance.yang@linux.dev> > Assisted-by: LLM > Signed-off-by: Samarth Narang <samarth.colleges@gmail.com> > --- > > Notes: > v1: https://lore.kernel.org/all/20261018122957.526467-1-samarth.colleges@gmail.com/ > > Changes since v1 (thanks, Lance): > - Fixes: point the uffd-wp and RWP tags at the commits that make the > registration modes reachable (63b2d4174c4a, 2d427bb01639). > - Shorten the comment; the uffd bit carries RWP state too. > - Add Lance's Tested-by. Generally, no need to rush the next version out, please. Let it soak for a few days so folks have time to review properly, instead of making everyone start over every time. Just saying :) Cheers, Lance ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2] mm/ksm: keep soft-dirty and uffd-wp when merging a page 2026-10-19 1:09 [PATCH v2] mm/ksm: keep soft-dirty and uffd-wp when merging a page Samarth Narang 2026-10-19 2:07 ` Lance Yang @ 2026-10-19 13:24 ` David Hildenbrand (Arm) 2026-10-20 5:55 ` Lance Yang 1 sibling, 1 reply; 11+ messages in thread From: David Hildenbrand (Arm) @ 2026-10-19 13:24 UTC (permalink / raw) To: Samarth Narang, Andrew Morton Cc: Xu Xin, Chengming Zhou, Peter Xu, Kiryl Shutsemau, Mike Rapoport, Lance Yang, linux-mm, linux-kernel, stable, Kiryl Shutsemau On 10/19/26 03:09, Samarth Narang wrote: > replace_page() maps the KSM page with a PTE built from scratch, so the > soft-dirty and uffd bits of the PTE it replaces are lost. Due to this, a > write before the merge no longer shows as soft-dirty, the next write to > a uffd-wp page raises no write-protect fault, and because the page is > mapped with the VMA's normal permissions, on a uffd-rwp VMA the next > access raises no RWP fault. > > Copy the soft-dirty and uffd bits from the original PTE to the new PTE, > and restore PAGE_NONE for RWP VMAs, as try_to_map_unused_to_zeropage() > does. > > Fixes: 0f8975ec4db2 ("mm: soft-dirty bits for user memory changes tracking") > Fixes: 63b2d4174c4a ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl") > Fixes: 2d427bb01639 ("mm/userfaultfd: add RWP fault delivery and expose UFFDIO_REGISTER_MODE_RWP") I would actually split that up into separate patches. Over-indicating soft-dirty (as raised by Sashiko) is in general not a problem. Losing WP bits is. UFFD, the gift that keeps on giving. How to deal RWP properly is a good question (see Sashiko review). I feel like some more stuff might be missing there to handle this correctly. -- Cheers, David ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2] mm/ksm: keep soft-dirty and uffd-wp when merging a page 2026-10-19 13:24 ` David Hildenbrand (Arm) @ 2026-10-20 5:55 ` Lance Yang 2026-10-20 13:03 ` David Hildenbrand (Arm) 2026-10-20 21:58 ` Mohammed EL Kadiri 0 siblings, 2 replies; 11+ messages in thread From: Lance Yang @ 2026-10-20 5:55 UTC (permalink / raw) To: david Cc: samarth.colleges, akpm, xu.xin, chengming.zhou, peterx, kas, rppt, lance.yang, linux-mm, linux-kernel, stable On Mon, Oct 19, 2026 at 03:24:11PM +0200, David Hildenbrand (Arm) wrote: >On 10/19/26 03:09, Samarth Narang wrote: >> replace_page() maps the KSM page with a PTE built from scratch, so the >> soft-dirty and uffd bits of the PTE it replaces are lost. Due to this, a >> write before the merge no longer shows as soft-dirty, the next write to >> a uffd-wp page raises no write-protect fault, and because the page is >> mapped with the VMA's normal permissions, on a uffd-rwp VMA the next >> access raises no RWP fault. >> >> Copy the soft-dirty and uffd bits from the original PTE to the new PTE, >> and restore PAGE_NONE for RWP VMAs, as try_to_map_unused_to_zeropage() >> does. >> >> Fixes: 0f8975ec4db2 ("mm: soft-dirty bits for user memory changes tracking") >> Fixes: 63b2d4174c4a ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl") >> Fixes: 2d427bb01639 ("mm/userfaultfd: add RWP fault delivery and expose UFFDIO_REGISTER_MODE_RWP") > >I would actually split that up into separate patches. > >Over-indicating soft-dirty (as raised by Sashiko) is in general not a problem. Right. >Losing WP bits is. > >UFFD, the gift that keeps on giving. Haha, yeah, I stared at the code a bit. Say we arm RWP on an existing KSM mapping, then do MADV_UNMERGEABLE. We're just replacing the shared page with a private copy. That shouldn't count as an access to the mapping ... no? But the protnone check sends us to do_uffd_rwp() before the FAULT_FLAG_UNSHARE handling. No FAULT_FLAG_ALLOW_RETRY here, so sync RWP gives us VM_FAULT_SIGBUS. Then break_ksm() does this: static int break_ksm(struct vm_area_struct *vma, unsigned long addr, unsigned long end, bool lock_vma) { vm_fault_t ret = 0; ... do { ... ret = handle_mm_fault(vma, addr, FAULT_FLAG_UNSHARE | FAULT_FLAG_REMOTE, NULL); } while (!(ret & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | VM_FAULT_OOM))); ... return (ret & VM_FAULT_OOM) ? -ENOMEM : 0; } So we report success with the page still merged. Async RWP does unshare it, but only after clearing the uffd bit. I'd let FAULT_FLAG_UNSHARE skip do_uffd_rwp(). We'd still need to carry PAGE_NONE over in wp_page_copy(), though. That PTE is rebuilt from vma->vm_page_prot, so the uffd bit alone won't stop reads. >How to deal RWP properly is a good question (see Sashiko review). I feel like >some more stuff might be missing there to handle this correctly. Tested, this is what I had in mind: ---8<--- diff --git a/mm/memory.c b/mm/memory.c index 976cd03954e3..d99f5ef1dd8c 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -4119,8 +4119,11 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf) if (unlikely(unshare)) { if (pte_soft_dirty(vmf->orig_pte)) entry = pte_mksoft_dirty(entry); - if (pte_uffd(vmf->orig_pte)) + if (pte_uffd(vmf->orig_pte)) { entry = pte_mkuffd(entry); + if (userfaultfd_rwp(vma)) + entry = pte_modify(entry, PAGE_NONE); + } } else { entry = maybe_mkwrite(pte_mkdirty(entry), vma); } @@ -6656,9 +6659,12 @@ static vm_fault_t handle_pte_fault(struct vm_fault *vmf) * VM_UFFD_RWP VMA, a protnone PTE without the uffd bit is * NUMA hinting and must still fall through to do_numa_page(). */ - if (userfaultfd_pte_rwp(vmf->vma, vmf->orig_pte)) - return do_uffd_rwp(vmf); - return do_numa_page(vmf); + if (userfaultfd_pte_rwp(vmf->vma, vmf->orig_pte)) { + if (!(vmf->flags & FAULT_FLAG_UNSHARE)) + return do_uffd_rwp(vmf); + } else { + return do_numa_page(vmf); + } } spin_lock(vmf->ptl); -- Cheers, Lance ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2] mm/ksm: keep soft-dirty and uffd-wp when merging a page 2026-10-20 5:55 ` Lance Yang @ 2026-10-20 13:03 ` David Hildenbrand (Arm) 2026-10-20 13:29 ` Lance Yang 2026-10-20 21:58 ` Mohammed EL Kadiri 1 sibling, 1 reply; 11+ messages in thread From: David Hildenbrand (Arm) @ 2026-10-20 13:03 UTC (permalink / raw) To: Lance Yang Cc: samarth.colleges, akpm, xu.xin, chengming.zhou, peterx, kas, rppt, linux-mm, linux-kernel, stable On 10/20/26 07:55, Lance Yang wrote: > > On Mon, Oct 19, 2026 at 03:24:11PM +0200, David Hildenbrand (Arm) wrote: >> On 10/19/26 03:09, Samarth Narang wrote: >>> replace_page() maps the KSM page with a PTE built from scratch, so the >>> soft-dirty and uffd bits of the PTE it replaces are lost. Due to this, a >>> write before the merge no longer shows as soft-dirty, the next write to >>> a uffd-wp page raises no write-protect fault, and because the page is >>> mapped with the VMA's normal permissions, on a uffd-rwp VMA the next >>> access raises no RWP fault. >>> >>> Copy the soft-dirty and uffd bits from the original PTE to the new PTE, >>> and restore PAGE_NONE for RWP VMAs, as try_to_map_unused_to_zeropage() >>> does. >>> >>> Fixes: 0f8975ec4db2 ("mm: soft-dirty bits for user memory changes tracking") >>> Fixes: 63b2d4174c4a ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl") >>> Fixes: 2d427bb01639 ("mm/userfaultfd: add RWP fault delivery and expose UFFDIO_REGISTER_MODE_RWP") >> >> I would actually split that up into separate patches. >> >> Over-indicating soft-dirty (as raised by Sashiko) is in general not a problem. > > Right. > >> Losing WP bits is. >> >> UFFD, the gift that keeps on giving. > > Haha, yeah, I stared at the code a bit. Say we arm RWP on an existing KSM > mapping, then do MADV_UNMERGEABLE. We're just replacing the shared page > with a private copy. That shouldn't count as an access to the mapping ... > no? > > But the protnone check sends us to do_uffd_rwp() before the > FAULT_FLAG_UNSHARE handling. No FAULT_FLAG_ALLOW_RETRY here, so sync RWP > gives us VM_FAULT_SIGBUS. Then break_ksm() does this: > > static int break_ksm(struct vm_area_struct *vma, unsigned long addr, > unsigned long end, bool lock_vma) > { > vm_fault_t ret = 0; > ... > do { > ... > ret = handle_mm_fault(vma, addr, > FAULT_FLAG_UNSHARE | FAULT_FLAG_REMOTE, > NULL); > } while (!(ret & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | VM_FAULT_OOM))); > ... > return (ret & VM_FAULT_OOM) ? -ENOMEM : 0; > } > > So we report success with the page still merged. Async RWP does unshare > it, but only after clearing the uffd bit. > > I'd let FAULT_FLAG_UNSHARE skip do_uffd_rwp(). We'd still need to carry > PAGE_NONE over in wp_page_copy(), though. That PTE is rebuilt from > vma->vm_page_prot, so the uffd bit alone won't stop reads. > >> How to deal RWP properly is a good question (see Sashiko review). I feel like >> some more stuff might be missing there to handle this correctly. > > Tested, this is what I had in mind: > > ---8<--- > diff --git a/mm/memory.c b/mm/memory.c > index 976cd03954e3..d99f5ef1dd8c 100644 > --- a/mm/memory.c > +++ b/mm/memory.c > @@ -4119,8 +4119,11 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf) > if (unlikely(unshare)) { > if (pte_soft_dirty(vmf->orig_pte)) > entry = pte_mksoft_dirty(entry); > - if (pte_uffd(vmf->orig_pte)) > + if (pte_uffd(vmf->orig_pte)) { > entry = pte_mkuffd(entry); > + if (userfaultfd_rwp(vma)) > + entry = pte_modify(entry, PAGE_NONE); > + } > } else { > entry = maybe_mkwrite(pte_mkdirty(entry), vma); > } > @@ -6656,9 +6659,12 @@ static vm_fault_t handle_pte_fault(struct vm_fault *vmf) > * VM_UFFD_RWP VMA, a protnone PTE without the uffd bit is > * NUMA hinting and must still fall through to do_numa_page(). > */ > - if (userfaultfd_pte_rwp(vmf->vma, vmf->orig_pte)) > - return do_uffd_rwp(vmf); > - return do_numa_page(vmf); > + if (userfaultfd_pte_rwp(vmf->vma, vmf->orig_pte)) { > + if (!(vmf->flags & FAULT_FLAG_UNSHARE)) > + return do_uffd_rwp(vmf); > + } else { > + return do_numa_page(vmf); > + } > } Looks like a reasonable direction (without looking into all the details). I've been also wondering whether KSM should simply skip these uffd regions, they it never worked properly ... but I'm sure we'd run into issue with leftover uffd pte bits :( -- Cheers, David ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2] mm/ksm: keep soft-dirty and uffd-wp when merging a page 2026-10-20 13:03 ` David Hildenbrand (Arm) @ 2026-10-20 13:29 ` Lance Yang 2026-10-21 8:21 ` David Hildenbrand (Arm) 0 siblings, 1 reply; 11+ messages in thread From: Lance Yang @ 2026-10-20 13:29 UTC (permalink / raw) To: David Hildenbrand (Arm) Cc: samarth.colleges, akpm, xu.xin, chengming.zhou, peterx, kas, rppt, linux-mm, linux-kernel, stable On 2026/10/20 21:03, David Hildenbrand (Arm) wrote: > On 10/20/26 07:55, Lance Yang wrote: >> >> On Mon, Oct 19, 2026 at 03:24:11PM +0200, David Hildenbrand (Arm) wrote: >>> On 10/19/26 03:09, Samarth Narang wrote: >>>> replace_page() maps the KSM page with a PTE built from scratch, so the >>>> soft-dirty and uffd bits of the PTE it replaces are lost. Due to this, a >>>> write before the merge no longer shows as soft-dirty, the next write to >>>> a uffd-wp page raises no write-protect fault, and because the page is >>>> mapped with the VMA's normal permissions, on a uffd-rwp VMA the next >>>> access raises no RWP fault. >>>> >>>> Copy the soft-dirty and uffd bits from the original PTE to the new PTE, >>>> and restore PAGE_NONE for RWP VMAs, as try_to_map_unused_to_zeropage() >>>> does. >>>> >>>> Fixes: 0f8975ec4db2 ("mm: soft-dirty bits for user memory changes tracking") >>>> Fixes: 63b2d4174c4a ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl") >>>> Fixes: 2d427bb01639 ("mm/userfaultfd: add RWP fault delivery and expose UFFDIO_REGISTER_MODE_RWP") >>> >>> I would actually split that up into separate patches. >>> >>> Over-indicating soft-dirty (as raised by Sashiko) is in general not a problem. >> >> Right. >> >>> Losing WP bits is. >>> >>> UFFD, the gift that keeps on giving. >> >> Haha, yeah, I stared at the code a bit. Say we arm RWP on an existing KSM >> mapping, then do MADV_UNMERGEABLE. We're just replacing the shared page >> with a private copy. That shouldn't count as an access to the mapping ... >> no? >> >> But the protnone check sends us to do_uffd_rwp() before the >> FAULT_FLAG_UNSHARE handling. No FAULT_FLAG_ALLOW_RETRY here, so sync RWP >> gives us VM_FAULT_SIGBUS. Then break_ksm() does this: >> >> static int break_ksm(struct vm_area_struct *vma, unsigned long addr, >> unsigned long end, bool lock_vma) >> { >> vm_fault_t ret = 0; >> ... >> do { >> ... >> ret = handle_mm_fault(vma, addr, >> FAULT_FLAG_UNSHARE | FAULT_FLAG_REMOTE, >> NULL); >> } while (!(ret & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | VM_FAULT_OOM))); >> ... >> return (ret & VM_FAULT_OOM) ? -ENOMEM : 0; >> } >> >> So we report success with the page still merged. Async RWP does unshare >> it, but only after clearing the uffd bit. >> >> I'd let FAULT_FLAG_UNSHARE skip do_uffd_rwp(). We'd still need to carry >> PAGE_NONE over in wp_page_copy(), though. That PTE is rebuilt from >> vma->vm_page_prot, so the uffd bit alone won't stop reads. >> >>> How to deal RWP properly is a good question (see Sashiko review). I feel like >>> some more stuff might be missing there to handle this correctly. >> >> Tested, this is what I had in mind: >> >> ---8<--- >> diff --git a/mm/memory.c b/mm/memory.c >> index 976cd03954e3..d99f5ef1dd8c 100644 >> --- a/mm/memory.c >> +++ b/mm/memory.c >> @@ -4119,8 +4119,11 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf) >> if (unlikely(unshare)) { >> if (pte_soft_dirty(vmf->orig_pte)) >> entry = pte_mksoft_dirty(entry); >> - if (pte_uffd(vmf->orig_pte)) >> + if (pte_uffd(vmf->orig_pte)) { >> entry = pte_mkuffd(entry); >> + if (userfaultfd_rwp(vma)) >> + entry = pte_modify(entry, PAGE_NONE); >> + } >> } else { >> entry = maybe_mkwrite(pte_mkdirty(entry), vma); >> } >> @@ -6656,9 +6659,12 @@ static vm_fault_t handle_pte_fault(struct vm_fault *vmf) >> * VM_UFFD_RWP VMA, a protnone PTE without the uffd bit is >> * NUMA hinting and must still fall through to do_numa_page(). >> */ >> - if (userfaultfd_pte_rwp(vmf->vma, vmf->orig_pte)) >> - return do_uffd_rwp(vmf); >> - return do_numa_page(vmf); >> + if (userfaultfd_pte_rwp(vmf->vma, vmf->orig_pte)) { >> + if (!(vmf->flags & FAULT_FLAG_UNSHARE)) >> + return do_uffd_rwp(vmf); >> + } else { >> + return do_numa_page(vmf); >> + } >> } > > Looks like a reasonable direction (without looking into all the details). > > I've been also wondering whether KSM should simply skip these uffd regions, they > it never worked properly ... but I'm sure we'd run into issue with leftover uffd +1. Did it ever actually work there :) Why not just skip them and call it a day :D > pte bits :( > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2] mm/ksm: keep soft-dirty and uffd-wp when merging a page 2026-10-20 13:29 ` Lance Yang @ 2026-10-21 8:21 ` David Hildenbrand (Arm) 2026-10-21 8:55 ` Kiryl Shutsemau 0 siblings, 1 reply; 11+ messages in thread From: David Hildenbrand (Arm) @ 2026-10-21 8:21 UTC (permalink / raw) To: Lance Yang Cc: samarth.colleges, akpm, xu.xin, chengming.zhou, peterx, kas, rppt, linux-mm, linux-kernel, stable On 10/20/26 15:29, Lance Yang wrote: > > > On 2026/10/20 21:03, David Hildenbrand (Arm) wrote: >> On 10/20/26 07:55, Lance Yang wrote: >>> >>> >>> Right. >>> >>> >>> Haha, yeah, I stared at the code a bit. Say we arm RWP on an existing KSM >>> mapping, then do MADV_UNMERGEABLE. We're just replacing the shared page >>> with a private copy. That shouldn't count as an access to the mapping ... >>> no? >>> >>> But the protnone check sends us to do_uffd_rwp() before the >>> FAULT_FLAG_UNSHARE handling. No FAULT_FLAG_ALLOW_RETRY here, so sync RWP >>> gives us VM_FAULT_SIGBUS. Then break_ksm() does this: >>> >>> static int break_ksm(struct vm_area_struct *vma, unsigned long addr, >>> unsigned long end, bool lock_vma) >>> { >>> vm_fault_t ret = 0; >>> ... >>> do { >>> ... >>> ret = handle_mm_fault(vma, addr, >>> FAULT_FLAG_UNSHARE | FAULT_FLAG_REMOTE, >>> NULL); >>> } while (!(ret & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | VM_FAULT_OOM))); >>> ... >>> return (ret & VM_FAULT_OOM) ? -ENOMEM : 0; >>> } >>> >>> So we report success with the page still merged. Async RWP does unshare >>> it, but only after clearing the uffd bit. >>> >>> I'd let FAULT_FLAG_UNSHARE skip do_uffd_rwp(). We'd still need to carry >>> PAGE_NONE over in wp_page_copy(), though. That PTE is rebuilt from >>> vma->vm_page_prot, so the uffd bit alone won't stop reads. >>> >>> >>> Tested, this is what I had in mind: >>> >>> ---8<--- >>> diff --git a/mm/memory.c b/mm/memory.c >>> index 976cd03954e3..d99f5ef1dd8c 100644 >>> --- a/mm/memory.c >>> +++ b/mm/memory.c >>> @@ -4119,8 +4119,11 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf) >>> if (unlikely(unshare)) { >>> if (pte_soft_dirty(vmf->orig_pte)) >>> entry = pte_mksoft_dirty(entry); >>> - if (pte_uffd(vmf->orig_pte)) >>> + if (pte_uffd(vmf->orig_pte)) { >>> entry = pte_mkuffd(entry); >>> + if (userfaultfd_rwp(vma)) >>> + entry = pte_modify(entry, PAGE_NONE); >>> + } >>> } else { >>> entry = maybe_mkwrite(pte_mkdirty(entry), vma); >>> } >>> @@ -6656,9 +6659,12 @@ static vm_fault_t handle_pte_fault(struct vm_fault *vmf) >>> * VM_UFFD_RWP VMA, a protnone PTE without the uffd bit is >>> * NUMA hinting and must still fall through to do_numa_page(). >>> */ >>> - if (userfaultfd_pte_rwp(vmf->vma, vmf->orig_pte)) >>> - return do_uffd_rwp(vmf); >>> - return do_numa_page(vmf); >>> + if (userfaultfd_pte_rwp(vmf->vma, vmf->orig_pte)) { >>> + if (!(vmf->flags & FAULT_FLAG_UNSHARE)) >>> + return do_uffd_rwp(vmf); >>> + } else { >>> + return do_numa_page(vmf); >>> + } >>> } >> >> Looks like a reasonable direction (without looking into all the details). >> >> I've been also wondering whether KSM should simply skip these uffd regions, they >> it never worked properly ... but I'm sure we'd run into issue with leftover uffd > > +1. Did it ever actually work there :) Why not just skip them and > call it a day :D I think QEMU just always sets MADV_MERGABLE and later activates uffd. So that needs some care to not disable them. So let's rather try to get it fixed properly. Can you send out proper patches? Thanks! -- Cheers, David ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2] mm/ksm: keep soft-dirty and uffd-wp when merging a page 2026-10-21 8:21 ` David Hildenbrand (Arm) @ 2026-10-21 8:55 ` Kiryl Shutsemau 2026-10-21 9:49 ` Lance Yang 0 siblings, 1 reply; 11+ messages in thread From: Kiryl Shutsemau @ 2026-10-21 8:55 UTC (permalink / raw) To: David Hildenbrand (Arm) Cc: Lance Yang, samarth.colleges, akpm, xu.xin, chengming.zhou, peterx, rppt, linux-mm, linux-kernel, stable On Wed, Oct 21, 2026 at 10:21:53AM +0200, David Hildenbrand (Arm) wrote: > > +1. Did it ever actually work there :) Why not just skip them and > > call it a day :D > > I think QEMU just always sets MADV_MERGABLE and later activates uffd. So that > needs some care to not disable them. So let's rather try to get it fixed properly. > > Can you send out proper patches? Thanks! +1. Lance's direction is right. Unsharing is not an access: do_wp_page() already skips the uffd-wp fault on FAULT_FLAG_UNSHARE, and RWP should do the same. -- Kiryl Shutsemau / Kirill A. Shutemov ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2] mm/ksm: keep soft-dirty and uffd-wp when merging a page 2026-10-21 8:55 ` Kiryl Shutsemau @ 2026-10-21 9:49 ` Lance Yang 2026-10-21 16:12 ` Lance Yang 0 siblings, 1 reply; 11+ messages in thread From: Lance Yang @ 2026-10-21 9:49 UTC (permalink / raw) To: Kiryl Shutsemau, David Hildenbrand (Arm) Cc: samarth.colleges, akpm, xu.xin, chengming.zhou, peterx, rppt, linux-mm, linux-kernel, stable On 2026/10/21 16:55, Kiryl Shutsemau wrote: > On Wed, Oct 21, 2026 at 10:21:53AM +0200, David Hildenbrand (Arm) wrote: >>> +1. Did it ever actually work there :) Why not just skip them and >>> call it a day :D >> >> I think QEMU just always sets MADV_MERGABLE and later activates uffd. So that >> needs some care to not disable them. So let's rather try to get it fixed properly. >> >> Can you send out proper patches? Thanks! Thanks David! Will take it over next week and get proper patches out :) > > +1. > > Lance's direction is right. Unsharing is not an access: do_wp_page() > already skips the uffd-wp fault on FAULT_FLAG_UNSHARE, and RWP should do > the same. Thanks Kiryl! Will take a close look at that :) Cheers, Lance ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2] mm/ksm: keep soft-dirty and uffd-wp when merging a page 2026-10-21 9:49 ` Lance Yang @ 2026-10-21 16:12 ` Lance Yang 0 siblings, 0 replies; 11+ messages in thread From: Lance Yang @ 2026-10-21 16:12 UTC (permalink / raw) To: samarth.colleges Cc: akpm, xu.xin, Kiryl Shutsemau, chengming.zhou, peterx, rppt, David Hildenbrand (Arm), linux-mm, linux-kernel, stable Hi Samarth, Could you send a v3 with just the soft-dirty fix, as David suggested? Leave the uffd-wp/RWP bits to me (I'll take a closer look). On 2026/10/21 17:49, Lance Yang wrote: > > > On 2026/10/21 16:55, Kiryl Shutsemau wrote: >> On Wed, Oct 21, 2026 at 10:21:53AM +0200, David Hildenbrand (Arm) wrote: >>>> +1. Did it ever actually work there :) Why not just skip them and >>>> call it a day :D >>> >>> I think QEMU just always sets MADV_MERGABLE and later activates uffd. >>> So that >>> needs some care to not disable them. So let's rather try to get it >>> fixed properly. >>> >>> Can you send out proper patches? Thanks! > > Thanks David! Will take it over next week and get proper patches out :) > >> >> +1. >> >> Lance's direction is right. Unsharing is not an access: do_wp_page() >> already skips the uffd-wp fault on FAULT_FLAG_UNSHARE, and RWP should do >> the same. > > Thanks Kiryl! Will take a close look at that :) > > Cheers, Lance > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2] mm/ksm: keep soft-dirty and uffd-wp when merging a page 2026-10-20 5:55 ` Lance Yang 2026-10-20 13:03 ` David Hildenbrand (Arm) @ 2026-10-20 21:58 ` Mohammed EL Kadiri 1 sibling, 0 replies; 11+ messages in thread From: Mohammed EL Kadiri @ 2026-10-20 21:58 UTC (permalink / raw) To: lance.yang Cc: david, samarth.colleges, akpm, xu.xin, chengming.zhou, peterx, kas, rppt, linux-mm, linux-kernel, stable This works for me, on b306deee4cba (mm-testing), x86_64, CONFIG_KSM=y, CONFIG_USERFAULTFD=y, CONFIG_DEBUG_VM=y, KASAN enabled, THP disabled. Reproducer: merge 64 identical anon pages via KSM, arm synchronous userfaultfd-wp on one page, then MADV_UNMERGEABLE it without touching it. The page should come out private with WP semantics intact. On the same commit, before applying your wp_page_copy()/handle_pte_fault() fix: UNMERGE ret=0 errno=0 AFTER_UNMERGE target_pfn=1153393 peer_pfn=1153393 target_KPF_KSM=1 FAIL: MADV_UNMERGEABLE returned success but target remains shared/KSM and every run also hits this in dmesg: FAULT_FLAG_ALLOW_RETRY missing c80 Call Trace: handle_userfault.cold+0x30/0x3f __handle_mm_fault+0xde9/0x1c30 handle_mm_fault+0x13b/0x440 break_ksm+0x8a/0x100 ksm_madvise+0x467/0x780 madvise_vma_behavior+0x1d1/0x1e40 madvise_do_behavior+0x431/0x14b0 do_madvise+0x162/0x210 break_ksm()'s internal fault-in to unshare the page is landing in the uffd-wp fault handler, which isn't expecting it. 8/8 runs across two boots, same trace every time. After applying the fix: AFTER_UNMERGE target_pfn=1063999 peer_pfn=1064929 target_KPF_KSM=0 PASS: target is private and no longer KSM-backed FAULT event=18 flags=0x8 address=0x7f3dcb727000 PASS: read generated RWP fault and remained blocked No warnings or call traces in dmesg. 8/8 runs across two boots. Tested-by: Mohammed EL Kadiri <med08elkadiri@gmail.com> ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-10-21 16:12 UTC | newest] Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-10-19 1:09 [PATCH v2] mm/ksm: keep soft-dirty and uffd-wp when merging a page Samarth Narang 2026-10-19 2:07 ` Lance Yang 2026-10-19 13:24 ` David Hildenbrand (Arm) 2026-10-20 5:55 ` Lance Yang 2026-10-20 13:03 ` David Hildenbrand (Arm) 2026-10-20 13:29 ` Lance Yang 2026-10-21 8:21 ` David Hildenbrand (Arm) 2026-10-21 8:55 ` Kiryl Shutsemau 2026-10-21 9:49 ` Lance Yang 2026-10-21 16:12 ` Lance Yang 2026-10-20 21:58 ` Mohammed EL Kadiri
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®