* [PATCH 0/4] mm: reject zone device folios in more folio walkers
@ 2026-07-28 19:47 Gregory Price
2026-07-28 19:47 ` [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio() Gregory Price
` (3 more replies)
0 siblings, 4 replies; 15+ messages in thread
From: Gregory Price @ 2026-07-28 19:47 UTC (permalink / raw)
To: linux-mm
Cc: damon, linux-kernel, kernel-team, sj, akpm, david, ljs, ziy,
baolin.wang, liam, npache, ryan.roberts, dev.jain, baohua,
lance.yang, usama.arif, vbabka, jannh, matthew.brost,
joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple
Several LRU-oriented mm walkers resolve the folio backing a PMD/hugetlb
entry (or a physical pfn) and then reclaim, age, migrate, or lazyfree it
without ever checking for ZONE_DEVICE memory.
This series adds missing folio_is_zone_device() rejections, matching
the checks that comparable walkers already perform.
The changes fall into two groups:
1) Genuine gaps:
- mm/huge_memory, mm/madvise: the !pmd_present branch above these sites
only filters device-private entries (which are non-present).
A present zone device PMD (e.g. device-coherent) would still reach the
folio and be lazyfreed / aged / paged out. Add an explicit check.
- mm/mempolicy: queue_folios_pmd() can see a present zone device PMD
(e.g. device-coherent) and queue it for migration.
2) Defensive / consistency:
- mm/damon: damon_get_folio() already excludes zone device memory
implicitly (pfn_to_online_page(), lru checks). The explicit check
is added in the single damon_get_folio() chokepoint so every DAMON
caller is covered uniformly and the guarantee is stated explicitly.
- mm/mempolicy: queue_folios_hugetlb() cannot see zone device memory
(hugetlb folios are never ZONE_DEVICE). We add the check to keep
all three mempolicy walkers consistent.
No crash reproducer - this is a correctness/hardening cleanup found by
inspection. All checks are placed after the folio is resolved and before
it is acted upon, on paths that already hold the relevant page-table lock,
so no locking or refcount changes are involved.
Gregory Price (4):
mm/damon: defensively skip zone device folios in damon_get_folio()
mm/huge_memory: skip zone device folios in madvise_free_huge_pmd()
mm/madvise: skip zone device folios in cold/pageout PMD range
mm/mempolicy: skip zone device folios when queueing folios
mm/damon/ops-common.c | 3 ++-
mm/huge_memory.c | 4 ++++
mm/madvise.c | 3 +++
mm/mempolicy.c | 4 ++++
4 files changed, 13 insertions(+), 1 deletion(-)
--
2.55.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio()
2026-07-28 19:47 [PATCH 0/4] mm: reject zone device folios in more folio walkers Gregory Price
@ 2026-07-28 19:47 ` Gregory Price
2026-07-28 19:57 ` sashiko-bot
2026-07-29 0:50 ` SJ Park
2026-07-28 19:47 ` [PATCH 2/4] mm/huge_memory: skip zone device folios in madvise_free_huge_pmd() Gregory Price
` (2 subsequent siblings)
3 siblings, 2 replies; 15+ messages in thread
From: Gregory Price @ 2026-07-28 19:47 UTC (permalink / raw)
To: linux-mm
Cc: damon, linux-kernel, kernel-team, sj, akpm, david, ljs, ziy,
baolin.wang, liam, npache, ryan.roberts, dev.jain, baohua,
lance.yang, usama.arif, vbabka, jannh, matthew.brost,
joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple
All DAMON physical- and virtual-address operations obtain their folios
through damon_get_folio(). That helper already excludes ZONE_DEVICE
memory implicitly via pfn_to_online_page() and folio_test_lru(), but
this is inconsistent with other callers in mm/ which test explicitly.
Add an explicit folio_is_zone_device() rejection in damon_get_folio()
so the guarantee lives in one place and covers every caller uniformly,
consistent with other mm walkers that reject zone device folios.
Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
---
mm/damon/ops-common.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c
index d7d7f100389b..d8bca7355b4f 100644
--- a/mm/damon/ops-common.c
+++ b/mm/damon/ops-common.c
@@ -32,7 +32,8 @@ struct folio *damon_get_folio(unsigned long pfn)
folio = page_folio(page);
if (!folio_try_get(folio))
return NULL;
- if (unlikely(page_folio(page) != folio) || !folio_test_lru(folio)) {
+ if (unlikely(page_folio(page) != folio) || !folio_test_lru(folio) ||
+ folio_is_zone_device(folio)) {
folio_put(folio);
folio = NULL;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 2/4] mm/huge_memory: skip zone device folios in madvise_free_huge_pmd()
2026-07-28 19:47 [PATCH 0/4] mm: reject zone device folios in more folio walkers Gregory Price
2026-07-28 19:47 ` [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio() Gregory Price
@ 2026-07-28 19:47 ` Gregory Price
2026-07-28 20:01 ` sashiko-bot
2026-07-28 19:47 ` [PATCH 3/4] mm/madvise: skip zone device folios in cold/pageout PMD range Gregory Price
2026-07-28 19:47 ` [PATCH 4/4] mm/mempolicy: skip zone device folios when queueing folios Gregory Price
3 siblings, 1 reply; 15+ messages in thread
From: Gregory Price @ 2026-07-28 19:47 UTC (permalink / raw)
To: linux-mm
Cc: damon, linux-kernel, kernel-team, sj, akpm, david, ljs, ziy,
baolin.wang, liam, npache, ryan.roberts, dev.jain, baohua,
lance.yang, usama.arif, vbabka, jannh, matthew.brost,
joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple,
stable
madvise_free_huge_pmd() resolves the folio backing a PMD via pmd_folio()
and marks it lazyfree without checking for zone device memory.
The surrounding guards do not cover every zone device case:
- MADV_FREE only operates on anonymous VMAs (DAX mappings are excluded)
- !pmd_present() branch rejects device-private and migration entries
- present zone device PMD (device coherent THP) is not filtered.
Unlike vm_normal_page_pmd(), it performs no special/pfnmap check,
and would be marked lazyfree here.
Bail out when the folio is a zone device folio.
Fixes: 368076f52ebe ("mm/huge_memory: add device-private THP support to PMD operations")
Cc: <stable@vger.kernel.org>
Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
---
mm/huge_memory.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 5bd8d4f59a7b..e0ffdeeb3077 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2338,6 +2338,10 @@ bool madvise_free_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
}
folio = pmd_folio(orig_pmd);
+
+ if (folio_is_zone_device(folio))
+ goto out;
+
/*
* If other processes are mapping this folio, we couldn't discard
* the folio unless they all do MADV_FREE so let's skip the folio.
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 3/4] mm/madvise: skip zone device folios in cold/pageout PMD range
2026-07-28 19:47 [PATCH 0/4] mm: reject zone device folios in more folio walkers Gregory Price
2026-07-28 19:47 ` [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio() Gregory Price
2026-07-28 19:47 ` [PATCH 2/4] mm/huge_memory: skip zone device folios in madvise_free_huge_pmd() Gregory Price
@ 2026-07-28 19:47 ` Gregory Price
2026-07-28 19:58 ` sashiko-bot
2026-07-28 19:47 ` [PATCH 4/4] mm/mempolicy: skip zone device folios when queueing folios Gregory Price
3 siblings, 1 reply; 15+ messages in thread
From: Gregory Price @ 2026-07-28 19:47 UTC (permalink / raw)
To: linux-mm
Cc: damon, linux-kernel, kernel-team, sj, akpm, david, ljs, ziy,
baolin.wang, liam, npache, ryan.roberts, dev.jain, baohua,
lance.yang, usama.arif, vbabka, jannh, matthew.brost,
joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple
madvise_cold_or_pageout_pte_range() resolves the folio backing a PMD
via pmd_folio() and ages or reclaims it without checking for zone
device memory.
The surrounding guards do not cover every zone device case:
- can_madv_lru_vma() excludes VM_PFNMAP and VM_HUGETLB VMAs
(so device DAX is filtered)
- !pmd_present() branch above rejects device-private and
migration entries, which are non-present.
- A present zone device PMD - e.g. a device-coherent THP - is
not filtered by any of these, nor by pmd_folio() (unlike
vm_normal_page_pmd(), it performs no special/pfnmap check),
and would be aged or paged out here.
Skip ZONE_DEVICE folios explicitly during MADV_COLD/PAGEOUT.
Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
---
mm/madvise.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/mm/madvise.c b/mm/madvise.c
index 07a21ca31bad..ffd6a68320a8 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -395,6 +395,9 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
folio = pmd_folio(orig_pmd);
+ if (folio_is_zone_device(folio))
+ goto huge_unlock;
+
/* Do not interfere with other mappings of this folio */
if (folio_maybe_mapped_shared(folio))
goto huge_unlock;
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 4/4] mm/mempolicy: skip zone device folios when queueing folios
2026-07-28 19:47 [PATCH 0/4] mm: reject zone device folios in more folio walkers Gregory Price
` (2 preceding siblings ...)
2026-07-28 19:47 ` [PATCH 3/4] mm/madvise: skip zone device folios in cold/pageout PMD range Gregory Price
@ 2026-07-28 19:47 ` Gregory Price
2026-07-28 19:59 ` sashiko-bot
3 siblings, 1 reply; 15+ messages in thread
From: Gregory Price @ 2026-07-28 19:47 UTC (permalink / raw)
To: linux-mm
Cc: damon, linux-kernel, kernel-team, sj, akpm, david, ljs, ziy,
baolin.wang, liam, npache, ryan.roberts, dev.jain, baohua,
lance.yang, usama.arif, vbabka, jannh, matthew.brost,
joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple
queue_folios_pte_range() already pairs vm_normal_folio() with an
explicit folio_is_zone_device() check before adding folios to the
migration pagelist.
vm_normal_folio() alone does not reject zone device memory (a present
device-coherent page in a normal VMA is returned as "normal").
Mirror the explicit check in the two other walkers.
queue_folios_pmd() uses pmd_folio() directly and can encounter a present
zone device PMD - e.g. a device-coherent THP.
This is not filtered by existing checks:
!pmd_present() - only rejects non-present device-private and
migration entries
vma_migratable() - excludes DAX and VM_PFNMAP.
The early return also means such a folio is no longer counted in
qp->nr_failed under MPOL_MF_STRICT. This is the same pattern used
by queue_folios_pte_range() (skipping zone device without failing).
queue_folios_hugetlb() cannot see zone device memory - hugetlb folios
are never ZONE_DEVICE - so the check there is purely defensive and keeps
all three walkers consistent.
Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
---
mm/mempolicy.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 5720f7f54d94..bd79e61a40d1 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -668,6 +668,8 @@ static void queue_folios_pmd(pmd_t *pmd, struct mm_walk *walk)
}
if (!queue_folio_required(folio, qp))
return;
+ if (folio_is_zone_device(folio))
+ return;
if (!(qp->flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) ||
!vma_migratable(walk->vma) ||
!migrate_folio_add(folio, qp->pagelist, qp->flags))
@@ -797,6 +799,8 @@ static int queue_folios_hugetlb(pte_t *pte, unsigned long hmask,
folio = pfn_folio(pte_pfn(ptep));
if (!queue_folio_required(folio, qp))
goto unlock;
+ if (folio_is_zone_device(folio))
+ goto unlock;
if (!(flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) ||
!vma_migratable(walk->vma)) {
qp->nr_failed++;
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio()
2026-07-28 19:47 ` [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio() Gregory Price
@ 2026-07-28 19:57 ` sashiko-bot
2026-07-28 20:16 ` Gregory Price
2026-07-29 0:55 ` SJ Park
2026-07-29 0:50 ` SJ Park
1 sibling, 2 replies; 15+ messages in thread
From: sashiko-bot @ 2026-07-28 19:57 UTC (permalink / raw)
To: Gregory Price; +Cc: damon
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [Medium] The explicit `folio_is_zone_device()` check added by the patch is dead code and fails to achieve its stated intent.
Pre-existing issues:
- [High] Early return in damon_ptep_mkold and damon_pmdp_mkold skips MMU notifier aging for device-exclusive swap PTEs.
- [High] The scheme's `last_applied` pointer caches a freed folio pointer, leading to a dangling pointer comparison.
--
--- Patch [1]: [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio() ---
commit 8181b2e77c1b49bcb808528f343f72fdbf9d168c
Author: Gregory Price <gourry@gourry.net>
mm/damon: defensively skip zone device folios in damon_get_folio()
All DAMON physical- and virtual-address operations obtain their folios
through damon_get_folio(). That helper already excludes ZONE_DEVICE
memory implicitly via pfn_to_online_page() and folio_test_lru(), but
this is inconsistent with other callers in mm/ which test explicitly.
> diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c
> index 0981a5e3af172..0db1383de5d01 100644
> --- a/mm/damon/ops-common.c
> +++ b/mm/damon/ops-common.c
> @@ -32,7 +32,8 @@ struct folio *damon_get_folio(unsigned long pfn)
> folio = page_folio(page);
> if (!folio_try_get(folio))
> return NULL;
> - if (unlikely(page_folio(page) != folio) || !folio_test_lru(folio)) {
> + if (unlikely(page_folio(page) != folio) || !folio_test_lru(folio) ||
> + folio_is_zone_device(folio)) {
[Severity: Medium]
Since ZONE_DEVICE folios do not have the LRU flag set, won't the
!folio_test_lru(folio) check always evaluate to true for them?
Additionally, earlier in damon_get_folio(), pfn_to_online_page(pfn) is
called, which strictly returns NULL for ZONE_DEVICE memory. Doesn't this
mean ZONE_DEVICE memory will never reach this new folio_is_zone_device()
check at all, making it dead code?
> folio_put(folio);
> folio = NULL;
> }
[Severity: High]
This is a pre-existing issue, but I have a question about how
damon_get_folio() returning NULL interacts with device-exclusive memory.
When DAMON encounters a device-exclusive PFN swap PTE in damon_ptep_mkold()
or damon_pmdp_mkold(), damon_get_folio() returns NULL because
pfn_to_online_page() rejects it. Both of these callers then immediately
early-return on !folio:
mm/damon/ops-common.c:damon_ptep_mkold() {
...
folio = damon_get_folio(pfn);
if (!folio)
return;
...
}
Doesn't this early return silently bypass the mmu_notifier_clear_young()
call completely, breaking DAMON's ability to monitor device accesses
(which relies on the MMU notifier for device-exclusive PTEs)?
[Severity: High]
This isn't a bug introduced by this patch, but looking at how DAMOS
physical address apply functions interact with folios, I noticed
something about the last_applied pointer:
In mm/damon/paddr.c:damon_pa_pageout(), a reference is dropped:
mm/damon/paddr.c:damon_pa_pageout() {
...
folio_put(folio);
...
s->last_applied = folio;
}
Since folio_put() drops the reference, could this store a dangling
pointer across DAMON region processing boundaries?
If that physical memory is subsequently reallocated for a new folio,
it will reside at the exact same address. When this pointer is later
checked in damon_pa_invalid_damos_folio():
mm/damon/paddr.c:damon_pa_invalid_damos_folio() {
...
if (folio == s->last_applied) {
folio_put(folio);
return true;
}
...
}
Could this falsely match the dangling pointer and erroneously skip a
valid, newly allocated folio from DAMOS actions?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260728194714.3713735-1-gourry@gourry.net?part=1
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/4] mm/madvise: skip zone device folios in cold/pageout PMD range
2026-07-28 19:47 ` [PATCH 3/4] mm/madvise: skip zone device folios in cold/pageout PMD range Gregory Price
@ 2026-07-28 19:58 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-07-28 19:58 UTC (permalink / raw)
To: Gregory Price; +Cc: damon
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Direct assignment to *ptep bypasses set_pte_at(), causing hypervisor faults on paravirtualized architectures.
- [Critical] madvise_cold_or_pageout_pte_range() blindly calls pmd_folio() on PMD entries without checking if the VMA allows raw PFN mappings, leading to invalid folio pointer dereferences.
--
--- Patch [3]: [PATCH 3/4] mm/madvise: skip zone device folios in cold/pageout PMD range ---
commit f53274ca71e03d22eaac643cdc7488b95adca203
Author: Gregory Price <gourry@gourry.net>
mm/madvise: skip zone device folios in cold/pageout PMD range
This patch modifies madvise_cold_or_pageout_pte_range() to explicitly
filter out ZONE_DEVICE folios. It uses folio_is_zone_device() to prevent
aging or paging out device memory that might bypass existing VMA and PMD
checks.
> diff --git a/mm/madvise.c b/mm/madvise.c
> index 07a21ca31bad4..ffd6a68320a86 100644
> --- a/mm/madvise.c
> +++ b/mm/madvise.c
> @@ -395,6 +395,9 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
>
> folio = pmd_folio(orig_pmd);
>
[Severity: Critical]
This is a pre-existing issue, but does this code dereference an invalid
folio pointer?
The madvise_cold_or_pageout_pte_range() function handles MADV_COLD and
MADV_PAGEOUT hints, and the can_madv_lru_vma() filter rejects VM_PFNMAP but
allows VM_MIXEDMAP VMAs.
Device drivers can map raw PFNs (not backed by a struct page) as huge PMDs
into VM_MIXEDMAP VMAs using vmf_insert_pfn_pmd().
When encountering such a PMD, pmd_trans_huge() is true, but pmd_folio()
translates the raw PFN into a garbage struct folio pointer.
Could this cause a kernel panic due to an out-of-bounds read when
folio_is_zone_device() dereferences folio->flags on the invalid pointer?
> + if (folio_is_zone_device(folio))
> + goto huge_unlock;
> +
> /* Do not interfere with other mappings of this folio */
> if (folio_maybe_mapped_shared(folio))
> goto huge_unlock;
[ ... ]
While reviewing mm/madvise.c, I also noticed another pre-existing regression
in guard_install_set_pte():
> static int guard_install_set_pte(unsigned long addr, unsigned long next,
> pte_t *ptep, struct mm_walk *walk)
> {
> unsigned long *nr_pages = (unsigned long *)walk->private;
>
> /* Simply install a PTE marker, this causes segfault on access. */
> *ptep = make_pte_marker(PTE_MARKER_GUARD);
[Severity: Critical]
This is a pre-existing issue, but does this direct assignment bypass
architecture-specific hooks?
By assigning directly to *ptep instead of using set_pte_at(), this skips
hooks required by paravirtualized architectures.
On architectures like Xen PV where guest page tables are mapped read-only by
the hypervisor, will this direct write trigger a hypervisor fault and crash
the kernel if an unprivileged user calls madvise(..., MADV_GUARD_INSTALL) on
a valid anonymous VMA?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260728194714.3713735-1-gourry@gourry.net?part=3
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] mm/mempolicy: skip zone device folios when queueing folios
2026-07-28 19:47 ` [PATCH 4/4] mm/mempolicy: skip zone device folios when queueing folios Gregory Price
@ 2026-07-28 19:59 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-07-28 19:59 UTC (permalink / raw)
To: Gregory Price; +Cc: damon
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] queue_folios_pmd() blindly calls pmd_folio() on raw PFN PMDs, causing a kernel panic during mbind(MPOL_MF_STRICT) on VM_PFNMAP mappings.
--
--- Patch [4]: [PATCH 4/4] mm/mempolicy: skip zone device folios when queueing folios ---
commit 638b94b8502c12252205f411cec0cf58a9fd9ce2
Author: Gregory Price <gourry@gourry.net>
mm/mempolicy: skip zone device folios when queueing folios
This commit adds explicit zone device checks to queue_folios_pmd() and
queue_folios_hugetlb() to mirror the behavior in queue_folios_pte_range().
> diff --git a/mm/mempolicy.c b/mm/mempolicy.c
> index 5720f7f54d942..bd79e61a40d1a 100644
> --- a/mm/mempolicy.c
> +++ b/mm/mempolicy.c
> @@ -668,6 +668,8 @@ static void queue_folios_pmd(pmd_t *pmd, struct mm_walk *walk)
> }
> if (!queue_folio_required(folio, qp))
> return;
> + if (folio_is_zone_device(folio))
> + return;
[Severity: High]
This is a pre-existing issue, but can this code path trigger a kernel panic
if it encounters a raw PFN PMD from a VM_PFNMAP mapping?
Looking at queue_pages_test_walk() in mm/mempolicy.c, it allows unmigratable
VMAs (like VM_PFNMAP) to be walked if MPOL_MF_STRICT is specified:
if (!vma_migratable(vma) &&
!(flags & MPOL_MF_STRICT))
return 1;
if (flags & (MPOL_MF_STRICT | MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
return 0;
During the walk, queue_folios_pmd() unconditionally calls pmd_folio(pmdval)
on present PMDs. Since VM_PFNMAP raw PFNs lack a valid struct page,
pmd_folio() would return a garbage pointer, leading to a crash when
queue_folio_required() or the newly added folio_is_zone_device() dereferences
it.
Should queue_folios_pmd() be using vm_normal_folio_pmd() or similar to filter
out raw PFN mappings before attempting to extract the folio?
> if (!(qp->flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) ||
> !vma_migratable(walk->vma) ||
> !migrate_folio_add(folio, qp->pagelist, qp->flags))
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260728194714.3713735-1-gourry@gourry.net?part=4
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/4] mm/huge_memory: skip zone device folios in madvise_free_huge_pmd()
2026-07-28 19:47 ` [PATCH 2/4] mm/huge_memory: skip zone device folios in madvise_free_huge_pmd() Gregory Price
@ 2026-07-28 20:01 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-07-28 20:01 UTC (permalink / raw)
To: Gregory Price; +Cc: damon
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [Critical] madvise_cold_or_pageout_pte_range() fails to filter out zone device PMDs, risking invalid operations on device memory.
- [High] madvise_cold_or_pageout_pte_range() triggers a refcount livelock by elevating the folio refcount before acquiring the folio lock on the PMD path.
--
--- Patch [2]: [PATCH 2/4] mm/huge_memory: skip zone device folios in madvise_free_huge_pmd() ---
commit 624f2a18069c771c887a2d3f875451eb3bd7e41d
Author: Gregory Price <gourry@gourry.net>
Subject: mm/huge_memory: skip zone device folios in madvise_free_huge_pmd()
This commit addresses an issue in madvise_free_huge_pmd() where zone device
folios were being marked as lazyfree without proper checks. It adds a bailout
condition to skip the operation if the folio is a zone device folio.
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index 73522f296cee2..0b48112574882 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -2338,6 +2338,10 @@ bool madvise_free_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
> }
>
> folio = pmd_folio(orig_pmd);
> +
> + if (folio_is_zone_device(folio))
> + goto out;
> +
> /*
> * If other processes are mapping this folio, we couldn't discard
While reviewing the zone device filtering added here, I noticed a couple of
pre-existing issues in the related PMD handling path in mm/madvise.c.
mm/madvise.c:madvise_cold_or_pageout_pte_range() {
[ ... ]
folio = pmd_folio(orig_pmd);
/* Do not interfere with other mappings of this folio */
if (folio_maybe_mapped_shared(folio))
goto huge_unlock;
[Severity: Critical]
This is a pre-existing issue, but is it possible for a zone device PMD to be
processed here?
The folio is resolved from the PMD but lacks the folio_is_zone_device(folio)
filter (unlike the PTE path). If a DAX or device coherent THP is partially
advised, the split path could leave the pgmap pointer uninitialized on the
split folios, potentially causing a kernel panic when accessed. Could we add a
similar bailout here?
mm/madvise.c:madvise_cold_or_pageout_pte_range() {
[ ... ]
if (next - addr != HPAGE_PMD_SIZE) {
int err;
folio_get(folio);
spin_unlock(ptl);
folio_lock(folio);
err = split_folio(folio);
[Severity: High]
This isn't a bug introduced by this patch, but could this locking order create
a refcount livelock?
Calling folio_get() before blocking on folio_lock() elevates the folio's
refcount. When split_folio() later checks the expected refcount against
folio_ref_count(), wouldn't it fail with -EAGAIN if other tasks are also
blocked trying to lock the folio? Should the refcount be elevated only after
acquiring the folio lock?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260728194714.3713735-1-gourry@gourry.net?part=2
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio()
2026-07-28 19:57 ` sashiko-bot
@ 2026-07-28 20:16 ` Gregory Price
2026-07-29 0:55 ` SJ Park
1 sibling, 0 replies; 15+ messages in thread
From: Gregory Price @ 2026-07-28 20:16 UTC (permalink / raw)
To: sashiko-reviews; +Cc: damon
On Tue, Jul 28, 2026 at 07:57:04PM +0000, sashiko-bot@kernel.org wrote:
> --- Patch [1]: [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio() ---
> commit 8181b2e77c1b49bcb808528f343f72fdbf9d168c
> Author: Gregory Price <gourry@gourry.net>
>
> mm/damon: defensively skip zone device folios in damon_get_folio()
>
> All DAMON physical- and virtual-address operations obtain their folios
> through damon_get_folio(). That helper already excludes ZONE_DEVICE
> memory implicitly via pfn_to_online_page() and folio_test_lru(), but
> this is inconsistent with other callers in mm/ which test explicitly.
>
> > diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c
> > index 0981a5e3af172..0db1383de5d01 100644
> > --- a/mm/damon/ops-common.c
> > +++ b/mm/damon/ops-common.c
> > @@ -32,7 +32,8 @@ struct folio *damon_get_folio(unsigned long pfn)
> > folio = page_folio(page);
> > if (!folio_try_get(folio))
> > return NULL;
> > - if (unlikely(page_folio(page) != folio) || !folio_test_lru(folio)) {
> > + if (unlikely(page_folio(page) != folio) || !folio_test_lru(folio) ||
> > + folio_is_zone_device(folio)) {
>
> [Severity: Medium]
> Since ZONE_DEVICE folios do not have the LRU flag set, won't the
> !folio_test_lru(folio) check always evaluate to true for them?
>
> Additionally, earlier in damon_get_folio(), pfn_to_online_page(pfn) is
> called, which strictly returns NULL for ZONE_DEVICE memory. Doesn't this
> mean ZONE_DEVICE memory will never reach this new folio_is_zone_device()
> check at all, making it dead code?
>
pfn_to_online_page() says this:
/* The presence of a pgmap indicates ZONE_DEVICE offline pfn */
if (pgmap)
return NULL;
Which is the kind of implementation detail that could easily come around
to bite us. I'm ok dropping this patch if folks think it's too paranoid.
~Gregory
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio()
2026-07-28 19:47 ` [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio() Gregory Price
2026-07-28 19:57 ` sashiko-bot
@ 2026-07-29 0:50 ` SJ Park
2026-07-29 2:01 ` Gregory Price
1 sibling, 1 reply; 15+ messages in thread
From: SJ Park @ 2026-07-29 0:50 UTC (permalink / raw)
To: Gregory Price
Cc: SJ Park, linux-mm, damon, linux-kernel, kernel-team, akpm, david,
ljs, ziy, baolin.wang, liam, npache, ryan.roberts, dev.jain,
baohua, lance.yang, usama.arif, vbabka, jannh, matthew.brost,
joshua.hahnjy, rakie.kim, byungchul, ying.huang, apopple
Hi Gregory,
On Tue, 28 Jul 2026 15:47:11 -0400 Gregory Price <gourry@gourry.net> wrote:
> All DAMON physical- and virtual-address operations obtain their folios
> through damon_get_folio(). That helper already excludes ZONE_DEVICE
> memory implicitly via pfn_to_online_page() and folio_test_lru(), but
> this is inconsistent with other callers in mm/ which test explicitly.
>
> Add an explicit folio_is_zone_device() rejection in damon_get_folio()
> so the guarantee lives in one place and covers every caller uniformly,
> consistent with other mm walkers that reject zone device folios.
Thank you for checking this and sharing this nice patch!
However, I'm not very sure adding a call that not really required for only
making it looks consistent with others is the right choice. I'm especially
concerned if this will confuse future readers including myself.
If this is a hardening purpose, we have CONFIG_DAMON_DEBUG_SANITY for the
purpose. What about using it with a good comment explaining why we doing that?
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio()
2026-07-28 19:57 ` sashiko-bot
2026-07-28 20:16 ` Gregory Price
@ 2026-07-29 0:55 ` SJ Park
1 sibling, 0 replies; 15+ messages in thread
From: SJ Park @ 2026-07-29 0:55 UTC (permalink / raw)
To: sashiko-bot; +Cc: SJ Park, Gregory Price, damon
On Tue, 28 Jul 2026 19:57:04 +0000 sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
>
> New issues:
> - [Medium] The explicit `folio_is_zone_device()` check added by the patch is dead code and fails to achieve its stated intent.
>
> Pre-existing issues:
> - [High] Early return in damon_ptep_mkold and damon_pmdp_mkold skips MMU notifier aging for device-exclusive swap PTEs.
> - [High] The scheme's `last_applied` pointer caches a freed folio pointer, leading to a dangling pointer comparison.
> --
>
> --- Patch [1]: [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio() ---
> commit 8181b2e77c1b49bcb808528f343f72fdbf9d168c
> Author: Gregory Price <gourry@gourry.net>
>
> mm/damon: defensively skip zone device folios in damon_get_folio()
>
> All DAMON physical- and virtual-address operations obtain their folios
> through damon_get_folio(). That helper already excludes ZONE_DEVICE
> memory implicitly via pfn_to_online_page() and folio_test_lru(), but
> this is inconsistent with other callers in mm/ which test explicitly.
>
> > diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c
> > index 0981a5e3af172..0db1383de5d01 100644
> > --- a/mm/damon/ops-common.c
> > +++ b/mm/damon/ops-common.c
> > @@ -32,7 +32,8 @@ struct folio *damon_get_folio(unsigned long pfn)
> > folio = page_folio(page);
> > if (!folio_try_get(folio))
> > return NULL;
> > - if (unlikely(page_folio(page) != folio) || !folio_test_lru(folio)) {
> > + if (unlikely(page_folio(page) != folio) || !folio_test_lru(folio) ||
> > + folio_is_zone_device(folio)) {
>
> [Severity: Medium]
> Since ZONE_DEVICE folios do not have the LRU flag set, won't the
> !folio_test_lru(folio) check always evaluate to true for them?
>
> Additionally, earlier in damon_get_folio(), pfn_to_online_page(pfn) is
> called, which strictly returns NULL for ZONE_DEVICE memory. Doesn't this
> mean ZONE_DEVICE memory will never reach this new folio_is_zone_device()
> check at all, making it dead code?
This is what Gregory already mentioned about in the commit message. I added a
question about this, too, though. Let's keep discussing in the main thread.
>
> > folio_put(folio);
> > folio = NULL;
> > }
>
> [Severity: High]
> This is a pre-existing issue, but I have a question about how
> damon_get_folio() returning NULL interacts with device-exclusive memory.
>
> When DAMON encounters a device-exclusive PFN swap PTE in damon_ptep_mkold()
> or damon_pmdp_mkold(), damon_get_folio() returns NULL because
> pfn_to_online_page() rejects it. Both of these callers then immediately
> early-return on !folio:
>
> mm/damon/ops-common.c:damon_ptep_mkold() {
> ...
> folio = damon_get_folio(pfn);
> if (!folio)
> return;
> ...
> }
>
> Doesn't this early return silently bypass the mmu_notifier_clear_young()
> call completely, breaking DAMON's ability to monitor device accesses
> (which relies on the MMU notifier for device-exclusive PTEs)?
This is an intended behavior.
>
> [Severity: High]
> This isn't a bug introduced by this patch, but looking at how DAMOS
> physical address apply functions interact with folios, I noticed
> something about the last_applied pointer:
>
> In mm/damon/paddr.c:damon_pa_pageout(), a reference is dropped:
>
> mm/damon/paddr.c:damon_pa_pageout() {
> ...
> folio_put(folio);
> ...
> s->last_applied = folio;
> }
>
> Since folio_put() drops the reference, could this store a dangling
> pointer across DAMON region processing boundaries?
>
> If that physical memory is subsequently reallocated for a new folio,
> it will reside at the exact same address. When this pointer is later
> checked in damon_pa_invalid_damos_folio():
>
> mm/damon/paddr.c:damon_pa_invalid_damos_folio() {
> ...
> if (folio = s->last_applied) {
> folio_put(folio);
> return true;
> }
> ...
> }
>
> Could this falsely match the dangling pointer and erroneously skip a
> valid, newly allocated folio from DAMOS actions?
I agree it is not super ideal, but missing one access event from DAMON's
best-effort monitoring is no problem.
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260728194714.3713735-1-gourry@gourry.net?part=1
>
Thanks,
SJ
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio()
2026-07-29 0:50 ` SJ Park
@ 2026-07-29 2:01 ` Gregory Price
2026-07-29 14:22 ` SJ Park
0 siblings, 1 reply; 15+ messages in thread
From: Gregory Price @ 2026-07-29 2:01 UTC (permalink / raw)
To: SJ Park
Cc: linux-mm, damon, linux-kernel, kernel-team, akpm, david, ljs, ziy,
baolin.wang, liam, npache, ryan.roberts, dev.jain, baohua,
lance.yang, usama.arif, vbabka, jannh, matthew.brost,
joshua.hahnjy, rakie.kim, byungchul, ying.huang, apopple
On Tue, Jul 28, 2026 at 05:50:36PM -0700, SJ Park wrote:
> Hi Gregory,
>
>
> On Tue, 28 Jul 2026 15:47:11 -0400 Gregory Price <gourry@gourry.net> wrote:
>
> > All DAMON physical- and virtual-address operations obtain their folios
> > through damon_get_folio(). That helper already excludes ZONE_DEVICE
> > memory implicitly via pfn_to_online_page() and folio_test_lru(), but
> > this is inconsistent with other callers in mm/ which test explicitly.
> >
> > Add an explicit folio_is_zone_device() rejection in damon_get_folio()
> > so the guarantee lives in one place and covers every caller uniformly,
> > consistent with other mm walkers that reject zone device folios.
>
> Thank you for checking this and sharing this nice patch!
>
> However, I'm not very sure adding a call that not really required for only
> making it looks consistent with others is the right choice. I'm especially
> concerned if this will confuse future readers including myself.
>
> If this is a hardening purpose, we have CONFIG_DAMON_DEBUG_SANITY for the
> purpose. What about using it with a good comment explaining why we doing that?
>
It's actually two fold:
1) make zone_device more consistently handled across mm/
2) make these checks possible to abstract out later
In the private node work - every location that we'd need to filter
folios based on private node membership is a zone_device check.
Where zone device checks are missing (like here) there's some other
implicit reason (specific to zone device) that allows it to be avoided.
I pointed out in the sashiko feedback that DAMON depends on a check
for folio->pgmap in the hotplug code. This is all quite fragile, and
we can see that at least one patch in this series fixes an actual bug.
It seemed warranted to go audit every service and add the zone_device
checks to make it clear there's a zone device interaction - even if
presently unreachable - should some silent, implicit filter change.
The goal is to come back around and replace these with something like:
bool folio_allows_mm_op(struct folio *folio,
enum node_states feature)
{
if (folio_is_zone_device(folio) ||
!node_state(folio_nid(folio), feature));
}
- if (folio_is_zone_device(folio))
+ if (folio_allows_mm_op(folio, N_MEMORY_DAMON))
If we ever get to folios having memdesc flags beyond page flags,
this also gives us a single mm-wide location for these kinds of
checks in the future.
~Gregory
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio()
2026-07-29 2:01 ` Gregory Price
@ 2026-07-29 14:22 ` SJ Park
2026-07-29 15:14 ` Gregory Price
0 siblings, 1 reply; 15+ messages in thread
From: SJ Park @ 2026-07-29 14:22 UTC (permalink / raw)
To: Gregory Price
Cc: SJ Park, linux-mm, damon, linux-kernel, kernel-team, akpm, david,
ljs, ziy, baolin.wang, liam, npache, ryan.roberts, dev.jain,
baohua, lance.yang, usama.arif, vbabka, jannh, matthew.brost,
joshua.hahnjy, rakie.kim, byungchul, ying.huang, apopple
On Tue, 28 Jul 2026 22:01:01 -0400 Gregory Price <gourry@gourry.net> wrote:
> On Tue, Jul 28, 2026 at 05:50:36PM -0700, SJ Park wrote:
> > Hi Gregory,
> >
> >
> > On Tue, 28 Jul 2026 15:47:11 -0400 Gregory Price <gourry@gourry.net> wrote:
> >
> > > All DAMON physical- and virtual-address operations obtain their folios
> > > through damon_get_folio(). That helper already excludes ZONE_DEVICE
> > > memory implicitly via pfn_to_online_page() and folio_test_lru(), but
> > > this is inconsistent with other callers in mm/ which test explicitly.
> > >
> > > Add an explicit folio_is_zone_device() rejection in damon_get_folio()
> > > so the guarantee lives in one place and covers every caller uniformly,
> > > consistent with other mm walkers that reject zone device folios.
> >
> > Thank you for checking this and sharing this nice patch!
> >
> > However, I'm not very sure adding a call that not really required for only
> > making it looks consistent with others is the right choice. I'm especially
> > concerned if this will confuse future readers including myself.
> >
> > If this is a hardening purpose, we have CONFIG_DAMON_DEBUG_SANITY for the
> > purpose. What about using it with a good comment explaining why we doing that?
> >
>
> It's actually two fold:
>
> 1) make zone_device more consistently handled across mm/
> 2) make these checks possible to abstract out later
>
> In the private node work - every location that we'd need to filter
> folios based on private node membership is a zone_device check.
>
> Where zone device checks are missing (like here) there's some other
> implicit reason (specific to zone device) that allows it to be avoided.
>
> I pointed out in the sashiko feedback that DAMON depends on a check
> for folio->pgmap in the hotplug code. This is all quite fragile, and
> we can see that at least one patch in this series fixes an actual bug.
>
> It seemed warranted to go audit every service and add the zone_device
> checks to make it clear there's a zone device interaction - even if
> presently unreachable - should some silent, implicit filter change.
>
> The goal is to come back around and replace these with something like:
>
> bool folio_allows_mm_op(struct folio *folio,
> enum node_states feature)
> {
> if (folio_is_zone_device(folio) ||
> !node_state(folio_nid(folio), feature));
> }
>
> - if (folio_is_zone_device(folio))
> + if (folio_allows_mm_op(folio, N_MEMORY_DAMON))
>
> If we ever get to folios having memdesc flags beyond page flags,
> this also gives us a single mm-wide location for these kinds of
> checks in the future.
Thank you for kindly explaining the motivation.
So, what do you think about adding the check under CONFIG_DAMON_DEBUG_SANITY
with good comments at the moment, and later converting to folio_allows_mm_ops()
together?
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio()
2026-07-29 14:22 ` SJ Park
@ 2026-07-29 15:14 ` Gregory Price
0 siblings, 0 replies; 15+ messages in thread
From: Gregory Price @ 2026-07-29 15:14 UTC (permalink / raw)
To: SJ Park
Cc: linux-mm, damon, linux-kernel, kernel-team, akpm, david, ljs, ziy,
baolin.wang, liam, npache, ryan.roberts, dev.jain, baohua,
lance.yang, usama.arif, vbabka, jannh, matthew.brost,
joshua.hahnjy, rakie.kim, byungchul, ying.huang, apopple
On Wed, Jul 29, 2026 at 07:22:28AM -0700, SJ Park wrote:
> On Tue, 28 Jul 2026 22:01:01 -0400 Gregory Price <gourry@gourry.net> wrote:
>
> So, what do you think about adding the check under CONFIG_DAMON_DEBUG_SANITY
> with good comments at the moment, and later converting to folio_allows_mm_ops()
> together?
>
I think probably we can drop the commit since it'll be a little odd to
add ifdef's and then take them out later (the latter check will be
functional, not just a sanity check).
~Gregory
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-07-29 15:14 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-28 19:47 [PATCH 0/4] mm: reject zone device folios in more folio walkers Gregory Price
2026-07-28 19:47 ` [PATCH 1/4] mm/damon: defensively skip zone device folios in damon_get_folio() Gregory Price
2026-07-28 19:57 ` sashiko-bot
2026-07-28 20:16 ` Gregory Price
2026-07-29 0:55 ` SJ Park
2026-07-29 0:50 ` SJ Park
2026-07-29 2:01 ` Gregory Price
2026-07-29 14:22 ` SJ Park
2026-07-29 15:14 ` Gregory Price
2026-07-28 19:47 ` [PATCH 2/4] mm/huge_memory: skip zone device folios in madvise_free_huge_pmd() Gregory Price
2026-07-28 20:01 ` sashiko-bot
2026-07-28 19:47 ` [PATCH 3/4] mm/madvise: skip zone device folios in cold/pageout PMD range Gregory Price
2026-07-28 19:58 ` sashiko-bot
2026-07-28 19:47 ` [PATCH 4/4] mm/mempolicy: skip zone device folios when queueing folios Gregory Price
2026-07-28 19:59 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox