mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion
@ 2026-09-15 15:12 Longlong Xia
  2026-09-15 15:12 ` [PATCH 01/14] mm/ksm: constify ksm_next_page_ops Longlong Xia
                   ` (11 more replies)
  0 siblings, 12 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 15:12 UTC (permalink / raw)
  To: Andrew Morton, linux-mm
  Cc: Longlong Xia, David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

From: Longlong Xia <xialonglong@kylinos.cn>

Clean up KSM's scan helpers, advisor naming and sysfs formatting, then
pass folios through the merge path and update the related comments.

Patches 11-13 convert the merge targets of the merge path to folios,
continuing the earlier conversion of write_protect_page(),
stable_tree_insert() and the ksm_get_folio() helpers.

Before this series the merge path talked to the stable tree in folios
but to the merge helpers in pages, so the same ksm folio was wrapped
and unwrapped at every level:

  stable_tree_search() returns a folio
        |
        v
      try_to_merge_with_ksm_page(..., &kfolio->page)   <- unwrap
        |
        v
  try_to_merge_one_page(..., kpage)                    <- page all the way
        |
        v
  replace_page(vma, page, kpage, ...)
        |
        v
  kfolio = page_folio(kpage)                           <- re-wrap
  folio  = page_folio(page)                            <- re-wrap

With patches 11-13 every function in the chain takes the ksm folio
directly:

  stable_tree_search() returns a folio
        |
        v
      try_to_merge_with_ksm_folio(..., kfolio)
        |
        v
  try_to_merge_one_page(..., kfolio)
        |
        v
  replace_page(vma, folio, kfolio, ...)
        |
        v
  folio_page(folio, 0) only where a 4K page is needed (pte and rmap)

No functional change intended.

This series is based on next-20260914 (1a1de54f7369).

Longlong Xia (14):
  mm/ksm: constify ksm_next_page_ops
  mm/ksm: rename advisor_ctx to ksm_advisor_ctx
  mm/ksm: use the correct format specifier for max_page_sharing
  mm/ksm: add advance_scan_mm_slot() helper
  mm/ksm: make remove_stable_node_chain() return bool
  mm/ksm: clear all slab cache pointers in ksm_slab_free()
  mm/ksm: reuse the zero page pointer for merge tracing
  mm/ksm: document the two remove_rmap_item_from_tree() calls
  mm/ksm: move the no_vmas label out of the if block
  mm/ksm: extract ksm_begin_full_scan() from scan_get_next_rmap_item()
  mm/ksm: pass folios to replace_page()
  mm/ksm: take the ksm folio in try_to_merge_one_page()
  mm/ksm: take the ksm folio in try_to_merge_with_ksm_page()
  mm/ksm: update merge helper comments for folios

 mm/ksm.c | 270 +++++++++++++++++++++++++++++++------------------------
 1 file changed, 152 insertions(+), 118 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 01/14] mm/ksm: constify ksm_next_page_ops
  2026-09-15 15:12 [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Longlong Xia
@ 2026-09-15 15:12 ` Longlong Xia
  2026-09-15 15:12 ` [PATCH 02/14] mm/ksm: rename advisor_ctx to ksm_advisor_ctx Longlong Xia
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 15:12 UTC (permalink / raw)
  To: Andrew Morton, linux-mm
  Cc: Longlong Xia, David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

From: Longlong Xia <xialonglong@kylinos.cn>

ksm_next_page_ops is never modified. Mark it const so it can reside in
read-only memory.

No functional change intended.

Assisted-by: Zcode:GLM-5.3
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>

---
 mm/ksm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index 624f37975e12..f637f3baea69 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -2603,7 +2603,7 @@ static int ksm_next_page_pmd_entry(pmd_t *pmdp, unsigned long addr, unsigned lon
 	return 1;
 }
 
-static struct mm_walk_ops ksm_next_page_ops = {
+static const struct mm_walk_ops ksm_next_page_ops = {
 	.pmd_entry = ksm_next_page_pmd_entry,
 	.walk_lock = PGWALK_RDLOCK,
 };
-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 02/14] mm/ksm: rename advisor_ctx to ksm_advisor_ctx
  2026-09-15 15:12 [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Longlong Xia
  2026-09-15 15:12 ` [PATCH 01/14] mm/ksm: constify ksm_next_page_ops Longlong Xia
@ 2026-09-15 15:12 ` Longlong Xia
  2026-09-15 15:12 ` [PATCH 03/14] mm/ksm: use the correct format specifier for max_page_sharing Longlong Xia
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 15:12 UTC (permalink / raw)
  To: Andrew Morton, linux-mm
  Cc: Longlong Xia, David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

From: Longlong Xia <xialonglong@kylinos.cn>

Rename the advisor context to match the ksm_advisor_ prefix used by
its tunables.

No functional change intended.

Assisted-by: Zcode:GLM-5.3
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>

---
 mm/ksm.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index f637f3baea69..1e4d77852fc8 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -334,7 +334,7 @@ struct advisor_ctx {
 	unsigned long change;
 	unsigned long long cpu_time;
 };
-static struct advisor_ctx advisor_ctx;
+static struct advisor_ctx ksm_advisor_ctx;
 
 /* Define different advisor's */
 enum ksm_advisor_type {
@@ -356,7 +356,7 @@ static void set_advisor_defaults(void)
 	if (ksm_advisor == KSM_ADVISOR_NONE) {
 		ksm_thread_pages_to_scan = DEFAULT_PAGES_TO_SCAN;
 	} else if (ksm_advisor == KSM_ADVISOR_SCAN_TIME) {
-		advisor_ctx = (const struct advisor_ctx){ 0 };
+		ksm_advisor_ctx = (const struct advisor_ctx){ 0 };
 		ksm_thread_pages_to_scan = ksm_advisor_min_pages_to_scan;
 	}
 }
@@ -365,7 +365,7 @@ static void set_advisor_defaults(void)
 static inline void advisor_start_scan(void)
 {
 	if (ksm_advisor == KSM_ADVISOR_SCAN_TIME)
-		advisor_ctx.start_scan = ktime_get();
+		ksm_advisor_ctx.start_scan = ktime_get();
 }
 
 /*
@@ -419,18 +419,18 @@ static void scan_time_advisor(void)
 	unsigned long scan_time;
 
 	/* Convert scan time to seconds */
-	scan_time = div_s64(ktime_ms_delta(ktime_get(), advisor_ctx.start_scan),
+	scan_time = div_s64(ktime_ms_delta(ktime_get(), ksm_advisor_ctx.start_scan),
 			    MSEC_PER_SEC);
 	scan_time = scan_time ? scan_time : 1;
 
 	/* Calculate CPU consumption of ksmd background thread */
 	cpu_time = task_sched_runtime(current);
-	cpu_time_diff = cpu_time - advisor_ctx.cpu_time;
+	cpu_time_diff = cpu_time - ksm_advisor_ctx.cpu_time;
 	cpu_time_diff_ms = cpu_time_diff / 1000 / 1000;
 
 	cpu_percent = (cpu_time_diff_ms * 100) / (scan_time * 1000);
 	cpu_percent = cpu_percent ? cpu_percent : 1;
-	last_scan_time = prev_scan_time(&advisor_ctx, scan_time);
+	last_scan_time = prev_scan_time(&ksm_advisor_ctx, scan_time);
 
 	/* Calculate scan time as percentage of target scan time */
 	factor = ksm_advisor_target_scan_time * 100 / scan_time;
@@ -442,7 +442,7 @@ static void scan_time_advisor(void)
 	 */
 	change = scan_time * 100 / last_scan_time;
 	change = change ? change : 1;
-	change = ewma(advisor_ctx.change, change);
+	change = ewma(ksm_advisor_ctx.change, change);
 
 	/* Calculate new scan rate based on target scan rate. */
 	pages = ksm_thread_pages_to_scan * 100 / factor;
@@ -458,9 +458,9 @@ static void scan_time_advisor(void)
 	pages = min(pages, ksm_advisor_max_pages_to_scan);
 
 	/* Update advisor context */
-	advisor_ctx.change = change;
-	advisor_ctx.scan_time = scan_time;
-	advisor_ctx.cpu_time = cpu_time;
+	ksm_advisor_ctx.change = change;
+	ksm_advisor_ctx.scan_time = scan_time;
+	ksm_advisor_ctx.cpu_time = cpu_time;
 
 	ksm_thread_pages_to_scan = pages;
 	trace_ksm_advisor(scan_time, pages, cpu_percent);
-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 03/14] mm/ksm: use the correct format specifier for max_page_sharing
  2026-09-15 15:12 [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Longlong Xia
  2026-09-15 15:12 ` [PATCH 01/14] mm/ksm: constify ksm_next_page_ops Longlong Xia
  2026-09-15 15:12 ` [PATCH 02/14] mm/ksm: rename advisor_ctx to ksm_advisor_ctx Longlong Xia
@ 2026-09-15 15:12 ` Longlong Xia
  2026-09-15 15:12 ` [PATCH 04/14] mm/ksm: add advance_scan_mm_slot() helper Longlong Xia
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 15:12 UTC (permalink / raw)
  To: Andrew Morton, linux-mm
  Cc: Longlong Xia, David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

From: Longlong Xia <xialonglong@kylinos.cn>

Use %d to match the int type of ksm_max_page_sharing. The accepted
values are at least two, so the sysfs output is unchanged.

Assisted-by: Zcode:GLM-5.3
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>

---
 mm/ksm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index 1e4d77852fc8..18d037f571d3 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -3676,7 +3676,7 @@ KSM_ATTR(use_zero_pages);
 static ssize_t max_page_sharing_show(struct kobject *kobj,
 				     struct kobj_attribute *attr, char *buf)
 {
-	return sysfs_emit(buf, "%u\n", ksm_max_page_sharing);
+	return sysfs_emit(buf, "%d\n", ksm_max_page_sharing);
 }
 
 static ssize_t max_page_sharing_store(struct kobject *kobj,
-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 04/14] mm/ksm: add advance_scan_mm_slot() helper
  2026-09-15 15:12 [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Longlong Xia
                   ` (2 preceding siblings ...)
  2026-09-15 15:12 ` [PATCH 03/14] mm/ksm: use the correct format specifier for max_page_sharing Longlong Xia
@ 2026-09-15 15:12 ` Longlong Xia
  2026-09-15 15:12 ` [PATCH 05/14] mm/ksm: make remove_stable_node_chain() return bool Longlong Xia
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 15:12 UTC (permalink / raw)
  To: Andrew Morton, linux-mm
  Cc: Longlong Xia, David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

From: Longlong Xia <xialonglong@kylinos.cn>

Factor the four mm-slot cursor advances in scan_get_next_rmap_item()
and unmerge_and_remove_all_rmap_items() into a helper. Assert that
ksm_mmlist_lock is held.

No functional change intended.

Assisted-by: Zcode:GLM-5.3
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>

---
 mm/ksm.c | 34 ++++++++++++++++++++--------------
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index 18d037f571d3..aa33522627c7 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1119,6 +1119,22 @@ static inline void folio_set_stable_node(struct folio *folio,
 		   (void *)((unsigned long)stable_node | FOLIO_MAPPING_KSM));
 }
 
+/*
+ * Move the ksmd cursor onto the mm slot that follows @mm_slot in the
+ * ksm_mm_head list, and return the new cursor (@mm_slot may be
+ * &ksm_mm_head to (re)start from the first slot).  Called with
+ * ksm_mmlist_lock held.
+ */
+static struct ksm_mm_slot *advance_scan_mm_slot(struct ksm_mm_slot *mm_slot)
+{
+	struct mm_slot *slot;
+
+	lockdep_assert_held(&ksm_mmlist_lock);
+	slot = list_entry(mm_slot->slot.mm_node.next, struct mm_slot, mm_node);
+	ksm_scan.mm_slot = mm_slot_entry(slot, struct ksm_mm_slot, slot);
+	return ksm_scan.mm_slot;
+}
+
 #ifdef CONFIG_SYSFS
 /*
  * Only called through the sysfs control interface:
@@ -1215,15 +1231,12 @@ static int remove_all_stable_nodes(void)
 static int unmerge_and_remove_all_rmap_items(void)
 {
 	struct ksm_mm_slot *mm_slot;
-	struct mm_slot *slot;
 	struct mm_struct *mm;
 	struct vm_area_struct *vma;
 	int err = 0;
 
 	spin_lock(&ksm_mmlist_lock);
-	slot = list_entry(ksm_mm_head.slot.mm_node.next,
-			  struct mm_slot, mm_node);
-	ksm_scan.mm_slot = mm_slot_entry(slot, struct ksm_mm_slot, slot);
+	advance_scan_mm_slot(&ksm_mm_head);
 	spin_unlock(&ksm_mmlist_lock);
 
 	for (mm_slot = ksm_scan.mm_slot; mm_slot != &ksm_mm_head;
@@ -1253,9 +1266,7 @@ static int unmerge_and_remove_all_rmap_items(void)
 		mmap_read_unlock(mm);
 
 		spin_lock(&ksm_mmlist_lock);
-		slot = list_entry(mm_slot->slot.mm_node.next,
-				  struct mm_slot, mm_node);
-		ksm_scan.mm_slot = mm_slot_entry(slot, struct ksm_mm_slot, slot);
+		advance_scan_mm_slot(mm_slot);
 		if (ksm_test_exit(mm)) {
 			mm_slot_remove(&mm_slot->slot);
 			spin_unlock(&ksm_mmlist_lock);
@@ -2662,10 +2673,7 @@ static struct ksm_rmap_item *scan_get_next_rmap_item(struct page **page)
 			root_unstable_tree[nid] = RB_ROOT;
 
 		spin_lock(&ksm_mmlist_lock);
-		slot = list_entry(mm_slot->slot.mm_node.next,
-				  struct mm_slot, mm_node);
-		mm_slot = mm_slot_entry(slot, struct ksm_mm_slot, slot);
-		ksm_scan.mm_slot = mm_slot;
+		mm_slot = advance_scan_mm_slot(mm_slot);
 		spin_unlock(&ksm_mmlist_lock);
 		/*
 		 * Although we tested list_empty() above, a racing __ksm_exit
@@ -2758,9 +2766,7 @@ static struct ksm_rmap_item *scan_get_next_rmap_item(struct page **page)
 	remove_trailing_rmap_items(ksm_scan.rmap_list);
 
 	spin_lock(&ksm_mmlist_lock);
-	slot = list_entry(mm_slot->slot.mm_node.next,
-			  struct mm_slot, mm_node);
-	ksm_scan.mm_slot = mm_slot_entry(slot, struct ksm_mm_slot, slot);
+	advance_scan_mm_slot(mm_slot);
 	if (ksm_scan.address == 0) {
 		/*
 		 * We've completed a full scan of all vmas, holding mmap_lock
-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 05/14] mm/ksm: make remove_stable_node_chain() return bool
  2026-09-15 15:12 [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Longlong Xia
                   ` (3 preceding siblings ...)
  2026-09-15 15:12 ` [PATCH 04/14] mm/ksm: add advance_scan_mm_slot() helper Longlong Xia
@ 2026-09-15 15:12 ` Longlong Xia
  2026-09-15 15:12 ` [PATCH 06/14] mm/ksm: clear all slab cache pointers in ksm_slab_free() Longlong Xia
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 15:12 UTC (permalink / raw)
  To: Andrew Morton, linux-mm
  Cc: Longlong Xia, David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

From: Longlong Xia <xialonglong@kylinos.cn>

remove_stable_node_chain() only returns true or false. Use bool and
return remove_stable_node() directly in the non-chain case.

No functional change intended.

Assisted-by: Zcode:GLM-5.3
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>

---
 mm/ksm.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index aa33522627c7..99f0bd3a1ae3 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1177,18 +1177,15 @@ static int remove_stable_node(struct ksm_stable_node *stable_node)
 	return err;
 }
 
-static int remove_stable_node_chain(struct ksm_stable_node *stable_node,
-				    struct rb_root *root)
+static bool remove_stable_node_chain(struct ksm_stable_node *stable_node,
+				     struct rb_root *root)
 {
 	struct ksm_stable_node *dup;
 	struct hlist_node *hlist_safe;
 
 	if (!is_stable_node_chain(stable_node)) {
 		VM_BUG_ON(is_stable_node_dup(stable_node));
-		if (remove_stable_node(stable_node))
-			return true;
-		else
-			return false;
+		return remove_stable_node(stable_node);
 	}
 
 	hlist_for_each_entry_safe(dup, hlist_safe,
-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 06/14] mm/ksm: clear all slab cache pointers in ksm_slab_free()
  2026-09-15 15:12 [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Longlong Xia
                   ` (4 preceding siblings ...)
  2026-09-15 15:12 ` [PATCH 05/14] mm/ksm: make remove_stable_node_chain() return bool Longlong Xia
@ 2026-09-15 15:12 ` Longlong Xia
  2026-09-15 15:12 ` [PATCH 07/14] mm/ksm: reuse the zero page pointer for merge tracing Longlong Xia
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 15:12 UTC (permalink / raw)
  To: Andrew Morton, linux-mm
  Cc: Longlong Xia, David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

From: Longlong Xia <xialonglong@kylinos.cn>

ksm_slab_free() only clears mm_slot_cache after destroying the caches.
Clear rmap_item_cache and stable_node_cache as well.

No functional change intended.

Assisted-by: Zcode:GLM-5.3
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>

---
 mm/ksm.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/mm/ksm.c b/mm/ksm.c
index 99f0bd3a1ae3..78040ed99ccf 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -523,6 +523,8 @@ static void __init ksm_slab_free(void)
 	kmem_cache_destroy(stable_node_cache);
 	kmem_cache_destroy(rmap_item_cache);
 	mm_slot_cache = NULL;
+	stable_node_cache = NULL;
+	rmap_item_cache = NULL;
 }
 
 static __always_inline bool is_stable_node_chain(struct ksm_stable_node *chain)
-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 07/14] mm/ksm: reuse the zero page pointer for merge tracing
  2026-09-15 15:12 [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Longlong Xia
                   ` (5 preceding siblings ...)
  2026-09-15 15:12 ` [PATCH 06/14] mm/ksm: clear all slab cache pointers in ksm_slab_free() Longlong Xia
@ 2026-09-15 15:12 ` Longlong Xia
  2026-09-15 15:12 ` [PATCH 08/14] mm/ksm: document the two remove_rmap_item_from_tree() calls Longlong Xia
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 15:12 UTC (permalink / raw)
  To: Andrew Morton, linux-mm
  Cc: Longlong Xia, David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

From: Longlong Xia <xialonglong@kylinos.cn>

Cache ZERO_PAGE() in try_to_merge_with_zero_page() for use by both the
merge attempt and its tracepoint.

No functional change intended.

Assisted-by: Zcode:GLM-5.3
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>

---
 mm/ksm.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index 78040ed99ccf..7fc9dac5d67c 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1580,15 +1580,14 @@ static int try_to_merge_with_zero_page(struct ksm_rmap_item *rmap_item,
 	 */
 	if (ksm_use_zero_pages && (rmap_item->oldchecksum == zero_checksum)) {
 		struct vm_area_struct *vma;
+		struct page *zero_page = ZERO_PAGE(rmap_item->address);
 
 		mmap_read_lock(mm);
 		vma = find_mergeable_vma(mm, rmap_item->address);
 		if (vma) {
-			err = try_to_merge_one_page(vma, page,
-					ZERO_PAGE(rmap_item->address));
-			trace_ksm_merge_one_page(
-				page_to_pfn(ZERO_PAGE(rmap_item->address)),
-				rmap_item, mm, err);
+			err = try_to_merge_one_page(vma, page, zero_page);
+			trace_ksm_merge_one_page(page_to_pfn(zero_page),
+						 rmap_item, mm, err);
 		} else {
 			/*
 			 * If the vma is out of date, we do not need to
-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 08/14] mm/ksm: document the two remove_rmap_item_from_tree() calls
  2026-09-15 15:12 [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Longlong Xia
                   ` (6 preceding siblings ...)
  2026-09-15 15:12 ` [PATCH 07/14] mm/ksm: reuse the zero page pointer for merge tracing Longlong Xia
@ 2026-09-15 15:12 ` Longlong Xia
  2026-09-15 15:12 ` [PATCH 09/14] mm/ksm: move the no_vmas label out of the if block Longlong Xia
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 15:12 UTC (permalink / raw)
  To: Andrew Morton, linux-mm
  Cc: Longlong Xia, David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

From: Longlong Xia <xialonglong@kylinos.cn>

Explain why cmp_and_merge_page() needs both tree-removal calls:
non-KSM pages are detached before the early returns, while KSM pages
are handled after stable_tree_search().

Assisted-by: Zcode:GLM-5.3
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>

---
 mm/ksm.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/mm/ksm.c b/mm/ksm.c
index 7fc9dac5d67c..1733b23cfaa2 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -2313,6 +2313,10 @@ static void cmp_and_merge_page(struct page *page, struct ksm_rmap_item *rmap_ite
 		if (!is_page_sharing_candidate(stable_node))
 			max_page_sharing_bypass = true;
 	} else {
+		/*
+		 * Detach before the checksum and zero-page checks, which can
+		 * return without reaching the removal below.
+		 */
 		remove_rmap_item_from_tree(rmap_item);
 
 		/*
@@ -2338,6 +2342,10 @@ static void cmp_and_merge_page(struct page *page, struct ksm_rmap_item *rmap_ite
 		return;
 	}
 
+	/*
+	 * A KSM page can still have an old tree association here; non-KSM
+	 * pages were already detached before the checks above.
+	 */
 	remove_rmap_item_from_tree(rmap_item);
 
 	if (kfolio) {
-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 09/14] mm/ksm: move the no_vmas label out of the if block
  2026-09-15 15:12 [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Longlong Xia
                   ` (7 preceding siblings ...)
  2026-09-15 15:12 ` [PATCH 08/14] mm/ksm: document the two remove_rmap_item_from_tree() calls Longlong Xia
@ 2026-09-15 15:12 ` Longlong Xia
  2026-09-15 15:12 ` [PATCH 10/14] mm/ksm: extract ksm_begin_full_scan() from scan_get_next_rmap_item() Longlong Xia
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 15:12 UTC (permalink / raw)
  To: Andrew Morton, linux-mm
  Cc: Longlong Xia, David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

From: Longlong Xia <xialonglong@kylinos.cn>

Move no_vmas before the if statement to avoid jumping into its body.
Both goto paths have already found ksm_test_exit(mm) true, and mm_users
cannot rise from zero again, so rechecking the condition is safe.

No functional change intended.

Suggested-by: David Hildenbrand (Arm) <david@kernel.org>
Assisted-by: Zcode:GLM-5.3
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>

---
 mm/ksm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index 1733b23cfaa2..59887a2b4406 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -2760,8 +2760,8 @@ static struct ksm_rmap_item *scan_get_next_rmap_item(struct page **page)
 		}
 	}
 
-	if (ksm_test_exit(mm)) {
 no_vmas:
+	if (ksm_test_exit(mm)) {
 		ksm_scan.address = 0;
 		ksm_scan.rmap_list = &mm_slot->rmap_list;
 	}
-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 10/14] mm/ksm: extract ksm_begin_full_scan() from scan_get_next_rmap_item()
  2026-09-15 15:12 [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Longlong Xia
                   ` (8 preceding siblings ...)
  2026-09-15 15:12 ` [PATCH 09/14] mm/ksm: move the no_vmas label out of the if block Longlong Xia
@ 2026-09-15 15:12 ` Longlong Xia
  2026-09-15 15:23 ` [PATCH 11/14] mm/ksm: pass folios to replace_page() Longlong Xia
  2026-09-15 16:48 ` [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Matthew Wilcox
  11 siblings, 0 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 15:12 UTC (permalink / raw)
  To: Andrew Morton, linux-mm
  Cc: Longlong Xia, David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

From: Longlong Xia <xialonglong@kylinos.cn>

Extract the once-per-full-scan setup into ksm_begin_full_scan() to
shorten scan_get_next_rmap_item().

Move next_mm out of the if block. Reset address and rmap_list only when
starting a new mm, preserving both cursors when resuming a scan.

No functional change intended.

Assisted-by: Zcode:GLM-5.3
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>

---
 mm/ksm.c | 108 ++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 64 insertions(+), 44 deletions(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index 59887a2b4406..8884964d5a53 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1137,6 +1137,64 @@ static struct ksm_mm_slot *advance_scan_mm_slot(struct ksm_mm_slot *mm_slot)
 	return ksm_scan.mm_slot;
 }
 
+/*
+ * ksm_begin_full_scan - start a new full scan of all mergeable mms
+ *
+ * Called when the scanning cursor has come back around to ksm_mm_head:
+ * drain the per-cpu pagevecs, prune the migrate_nodes list and reset
+ * the unstable trees for the new pass, then move the cursor onto the
+ * first mm slot.  Returns the new cursor, which is &ksm_mm_head itself
+ * if a racing __ksm_exit removed the last mm from the list.
+ */
+static struct ksm_mm_slot *ksm_begin_full_scan(void)
+{
+	struct ksm_mm_slot *mm_slot;
+	int nid;
+
+	advisor_start_scan();
+	trace_ksm_start_scan(ksm_scan.seqnr, ksm_rmap_items);
+
+	/*
+	 * A number of pages can hang around indefinitely in per-cpu
+	 * LRU cache, raised page count preventing write_protect_page
+	 * from merging them.  Though it doesn't really matter much,
+	 * it is puzzling to see some stuck in pages_volatile until
+	 * other activity jostles them out, and they also prevented
+	 * LTP's KSM test from succeeding deterministically; so drain
+	 * them here (here rather than on entry to ksm_do_scan(),
+	 * so we don't IPI too often when pages_to_scan is set low).
+	 */
+	lru_add_drain_all();
+
+	/*
+	 * Whereas stale stable_nodes on the stable_tree itself
+	 * get pruned in the regular course of stable_tree_search(),
+	 * those moved out to the migrate_nodes list can accumulate:
+	 * so prune them once before each full scan.
+	 */
+	if (!ksm_merge_across_nodes) {
+		struct ksm_stable_node *stable_node, *next;
+		struct folio *folio;
+
+		list_for_each_entry_safe(stable_node, next,
+					 &migrate_nodes, list) {
+			folio = ksm_get_folio(stable_node,
+					      KSM_GET_FOLIO_NOLOCK);
+			if (folio)
+				folio_put(folio);
+			cond_resched();
+		}
+	}
+
+	for (nid = 0; nid < ksm_nr_node_ids; nid++)
+		root_unstable_tree[nid] = RB_ROOT;
+
+	spin_lock(&ksm_mmlist_lock);
+	mm_slot = advance_scan_mm_slot(&ksm_mm_head);
+	spin_unlock(&ksm_mmlist_lock);
+	return mm_slot;
+}
+
 #ifdef CONFIG_SYSFS
 /*
  * Only called through the sysfs control interface:
@@ -2633,65 +2691,24 @@ static struct ksm_rmap_item *scan_get_next_rmap_item(struct page **page)
 	struct vm_area_struct *vma;
 	struct ksm_rmap_item *rmap_item;
 	struct vma_iterator vmi;
-	int nid;
 
 	if (list_empty(&ksm_mm_head.slot.mm_node))
 		return NULL;
 
 	mm_slot = ksm_scan.mm_slot;
 	if (mm_slot == &ksm_mm_head) {
-		advisor_start_scan();
-		trace_ksm_start_scan(ksm_scan.seqnr, ksm_rmap_items);
-
-		/*
-		 * A number of pages can hang around indefinitely in per-cpu
-		 * LRU cache, raised page count preventing write_protect_page
-		 * from merging them.  Though it doesn't really matter much,
-		 * it is puzzling to see some stuck in pages_volatile until
-		 * other activity jostles them out, and they also prevented
-		 * LTP's KSM test from succeeding deterministically; so drain
-		 * them here (here rather than on entry to ksm_do_scan(),
-		 * so we don't IPI too often when pages_to_scan is set low).
-		 */
-		lru_add_drain_all();
-
-		/*
-		 * Whereas stale stable_nodes on the stable_tree itself
-		 * get pruned in the regular course of stable_tree_search(),
-		 * those moved out to the migrate_nodes list can accumulate:
-		 * so prune them once before each full scan.
-		 */
-		if (!ksm_merge_across_nodes) {
-			struct ksm_stable_node *stable_node, *next;
-			struct folio *folio;
-
-			list_for_each_entry_safe(stable_node, next,
-						 &migrate_nodes, list) {
-				folio = ksm_get_folio(stable_node,
-						      KSM_GET_FOLIO_NOLOCK);
-				if (folio)
-					folio_put(folio);
-				cond_resched();
-			}
-		}
-
-		for (nid = 0; nid < ksm_nr_node_ids; nid++)
-			root_unstable_tree[nid] = RB_ROOT;
-
-		spin_lock(&ksm_mmlist_lock);
-		mm_slot = advance_scan_mm_slot(mm_slot);
-		spin_unlock(&ksm_mmlist_lock);
+		mm_slot = ksm_begin_full_scan();
 		/*
 		 * Although we tested list_empty() above, a racing __ksm_exit
 		 * of the last mm on the list may have removed it since then.
 		 */
 		if (mm_slot == &ksm_mm_head)
 			return NULL;
-next_mm:
 		ksm_scan.address = 0;
 		ksm_scan.rmap_list = &mm_slot->rmap_list;
 	}
 
+next_mm:
 	slot = &mm_slot->slot;
 	mm = slot->mm;
 	vma_iter_init(&vmi, mm, ksm_scan.address);
@@ -2811,8 +2828,11 @@ static struct ksm_rmap_item *scan_get_next_rmap_item(struct page **page)
 
 	/* Repeat until we've completed scanning the whole list */
 	mm_slot = ksm_scan.mm_slot;
-	if (mm_slot != &ksm_mm_head)
+	if (mm_slot != &ksm_mm_head) {
+		ksm_scan.address = 0;
+		ksm_scan.rmap_list = &mm_slot->rmap_list;
 		goto next_mm;
+	}
 
 	advisor_stop_scan();
 
-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 11/14] mm/ksm: pass folios to replace_page()
  2026-09-15 15:12 [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Longlong Xia
                   ` (9 preceding siblings ...)
  2026-09-15 15:12 ` [PATCH 10/14] mm/ksm: extract ksm_begin_full_scan() from scan_get_next_rmap_item() Longlong Xia
@ 2026-09-15 15:23 ` Longlong Xia
  2026-09-15 15:23   ` [PATCH 12/14] mm/ksm: take the ksm folio in try_to_merge_one_page() Longlong Xia
                     ` (2 more replies)
  2026-09-15 16:48 ` [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Matthew Wilcox
  11 siblings, 3 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 15:23 UTC (permalink / raw)
  To: Andrew Morton, linux-mm
  Cc: Longlong Xia, David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

From: Longlong Xia <xialonglong@kylinos.cn>

Pass the source and target folios directly to replace_page(). Any
large source folio has already been split; KSM and zero-page targets
are order-0.

No functional change intended.

Assisted-by: Zcode:GLM-5.3
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>

---
 mm/ksm.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index 8884964d5a53..4a4347e9ce39 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1453,18 +1453,18 @@ static int write_protect_page(struct vm_area_struct *vma, struct folio *folio,
 /**
  * replace_page - replace page in vma by new ksm page
  * @vma:      vma that holds the pte pointing to page
- * @page:     the page we are replacing by kpage
- * @kpage:    the ksm page we replace page by
+ * @folio:    the folio we are replacing by kfolio
+ * @kfolio:   the ksm folio we replace folio by
  * @orig_pte: the original value of the pte
  *
  * Returns 0 on success, -EFAULT on failure.
  */
-static int replace_page(struct vm_area_struct *vma, struct page *page,
-			struct page *kpage, pte_t orig_pte)
+static int replace_page(struct vm_area_struct *vma, struct folio *folio,
+			struct folio *kfolio, pte_t orig_pte)
 {
-	struct folio *kfolio = page_folio(kpage);
+	struct page *page = folio_page(folio, 0);
+	struct page *kpage = folio_page(kfolio, 0);
 	struct mm_struct *mm = vma->vm_mm;
-	struct folio *folio = page_folio(page);
 	pmd_t *pmd;
 	pmd_t pmde;
 	pte_t *ptep;
@@ -1613,7 +1613,8 @@ static int try_to_merge_one_page(struct vm_area_struct *vma,
 				folio_mark_dirty(folio);
 			err = 0;
 		} else if (pages_identical(page, kpage))
-			err = replace_page(vma, page, kpage, orig_pte);
+			err = replace_page(vma, folio, page_folio(kpage),
+					   orig_pte);
 	}
 
 out_unlock:
-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 12/14] mm/ksm: take the ksm folio in try_to_merge_one_page()
  2026-09-15 15:23 ` [PATCH 11/14] mm/ksm: pass folios to replace_page() Longlong Xia
@ 2026-09-15 15:23   ` Longlong Xia
  2026-09-15 15:23   ` [PATCH 13/14] mm/ksm: take the ksm folio in try_to_merge_with_ksm_page() Longlong Xia
  2026-09-15 15:23   ` [PATCH 14/14] mm/ksm: update merge helper comments for folios Longlong Xia
  2 siblings, 0 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 15:23 UTC (permalink / raw)
  To: Andrew Morton, linux-mm
  Cc: Longlong Xia, David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

From: Longlong Xia <xialonglong@kylinos.cn>

Pass the order-0 KSM or zero-page target as a folio, preserving NULL
for the initial KSM upgrade. Keep the source as struct page because
it may be a tail page of a large folio that is split before merging.

No functional change intended.

Assisted-by: Zcode:GLM-5.3
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>

---
 mm/ksm.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index 4a4347e9ce39..10fcae7132b1 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1556,20 +1556,20 @@ static int replace_page(struct vm_area_struct *vma, struct folio *folio,
 /*
  * try_to_merge_one_page - take two pages and merge them into one
  * @vma: the vma that holds the pte pointing to page
- * @page: the PageAnon page that we want to replace with kpage
- * @kpage: the KSM page that we want to map instead of page,
- *         or NULL the first time when we want to use page as kpage.
+ * @page: the PageAnon page that we want to replace with kfolio
+ * @kfolio: the ksm folio that we want to map instead of page,
+ *          or NULL the first time when we want to use page as ksm page.
  *
  * This function returns 0 if the pages were merged, -EFAULT otherwise.
  */
 static int try_to_merge_one_page(struct vm_area_struct *vma,
-				 struct page *page, struct page *kpage)
+				 struct page *page, struct folio *kfolio)
 {
 	struct folio *folio = page_folio(page);
 	pte_t orig_pte = __pte(0);
 	int err = -EFAULT;
 
-	if (page == kpage)			/* ksm page forked */
+	if (kfolio && page == &kfolio->page)	/* ksm page forked */
 		return 0;
 
 	if (!folio_test_anon(folio))
@@ -1597,7 +1597,7 @@ static int try_to_merge_one_page(struct vm_area_struct *vma,
 	 * case, we need to lock and check page_count is not raised.
 	 */
 	if (write_protect_page(vma, folio, &orig_pte) == 0) {
-		if (!kpage) {
+		if (!kfolio) {
 			/*
 			 * While we hold folio lock, upgrade folio from
 			 * anon to a NULL stable_node with the KSM flag set:
@@ -1612,9 +1612,8 @@ static int try_to_merge_one_page(struct vm_area_struct *vma,
 			if (!folio_test_dirty(folio))
 				folio_mark_dirty(folio);
 			err = 0;
-		} else if (pages_identical(page, kpage))
-			err = replace_page(vma, folio, page_folio(kpage),
-					   orig_pte);
+		} else if (pages_identical(page, &kfolio->page))
+			err = replace_page(vma, folio, kfolio, orig_pte);
 	}
 
 out_unlock:
@@ -1644,7 +1643,8 @@ static int try_to_merge_with_zero_page(struct ksm_rmap_item *rmap_item,
 		mmap_read_lock(mm);
 		vma = find_mergeable_vma(mm, rmap_item->address);
 		if (vma) {
-			err = try_to_merge_one_page(vma, page, zero_page);
+			err = try_to_merge_one_page(vma, page,
+						     page_folio(zero_page));
 			trace_ksm_merge_one_page(page_to_pfn(zero_page),
 						 rmap_item, mm, err);
 		} else {
@@ -1678,7 +1678,7 @@ static int try_to_merge_with_ksm_page(struct ksm_rmap_item *rmap_item,
 	if (!vma)
 		goto out;
 
-	err = try_to_merge_one_page(vma, page, kpage);
+	err = try_to_merge_one_page(vma, page, page_folio(kpage));
 	if (err)
 		goto out;
 
-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 13/14] mm/ksm: take the ksm folio in try_to_merge_with_ksm_page()
  2026-09-15 15:23 ` [PATCH 11/14] mm/ksm: pass folios to replace_page() Longlong Xia
  2026-09-15 15:23   ` [PATCH 12/14] mm/ksm: take the ksm folio in try_to_merge_one_page() Longlong Xia
@ 2026-09-15 15:23   ` Longlong Xia
  2026-09-15 15:23   ` [PATCH 14/14] mm/ksm: update merge helper comments for folios Longlong Xia
  2 siblings, 0 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 15:23 UTC (permalink / raw)
  To: Andrew Morton, linux-mm
  Cc: Longlong Xia, David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

From: Longlong Xia <xialonglong@kylinos.cn>

Pass the KSM target as a folio and rename the helper accordingly.
Preserve NULL for the initial upgrade of the source page to KSM.

No functional change intended.

Assisted-by: Zcode:GLM-5.3
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>

---
 mm/ksm.c | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index 10fcae7132b1..937d1ffea4cc 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1661,13 +1661,13 @@ static int try_to_merge_with_zero_page(struct ksm_rmap_item *rmap_item,
 }
 
 /*
- * try_to_merge_with_ksm_page - like try_to_merge_two_pages,
- * but no new kernel page is allocated: kpage must already be a ksm page.
+ * try_to_merge_with_ksm_folio - like try_to_merge_two_pages,
+ * but no new kernel page is allocated: kfolio must already be a ksm page.
  *
  * This function returns 0 if the pages were merged, -EFAULT otherwise.
  */
-static int try_to_merge_with_ksm_page(struct ksm_rmap_item *rmap_item,
-				      struct page *page, struct page *kpage)
+static int try_to_merge_with_ksm_folio(struct ksm_rmap_item *rmap_item,
+				      struct page *page, struct folio *kfolio)
 {
 	struct mm_struct *mm = rmap_item->mm;
 	struct vm_area_struct *vma;
@@ -1678,7 +1678,7 @@ static int try_to_merge_with_ksm_page(struct ksm_rmap_item *rmap_item,
 	if (!vma)
 		goto out;
 
-	err = try_to_merge_one_page(vma, page, page_folio(kpage));
+	err = try_to_merge_one_page(vma, page, kfolio);
 	if (err)
 		goto out;
 
@@ -1697,8 +1697,9 @@ static int try_to_merge_with_ksm_page(struct ksm_rmap_item *rmap_item,
 	get_anon_vma(vma->anon_vma);
 out:
 	mmap_read_unlock(mm);
-	trace_ksm_merge_with_ksm_page(kpage, page_to_pfn(kpage ? kpage : page),
-				rmap_item, mm, err);
+	trace_ksm_merge_with_ksm_page(kfolio ? &kfolio->page : NULL,
+				      kfolio ? folio_pfn(kfolio) : page_to_pfn(page),
+				      rmap_item, mm, err);
 	return err;
 }
 
@@ -1710,7 +1711,7 @@ static int try_to_merge_with_ksm_page(struct ksm_rmap_item *rmap_item,
  * pages into one ksm page, NULL otherwise.
  *
  * Note that this function upgrades page to ksm page: if one of the pages
- * is already a ksm page, try_to_merge_with_ksm_page should be used.
+ * is already a ksm page, try_to_merge_with_ksm_folio should be used.
  */
 static struct folio *try_to_merge_two_pages(struct ksm_rmap_item *rmap_item,
 					   struct page *page,
@@ -1719,10 +1720,10 @@ static struct folio *try_to_merge_two_pages(struct ksm_rmap_item *rmap_item,
 {
 	int err;
 
-	err = try_to_merge_with_ksm_page(rmap_item, page, NULL);
+	err = try_to_merge_with_ksm_folio(rmap_item, page, NULL);
 	if (!err) {
-		err = try_to_merge_with_ksm_page(tree_rmap_item,
-							tree_page, page);
+		err = try_to_merge_with_ksm_folio(tree_rmap_item,
+						 tree_page, page_folio(page));
 		/*
 		 * If that fails, we have a ksm page with only one pte
 		 * pointing to it: so break it.
@@ -2411,7 +2412,7 @@ static void cmp_and_merge_page(struct page *page, struct ksm_rmap_item *rmap_ite
 		if (kfolio == ERR_PTR(-EBUSY))
 			return;
 
-		err = try_to_merge_with_ksm_page(rmap_item, page, &kfolio->page);
+		err = try_to_merge_with_ksm_folio(rmap_item, page, kfolio);
 		if (!err) {
 			/*
 			 * The page was successfully merged:
-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 14/14] mm/ksm: update merge helper comments for folios
  2026-09-15 15:23 ` [PATCH 11/14] mm/ksm: pass folios to replace_page() Longlong Xia
  2026-09-15 15:23   ` [PATCH 12/14] mm/ksm: take the ksm folio in try_to_merge_one_page() Longlong Xia
  2026-09-15 15:23   ` [PATCH 13/14] mm/ksm: take the ksm folio in try_to_merge_with_ksm_page() Longlong Xia
@ 2026-09-15 15:23   ` Longlong Xia
  2 siblings, 0 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 15:23 UTC (permalink / raw)
  To: Andrew Morton, linux-mm
  Cc: Longlong Xia, David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

From: Longlong Xia <xialonglong@kylinos.cn>

Update stale page names and the put_page() reference in the folio
helpers' comments. Correct stable_tree_search()'s return-value
description to match its folio and error-pointer results.

Assisted-by: Zcode:GLM-5.3
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>

---
 mm/ksm.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index 937d1ffea4cc..8deb1abd64c2 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1707,8 +1707,8 @@ static int try_to_merge_with_ksm_folio(struct ksm_rmap_item *rmap_item,
  * try_to_merge_two_pages - take two identical pages and prepare them
  * to be merged into one page.
  *
- * This function returns the kpage if we successfully merged two identical
- * pages into one ksm page, NULL otherwise.
+ * This function returns the KSM folio if we successfully merged two
+ * identical pages into one, NULL otherwise.
  *
  * Note that this function upgrades page to ksm page: if one of the pages
  * is already a ksm page, try_to_merge_with_ksm_folio should be used.
@@ -1797,7 +1797,7 @@ static struct folio *stable_node_dup(struct ksm_stable_node **_stable_node_dup,
 			found = dup;
 			found_rmap_hlist_len = found->rmap_hlist_len;
 			tree_folio = folio;
-			/* skip put_page for found candidate */
+			/* Skip folio_put() for the selected candidate. */
 			if (!prune_stale_stable_nodes &&
 			    is_page_sharing_candidate(found))
 				break;
@@ -1870,13 +1870,13 @@ static struct folio *stable_node_dup(struct ksm_stable_node **_stable_node_dup,
 
 /*
  * Like for ksm_get_folio, this function can free the *_stable_node and
- * *_stable_node_dup if the returned tree_page is NULL.
+ * *_stable_node_dup if the returned folio is NULL.
  *
  * It can also free and overwrite *_stable_node with the found
  * stable_node_dup if the chain is collapsed (in which case
  * *_stable_node will be equal to *_stable_node_dup like if the chain
- * never existed). It's up to the caller to verify tree_page is not
- * NULL before dereferencing *_stable_node or *_stable_node_dup.
+ * never existed). It's up to the caller to verify the returned folio is
+ * not NULL before dereferencing *_stable_node or *_stable_node_dup.
  *
  * *_stable_node_dup is really a second output parameter of this
  * function and will be overwritten in all cases, the caller doesn't
@@ -1917,8 +1917,8 @@ static __always_inline struct folio *chain(struct ksm_stable_node **s_n_d,
  * This function checks if there is a page inside the stable tree
  * with identical content to the page that we are scanning right now.
  *
- * This function returns the stable tree node of identical content if found,
- * -EBUSY if the stable node's page is being migrated, NULL otherwise.
+ * This function returns a referenced folio with identical content if found,
+ * ERR_PTR(-EBUSY) if the matching folio could not be locked, NULL otherwise.
  */
 static struct folio *stable_tree_search(struct page *page)
 {
@@ -2005,11 +2005,11 @@ static struct folio *stable_tree_search(struct page *page)
 			}
 
 			/*
-			 * Lock and unlock the stable_node's page (which
-			 * might already have been migrated) so that page
-			 * migration is sure to notice its raised count.
+			 * Lock and unlock the stable_node's folio (which
+			 * might already have been migrated) so that
+			 * folio migration is sure to notice its raised count.
 			 * It would be more elegant to return stable_node
-			 * than kpage, but that involves more changes.
+			 * than tree_folio, but that involves more changes.
 			 */
 			tree_folio = ksm_get_folio(stable_node_dup,
 						   KSM_GET_FOLIO_TRYLOCK);
-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion
  2026-09-15 15:12 [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Longlong Xia
                   ` (10 preceding siblings ...)
  2026-09-15 15:23 ` [PATCH 11/14] mm/ksm: pass folios to replace_page() Longlong Xia
@ 2026-09-15 16:48 ` Matthew Wilcox
  2026-09-15 22:25   ` Longlong Xia
  11 siblings, 1 reply; 19+ messages in thread
From: Matthew Wilcox @ 2026-09-15 16:48 UTC (permalink / raw)
  To: Longlong Xia
  Cc: Andrew Morton, linux-mm, Longlong Xia, David Hildenbrand, Xu Xin,
	Chengming Zhou, linux-kernel

On Tue, Sep 15, 2026 at 11:12:14PM +0800, Longlong Xia wrote:
> From: Longlong Xia <xialonglong@kylinos.cn>
> 
> Clean up KSM's scan helpers, advisor naming and sysfs formatting, then
> pass folios through the merge path and update the related comments.

I'm not an expert in KSM, but it's not clear to me whether KSM should be
working in folios or pages.  That's why I stopped where I did, in the
hope that somebody with expertise would step in.  You have 17 commits
to Linux, one in KSM, so I'm not convinced you have relevant expertise.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion
  2026-09-15 16:48 ` [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Matthew Wilcox
@ 2026-09-15 22:25   ` Longlong Xia
  2026-09-16  6:37     ` David Hildenbrand (Arm)
  0 siblings, 1 reply; 19+ messages in thread
From: Longlong Xia @ 2026-09-15 22:25 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: Longlong Xia, Andrew Morton, linux-mm, Longlong Xia,
	David Hildenbrand, Xu Xin, Chengming Zhou, linux-kernel

Thanks for the review. You are right that I did not justify the
page/folio boundary clearly enough.

Patches 11-13 only avoid converting the target page back to a folio and
provide no functional or performance benefit by themselves.

I will separate the independent cleanups and drop or rework 11-13 after
getting guidance from the KSM maintainers. I also found a NULL/bisectability
issue in v1 patch 12, which I will fix before any follow-up.

Thanks,
Longlong


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion
  2026-09-15 22:25   ` Longlong Xia
@ 2026-09-16  6:37     ` David Hildenbrand (Arm)
  2026-09-16  8:46       ` Longlong Xia
  0 siblings, 1 reply; 19+ messages in thread
From: David Hildenbrand (Arm) @ 2026-09-16  6:37 UTC (permalink / raw)
  To: Longlong Xia, Matthew Wilcox
  Cc: Andrew Morton, linux-mm, Longlong Xia, Xu Xin, Chengming Zhou,
	linux-kernel

On 9/16/26 00:25, Longlong Xia wrote:
> Thanks for the review. You are right that I did not justify the
> page/folio boundary clearly enough.
> 
> Patches 11-13 only avoid converting the target page back to a folio and
> provide no functional or performance benefit by themselves.
> 
> I will separate the independent cleanups and drop or rework 11-13 after
> getting guidance from the KSM maintainers. I also found a NULL/bisectability
> issue in v1 patch 12, which I will fix before any follow-up.

In general: once we have a ksm folio (folio_test_ksm()), it can only be a small
folio and we can operate on the folio only.

Until that point, we really need the page, because we might be dealing with a
page in a large folio. Sure, we can carry a folio+page pair to reduce repeated
folio lookups, but be aware that we have to re-lookup the folio and take care of
references whenever we call into something that could end up splitting the
folio. So we have to be a bit careful around that.

-- 
Cheers,

David

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion
  2026-09-16  6:37     ` David Hildenbrand (Arm)
@ 2026-09-16  8:46       ` Longlong Xia
  0 siblings, 0 replies; 19+ messages in thread
From: Longlong Xia @ 2026-09-16  8:46 UTC (permalink / raw)
  To: David Hildenbrand (Arm), Matthew Wilcox
  Cc: Andrew Morton, linux-mm, Longlong Xia, Xu Xin, Chengming Zhou,
	linux-kernel


On 2026/9/16 14:37, David Hildenbrand (Arm) wrote:
> On 9/16/26 00:25, Longlong Xia wrote:
>> Thanks for the review. You are right that I did not justify the
>> page/folio boundary clearly enough.
>>
>> Patches 11-13 only avoid converting the target page back to a folio and
>> provide no functional or performance benefit by themselves.
>>
>> I will separate the independent cleanups and drop or rework 11-13 after
>> getting guidance from the KSM maintainers. I also found a NULL/bisectability
>> issue in v1 patch 12, which I will fix before any follow-up.
> In general: once we have a ksm folio (folio_test_ksm()), it can only be a small
> folio and we can operate on the folio only.
>
> Until that point, we really need the page, because we might be dealing with a
> page in a large folio. Sure, we can carry a folio+page pair to reduce repeated
> folio lookups, but be aware that we have to re-lookup the folio and take care of
> references whenever we call into something that could end up splitting the
> folio. So we have to be a bit careful around that.

Hi David,

Thanks for the clarification. I understand that the page must be 
retained until we confirm it is a KSM folio.

I will drop patches 11–13 from this series and send a new version 
without them. Any reworked folio conversion patches will be sent 
separately later.

Best regards,
Longlong


>


^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2026-09-16  8:47 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-15 15:12 [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Longlong Xia
2026-09-15 15:12 ` [PATCH 01/14] mm/ksm: constify ksm_next_page_ops Longlong Xia
2026-09-15 15:12 ` [PATCH 02/14] mm/ksm: rename advisor_ctx to ksm_advisor_ctx Longlong Xia
2026-09-15 15:12 ` [PATCH 03/14] mm/ksm: use the correct format specifier for max_page_sharing Longlong Xia
2026-09-15 15:12 ` [PATCH 04/14] mm/ksm: add advance_scan_mm_slot() helper Longlong Xia
2026-09-15 15:12 ` [PATCH 05/14] mm/ksm: make remove_stable_node_chain() return bool Longlong Xia
2026-09-15 15:12 ` [PATCH 06/14] mm/ksm: clear all slab cache pointers in ksm_slab_free() Longlong Xia
2026-09-15 15:12 ` [PATCH 07/14] mm/ksm: reuse the zero page pointer for merge tracing Longlong Xia
2026-09-15 15:12 ` [PATCH 08/14] mm/ksm: document the two remove_rmap_item_from_tree() calls Longlong Xia
2026-09-15 15:12 ` [PATCH 09/14] mm/ksm: move the no_vmas label out of the if block Longlong Xia
2026-09-15 15:12 ` [PATCH 10/14] mm/ksm: extract ksm_begin_full_scan() from scan_get_next_rmap_item() Longlong Xia
2026-09-15 15:23 ` [PATCH 11/14] mm/ksm: pass folios to replace_page() Longlong Xia
2026-09-15 15:23   ` [PATCH 12/14] mm/ksm: take the ksm folio in try_to_merge_one_page() Longlong Xia
2026-09-15 15:23   ` [PATCH 13/14] mm/ksm: take the ksm folio in try_to_merge_with_ksm_page() Longlong Xia
2026-09-15 15:23   ` [PATCH 14/14] mm/ksm: update merge helper comments for folios Longlong Xia
2026-09-15 16:48 ` [PATCH 00/14] mm/ksm: merge-path cleanups and folio conversion Matthew Wilcox
2026-09-15 22:25   ` Longlong Xia
2026-09-16  6:37     ` David Hildenbrand (Arm)
2026-09-16  8:46       ` Longlong Xia

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®