Re: [Patch mm-hotfixes v4] mm/page_vma_mapped: fix device-private PMD handling

From: Wei Yang

Date: Fri Jun 26 2026 - 22:07:33 EST


On Fri, Jun 26, 2026 at 12:07:56PM +0200, David Hildenbrand (Arm) wrote:
>On 6/24/26 08:53, Wei Yang wrote:
[...]
>
>This is extremely hard to review given the existing crap handling here. I'm
>really sorry, but it makes my head hurt (I'm not kidding :) ).
>
>It's completely unclear why we only have to check for a subset of the cases
>after taking the lock.
>
>Could we simply extend the existing migration pmd handling and leave the
>!pmd_present() case for pmd_none()?
>
>That leaves no question to "which transitions are actually allowed", including
>"could we accidentally assume something is a page table when really it isn't".
>
>
>So what about something like the following?
>
>The "thp_migration_supported()" is not required when checking for
>pmd_is_migration_entry(), as that defaults to "false" when not compiled in.
>
>Untested:
>

Hi David

I did a little adjustment like below. Want to check with you at first.

>
>>From 048ecd33673ec649e168fbbb97749a7c0e344fcd Mon Sep 17 00:00:00 2001
>From: "David Hildenbrand (Arm)" <david@xxxxxxxxxx>
>Date: Fri, 26 Jun 2026 12:03:40 +0200
>Subject: [PATCH] tmp
>
>Signed-off-by: David Hildenbrand (Arm) <david@xxxxxxxxxx>
>---
> mm/page_vma_mapped.c | 29 +++++++++++++++++------------
> 1 file changed, 17 insertions(+), 12 deletions(-)
>
>diff --git a/mm/page_vma_mapped.c b/mm/page_vma_mapped.c
>index 2ccbabfb2cc17..ed2a23a90e8dd 100644
>--- a/mm/page_vma_mapped.c
>+++ b/mm/page_vma_mapped.c
>@@ -243,21 +243,31 @@ bool page_vma_mapped_walk(struct page_vma_mapped_walk *pvmw)
> */
> pmde = pmdp_get_lockless(pvmw->pmd);
>
>- if (pmd_trans_huge(pmde) || pmd_is_migration_entry(pmde)) {
>+ if (pmd_trans_huge(pmde) || pmd_is_migration_entry(pmde) ||
>+ pmd_is_device_private_entry(pmde)) {
> pvmw->ptl = pmd_lock(mm, pvmw->pmd);
> pmde = *pvmw->pmd;
>- if (!pmd_present(pmde)) {
>+ if (pmd_is_migration_entry(pmde)) {
> softleaf_t entry;
>

How about:
const softleaf_t entry = softleaf_from_pmd(pmde);

>- if (!thp_migration_supported() ||
>- !(pvmw->flags & PVMW_MIGRATION))
>+ if (!(pvmw->flags & PVMW_MIGRATION))
> return not_found(pvmw);
> entry = softleaf_from_pmd(pmde);

could be removed.

>+ if (!check_pmd(softleaf_to_pfn(entry), pvmw))
>+ return not_found(pvmw);
>+ return true;
>+ } else if (pmd_is_device_private_entry(pmde)) {
>+ softleaf_t entry;

The same.

>
>- if (!softleaf_is_migration(entry) ||
>- !check_pmd(softleaf_to_pfn(entry), pvmw))
>+ if (pvmw->flags & PVMW_MIGRATION)
>+ return not_found(pvmw);
>+ entry = softleaf_from_pmd(pmde);
>+ if (!check_pmd(softleaf_to_pfn(entry), pvmw))
> return not_found(pvmw);
> return true;
>+ } else if (!pmd_present(pmde) ){
>+ return not_found(pvmw);
> }
> if (likely(pmd_trans_huge(pmde))) {
> if (pvmw->flags & PVMW_MIGRATION)

How about merge this with above? And put at the first case?

Below is what it looks like:

if (pmd_trans_huge(pmde) || pmd_is_migration_entry(pmde) ||
pmd_is_device_private_entry(pmde)) {
pvmw->ptl = pmd_lock(mm, pvmw->pmd);
pmde = *pvmw->pmd;
if (likely(pmd_trans_huge(pmde))) {
if (pvmw->flags & PVMW_MIGRATION)
return not_found(pvmw);
if (!check_pmd(pmd_pfn(pmde), pvmw))
return not_found(pvmw);
return true;
} else if (pmd_is_migration_entry(pmde)) {
const softleaf_t entry = softleaf_from_pmd(pmde);

if (!(pvmw->flags & PVMW_MIGRATION))
return not_found(pvmw);
if (!check_pmd(softleaf_to_pfn(entry), pvmw))
return not_found(pvmw);
return true;
} else if (pmd_is_device_private_entry(pmde)) {
const softleaf_t entry = softleaf_from_pmd(pmde);

if (pvmw->flags & PVMW_MIGRATION)
return not_found(pvmw);
if (!check_pmd(softleaf_to_pfn(entry), pvmw))
return not_found(pvmw);
return true;
} else if (!pmd_present(pmde)) {
return not_found(pvmw);
}
/* THP pmd was split under us: handle on pte level */
spin_unlock(pvmw->ptl);
pvmw->ptl = NULL;
} else if (!pmd_present(pmde)) {

Test with split_huge_page_test/khugepaged/hmm-test/migration in selftets,
looks good.

--
Wei Yang
Help you, Help me