[PATCH 3/4] mm/ksm: make break_ksm() more scalable

From: xu.xin16

Date: Fri Sep 11 2026 - 04:21:37 EST


From: Xu Xin (ZTE) <xu.xin@xxxxxxxxx>

Currently the last argument 'walk_lock' of break_ksm() is used to
indicate whether the page_walk is protected by mmap_read_lock or
mmap_write_lock. If 'walk_lock' is true, we suppose its context to
be under mmap_write_lock() protection, then mark it PGWALK_WRLOCK and
make its vma be write-locked during the walk; If 'walk_lock' is
false, we suppose its context to be mmap_read_lock(), then mark it
PGWALK_RDLOCK.

This change is prepared for the latter patch to enable VMA
read-locking where break_ksm() might be under the third new proctecion
way: VMA read-locking, so we have to replace the boolean variable to
the enum 'page_walk_lock', but without any function changed.

No functional change intended.

Signed-off-by: Xu Xin (ZTE) <xu.xin@xxxxxxxxx>
---
mm/ksm.c | 21 ++++++++-------------
1 file changed, 8 insertions(+), 13 deletions(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index 8df66b4e5de0..dda105681d7f 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -660,16 +660,11 @@ static int break_ksm_pmd_entry(pmd_t *pmdp, unsigned long addr, unsigned long en
return found;
}

-static const struct mm_walk_ops break_ksm_ops = {
+static struct mm_walk_ops break_ksm_ops = {
.pmd_entry = break_ksm_pmd_entry,
.walk_lock = PGWALK_RDLOCK,
};

-static const struct mm_walk_ops break_ksm_lock_vma_ops = {
- .pmd_entry = break_ksm_pmd_entry,
- .walk_lock = PGWALK_WRLOCK,
-};
-
/*
* Though it's very tempting to unmerge rmap_items from stable tree rather
* than check every pte of a given vma, the locking doesn't quite work for
@@ -696,11 +691,11 @@ static const struct mm_walk_ops break_ksm_lock_vma_ops = {
* protection keys here anyway.
*/
static int break_ksm(struct vm_area_struct *vma, unsigned long addr,
- unsigned long end, bool lock_vma)
+ unsigned long end, enum page_walk_lock walk_lock)
{
vm_fault_t ret = 0;
- const struct mm_walk_ops *ops = lock_vma ?
- &break_ksm_lock_vma_ops : &break_ksm_ops;
+ struct mm_walk_ops *ops = &break_ksm_ops;
+ ops->walk_lock = walk_lock;

do {
int ksm_page;
@@ -807,7 +802,7 @@ static void break_cow(struct ksm_rmap_item *rmap_item)
mmap_read_lock(mm);
vma = find_mergeable_vma(mm, addr);
if (vma)
- break_ksm(vma, addr, addr + PAGE_SIZE, false);
+ break_ksm(vma, addr, addr + PAGE_SIZE, PGWALK_RDLOCK);
mmap_read_unlock(mm);
}

@@ -1245,7 +1240,7 @@ static int unmerge_and_remove_all_rmap_items(void)
for_each_vma(vmi, vma) {
if (!(vma->vm_flags & VM_MERGEABLE) || !vma->anon_vma)
continue;
- err = break_ksm(vma, vma->vm_start, vma->vm_end, false);
+ err = break_ksm(vma, vma->vm_start, vma->vm_end, PGWALK_RDLOCK);
if (err)
goto error;
}
@@ -2885,7 +2880,7 @@ static int __ksm_del_vma(struct vm_area_struct *vma)
return 0;

if (vma->anon_vma) {
- err = break_ksm(vma, vma->vm_start, vma->vm_end, true);
+ err = break_ksm(vma, vma->vm_start, vma->vm_end, PGWALK_WRLOCK);
if (err)
return err;
}
@@ -3037,7 +3032,7 @@ int ksm_madvise(struct vm_area_struct *vma, unsigned long start,
return 0; /* just ignore the advice */

if (vma->anon_vma) {
- err = break_ksm(vma, start, end, true);
+ err = break_ksm(vma, start, end, PGWALK_WRLOCK);
if (err)
return err;
}
--
2.25.1