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] mm/ksm: keep soft-dirty and uffd-wp when merging a page
Date: Mon, 19 Oct 2026 12:32:30 +0000	[thread overview]
Message-ID: <sashiko-outbox-177071@kernel.org> (raw)
In-Reply-To: <20261018122957.526467-1-samarth.colleges@gmail.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] mm/ksm: broken FAULT_FLAG_UNSHARE in break_ksm() on uffd-rwp KSM PTEs
- [Medium] mm/ksm: replace_page() spuriously sets soft-dirty on KSM zero pages
--

commit a0c91d60795a1c981863694b2d5797c97c36486f
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 from the
original PTE when replace_page() installs a KSM page, and restores
PAGE_NONE permissions on VM_UFFD_RWP VMAs.

> diff --git a/mm/ksm.c b/mm/ksm.c
> index dbfb8f98b1892..b0d0555aa1b57 100644
> --- a/mm/ksm.c
> +++ b/mm/ksm.c
[ ... ]
> @@ -1463,6 +1464,18 @@ static int replace_page(struct vm_area_struct *vma, struct page *page,
>  		dec_mm_counter(mm, MM_ANONPAGES);
>  	}
>  
> +	/*
> +	 * The old PTE may carry soft-dirty and uffd-wp state that tracks writes
> +	 * to this address. Make sure to preserve these bits in the new PTE.
> +	 * On a uffd-rwp VMA, also restore PAGE_NONE.
> +	 */
> +	if (pte_soft_dirty(orig_pte))
> +		newpte = pte_mksoft_dirty(newpte);

[Severity: Medium]
When ksm_use_zero_pages is enabled, the zero-page branch just above in
replace_page() constructs newpte using pte_mkdirty():

mm/ksm.c:replace_page() {
	if (!is_zero_pfn(page_to_pfn(kpage))) {
		...
	} else {
		newpte = pte_mkdirty(pte_mkspecial(pfn_pte(page_to_pfn(kpage), vma->vm_page_prot)));
		...
	}
}

On architectures with CONFIG_HAVE_ARCH_SOFT_DIRTY, pte_mkdirty() sets both
the hardware dirty bit 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);
}

If pte_soft_dirty(orig_pte) is false when merging with the KSM zero page,
won't _PAGE_SOFT_DIRTY remain set on newpte unless there is an else branch
calling pte_clear_soft_dirty(newpte) (similar to remove_migration_pte() in
mm/migrate.c)?

> +	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 this interact with KSM unmerging via break_ksm() (called from
madvise(MADV_UNMERGEABLE), __ksm_del_vma(), break_cow(), and
unmerge_and_remove_all_rmap_items())?

When replace_page() installs a KSM page or KSM zero page with
pte_mkuffd(newpte) and PAGE_NONE on a VM_UFFD_RWP VMA, break_ksm()
subsequently tries to unshare it by calling handle_mm_fault() with
FAULT_FLAG_UNSHARE | FAULT_FLAG_REMOTE (and without
FAULT_FLAG_ALLOW_RETRY):

mm/ksm.c:break_ksm() {
	do {
		ksm_page = walk_page_range_vma(vma, addr, end, ops, &addr);
		if (ksm_page <= 0)
			return ksm_page;
		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;
}

However, handle_pte_fault() checks pte_protnone() and
userfaultfd_pte_rwp() before checking FAULT_FLAG_WRITE |
FAULT_FLAG_UNSHARE:

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);
	}
}

In synchronous RWP mode (!userfaultfd_rwp_async(vma)), do_uffd_rwp() calls
handle_userfault(vmf, VM_UFFD_RWP), which warns under CONFIG_DEBUG_VM
because FAULT_FLAG_ALLOW_RETRY is missing and returns VM_FAULT_SIGBUS.
break_ksm() then terminates its loop and returns 0 without unmerging the
KSM page (leaving KSM pages mapped after clearing VM_MERGEABLE or freeing
rmap_items).

In asynchronous RWP mode (userfaultfd_rwp_async(vma)), the first loop
iteration in break_ksm() runs do_uffd_rwp() and strips _PAGE_UFFD and
PAGE_NONE without unsharing, and the second iteration unshares the page via
do_wp_page() -> wp_page_copy() with RWP protection lost.

Also, in wp_page_copy(), the unshare path preserves pte_mkuffd(entry) on
top of vma->vm_page_prot, but does not restore 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);
		}
}

Should FAULT_FLAG_UNSHARE bypass do_uffd_rwp() in handle_pte_fault() and
restore PAGE_NONE in wp_page_copy()?

>  
>  	flush_cache_page(vma, addr, pte_pfn(ptep_get(ptep)));
>  	/*
>  	 * No need to notify as we are replacing a read only page with another

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


      parent reply	other threads:[~2026-10-19 12:32 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-18 12:29 [PATCH] mm/ksm: keep soft-dirty and uffd-wp when merging a page Samarth Narang
2026-10-19  1:02 ` Lance Yang
2026-10-19  1:16   ` Samarth Narang
2026-10-19 12:32 ` sashiko-bot [this message]

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-177071@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.