Batch unmap of uffd-wp file folios
Subsystems (4)
cover Batch unmap of uffd-wp file folios
Currently, batched unmapping is supported if:
1) folio is a file folio, not belonging to uffd-wp VMA
2) folio is anonymous and not swapbacked (lazyfree), not belonging to uffd-wp VMA
So the cases which are not supported are
1) folio belonging to uffd-wp VMA
2) folio is anonymous and swapbacked
It is easy to see that this adds a lot of cognitive load while reading try_to_unmap_one - we need to remember throughout whether nr_pages == 1 or > 1.
The uffd-wp handling in try_to_unmap_one is regarding preserving the uffd-wp state for file folios via pte_install_uffd_wp_if_needed (for anon folio, we handle that while constructing the swap pte).
Stop special casing on uffd-wp VMAs by simply adding batching support to pte_install_uffd_wp_if_needed.
---
This is a split from:
https://lore.kernel.org/all/[email protected]/
mm-selftests pass.
I have based this on mm-new since my try_to_unmap_one refactoring changes weren't there in mm-unstable yet. But I suspect this series wouldn't have conflicted there, or conflicted trivially.
mm-new currently has Kiryl's uffd-rwp series, which confuses me about the terminology followed by my patchset (and the existing functions):
shall I call it uffd-wp bit or uffd bit?
Dev Jain (3):
mm/memory: move pte_install_uffd_wp_if_needed() into memory.c mm/memory: batch set uffd-wp markers during zapping mm/rmap: batch unmap file folios belonging to uffd-wp VMAs
include/linux/mm.h | 4 ++ include/linux/mm_inline.h | 53 ------------------------ mm/memory.c | 84 +++++++++++++++++++++++++++++---------- mm/rmap.c | 6 +-- 4 files changed, 70 insertions(+), 77 deletions(-)
Signature · 1 line
2.43.0
PATCH 1/3 mm/memory: move pte_install_uffd_wp_if_needed() into memory.c
pte_install_uffd_wp_if_needed() has grown too large for mm_inline.h. Move it to memory.c.
While at it, convert the comment to kerneldoc and rename the local arguments from pte/pteval to ptep/pte so the pointer and pte value are easier to distinguish.
--- include/linux/mm.h | 2 ++ include/linux/mm_inline.h | 53 ---------------------------------- mm/memory.c | 60 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 53 deletions(-)
include/linux/mm.h +2 -0
@@ -5406,4 +5406,6 @@ void map_anon_folio_pte_nopf(struct folio *folio, pte_t *pte, struct vm_area_struct *vma, unsigned long addr, bool uffd_wp); +bool pte_install_uffd_wp_if_needed (struct vm_area_struct *vma, +unsigned long addr,pte_t *ptep,pte_t pte);#endif /* _LINUX_MM_H */
include/linux/mm_inline.h +0 -53
59 lines not on this page · raw message
mm/memory.c +60 -0
66 lines not on this page · raw message
Signature · 1 line
2.43.0
David Hildenbrand (Arm)
maintainerRe: [PATCH 1/3] mm/memory: move pte_install_uffd_wp_if_needed() into memory.c
Quoted 19 lines · Dev Jain
pte_install_uffd_wp_if_needed()has grown too large formm_inline.h. Move it tomemory.c.While at it, convert the comment to kerneldoc and rename the local arguments from pte/pteval to ptep/pte so the pointer and pte value are easier to distinguish.
Signed-off-by Dev Jain <[email protected]>--- include/linux/mm.h | 2 ++ include/linux/mm_inline.h | 53 ---------------------------------- mm/memory.c | 60 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 53 deletions(-)include/linux/mm.h +0
-0
include/linux/mm.h void map_anon_folio_pte_nopf(struct folio *folio, pte_t *pte, · line 5410
Quoted 5 lines
include/linux/mm.h +2
-0@@ -5406,4 +5406,6 @@ void map_anon_folio_pte_nopf(struct folio *folio, pte_t *pte, struct vm_area_struct *vma, unsigned long addr, bool uffd_wp); +bool pte_install_uffd_wp_if_needed (struct vm_area_struct *vma, +unsigned long addr,pte_t *ptep,pte_t pte);
This could probably go to mm/internal.h instead?
Apart from that LGTM.
Signature · 3 lines
Cheers, David
Re: [PATCH 1/3] mm/memory: move pte_install_uffd_wp_if_needed() into memory.c
Quoted 23 lines · David Hildenbrand (Arm)
Quoted 22 lines · Dev Jain
pte_install_uffd_wp_if_needed()has grown too large formm_inline.h. Move it tomemory.c.While at it, convert the comment to kerneldoc and rename the local arguments from pte/pteval to ptep/pte so the pointer and pte value are easier to distinguish.
Signed-off-by Dev Jain <[email protected]>--- include/linux/mm.h | 2 ++ include/linux/mm_inline.h | 53 ---------------------------------- mm/memory.c | 60 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 53 deletions(-)include/linux/mm.h +0
-0@@ -5406,4 +5406,6 @@ void map_anon_folio_pte_nopf(struct folio *folio, pte_t *pte, struct vm_area_struct *vma, unsigned long addr, bool uffd_wp);
Quoted 6 lines
include/linux/mm.h void map_anon_folio_pte_nopf(struct folio *folio, pte_t *pte, · line 5410
Quoted 2 lines
include/linux/mm.h +2
-0+bool pte_install_uffd_wp_if_needed (struct vm_area_struct *vma, +unsigned long addr,pte_t *ptep,pte_t pte);This could probably go to
mm/internal.hinstead?Apart from that LGTM.
Correct, I'll do that.
Quoted 1 line
PATCH 2/3 mm/memory: batch set uffd-wp markers during zapping
In reply to Dev JainEnable batch setting of uffd-wp ptes.
The code paths passing nr > 1 to zap_install_uffd_wp_if_needed() produce that nr through either folio_pte_batch or swap_pte_batch, therefore batching is correct:
1) all ptes belong to the same type of VMA (anonymous or non-anonymous, wp-armed or non-wp-armed)
2) all ptes being marked with uffd-wp or all being not marked (same is the case with the pte_swp_uffd_wp_any check)
3) uffd_supports_wp_marker() is independent of the function parameters
Note that we will have to use set_pte_at() in a loop instead of set_ptes() since the latter cannot handle present->non-present conversion for nr_pages > 1.
Rename the function to cond_install_uffd_wp_ptes.
---
To handle nonpresent->nonpresent transition in the ptes, we can have a set_nonpresent_ptes() (in my unmap series) : if !softleaf_has_pfn(), use set the same pte value to all ptep's in the patch. if softleaf_has_pfn(), then add a softleaf_next_pfn() to construct the next softleaf, and pte_next_softleaf() to call softleaf_next_pfn() and preserve the wp bit, s-d bit, etc from the previous pte.
include/linux/mm.h | 6 +++-- mm/memory.c | 64 +++++++++++++++++----------------------------- mm/rmap.c | 2 +- 3 files changed, 29 insertions(+), 43 deletions(-)
include/linux/mm.h +4 -2
@@ -5406,6 +5406,8 @@ void map_anon_folio_pte_nopf(struct folio *folio, pte_t *pte, struct vm_area_struct *vma, unsigned long addr, bool uffd_wp); -bool pte_install_uffd_wp_if_needed (struct vm_area_struct *vma, -unsigned long addr,pte_t *ptep,pte_t pte); +bool cond_install_uffd_wp_ptes (struct vm_area_struct *vma,unsigned long addr, +pte_t *ptep,pte_t pte, +unsigned long nr_ptes); +#endif /* _LINUX_MM_H */
mm/memory.c +24 -40
93 lines not on this page · raw message
mm/rmap.c +1 -1
@@ -2345,7 +2345,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,* we may want to replace a none pte with a marker pte if * it's file-backed, so we don't lose the tracking info. */ -pte_install_uffd_wp_if_needed (vma, address, pvmw.pte, pteval); +cond_install_uffd_wp_ptes (vma, address, pvmw.pte, pteval,1 );/* Update high watermark before we lower rss */ update_hiwater_rss (mm);
Signature · 1 line
2.43.0
David Hildenbrand (Arm)
maintainerRe: [PATCH 2/3] mm/memory: batch set uffd-wp markers during zapping
Quoted 39 lines · Dev Jain
Enable batch setting of uffd-wp ptes.
The code paths passing nr > 1 to
zap_install_uffd_wp_if_needed()produce that nr through eitherfolio_pte_batchorswap_pte_batch, therefore batching is correct:1) all ptes belong to the same type of VMA (anonymous or non-anonymous, wp-armed or non-wp-armed)
2) all ptes being marked with uffd-wp or all being not marked (same is the case with the
pte_swp_uffd_wp_anycheck)3)
uffd_supports_wp_marker()is independent of the function parametersNote that we will have to use
set_pte_at()in a loop instead ofset_ptes()since the latter cannot handle present->non-present conversion fornr_pages> 1.Rename the function to
cond_install_uffd_wp_ptes.Signed-off-by Dev Jain <[email protected]>---
To handlenonpresent->nonpresenttransition in the ptes, we can have aset_nonpresent_ptes()(in my unmap series) : if !softleaf_has_pfn(), use set the same pte value to all ptep's in the patch. ifsoftleaf_has_pfn(), then add asoftleaf_next_pfn()to construct the next softleaf, andpte_next_softleaf()to callsoftleaf_next_pfn()and preserve the wp bit, s-d bit, etc from the previous pte.include/linux/mm.h | 6 +++-- mm/memory.c | 64 +++++++++++++++++----------------------------- mm/rmap.c | 2 +- 3 files changed, 29 insertions(+), 43 deletions(-)include/linux/mm.h +0
-0
include/linux/mm.h void map_anon_folio_pte_nopf(struct folio *folio, pte_t *pte, · line 5411
Quoted 8 lines
include/linux/mm.h +3
-2@@ -5406,6 +5406,8 @@ void map_anon_folio_pte_nopf(struct folio *folio, pte_t *pte, struct vm_area_struct *vma, unsigned long addr, bool uffd_wp); -bool pte_install_uffd_wp_if_needed (struct vm_area_struct *vma, -unsigned long addr,pte_t *ptep,pte_t pte); +bool cond_install_uffd_wp_ptes (struct vm_area_struct *vma,unsigned long addr, +pte_t *ptep,pte_t pte, +unsigned long nr_ptes);
Two tab ...
Quoted 55 lines
include/linux/mm.h +1
-0+#endif /* _LINUX_MM_H */ mm/memory.c +18
-16@@ -1676,27 +1676,29 @@ static inline bool zap_drop_markers(struct zap_details *details) }/** -* pte_install_uffd_wp_if_needed - install uffd-wp marker after clearing a PTE -* @vma: The VMA the page is mapped into. -* @addr: Address the page is mapped at. -* @ptep: Page table pointer for this entry. +* cond_install_uffd_wp_ptes - install uffd-wp markers after clearing PTEs +* @vma: The VMA the pages are mapped into. +* @addr: Address the first page of this batch is mapped at. +* @ptep: Page table pointer for the first entry of this batch. * @pte: Old value of the entry pointed to by @ptep. +* @nr_ptes: Number of entries to install. * -* If the PTE was write-protected by uffd-wp in any form, arm a special PTE -* to replace a none PTE. NOTE! This should only be called when the PTE is -* already cleared so we will never accidentally replace something valuable. -* Meanwhile none PTEs also mean we are not demoting the PTE so a TLB flush is -* not needed. E.g., when the PTE was cleared, the caller should have taken care -* of the TLB flush. +* If the PTEs were write-protected by uffd-wp in any form, arm special +* PTEs to replace none PTEs. NOTE! This should only be called when the PTEs +* are already cleared so we will never accidentally replace something +* valuable. Meanwhile none PTEs also mean we are not demoting the PTEs so a +* TLB flush is not needed. E.g., when PTEs were cleared, the caller should +* have taken care of the TLB flush. * -* Must be called with the page table lock held so that no thread will see the -* none PTE, and if they see it, they'll fault and serialize at the page table -* lock. +* Must be called with the page table lock held so that no thread will see +* the none PTEs, and if they see them, they'll fault and serialize at the +* page table lock. * -* Returns true if an uffd-wp PTE was installed, false otherwise. +* Returns true if uffd-wp PTEs were installed, false otherwise. */ -bool pte_install_uffd_wp_if_needed (struct vm_area_struct *vma, -unsigned long addr,pte_t *ptep,pte_t pte) +bool cond_install_uffd_wp_ptes (struct vm_area_struct *vma, +unsigned long addr,pte_t *ptep,pte_t pte, +unsigned long nr_ptes) {bool arm_uffd_pte = false;@@ -1726,13 +1728,14 @@ bool pte_install_uffd_wp_if_needed(struct vm_area_struct *vma,if (unlikely (pte_swp_uffd_any (pte))) arm_uffd_pte = true;
mm/memory.c bool pte_install_uffd_wp_if_needed(struct vm_area_struct *vma, · line 1733
Quoted 10 lines
mm/memory.c +4
-3-if (unlikely (arm_uffd_pte)) { +if (likely (!arm_uffd_pte)) +return false; + +for (unsigned long i =0 ; i < nr_ptes; ++i, ++ptep, addr +=PAGE_SIZE )set_pte_at (vma->vm_mm, addr, ptep,make_pte_marker (PTE_MARKER_UFFD_WP )); -return true; - }
Can we keep the "for (;;)" style of iterating PTEs that we use elsewhere?
Quoted 42 lines
mm/memory.c +2
-21-return false; +return true; }/* @@ -1746,29 +1749,10 @@ zap_install_uffd_wp_if_needed(struct vm_area_struct *vma, unsigned long addr, pte_t *pte, int nr, struct zap_details *details, pte_t pteval) { - bool was_installed = false; - -if (!uffd_supports_wp_marker ()) -return false; - -/* Zap on anonymous always means dropping everything */ -if (vma_is_anonymous (vma)) -return false; - if (zap_drop_markers(details)) return false; -for (;;) { -/* the PFN in the PTE is irrelevant. */ -if (pte_install_uffd_wp_if_needed (vma, addr, pte, pteval)) - was_installed = true; -if (--nr ==0 ) -break ; - pte++; - addr +=PAGE_SIZE ; - } - -return was_installed; +return cond_install_uffd_wp_ptes (vma, addr, pte, pteval, nr); } static __always_inline void zap_present_folio_ptes(struct mmu_gather *tlb,mm/rmap.c +0
-0
mm/rmap.c static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma, · line 2348
Quoted 5 lines
mm/rmap.c +1
-1@@ -2345,7 +2345,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,* we may want to replace a none pte with a marker pte if * it's file-backed, so we don't lose the tracking info. */ -pte_install_uffd_wp_if_needed (vma, address, pvmw.pte, pteval); +cond_install_uffd_wp_ptes (vma, address, pvmw.pte, pteval,1 );
Was about to ask whether we should provide a wrapper, but the next patch converts this case.
Signature · 3 lines
Cheers, David
Re: [PATCH 2/3] mm/memory: batch set uffd-wp markers during zapping
Quoted 43 lines · David Hildenbrand (Arm)
Quoted 42 lines · Dev Jain
Enable batch setting of uffd-wp ptes.
The code paths passing nr > 1 to
zap_install_uffd_wp_if_needed()produce that nr through eitherfolio_pte_batchorswap_pte_batch, therefore batching is correct:1) all ptes belong to the same type of VMA (anonymous or non-anonymous, wp-armed or non-wp-armed)
2) all ptes being marked with uffd-wp or all being not marked (same is the case with the
pte_swp_uffd_wp_anycheck)3)
uffd_supports_wp_marker()is independent of the function parametersNote that we will have to use
set_pte_at()in a loop instead ofset_ptes()since the latter cannot handle present->non-present conversion fornr_pages> 1.Rename the function to
cond_install_uffd_wp_ptes.Signed-off-by Dev Jain <[email protected]>---
To handlenonpresent->nonpresenttransition in the ptes, we can have aset_nonpresent_ptes()(in my unmap series) : if !softleaf_has_pfn(), use set the same pte value to all ptep's in the patch. ifsoftleaf_has_pfn(), then add asoftleaf_next_pfn()to construct the next softleaf, andpte_next_softleaf()to callsoftleaf_next_pfn()and preserve the wp bit, s-d bit, etc from the previous pte.include/linux/mm.h | 6 +++-- mm/memory.c | 64 +++++++++++++++++----------------------------- mm/rmap.c | 2 +- 3 files changed, 29 insertions(+), 43 deletions(-)include/linux/mm.h +0
-0@@ -5406,6 +5406,8 @@ void map_anon_folio_pte_nopf(struct folio *folio, pte_t *pte, struct vm_area_struct *vma, unsigned long addr, bool uffd_wp);
Quoted 8 lines
include/linux/mm.h void map_anon_folio_pte_nopf(struct folio *folio, pte_t *pte, · line 5411
Quoted 5 lines
include/linux/mm.h +3
-2-bool pte_install_uffd_wp_if_needed (struct vm_area_struct *vma, -unsigned long addr,pte_t *ptep,pte_t pte); +bool cond_install_uffd_wp_ptes (struct vm_area_struct *vma,unsigned long addr, +pte_t *ptep,pte_t pte, +unsigned long nr_ptes);Two tab ...
Ok.
Quoted 57 lines
Quoted 57 lines
include/linux/mm.h +1
-0+#endif /* _LINUX_MM_H */ mm/memory.c +18
-16@@ -1676,27 +1676,29 @@ static inline bool zap_drop_markers(struct zap_details *details) }/** -* pte_install_uffd_wp_if_needed - install uffd-wp marker after clearing a PTE -* @vma: The VMA the page is mapped into. -* @addr: Address the page is mapped at. -* @ptep: Page table pointer for this entry. +* cond_install_uffd_wp_ptes - install uffd-wp markers after clearing PTEs +* @vma: The VMA the pages are mapped into. +* @addr: Address the first page of this batch is mapped at. +* @ptep: Page table pointer for the first entry of this batch. * @pte: Old value of the entry pointed to by @ptep. +* @nr_ptes: Number of entries to install. * -* If the PTE was write-protected by uffd-wp in any form, arm a special PTE -* to replace a none PTE. NOTE! This should only be called when the PTE is -* already cleared so we will never accidentally replace something valuable. -* Meanwhile none PTEs also mean we are not demoting the PTE so a TLB flush is -* not needed. E.g., when the PTE was cleared, the caller should have taken care -* of the TLB flush. +* If the PTEs were write-protected by uffd-wp in any form, arm special +* PTEs to replace none PTEs. NOTE! This should only be called when the PTEs +* are already cleared so we will never accidentally replace something +* valuable. Meanwhile none PTEs also mean we are not demoting the PTEs so a +* TLB flush is not needed. E.g., when PTEs were cleared, the caller should +* have taken care of the TLB flush. * -* Must be called with the page table lock held so that no thread will see the -* none PTE, and if they see it, they'll fault and serialize at the page table -* lock. +* Must be called with the page table lock held so that no thread will see +* the none PTEs, and if they see them, they'll fault and serialize at the +* page table lock. * -* Returns true if an uffd-wp PTE was installed, false otherwise. +* Returns true if uffd-wp PTEs were installed, false otherwise. */ -bool pte_install_uffd_wp_if_needed (struct vm_area_struct *vma, -unsigned long addr,pte_t *ptep,pte_t pte) +bool cond_install_uffd_wp_ptes (struct vm_area_struct *vma, +unsigned long addr,pte_t *ptep,pte_t pte, +unsigned long nr_ptes) {bool arm_uffd_pte = false;@@ -1726,13 +1728,14 @@ bool pte_install_uffd_wp_if_needed(struct vm_area_struct *vma,if (unlikely (pte_swp_uffd_any (pte))) arm_uffd_pte = true;
Quoted 11 lines
mm/memory.c bool pte_install_uffd_wp_if_needed(struct vm_area_struct *vma, · line 1733
Quoted 9 lines
mm/memory.c +4
-3-if (unlikely (arm_uffd_pte)) { +if (likely (!arm_uffd_pte)) +return false; + +for (unsigned long i =0 ; i < nr_ptes; ++i, ++ptep, addr +=PAGE_SIZE )set_pte_at (vma->vm_mm, addr, ptep,make_pte_marker (PTE_MARKER_UFFD_WP )); -return true; - }Can we keep the "for (;;)" style of iterating PTEs that we use elsewhere?
Ok.
Quoted 52 lines
Quoted 43 lines
mm/memory.c +2
-21-return false; +return true; }/* @@ -1746,29 +1749,10 @@ zap_install_uffd_wp_if_needed(struct vm_area_struct *vma, unsigned long addr, pte_t *pte, int nr, struct zap_details *details, pte_t pteval) { - bool was_installed = false; - -if (!uffd_supports_wp_marker ()) -return false; - -/* Zap on anonymous always means dropping everything */ -if (vma_is_anonymous (vma)) -return false; - if (zap_drop_markers(details)) return false; -for (;;) { -/* the PFN in the PTE is irrelevant. */ -if (pte_install_uffd_wp_if_needed (vma, addr, pte, pteval)) - was_installed = true; -if (--nr ==0 ) -break ; - pte++; - addr +=PAGE_SIZE ; - } - -return was_installed; +return cond_install_uffd_wp_ptes (vma, addr, pte, pteval, nr); } static __always_inline void zap_present_folio_ptes(struct mmu_gather *tlb,mm/rmap.c +0
-0mm/rmap.c static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma, · line 2348
Quoted 5 lines
mm/rmap.c +1
-1@@ -2345,7 +2345,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,* we may want to replace a none pte with a marker pte if * it's file-backed, so we don't lose the tracking info. */ -pte_install_uffd_wp_if_needed (vma, address, pvmw.pte, pteval); +cond_install_uffd_wp_ptes (vma, address, pvmw.pte, pteval,1 );Was about to ask whether we should provide a wrapper, but the next patch converts this case.
PATCH 3/3 mm/rmap: batch unmap file folios belonging to uffd-wp VMAs
In reply to Dev JainCommit a67fe41e214f ("mm: rmap: support batched unmapping for file large folios") extended batched unmapping for file folios. That also required making install_uffd_wp_pte_if_needed() support batching, but that was left out for the time being, and correctness was maintained by stopping batching in case the VMA the folio belongs to is marked uffd-wp.
Now that we have a batched version called cond_install_uffd_wp_ptes, simply call that. folio_unmap_pte_batch() ensures that the original state of the ptes is either all uffd or all non-uffd, so we maintain correctness.
If uffd-wp bit is there, we have the following transitions of ptes after unmapping, for a file folio:
present -> uffd-wp marker
We must ensure that these ptes are not reprocessed by the while loop - if the batch length is less than the number of pages in the folio, then we must skip over this batch.
The page_vma_mapped_walk API ensures this - check_pte() will return true only if any of [pvmw->pfn, pvmw->pfn + nr_pages) is mapped by the pte. There is no pfn underlying a uffd-wp marker pte, so check_pte returns false and we keep skipping until we hit a present entry, which is where we want to batch from next.
Note that for the uffd-rwp case, we already do not make a uffd marker in cond_install_uffd_wp_ptes.
---
Dropped David's ACK due to the uffd-rwp changes.
mm/rmap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
mm/rmap.c +2 -4
@@ -1965,9 +1965,6 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,if (pte_unused (pte))return 1 ; -if (userfaultfd_protected (vma)) -return 1 ; -/* * If unmap fails, we need to restore the ptes. To avoid accidentally * upgrading write permissions for ptes that were not originally
@@ -2345,7 +2342,8 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,* we may want to replace a none pte with a marker pte if * it's file-backed, so we don't lose the tracking info. */ -cond_install_uffd_wp_ptes (vma, address, pvmw.pte, pteval,1 ); +cond_install_uffd_wp_ptes (vma, address, pvmw.pte, pteval, + nr_pages);/* Update high watermark before we lower rss */ update_hiwater_rss (mm);
Signature · 1 line
2.43.0
Re: [PATCH 3/3] mm/rmap: batch unmap file folios belonging to uffd-wp VMAs
Quoted 51 lines · Dev Jain
Commit
a67fe41e214f("mm: rmap: support batched unmapping for file large folios") extended batched unmapping for file folios. That also required makinginstall_uffd_wp_pte_if_needed()support batching, but that was left out for the time being, and correctness was maintained by stopping batching in case the VMA the folio belongs to is marked uffd-wp.Now that we have a batched version called
cond_install_uffd_wp_ptes, simply call that.folio_unmap_pte_batch()ensures that the original state of the ptes is either all uffd or all non-uffd, so we maintain correctness.If uffd-wp bit is there, we have the following transitions of ptes after unmapping, for a file folio:
present -> uffd-wp marker
We must ensure that these ptes are not reprocessed by the while loop - if the batch length is less than the number of pages in the folio, then we must skip over this batch.
The
page_vma_mapped_walkAPI ensures this -check_pte()will return true only if any of [pvmw->pfn,pvmw->pfn+nr_pages) is mapped by the pte. There is no pfn underlying a uffd-wp marker pte, socheck_ptereturns false and we keep skipping until we hit a present entry, which is where we want to batch from next.Note that for the uffd-rwp case, we already do not make a uffd marker in
cond_install_uffd_wp_ptes.Signed-off-by Dev Jain <[email protected]>---
Dropped David's ACK due to the uffd-rwp changes.mm/rmap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)mm/rmap.c +0
-3@@ -1965,9 +1965,6 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,if (pte_unused (pte))return 1 ; -if (userfaultfd_protected (vma)) -return 1 ; -/* * If unmap fails, we need to restore the ptes. To avoid accidentally * upgrading write permissions for ptes that were not originally
mm/rmap.c static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma, · line 2349
Quoted 9 lines
mm/rmap.c +2
-1@@ -2345,7 +2342,8 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,* we may want to replace a none pte with a marker pte if * it's file-backed, so we don't lose the tracking info. */ -cond_install_uffd_wp_ptes (vma, address, pvmw.pte, pteval,1 ); +cond_install_uffd_wp_ptes (vma, address, pvmw.pte, pteval, + nr_pages);/* Update high watermark before we lower rss */ update_hiwater_rss (mm);
Signature · 3 lines
Cheers, David
Andrew Morton
maintainerQuoted 15 lines · On Wed, 15 Jul 2026 11:18:33 +0000 Dev Jain <[email protected]> wrote:
Currently, batched unmapping is supported if:
1) folio is a file folio, not belonging to uffd-wp VMA
2) folio is anonymous and not swapbacked (lazyfree), not belonging to uffd-wp VMASo the cases which are not supported are
1) folio belonging to uffd-wp VMA
2) folio is anonymous and swapbackedIt is easy to see that this adds a lot of cognitive load while reading
try_to_unmap_one- we need to remember throughout whethernr_pages== 1 or > 1.
Quoted 6 lines
The uffd-wp handling in
try_to_unmap_oneis regarding preserving the uffd-wp state for file folios viapte_install_uffd_wp_if_needed(for anon folio, we handle that while constructing the swap pte).Stop special casing on uffd-wp VMAs by simply adding batching support to
pte_install_uffd_wp_if_needed.
Thanks, I'll await reviewer input on this.
Sashiko might have found a pre-existing issue:
https://sashiko.dev/#/patchset/[email protected]
Quoted 21 lines · Andrew Morton
Quoted 19 lines · On Wed, 15 Jul 2026 11:18:33 +0000 Dev Jain <[email protected]> wrote:
Currently, batched unmapping is supported if:
1) folio is a file folio, not belonging to uffd-wp VMA
2) folio is anonymous and not swapbacked (lazyfree), not belonging to uffd-wp VMASo the cases which are not supported are
1) folio belonging to uffd-wp VMA
2) folio is anonymous and swapbackedIt is easy to see that this adds a lot of cognitive load while reading
try_to_unmap_one- we need to remember throughout whethernr_pages== 1 or > 1.The uffd-wp handling in
try_to_unmap_oneis regarding preserving the uffd-wp state for file folios viapte_install_uffd_wp_if_needed(for anon folio, we handle that while constructing the swap pte).
Quoted 7 lines
Quoted 2 lines
Stop special casing on uffd-wp VMAs by simply adding batching support to
pte_install_uffd_wp_if_needed.Thanks, I'll await reviewer input on this.
Sashiko might have found a pre-existing issue:
https://sashiko.dev/#/patchset/[email protected]
That was unexpected from Sashiko.
"When a large folio registered with uffd-wp is unmapped via try_to_unmap_one(), folio_unmap_pte_batch() batches and clears multiple PTEs."
At patch 2, there is no batching support yet for uffd-wp folios.