[PATCH] tmp
From: David Hildenbrand (Arm)
Date: Thu Oct 01 2026 - 16:19:57 EST
Signed-off-by: David Hildenbrand (Arm) <david@xxxxxxxxxx>
---
include/linux/mm.h | 4 +++-
mm/memory.c | 48 ++++++++++++++++++++++++++++++++++++++++------
2 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index c49ef99b4413..b90e547797a9 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -3193,6 +3193,8 @@ struct folio *vm_normal_folio_pmd(struct vm_area_struct *vma,
unsigned long addr, pmd_t pmd);
struct page *vm_normal_page_pmd(struct vm_area_struct *vma, unsigned long addr,
pmd_t pmd);
+struct folio *vm_normal_folio_pud(struct vm_area_struct *vma,
+ unsigned long addr, pud_t pud);
struct page *vm_normal_page_pud(struct vm_area_struct *vma, unsigned long addr,
pud_t pud);
@@ -3245,7 +3247,7 @@ struct follow_pfnmap_args {
unsigned long addr_mask;
pgprot_t pgprot;
bool writable;
- bool special;
+ bool cow;
};
int follow_pfnmap_start(struct follow_pfnmap_args *args);
void follow_pfnmap_end(struct follow_pfnmap_args *args);
diff --git a/mm/memory.c b/mm/memory.c
index 926276d41920..764b79204ab7 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -843,7 +843,7 @@ struct page *vm_normal_page_pmd(struct vm_area_struct *vma, unsigned long addr,
* @addr: The address where the @pmd is mapped.
* @pmd: The PMD.
*
- * Get the "struct folio" associated with a PTE. See __vm_normal_page()
+ * Get the "struct folio" associated with a PMD. See __vm_normal_page()
* for details on "normal" and "special" mappings.
*
* Return: Returns the "struct folio" if this is a "normal" mapping. Returns
@@ -879,6 +879,28 @@ struct page *vm_normal_page_pud(struct vm_area_struct *vma,
return __vm_normal_page(vma, addr, pud_pfn(pud), pud_special(pud),
&entry, sizeof(entry), PGTABLE_LEVEL_PUD);
}
+
+/**
+ * vm_normal_folio_pud() - Get the "struct folio" associated with a PUD
+ * @vma: The VMA mapping the @pud.
+ * @addr: The address where the @pud is mapped.
+ * @pud: The PUD.
+ *
+ * Get the "struct folio" associated with a PUD. See __vm_normal_page()
+ * for details on "normal" and "special" mappings.
+ *
+ * Return: Returns the "struct folio" if this is a "normal" mapping. Returns
+ * NULL if this is a "special" mapping.
+ */
+struct folio *vm_normal_folio_pud(struct vm_area_struct *vma,
+ unsigned long addr, pud_t pud)
+{
+ struct page *page = vm_normal_page_pud(vma, addr, pud);
+
+ if (page)
+ return page_folio(page);
+ return NULL;
+}
#endif
/**
@@ -6947,7 +6969,7 @@ static inline void pfnmap_args_setup(struct follow_pfnmap_args *args,
spinlock_t *lock, pte_t *ptep,
pgprot_t pgprot, unsigned long pfn_base,
unsigned long addr_mask, bool writable,
- bool special)
+ struct folio *folio)
{
args->lock = lock;
args->ptep = ptep;
@@ -6955,7 +6977,7 @@ static inline void pfnmap_args_setup(struct follow_pfnmap_args *args,
args->addr_mask = addr_mask;
args->pgprot = pgprot;
args->writable = writable;
- args->special = special;
+ args->cow = folio && folio_test_anon(folio);
}
static inline void pfnmap_lockdep_assert(struct vm_area_struct *vma)
@@ -7008,6 +7030,7 @@ int follow_pfnmap_start(struct follow_pfnmap_args *args)
struct vm_area_struct *vma = args->vma;
unsigned long address = args->address;
struct mm_struct *mm = vma->vm_mm;
+ struct folio *folio = NULL;
spinlock_t *lock;
pgd_t *pgdp;
p4d_t *p4dp, p4d;
@@ -7047,9 +7070,12 @@ int follow_pfnmap_start(struct follow_pfnmap_args *args)
spin_unlock(lock);
goto retry;
}
+
+ if (vma_is_cow_mapping(vma))
+ folio = vm_normal_folio_pud(vma, address, pud);
pfnmap_args_setup(args, lock, NULL, pud_pgprot(pud),
pud_pfn(pud), PUD_MASK, pud_write(pud),
- pud_special(pud));
+ folio);
return 0;
}
@@ -7068,9 +7094,12 @@ int follow_pfnmap_start(struct follow_pfnmap_args *args)
spin_unlock(lock);
goto retry;
}
+
+ if (vma_is_cow_mapping(vma))
+ folio = vm_normal_folio_pmd(vma, address, pmd);
pfnmap_args_setup(args, lock, NULL, pmd_pgprot(pmd),
pmd_pfn(pmd), PMD_MASK, pmd_write(pmd),
- pmd_special(pmd));
+ folio);
return 0;
}
@@ -7080,9 +7109,12 @@ int follow_pfnmap_start(struct follow_pfnmap_args *args)
pte = ptep_get(ptep);
if (!pte_present(pte))
goto unlock;
+
+ if (vma_is_cow_mapping(vma))
+ folio = vm_normal_folio(vma, address, pte);
pfnmap_args_setup(args, lock, ptep, pte_pgprot(pte),
pte_pfn(pte), PAGE_MASK, pte_write(pte),
- pte_special(pte));
+ folio);
return 0;
unlock:
pte_unmap_unlock(ptep, lock);
@@ -7145,6 +7177,10 @@ int generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
writable = args.writable;
follow_pfnmap_end(&args);
+ /* Reject CoW'ed anonymous folios. */
+ if (args.cow)
+ return -EINVAL;
+
if ((write & FOLL_WRITE) && !writable)
return -EINVAL;
--
2.43.0
--
Cheers,
David