All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Samarth Narang" <samarth.colleges@gmail.com>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"David Hildenbrand" <david@kernel.org>
Cc: "Xu Xin" <xu.xin@linux.dev>,
	"Chengming Zhou" <chengming.zhou@linux.dev>,
	"Peter Xu" <peterx@redhat.com>,
	"Kiryl Shutsemau" <kas@kernel.org>,
	"Mike Rapoport" <rppt@kernel.org>,
	"Lance Yang" <lance.yang@linux.dev>,
	linux-mm@kvack.org
Subject: Re: [PATCH v2] mm/ksm: keep soft-dirty and uffd-wp when merging a page
Date: Mon, 19 Oct 2026 13:15:57 +0000	[thread overview]
Message-ID: <sashiko-outbox-177114@kernel.org> (raw)
In-Reply-To: <20261019010934.697895-1-samarth.colleges@gmail.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] mm/ksm: installing PAGE_NONE in replace_page() breaks break_ksm() on RWP PTEs
- [Medium] mm/ksm: replace_page() sets soft-dirty on clean KSM zero-page PTEs
--

commit e9f8ba7271894cc9b005a46048d0bcc61cff0fff
Author: Samarth Narang <samarth.colleges@gmail.com>

mm/ksm: keep soft-dirty and uffd-wp when merging a page

This commit preserves the soft-dirty and userfaultfd bits when replace_page()
installs a KSM PTE in place of an anonymous page. For VMAs registered with
userfaultfd RWP, it also modifies the new PTE with PAGE_NONE when the uffd bit
is set.

> diff --git a/mm/ksm.c b/mm/ksm.c
> index dbfb8f98b1892..de144fa07c493 100644
> --- a/mm/ksm.c
> +++ b/mm/ksm.c
[ ... ]
> @@ -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);

[Severity: Medium]
When ksm_use_zero_pages is enabled and replace_page() merges a zero-filled
page whose soft-dirty bit was cleared, earlier in replace_page() the zero-page
PTE is constructed with pte_mkdirty():

    newpte = pte_mkdirty(pte_mkspecial(pfn_pte(page_to_pfn(kpage), vma->vm_page_prot)));

On architectures such as x86, pte_mkdirty() sets both _PAGE_DIRTY and
_PAGE_SOFT_DIRTY:

arch/x86/include/asm/pgtable.h:pte_mkdirty() {
	pte = pte_set_flags(pte, _PAGE_DIRTY | _PAGE_SOFT_DIRTY);

	return pte_mksaveddirty(pte);
}

Without an else branch calling pte_clear_soft_dirty(newpte) (similar to
remove_migration_pte() in mm/migrate.c), won't clean pages merged with the KSM
zero page end up falsely marked soft-dirty in /proc/<pid>/pagemap?

> +	if (pte_uffd(orig_pte))
> +		newpte = pte_mkuffd(newpte);
> +	if (pte_uffd(orig_pte) && userfaultfd_rwp(vma))
> +		newpte = pte_modify(newpte, PAGE_NONE);

[Severity: High]
How does installing a KSM PTE with PAGE_NONE and the uffd bit interact with
break_ksm() when unmerging KSM pages (via ksm_madvise() for MADV_UNMERGEABLE,
prep_move_vma() during mremap(), __ksm_del_vma(),
unmerge_and_remove_all_rmap_items(), or break_cow())?

break_ksm() invokes handle_mm_fault() with FAULT_FLAG_UNSHARE |
FAULT_FLAG_REMOTE (and without FAULT_FLAG_ALLOW_RETRY):

mm/ksm.c:break_ksm() {
	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)));
}

In handle_pte_fault(), the pte_protnone() check runs before the
FAULT_FLAG_UNSHARE check and dispatches to do_uffd_rwp():

mm/memory.c:handle_pte_fault() {
	if (pte_protnone(vmf->orig_pte) && vma_is_accessible(vmf->vma)) {
		if (userfaultfd_pte_rwp(vmf->vma, vmf->orig_pte))
			return do_uffd_rwp(vmf);
		return do_numa_page(vmf);
	}
}

1. In synchronous RWP mode (!userfaultfd_rwp_async(vmf->vma)), do_uffd_rwp()
calls handle_userfault(vmf, VM_UFFD_RWP). Because FAULT_FLAG_ALLOW_RETRY is
not set, handle_userfault() triggers the CONFIG_DEBUG_VM warning for missing
FAULT_FLAG_ALLOW_RETRY and returns VM_FAULT_SIGBUS. break_ksm() then exits its
loop and returns 0, leaving the KSM page (and any subsequent KSM pages in the
range) still mapped after MADV_UNMERGEABLE, mremap(), or VMA teardown.

2. In asynchronous RWP mode (userfaultfd_rwp_async(vmf->vma)), the first
iteration of break_ksm() runs do_uffd_rwp(), which restores vma->vm_page_prot,
clears the uffd bit, and marks the PTE young, and the second iteration
unshares the page via do_wp_page() -> wp_page_copy(), silently stripping RWP
protection during an internal KSM unmerge.

3. Even if handle_pte_fault() were to reach wp_page_copy() directly for
FAULT_FLAG_UNSHARE, wp_page_copy() copies pte_uffd(vmf->orig_pte) onto entry
built from vma->vm_page_prot without restoring PAGE_NONE when
userfaultfd_rwp(vma) is true:

mm/memory.c:wp_page_copy() {
		if (unlikely(unshare)) {
			if (pte_soft_dirty(vmf->orig_pte))
				entry = pte_mksoft_dirty(entry);
			if (pte_uffd(vmf->orig_pte))
				entry = pte_mkuffd(entry);
		}
}

Does FAULT_FLAG_UNSHARE in handle_pte_fault() and wp_page_copy() need to
handle RWP-protected PTEs before KSM merges them with PAGE_NONE?

>  
>  	flush_cache_page(vma, addr, pte_pfn(ptep_get(ptep)));
>  	/*

[]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261019010934.697895-1-samarth.colleges@gmail.com?part=1


  parent reply	other threads:[~2026-10-19 13:16 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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  2:11   ` Samarth Narang
2026-10-19 13:15 ` sashiko-bot [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-177114@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=chengming.zhou@linux.dev \
    --cc=david@kernel.org \
    --cc=kas@kernel.org \
    --cc=lance.yang@linux.dev \
    --cc=linux-mm@kvack.org \
    --cc=peterx@redhat.com \
    --cc=rppt@kernel.org \
    --cc=samarth.colleges@gmail.com \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=xu.xin@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.