From: Andrew Morton <akpm@linux-foundation.org>
To: mm-commits@vger.kernel.org,vbabka@kernel.org,usama.anjum@collabora.com,surenb@google.com,stable@vger.kernel.org,shuah@kernel.org,rppt@kernel.org,pfalcato@suse.de,peterx@redhat.com,mhocko@suse.com,ljs@kernel.org,liam@infradead.org,jannh@google.com,david@kernel.org,kas@kernel.org,akpm@linux-foundation.org
Subject: + fs-proc-task_mmu-fix-pagemap_scan-written-state-for-unpopulated-ptes.patch added to mm-hotfixes-unstable branch
Date: Tue, 07 Jul 2026 11:40:49 -0700 [thread overview]
Message-ID: <20260707184049.A05AC1F000E9@smtp.kernel.org> (raw)
The patch titled
Subject: fs/proc/task_mmu: fix PAGEMAP_SCAN written state for unpopulated ptes
has been added to the -mm mm-hotfixes-unstable branch. Its filename is
fs-proc-task_mmu-fix-pagemap_scan-written-state-for-unpopulated-ptes.patch
This patch will shortly appear at
https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches/fs-proc-task_mmu-fix-pagemap_scan-written-state-for-unpopulated-ptes.patch
This patch will later appear in the mm-hotfixes-unstable branch at
git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
Before you just go and hit "reply", please:
a) Consider who else should be cc'ed
b) Prefer to cc a suitable mailing list as well
c) Ideally: find the original patch on the mailing list and do a
reply-to-all to that, adding suitable additional cc's
*** Remember to use Documentation/process/submit-checklist.rst when testing your code ***
The -mm tree is included into linux-next via various
branches at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
and is updated there most days
------------------------------------------------------
From: "Kiryl Shutsemau (Meta)" <kas@kernel.org>
Subject: fs/proc/task_mmu: fix PAGEMAP_SCAN written state for unpopulated ptes
Date: Tue, 7 Jul 2026 16:13:49 +0100
PAGEMAP_SCAN reports an unpopulated pte differently depending on which
path serves the request. The PAGE_IS_WRITTEN fast path in
pagemap_scan_pmd_entry() reports a pte_none as written (and, under
PM_SCAN_WP_MATCHING, arms a marker); pagemap_page_category() returns 0 for
the same pte_none. A request that cannot take the fast path (an extra
category bit, category_anyof_mask or category_inverted) therefore reports
the pte as clean and skips arming it.
A range that was populated and then MADV_DONTNEED'd reads as written via
one mask and clean via another, and in the latter case is not re-armed for
the next round -- an incremental-dump consumer (e.g. CRIU) using a richer
mask drops the zapped range and stops tracking writes to it.
Report pte_none as written in pagemap_page_category() too. A pte_none
carries no uffd-wp marker, i.e. it is not write-protected -- the same
condition under which the present and swap cases already report
PAGE_IS_WRITTEN. The fast path applies no VMA test, so neither does this.
The hugetlb and fully-unpopulated-PMD (no page table) scans have no
PAGE_IS_WRITTEN fast path, so they do not exhibit the per-entry divergence
and are left unchanged.
Add a pagemap_ioctl selftest that populates a range, drops it with
MADV_DONTNEED, and checks that the fast path and the generic
(category_anyof_mask) path both report every page written.
Link: https://lore.kernel.org/20260707151349.92143-1-kirill@shutemov.name
Fixes: 12f6b01a0bcb ("fs/proc/task_mmu: add fast paths to get/clear PAGE_IS_WRITTEN flag")
Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
Cc: Muhammad Usama Anjum <usama.anjum@collabora.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: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Peter Xu <peterx@redhat.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@kernel.org>
Assisted-by: Claude:claude-fable-5
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
fs/proc/task_mmu.c | 14 ++++
tools/testing/selftests/mm/pagemap_ioctl.c | 56 ++++++++++++++++++-
2 files changed, 67 insertions(+), 3 deletions(-)
--- a/fs/proc/task_mmu.c~fs-proc-task_mmu-fix-pagemap_scan-written-state-for-unpopulated-ptes
+++ a/fs/proc/task_mmu.c
@@ -2432,8 +2432,18 @@ static unsigned long pagemap_page_catego
{
unsigned long categories;
- if (pte_none(pte))
- return 0;
+ if (pte_none(pte)) {
+ /*
+ * An unpopulated pte carries no uffd-wp marker, i.e. it is not
+ * write-protected, the same condition under which the present
+ * and swap cases below report PAGE_IS_WRITTEN. Report it here
+ * too so this generic path agrees with the PAGE_IS_WRITTEN fast
+ * path in pagemap_scan_pmd_entry(), which reports pte_none as
+ * written and, under PM_SCAN_WP_MATCHING, arms a marker. The
+ * fast path applies no VMA test, so neither does this.
+ */
+ return PAGE_IS_WRITTEN;
+ }
if (pte_present(pte)) {
struct page *page;
--- a/tools/testing/selftests/mm/pagemap_ioctl.c~fs-proc-task_mmu-fix-pagemap_scan-written-state-for-unpopulated-ptes
+++ a/tools/testing/selftests/mm/pagemap_ioctl.c
@@ -1051,6 +1051,57 @@ static void test_simple(void)
ksft_test_result(i == TEST_ITERATIONS, "Test %s\n", __func__);
}
+/*
+ * A range that was populated and then MADV_DONTNEED'd is genuine pte_none
+ * with no uffd-wp marker. Such a pte must read the same regardless of which
+ * PAGEMAP_SCAN path serves the request: both the PAGE_IS_WRITTEN fast path and
+ * the generic path (reached e.g. via category_anyof_mask) must report every
+ * page written.
+ */
+static void unpopulated_scan_test(void)
+{
+ int npages = 16, i;
+ long mem_size = npages * page_size;
+ struct page_region regions[16];
+ long fast = 0, slow = 0, ret;
+ char *mem;
+
+ mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (mem == MAP_FAILED)
+ ksft_exit_fail_msg("%s mmap failed\n", __func__);
+
+ wp_init(mem, mem_size);
+
+ /* Populate, then drop: the ptes become pte_none without a marker. */
+ memset(mem, 1, mem_size);
+ if (madvise(mem, mem_size, MADV_DONTNEED))
+ ksft_exit_fail_msg("%s MADV_DONTNEED failed\n", __func__);
+
+ /* Fast path: category_mask == return_mask == PAGE_IS_WRITTEN. */
+ ret = pagemap_ioctl(mem, mem_size, regions, npages, 0, 0,
+ PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
+ if (ret < 0)
+ ksft_exit_fail_msg("%s fast scan failed\n", __func__);
+ for (i = 0; i < ret; i++)
+ fast += LEN(regions[i]);
+
+ /* Generic path: same query expressed via category_anyof_mask. */
+ ret = pagemap_ioctl(mem, mem_size, regions, npages, 0, 0,
+ 0, PAGE_IS_WRITTEN, 0, PAGE_IS_WRITTEN);
+ if (ret < 0)
+ ksft_exit_fail_msg("%s generic scan failed\n", __func__);
+ for (i = 0; i < ret; i++)
+ slow += LEN(regions[i]);
+
+ ksft_test_result(fast == npages && slow == npages,
+ "%s unpopulated ptes reported written by both paths (%ld, %ld of %d)\n",
+ __func__, fast, slow, npages);
+
+ wp_free(mem, mem_size);
+ munmap(mem, mem_size);
+}
+
int sanity_tests(void)
{
unsigned long long mem_size, vec_size;
@@ -1559,7 +1610,7 @@ int main(int __attribute__((unused)) arg
if (!hugetlb_setup_default(4))
ksft_print_msg("HugeTLB test will be skipped\n");
- ksft_set_plan(117);
+ ksft_set_plan(118);
page_size = getpagesize();
hpage_size = read_pmd_pagesize();
@@ -1737,6 +1788,9 @@ int main(int __attribute__((unused)) arg
/* 17. ZEROPFN tests */
zeropfn_tests();
+ /* 18. Unpopulated pte scan-path consistency */
+ unpopulated_scan_test();
+
close(pagemap_fd);
ksft_finished();
}
_
Patches currently in -mm which might be from kas@kernel.org are
mm-hugetlb-fix-swap-entry-corruption-when-clearing-uffd-wp-at-fork.patch
fs-proc-task_mmu-fix-pagemap_scan-written-state-for-unpopulated-ptes.patch
next reply other threads:[~2026-07-07 18:40 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-07 18:40 Andrew Morton [this message]
-- strict thread matches above, loose matches on Subject: below --
2026-07-06 18:06 + fs-proc-task_mmu-fix-pagemap_scan-written-state-for-unpopulated-ptes.patch added to mm-hotfixes-unstable branch Andrew Morton
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=20260707184049.A05AC1F000E9@smtp.kernel.org \
--to=akpm@linux-foundation.org \
--cc=david@kernel.org \
--cc=jannh@google.com \
--cc=kas@kernel.org \
--cc=liam@infradead.org \
--cc=ljs@kernel.org \
--cc=mhocko@suse.com \
--cc=mm-commits@vger.kernel.org \
--cc=peterx@redhat.com \
--cc=pfalcato@suse.de \
--cc=rppt@kernel.org \
--cc=shuah@kernel.org \
--cc=stable@vger.kernel.org \
--cc=surenb@google.com \
--cc=usama.anjum@collabora.com \
--cc=vbabka@kernel.org \
/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.