* [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; 9+ 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] 9+ 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-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, 1 reply; 9+ 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] 9+ 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 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, 0 replies; 9+ 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] 9+ 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:47 ` [PATCH 4/4] mm/mempolicy: skip zone device folios when queueing folios Gregory Price
3 siblings, 0 replies; 9+ 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] 9+ 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
3 siblings, 0 replies; 9+ 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] 9+ 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-29 0:50 ` SJ Park
2026-07-29 2:01 ` Gregory Price
0 siblings, 1 reply; 9+ 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] 9+ 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; 9+ 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] 9+ 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; 9+ 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] 9+ 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; 9+ 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] 9+ messages in thread
end of thread, other threads:[~2026-07-29 15:15 UTC | newest]
Thread overview: 9+ 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-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 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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox