* [PATCH v4 1/5] mm/ksm: align smart scan skips with the scan number
2026-11-09 1:22 [PATCH v4 0/5] mm/ksm: keep smart scan from losing duplicate pages Qiliang Yuan
@ 2026-11-09 1:22 ` Qiliang Yuan
2026-11-09 1:22 ` [PATCH v4 2/5] docs/mm: ksm: describe how smart scan picks the scans to skip Qiliang Yuan
` (3 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Qiliang Yuan @ 2026-11-09 1:22 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Xu Xin, Chengming Zhou,
Stefan Roesch, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Shuah Khan,
Jonathan Corbet, Shuah Khan, Randy Dunlap
Cc: linux-mm, linux-kernel, linux-kselftest, linux-doc, Qiliang Yuan, stable
Smart scan skips pages that KSM has failed to de-duplicate for a while.
Once a page is three scans old, its rmap_item counts down its own number
of scans to skip, 1, 2, 4 and then 8 as it ages, so an old page is looked
at every ninth scan.
The unstable tree is rebuilt on every scan, so two identical pages that
are not in the stable tree yet can only be merged in a scan that looks
at both. Each countdown runs from when its own page became mergeable, so
two pages that became mergeable at different times end up on different
phases and, once both are old, may never be looked at in the same scan
again. They then stay unmerged for as long as they live. The pairs below
are counted by making a page mergeable, waiting for 0 to 20 full scans
before doing the same with an identical page, 20 times for each wait,
and checking the pair after another 64 full scans, on two boots per
kernel.
Pick the skipped scans by the global scan number instead, with periods
of 2, 4 and 8 scans. The periods being powers of two, every old page is
looked at on each scan that is a multiple of 8, whatever its age, so any
two pages meet at least every eighth scan. The longest period goes from
nine scans to eight, so ksmd looks at more of the pages that never
merge. The rest of the table is measured on 64M of such pages, median of
five runs of 256 scans on each of three boots per kernel, CPU time from
schedstat:
before after after/before
pairs merged (of 420) 361 420 116%
334 420 126%
pages looked at per scan 1792 2048 114%
ksmd CPU time per scan 6.30 ms 6.88 ms 109%
6.40 ms 6.96 ms 109%
6.15 ms 6.88 ms 112%
Fixes: 5e924ff54d08 ("mm/ksm: add "smart" page scanning mode")
Cc: stable@vger.kernel.org
Signed-off-by: Qiliang Yuan <odys.yuan@gmail.com>
Tested-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Xu Xin <xu.xin@linux.dev>
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
---
mm/ksm.c | 24 ++++++++++--------------
1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/mm/ksm.c b/mm/ksm.c
index d24b129932bf7..3053b438e9c10 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -197,7 +197,6 @@ struct ksm_stable_node {
* @head: pointer to stable_node heading this list in the stable tree
* @hlist: link into hlist of rmap_items hanging off that stable_node
* @age: number of scan iterations since creation (unstable node)
- * @remaining_skips: how many scans to skip (unstable node)
* @linear_page_index: the original page's index before merged by KSM (stable node)
*/
struct ksm_rmap_item {
@@ -214,7 +213,6 @@ struct ksm_rmap_item {
struct {
unsigned int oldchecksum;
rmap_age_t age;
- rmap_age_t remaining_skips;
}; /* when unstable */
unsigned long linear_page_index; /* for reverse mapping, when stable */
};
@@ -2457,16 +2455,14 @@ static struct ksm_rmap_item *get_next_rmap_item(struct ksm_mm_slot *mm_slot,
}
/*
- * Calculate skip age for the ksm page age. The age determines how often
- * de-duplicating has already been tried unsuccessfully. If the age is
- * smaller, the scanning of this page is skipped for less scans.
+ * Calculate how often a page of the given ksm page age is scanned. The age
+ * determines how often de-duplicating has already been tried
+ * unsuccessfully. The older the page, the fewer scans look at it.
*
* @age: rmap_item age of page
*/
-static unsigned int skip_age(rmap_age_t age)
+static unsigned int scan_period(rmap_age_t age)
{
- if (age <= 3)
- return 1;
if (age <= 5)
return 2;
if (age <= 8)
@@ -2516,17 +2512,17 @@ static bool should_skip_rmap_item(struct folio *folio,
return false;
/*
- * Are we still allowed to skip? If not, then don't skip it
- * and determine how much more often we are allowed to skip next.
+ * The unstable tree is rebuilt on every scan, so two identical pages
+ * can only be merged if both are looked at in the same scan. Pick the
+ * scans by the global scan number rather than per page: the periods
+ * are powers of two, so pages of any age meet on every scan that is a
+ * multiple of the longest one.
*/
- if (!rmap_item->remaining_skips) {
- rmap_item->remaining_skips = skip_age(age);
+ if (!(ksm_scan.seqnr & (scan_period(age) - 1)))
return false;
- }
/* Skip this page */
ksm_pages_skipped++;
- rmap_item->remaining_skips--;
remove_rmap_item_from_tree(rmap_item);
return true;
}
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v4 2/5] docs/mm: ksm: describe how smart scan picks the scans to skip
2026-11-09 1:22 [PATCH v4 0/5] mm/ksm: keep smart scan from losing duplicate pages Qiliang Yuan
2026-11-09 1:22 ` [PATCH v4 1/5] mm/ksm: align smart scan skips with the scan number Qiliang Yuan
@ 2026-11-09 1:22 ` Qiliang Yuan
2026-11-09 2:12 ` Xu Xin (vivo)
2026-11-09 1:22 ` [PATCH v4 3/5] selftests/mm: fail KSM helpers on short reads and writes Qiliang Yuan
` (2 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: Qiliang Yuan @ 2026-11-09 1:22 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Xu Xin, Chengming Zhou,
Stefan Roesch, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Shuah Khan,
Jonathan Corbet, Shuah Khan, Randy Dunlap
Cc: linux-mm, linux-kernel, linux-kselftest, linux-doc, Qiliang Yuan
Documentation/mm/ksm.rst covers the stable tree and its reverse mapping,
and Documentation/admin-guide/mm/ksm.rst only says that smart scan skips
pages KSM has failed to merge before.
Neither says how often an unmerged page is looked at, or that the scans
are picked by the global scan number so that identical pages of
different ages still meet in some scan, which merging through the
unstable tree depends on.
Add a section on smart scan that describes both.
Signed-off-by: Qiliang Yuan <odys.yuan@gmail.com>
Tested-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
---
Documentation/mm/ksm.rst | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/Documentation/mm/ksm.rst b/Documentation/mm/ksm.rst
index 5a80573162def..f954d221e8017 100644
--- a/Documentation/mm/ksm.rst
+++ b/Documentation/mm/ksm.rst
@@ -75,6 +75,22 @@ The whole list of stable_node "dups" linked in the stable_node
The frequency of such scans is defined by
``stable_node_chains_prune_millisecs`` sysfs tunable.
+Smart scan
+----------
+With ``smart_scan`` enabled, ksmd skips pages that it has already tried
+to merge without success. The ``age`` of a page's ksm_rmap_item counts
+the scans that went by while the page stayed unmerged. A page younger
+than three scans is looked at on every scan; after that it is looked at
+every second scan up to an age of five, every fourth scan up to an age
+of eight, and every eighth scan from then on.
+
+The scans that look at a page are picked by the global scan number
+``ksm_scan.seqnr``, not counted per page. The unstable tree is rebuilt
+on every scan, so two identical pages can only be merged in a scan that
+looks at both. As the periods are powers of two, every page is looked
+at on each scan whose number is a multiple of eight, so two identical
+pages meet at least every eighth scan whatever their ages.
+
Reference
---------
.. kernel-doc:: mm/ksm.c
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v4 2/5] docs/mm: ksm: describe how smart scan picks the scans to skip
2026-11-09 1:22 ` [PATCH v4 2/5] docs/mm: ksm: describe how smart scan picks the scans to skip Qiliang Yuan
@ 2026-11-09 2:12 ` Xu Xin (vivo)
0 siblings, 0 replies; 10+ messages in thread
From: Xu Xin (vivo) @ 2026-11-09 2:12 UTC (permalink / raw)
To: Qiliang Yuan
Cc: Andrew Morton, David Hildenbrand, Chengming Zhou, Stefan Roesch,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Shuah Khan, Jonathan Corbet,
Shuah Khan, Randy Dunlap, linux-mm, linux-kernel,
linux-kselftest, linux-doc
On Sun, Nov 08, 2026 at 08:22:51PM -0500, Qiliang Yuan wrote:
> Documentation/mm/ksm.rst covers the stable tree and its reverse mapping,
> and Documentation/admin-guide/mm/ksm.rst only says that smart scan skips
> pages KSM has failed to merge before.
>
> Neither says how often an unmerged page is looked at, or that the scans
> are picked by the global scan number so that identical pages of
> different ages still meet in some scan, which merging through the
> unstable tree depends on.
>
> Add a section on smart scan that describes both.
>
> Signed-off-by: Qiliang Yuan <odys.yuan@gmail.com>
> Tested-by: Andrew Morton <akpm@linux-foundation.org>
> Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
> ---
> Documentation/mm/ksm.rst | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
Reviewed-by: Xu Xin (vivo) <xu.xin@linux.dev>
>
> diff --git a/Documentation/mm/ksm.rst b/Documentation/mm/ksm.rst
> index 5a80573162def..f954d221e8017 100644
> --- a/Documentation/mm/ksm.rst
> +++ b/Documentation/mm/ksm.rst
> @@ -75,6 +75,22 @@ The whole list of stable_node "dups" linked in the stable_node
> The frequency of such scans is defined by
> ``stable_node_chains_prune_millisecs`` sysfs tunable.
>
> +Smart scan
> +----------
> +With ``smart_scan`` enabled, ksmd skips pages that it has already tried
> +to merge without success. The ``age`` of a page's ksm_rmap_item counts
> +the scans that went by while the page stayed unmerged. A page younger
> +than three scans is looked at on every scan; after that it is looked at
> +every second scan up to an age of five, every fourth scan up to an age
> +of eight, and every eighth scan from then on.
> +
> +The scans that look at a page are picked by the global scan number
> +``ksm_scan.seqnr``, not counted per page. The unstable tree is rebuilt
> +on every scan, so two identical pages can only be merged in a scan that
> +looks at both. As the periods are powers of two, every page is looked
> +at on each scan whose number is a multiple of eight, so two identical
> +pages meet at least every eighth scan whatever their ages.
> +
> Reference
> ---------
> .. kernel-doc:: mm/ksm.c
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 3/5] selftests/mm: fail KSM helpers on short reads and writes
2026-11-09 1:22 [PATCH v4 0/5] mm/ksm: keep smart scan from losing duplicate pages Qiliang Yuan
2026-11-09 1:22 ` [PATCH v4 1/5] mm/ksm: align smart scan skips with the scan number Qiliang Yuan
2026-11-09 1:22 ` [PATCH v4 2/5] docs/mm: ksm: describe how smart scan picks the scans to skip Qiliang Yuan
@ 2026-11-09 1:22 ` Qiliang Yuan
2026-11-09 2:29 ` Xu Xin (vivo)
2026-11-09 1:22 ` [PATCH v4 4/5] selftests/mm: move waiting for KSM full scans into a helper Qiliang Yuan
2026-11-09 1:22 ` [PATCH v4 5/5] selftests/mm: cover merging KSM pages aged by smart scan Qiliang Yuan
4 siblings, 1 reply; 10+ messages in thread
From: Qiliang Yuan @ 2026-11-09 1:22 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Xu Xin, Chengming Zhou,
Stefan Roesch, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Shuah Khan,
Jonathan Corbet, Shuah Khan, Randy Dunlap
Cc: linux-mm, linux-kernel, linux-kselftest, linux-doc, Qiliang Yuan
The KSM helpers in vm_util read and write KSM's sysfs and procfs files
with a single pread() or write(), and return -errno when the call does
not transfer what they asked for.
A read of zero bytes or a short write leaves errno at 0, so the helpers
then return 0, which their callers take as a value of 0 or as a write
that took effect. A short write of run makes ksm_start() wait for scans
of a ksmd that never started, a short read of full_scans makes it wait
for scans that never seem to complete, and short reads of
ksm_merging_pages or ksm_stat and a short write of use_zero_pages make
cases fail that should have been skipped.
Return -errno only when the call fails, and -EIO when it transfers less
than asked, so that callers skip or fail as they do on other errors.
Forcing each short read or write with an LD_PRELOAD shim on
ksm_functional_tests:
short read or write of before after
run cases fail, then hangs all skipped
full_scans hangs in the first case all skipped
ksm_merging_pages 9 of 11 cases fail all skipped
ksm_stat zero page case fails zero page case skipped
use_zero_pages zero page case fails zero page case skipped
Signed-off-by: Qiliang Yuan <odys.yuan@gmail.com>
---
The checks come from 93fb70aa5904 ("selftests/vm: add KSM unmerge
tests"), 3d0745e59c84 ("selftest: add a testcase of ksm zero pages")
and 42096aa24b82 ("selftest/mm: ksm_functional_tests: test in
mmap_and_merge_range() if anything got merged"), and b27f292de6b1
("selftests/mm: put general ksm operation into vm_util") turned the
use_zero_pages check into one of them. There are no Fixes tags, as
only short reads and writes forced with the shim hit them, and the
helpers are in vm_util only since v6.18.
---
tools/testing/selftests/mm/vm_util.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
index 515031b8283da..caea045fa7d46 100644
--- a/tools/testing/selftests/mm/vm_util.c
+++ b/tools/testing/selftests/mm/vm_util.c
@@ -920,6 +920,8 @@ long ksm_get_self_zero_pages(void)
close(proc_self_ksm_stat_fd);
if (read_size < 0)
return -errno;
+ if (!read_size)
+ return -EIO;
buf[read_size] = 0;
@@ -944,8 +946,10 @@ long ksm_get_self_merging_pages(void)
ret = pread(proc_self_ksm_merging_pages_fd, buf, sizeof(buf) - 1, 0);
close(proc_self_ksm_merging_pages_fd);
- if (ret <= 0)
+ if (ret < 0)
return -errno;
+ if (!ret)
+ return -EIO;
buf[ret] = 0;
return strtol(buf, NULL, 10);
@@ -963,8 +967,10 @@ long ksm_get_full_scans(void)
ret = pread(ksm_full_scans_fd, buf, sizeof(buf) - 1, 0);
close(ksm_full_scans_fd);
- if (ret <= 0)
+ if (ret < 0)
return -errno;
+ if (!ret)
+ return -EIO;
buf[ret] = 0;
return strtol(buf, NULL, 10);
@@ -981,7 +987,9 @@ int ksm_use_zero_pages(void)
ret = write(ksm_use_zero_pages_fd, "1", 1);
close(ksm_use_zero_pages_fd);
- return ret == 1 ? 0 : -errno;
+ if (ret < 0)
+ return -errno;
+ return ret == 1 ? 0 : -EIO;
}
int ksm_start(void)
@@ -1002,8 +1010,10 @@ int ksm_start(void)
}
ret = write(ksm_fd, "1", 1);
close(ksm_fd);
- if (ret != 1)
+ if (ret < 0)
return -errno;
+ if (ret != 1)
+ return -EIO;
do {
end_scans = ksm_get_full_scans();
if (end_scans < 0)
@@ -1024,7 +1034,9 @@ int ksm_stop(void)
ret = write(ksm_fd, "2", 1);
close(ksm_fd);
- return ret == 1 ? 0 : -errno;
+ if (ret < 0)
+ return -errno;
+ return ret == 1 ? 0 : -EIO;
}
int get_hardware_corrupted_size(unsigned long *val)
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v4 3/5] selftests/mm: fail KSM helpers on short reads and writes
2026-11-09 1:22 ` [PATCH v4 3/5] selftests/mm: fail KSM helpers on short reads and writes Qiliang Yuan
@ 2026-11-09 2:29 ` Xu Xin (vivo)
0 siblings, 0 replies; 10+ messages in thread
From: Xu Xin (vivo) @ 2026-11-09 2:29 UTC (permalink / raw)
To: Qiliang Yuan
Cc: Andrew Morton, David Hildenbrand, Chengming Zhou, Stefan Roesch,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Shuah Khan, Jonathan Corbet,
Shuah Khan, Randy Dunlap, linux-mm, linux-kernel,
linux-kselftest, linux-doc
On Sun, Nov 08, 2026 at 08:22:52PM -0500, Qiliang Yuan wrote:
> The KSM helpers in vm_util read and write KSM's sysfs and procfs files
> with a single pread() or write(), and return -errno when the call does
> not transfer what they asked for.
>
> A read of zero bytes or a short write leaves errno at 0, so the helpers
> then return 0, which their callers take as a value of 0 or as a write
> that took effect. A short write of run makes ksm_start() wait for scans
> of a ksmd that never started, a short read of full_scans makes it wait
> for scans that never seem to complete, and short reads of
> ksm_merging_pages or ksm_stat and a short write of use_zero_pages make
> cases fail that should have been skipped.
>
> Return -errno only when the call fails, and -EIO when it transfers less
> than asked, so that callers skip or fail as they do on other errors.
> Forcing each short read or write with an LD_PRELOAD shim on
> ksm_functional_tests:
>
> short read or write of before after
> run cases fail, then hangs all skipped
> full_scans hangs in the first case all skipped
> ksm_merging_pages 9 of 11 cases fail all skipped
> ksm_stat zero page case fails zero page case skipped
> use_zero_pages zero page case fails zero page case skipped
>
> Signed-off-by: Qiliang Yuan <odys.yuan@gmail.com>
> ---
> The checks come from 93fb70aa5904 ("selftests/vm: add KSM unmerge
> tests"), 3d0745e59c84 ("selftest: add a testcase of ksm zero pages")
> and 42096aa24b82 ("selftest/mm: ksm_functional_tests: test in
> mmap_and_merge_range() if anything got merged"), and b27f292de6b1
> ("selftests/mm: put general ksm operation into vm_util") turned the
> use_zero_pages check into one of them. There are no Fixes tags, as
> only short reads and writes forced with the shim hit them, and the
> helpers are in vm_util only since v6.18.
> ---
> tools/testing/selftests/mm/vm_util.c | 22 +++++++++++++++++-----
> 1 file changed, 17 insertions(+), 5 deletions(-)
Reviewed-by: Xu Xin (vivo) <xu.xin@linux.dev>
>
> diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
> index 515031b8283da..caea045fa7d46 100644
> --- a/tools/testing/selftests/mm/vm_util.c
> +++ b/tools/testing/selftests/mm/vm_util.c
> @@ -920,6 +920,8 @@ long ksm_get_self_zero_pages(void)
> close(proc_self_ksm_stat_fd);
> if (read_size < 0)
> return -errno;
> + if (!read_size)
> + return -EIO;
>
> buf[read_size] = 0;
>
> @@ -944,8 +946,10 @@ long ksm_get_self_merging_pages(void)
>
> ret = pread(proc_self_ksm_merging_pages_fd, buf, sizeof(buf) - 1, 0);
> close(proc_self_ksm_merging_pages_fd);
> - if (ret <= 0)
> + if (ret < 0)
> return -errno;
> + if (!ret)
> + return -EIO;
> buf[ret] = 0;
>
> return strtol(buf, NULL, 10);
> @@ -963,8 +967,10 @@ long ksm_get_full_scans(void)
>
> ret = pread(ksm_full_scans_fd, buf, sizeof(buf) - 1, 0);
> close(ksm_full_scans_fd);
> - if (ret <= 0)
> + if (ret < 0)
> return -errno;
> + if (!ret)
> + return -EIO;
> buf[ret] = 0;
>
> return strtol(buf, NULL, 10);
> @@ -981,7 +987,9 @@ int ksm_use_zero_pages(void)
>
> ret = write(ksm_use_zero_pages_fd, "1", 1);
> close(ksm_use_zero_pages_fd);
> - return ret == 1 ? 0 : -errno;
> + if (ret < 0)
> + return -errno;
> + return ret == 1 ? 0 : -EIO;
> }
>
> int ksm_start(void)
> @@ -1002,8 +1010,10 @@ int ksm_start(void)
> }
> ret = write(ksm_fd, "1", 1);
> close(ksm_fd);
> - if (ret != 1)
> + if (ret < 0)
> return -errno;
> + if (ret != 1)
> + return -EIO;
> do {
> end_scans = ksm_get_full_scans();
> if (end_scans < 0)
> @@ -1024,7 +1034,9 @@ int ksm_stop(void)
>
> ret = write(ksm_fd, "2", 1);
> close(ksm_fd);
> - return ret == 1 ? 0 : -errno;
> + if (ret < 0)
> + return -errno;
> + return ret == 1 ? 0 : -EIO;
> }
>
> int get_hardware_corrupted_size(unsigned long *val)
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 4/5] selftests/mm: move waiting for KSM full scans into a helper
2026-11-09 1:22 [PATCH v4 0/5] mm/ksm: keep smart scan from losing duplicate pages Qiliang Yuan
` (2 preceding siblings ...)
2026-11-09 1:22 ` [PATCH v4 3/5] selftests/mm: fail KSM helpers on short reads and writes Qiliang Yuan
@ 2026-11-09 1:22 ` Qiliang Yuan
2026-11-09 2:32 ` Xu Xin (vivo)
2026-11-09 1:22 ` [PATCH v4 5/5] selftests/mm: cover merging KSM pages aged by smart scan Qiliang Yuan
4 siblings, 1 reply; 10+ messages in thread
From: Qiliang Yuan @ 2026-11-09 1:22 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Xu Xin, Chengming Zhou,
Stefan Roesch, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Shuah Khan,
Jonathan Corbet, Shuah Khan, Randy Dunlap
Cc: linux-mm, linux-kernel, linux-kselftest, linux-doc, Qiliang Yuan
ksm_start() enables ksmd and then polls full_scans until two more full
scans have completed, so that any merging that can happen has happened.
There is no helper to wait for a number of full scans while ksmd is
already running, so a test that needs one has to copy that loop.
Move the loop into ksm_wait_full_scans() and make ksm_start() call it
after enabling ksmd. The count is now read after ksmd starts rather than
before, which can only make ksm_start() wait longer.
Signed-off-by: Qiliang Yuan <odys.yuan@gmail.com>
Tested-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
---
tools/testing/selftests/mm/vm_util.c | 31 ++++++++++++++++++-------------
tools/testing/selftests/mm/vm_util.h | 1 +
2 files changed, 19 insertions(+), 13 deletions(-)
diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
index caea045fa7d46..8184691211acc 100644
--- a/tools/testing/selftests/mm/vm_util.c
+++ b/tools/testing/selftests/mm/vm_util.c
@@ -992,35 +992,40 @@ int ksm_use_zero_pages(void)
return ret == 1 ? 0 : -EIO;
}
+int ksm_wait_full_scans(long nr)
+{
+ long start_scans, end_scans;
+
+ start_scans = ksm_get_full_scans();
+ if (start_scans < 0)
+ return start_scans;
+ do {
+ end_scans = ksm_get_full_scans();
+ if (end_scans < 0)
+ return end_scans;
+ } while (end_scans < start_scans + nr);
+
+ return 0;
+}
+
int ksm_start(void)
{
int ksm_fd;
ssize_t ret;
- long start_scans, end_scans;
ksm_fd = open("/sys/kernel/mm/ksm/run", O_RDWR);
if (ksm_fd < 0)
return -errno;
- /* Wait for two full scans such that any possible merging happened. */
- start_scans = ksm_get_full_scans();
- if (start_scans < 0) {
- close(ksm_fd);
- return start_scans;
- }
ret = write(ksm_fd, "1", 1);
close(ksm_fd);
if (ret < 0)
return -errno;
if (ret != 1)
return -EIO;
- do {
- end_scans = ksm_get_full_scans();
- if (end_scans < 0)
- return end_scans;
- } while (end_scans < start_scans + 2);
- return 0;
+ /* Wait for two full scans such that any possible merging happened. */
+ return ksm_wait_full_scans(2);
}
int ksm_stop(void)
diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
index b5d59729d4327..7e00030077d2f 100644
--- a/tools/testing/selftests/mm/vm_util.h
+++ b/tools/testing/selftests/mm/vm_util.h
@@ -162,6 +162,7 @@ void *sys_mremap(void *old_address, unsigned long old_size,
long ksm_get_self_zero_pages(void);
long ksm_get_self_merging_pages(void);
long ksm_get_full_scans(void);
+int ksm_wait_full_scans(long nr);
int ksm_use_zero_pages(void);
int ksm_start(void);
int ksm_stop(void);
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v4 4/5] selftests/mm: move waiting for KSM full scans into a helper
2026-11-09 1:22 ` [PATCH v4 4/5] selftests/mm: move waiting for KSM full scans into a helper Qiliang Yuan
@ 2026-11-09 2:32 ` Xu Xin (vivo)
0 siblings, 0 replies; 10+ messages in thread
From: Xu Xin (vivo) @ 2026-11-09 2:32 UTC (permalink / raw)
To: Qiliang Yuan
Cc: Andrew Morton, David Hildenbrand, Chengming Zhou, Stefan Roesch,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Shuah Khan, Jonathan Corbet,
Shuah Khan, Randy Dunlap, linux-mm, linux-kernel,
linux-kselftest, linux-doc
On Sun, Nov 08, 2026 at 08:22:53PM -0500, Qiliang Yuan wrote:
> ksm_start() enables ksmd and then polls full_scans until two more full
> scans have completed, so that any merging that can happen has happened.
>
> There is no helper to wait for a number of full scans while ksmd is
> already running, so a test that needs one has to copy that loop.
>
> Move the loop into ksm_wait_full_scans() and make ksm_start() call it
> after enabling ksmd. The count is now read after ksmd starts rather than
> before, which can only make ksm_start() wait longer.
>
> Signed-off-by: Qiliang Yuan <odys.yuan@gmail.com>
> Tested-by: Andrew Morton <akpm@linux-foundation.org>
> Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Xu Xin (vivo) <xu.xin@linux.dev>
> ---
> tools/testing/selftests/mm/vm_util.c | 31 ++++++++++++++++++-------------
> tools/testing/selftests/mm/vm_util.h | 1 +
> 2 files changed, 19 insertions(+), 13 deletions(-)
>
> diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
> index caea045fa7d46..8184691211acc 100644
> --- a/tools/testing/selftests/mm/vm_util.c
> +++ b/tools/testing/selftests/mm/vm_util.c
> @@ -992,35 +992,40 @@ int ksm_use_zero_pages(void)
> return ret == 1 ? 0 : -EIO;
> }
>
> +int ksm_wait_full_scans(long nr)
> +{
> + long start_scans, end_scans;
> +
> + start_scans = ksm_get_full_scans();
> + if (start_scans < 0)
> + return start_scans;
> + do {
> + end_scans = ksm_get_full_scans();
> + if (end_scans < 0)
> + return end_scans;
> + } while (end_scans < start_scans + nr);
> +
> + return 0;
> +}
> +
> int ksm_start(void)
> {
> int ksm_fd;
> ssize_t ret;
> - long start_scans, end_scans;
>
> ksm_fd = open("/sys/kernel/mm/ksm/run", O_RDWR);
> if (ksm_fd < 0)
> return -errno;
>
> - /* Wait for two full scans such that any possible merging happened. */
> - start_scans = ksm_get_full_scans();
> - if (start_scans < 0) {
> - close(ksm_fd);
> - return start_scans;
> - }
> ret = write(ksm_fd, "1", 1);
> close(ksm_fd);
> if (ret < 0)
> return -errno;
> if (ret != 1)
> return -EIO;
> - do {
> - end_scans = ksm_get_full_scans();
> - if (end_scans < 0)
> - return end_scans;
> - } while (end_scans < start_scans + 2);
>
> - return 0;
> + /* Wait for two full scans such that any possible merging happened. */
> + return ksm_wait_full_scans(2);
> }
>
> int ksm_stop(void)
> diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
> index b5d59729d4327..7e00030077d2f 100644
> --- a/tools/testing/selftests/mm/vm_util.h
> +++ b/tools/testing/selftests/mm/vm_util.h
> @@ -162,6 +162,7 @@ void *sys_mremap(void *old_address, unsigned long old_size,
> long ksm_get_self_zero_pages(void);
> long ksm_get_self_merging_pages(void);
> long ksm_get_full_scans(void);
> +int ksm_wait_full_scans(long nr);
> int ksm_use_zero_pages(void);
> int ksm_start(void);
> int ksm_stop(void);
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 5/5] selftests/mm: cover merging KSM pages aged by smart scan
2026-11-09 1:22 [PATCH v4 0/5] mm/ksm: keep smart scan from losing duplicate pages Qiliang Yuan
` (3 preceding siblings ...)
2026-11-09 1:22 ` [PATCH v4 4/5] selftests/mm: move waiting for KSM full scans into a helper Qiliang Yuan
@ 2026-11-09 1:22 ` Qiliang Yuan
2026-11-09 2:34 ` Xu Xin (vivo)
4 siblings, 1 reply; 10+ messages in thread
From: Qiliang Yuan @ 2026-11-09 1:22 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Xu Xin, Chengming Zhou,
Stefan Roesch, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Shuah Khan,
Jonathan Corbet, Shuah Khan, Randy Dunlap
Cc: linux-mm, linux-kernel, linux-kselftest, linux-doc, Qiliang Yuan
ksm_functional_tests checks merging and unmerging with ksmd's default
settings, but nothing there exercises smart scan, which skips pages KSM
has failed to merge for a while.
Smart scan used to time those skips per page, so two identical pages
that became mergeable some scans apart could end up never being looked
at in the same scan, and were never merged. "mm/ksm: align smart scan
skips with the scan number" fixed that.
Add ksm_get_smart_scan() and ksm_set_smart_scan() to vm_util, and a
case that enables smart scan, lets sixteen unique pages age for a dozen
scans, then makes a duplicate of each mergeable one scan apart, and
expects every pair to be merged 32 scans later:
kernel failures, two boots
before the fix 20/20, 20/20
with the fix 0/20, 0/20
Signed-off-by: Qiliang Yuan <odys.yuan@gmail.com>
Tested-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
---
tools/testing/selftests/mm/ksm_functional_tests.c | 89 ++++++++++++++++++++++-
tools/testing/selftests/mm/vm_util.c | 36 +++++++++
tools/testing/selftests/mm/vm_util.h | 2 +
3 files changed, 126 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/mm/ksm_functional_tests.c b/tools/testing/selftests/mm/ksm_functional_tests.c
index 31c06c72203fd..135191f99962d 100644
--- a/tools/testing/selftests/mm/ksm_functional_tests.c
+++ b/tools/testing/selftests/mm/ksm_functional_tests.c
@@ -695,6 +695,92 @@ static void test_fork_ksm_merging_page_count(void)
munmap(map, size);
}
+static void test_merge_aged_pairs(void)
+{
+ const unsigned int pairs = 16;
+ const unsigned long size = 2 * pairs * pagesize;
+ int old_smart_scan;
+ unsigned int i;
+ char *map;
+
+ ksft_print_msg("[RUN] %s\n", __func__);
+
+ old_smart_scan = ksm_get_smart_scan();
+ if (old_smart_scan < 0) {
+ ksft_test_result_skip("smart_scan not supported\n");
+ return;
+ }
+ if (ksm_set_smart_scan(true) < 0) {
+ ksft_test_result_fail("Enabling smart_scan failed\n");
+ return;
+ }
+
+ if (ksm_stop() < 0) {
+ ksft_test_result_fail("Disabling (unmerging) KSM failed\n");
+ goto restore;
+ }
+
+ map = mmap(NULL, size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ if (map == MAP_FAILED) {
+ ksft_test_result_fail("mmap() failed\n");
+ goto restore;
+ }
+ if (madvise(map, size, MADV_NOHUGEPAGE) && errno != EINVAL) {
+ ksft_test_result_fail("MADV_NOHUGEPAGE failed\n");
+ goto unmap;
+ }
+
+ /*
+ * Page i of the first half and page i of the second half form a
+ * pair with content no other page shares.
+ */
+ for (i = 0; i < pairs; i++) {
+ memset(map + i * pagesize, i + 1, pagesize);
+ memset(map + (pairs + i) * pagesize, i + 1, pagesize);
+ }
+
+ /* Let the first page of each pair age without a duplicate. */
+ if (madvise(map, size / 2, MADV_MERGEABLE)) {
+ ksft_test_result_fail("MADV_MERGEABLE failed\n");
+ goto unmap;
+ }
+ if (ksm_start() < 0 || ksm_wait_full_scans(12) < 0) {
+ ksft_test_result_fail("Running KSM failed\n");
+ goto unmap;
+ }
+
+ /*
+ * Make the duplicates mergeable one scan apart so that each pair
+ * starts out with a different distance in scans.
+ */
+ for (i = 0; i < pairs; i++) {
+ if (madvise(map + (pairs + i) * pagesize, pagesize,
+ MADV_MERGEABLE)) {
+ ksft_test_result_fail("MADV_MERGEABLE failed\n");
+ goto unmap;
+ }
+ if (ksm_wait_full_scans(1) < 0) {
+ ksft_test_result_fail("Running KSM failed\n");
+ goto unmap;
+ }
+ }
+
+ if (ksm_wait_full_scans(32) < 0) {
+ ksft_test_result_fail("Running KSM failed\n");
+ goto unmap;
+ }
+
+ ksft_test_result(ksm_get_self_merging_pages() == 2 * pairs,
+ "Pages aged by smart scan got merged\n");
+unmap:
+ ksm_stop();
+ munmap(map, size);
+restore:
+ if (ksm_set_smart_scan(old_smart_scan) < 0)
+ ksft_print_msg("Restoring smart_scan failed\n");
+}
+
static void init_global_file_handles(void)
{
mem_fd = open("/proc/self/mem", O_RDWR);
@@ -720,7 +806,7 @@ static void init_global_file_handles(void)
int main(int argc, char **argv)
{
- unsigned int tests = 9;
+ unsigned int tests = 10;
int err;
if (argc > 1 && !strcmp(argv[1], FORK_EXEC_CHILD_PRG_NAME)) {
@@ -753,6 +839,7 @@ int main(int argc, char **argv)
test_prctl_fork_exec();
test_prctl_unmerge();
test_fork_ksm_merging_page_count();
+ test_merge_aged_pairs();
err = ksft_get_fail_cnt();
if (err)
diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
index 8184691211acc..f26f9e4bfdbe9 100644
--- a/tools/testing/selftests/mm/vm_util.c
+++ b/tools/testing/selftests/mm/vm_util.c
@@ -992,6 +992,42 @@ int ksm_use_zero_pages(void)
return ret == 1 ? 0 : -EIO;
}
+int ksm_get_smart_scan(void)
+{
+ int smart_scan_fd;
+ char buf;
+ ssize_t ret;
+
+ smart_scan_fd = open("/sys/kernel/mm/ksm/smart_scan", O_RDONLY);
+ if (smart_scan_fd < 0)
+ return -errno;
+
+ ret = pread(smart_scan_fd, &buf, 1, 0);
+ close(smart_scan_fd);
+ if (ret < 0)
+ return -errno;
+ if (ret != 1)
+ return -EIO;
+
+ return buf == '1';
+}
+
+int ksm_set_smart_scan(bool enable)
+{
+ int smart_scan_fd;
+ ssize_t ret;
+
+ smart_scan_fd = open("/sys/kernel/mm/ksm/smart_scan", O_WRONLY);
+ if (smart_scan_fd < 0)
+ return -errno;
+
+ ret = write(smart_scan_fd, enable ? "1" : "0", 1);
+ close(smart_scan_fd);
+ if (ret < 0)
+ return -errno;
+ return ret == 1 ? 0 : -EIO;
+}
+
int ksm_wait_full_scans(long nr)
{
long start_scans, end_scans;
diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
index 7e00030077d2f..ab1325dc65800 100644
--- a/tools/testing/selftests/mm/vm_util.h
+++ b/tools/testing/selftests/mm/vm_util.h
@@ -163,6 +163,8 @@ long ksm_get_self_zero_pages(void);
long ksm_get_self_merging_pages(void);
long ksm_get_full_scans(void);
int ksm_wait_full_scans(long nr);
+int ksm_get_smart_scan(void);
+int ksm_set_smart_scan(bool enable);
int ksm_use_zero_pages(void);
int ksm_start(void);
int ksm_stop(void);
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v4 5/5] selftests/mm: cover merging KSM pages aged by smart scan
2026-11-09 1:22 ` [PATCH v4 5/5] selftests/mm: cover merging KSM pages aged by smart scan Qiliang Yuan
@ 2026-11-09 2:34 ` Xu Xin (vivo)
0 siblings, 0 replies; 10+ messages in thread
From: Xu Xin (vivo) @ 2026-11-09 2:34 UTC (permalink / raw)
To: Qiliang Yuan
Cc: Andrew Morton, David Hildenbrand, Chengming Zhou, Stefan Roesch,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Shuah Khan, Jonathan Corbet,
Shuah Khan, Randy Dunlap, linux-mm, linux-kernel,
linux-kselftest, linux-doc
On Sun, Nov 08, 2026 at 08:22:54PM -0500, Qiliang Yuan wrote:
> ksm_functional_tests checks merging and unmerging with ksmd's default
> settings, but nothing there exercises smart scan, which skips pages KSM
> has failed to merge for a while.
>
> Smart scan used to time those skips per page, so two identical pages
> that became mergeable some scans apart could end up never being looked
> at in the same scan, and were never merged. "mm/ksm: align smart scan
> skips with the scan number" fixed that.
>
> Add ksm_get_smart_scan() and ksm_set_smart_scan() to vm_util, and a
> case that enables smart scan, lets sixteen unique pages age for a dozen
> scans, then makes a duplicate of each mergeable one scan apart, and
> expects every pair to be merged 32 scans later:
>
> kernel failures, two boots
> before the fix 20/20, 20/20
> with the fix 0/20, 0/20
>
> Signed-off-by: Qiliang Yuan <odys.yuan@gmail.com>
> Tested-by: Andrew Morton <akpm@linux-foundation.org>
> Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
> ---
> tools/testing/selftests/mm/ksm_functional_tests.c | 89 ++++++++++++++++++++++-
> tools/testing/selftests/mm/vm_util.c | 36 +++++++++
> tools/testing/selftests/mm/vm_util.h | 2 +
> 3 files changed, 126 insertions(+), 1 deletion(-)
Reviewed-by: Xu Xin (vivo) <xu.xin@linux.dev>
>
> diff --git a/tools/testing/selftests/mm/ksm_functional_tests.c b/tools/testing/selftests/mm/ksm_functional_tests.c
> index 31c06c72203fd..135191f99962d 100644
> --- a/tools/testing/selftests/mm/ksm_functional_tests.c
> +++ b/tools/testing/selftests/mm/ksm_functional_tests.c
> @@ -695,6 +695,92 @@ static void test_fork_ksm_merging_page_count(void)
> munmap(map, size);
> }
>
> +static void test_merge_aged_pairs(void)
> +{
> + const unsigned int pairs = 16;
> + const unsigned long size = 2 * pairs * pagesize;
> + int old_smart_scan;
> + unsigned int i;
> + char *map;
> +
> + ksft_print_msg("[RUN] %s\n", __func__);
> +
> + old_smart_scan = ksm_get_smart_scan();
> + if (old_smart_scan < 0) {
> + ksft_test_result_skip("smart_scan not supported\n");
> + return;
> + }
> + if (ksm_set_smart_scan(true) < 0) {
> + ksft_test_result_fail("Enabling smart_scan failed\n");
> + return;
> + }
> +
> + if (ksm_stop() < 0) {
> + ksft_test_result_fail("Disabling (unmerging) KSM failed\n");
> + goto restore;
> + }
> +
> + map = mmap(NULL, size, PROT_READ | PROT_WRITE,
> + MAP_PRIVATE | MAP_ANON, -1, 0);
> + if (map == MAP_FAILED) {
> + ksft_test_result_fail("mmap() failed\n");
> + goto restore;
> + }
> + if (madvise(map, size, MADV_NOHUGEPAGE) && errno != EINVAL) {
> + ksft_test_result_fail("MADV_NOHUGEPAGE failed\n");
> + goto unmap;
> + }
> +
> + /*
> + * Page i of the first half and page i of the second half form a
> + * pair with content no other page shares.
> + */
> + for (i = 0; i < pairs; i++) {
> + memset(map + i * pagesize, i + 1, pagesize);
> + memset(map + (pairs + i) * pagesize, i + 1, pagesize);
> + }
> +
> + /* Let the first page of each pair age without a duplicate. */
> + if (madvise(map, size / 2, MADV_MERGEABLE)) {
> + ksft_test_result_fail("MADV_MERGEABLE failed\n");
> + goto unmap;
> + }
> + if (ksm_start() < 0 || ksm_wait_full_scans(12) < 0) {
> + ksft_test_result_fail("Running KSM failed\n");
> + goto unmap;
> + }
> +
> + /*
> + * Make the duplicates mergeable one scan apart so that each pair
> + * starts out with a different distance in scans.
> + */
> + for (i = 0; i < pairs; i++) {
> + if (madvise(map + (pairs + i) * pagesize, pagesize,
> + MADV_MERGEABLE)) {
> + ksft_test_result_fail("MADV_MERGEABLE failed\n");
> + goto unmap;
> + }
> + if (ksm_wait_full_scans(1) < 0) {
> + ksft_test_result_fail("Running KSM failed\n");
> + goto unmap;
> + }
> + }
> +
> + if (ksm_wait_full_scans(32) < 0) {
> + ksft_test_result_fail("Running KSM failed\n");
> + goto unmap;
> + }
> +
> + ksft_test_result(ksm_get_self_merging_pages() == 2 * pairs,
> + "Pages aged by smart scan got merged\n");
> +unmap:
> + ksm_stop();
> + munmap(map, size);
> +restore:
> + if (ksm_set_smart_scan(old_smart_scan) < 0)
> + ksft_print_msg("Restoring smart_scan failed\n");
> +}
> +
> static void init_global_file_handles(void)
> {
> mem_fd = open("/proc/self/mem", O_RDWR);
> @@ -720,7 +806,7 @@ static void init_global_file_handles(void)
>
> int main(int argc, char **argv)
> {
> - unsigned int tests = 9;
> + unsigned int tests = 10;
> int err;
>
> if (argc > 1 && !strcmp(argv[1], FORK_EXEC_CHILD_PRG_NAME)) {
> @@ -753,6 +839,7 @@ int main(int argc, char **argv)
> test_prctl_fork_exec();
> test_prctl_unmerge();
> test_fork_ksm_merging_page_count();
> + test_merge_aged_pairs();
>
> err = ksft_get_fail_cnt();
> if (err)
> diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
> index 8184691211acc..f26f9e4bfdbe9 100644
> --- a/tools/testing/selftests/mm/vm_util.c
> +++ b/tools/testing/selftests/mm/vm_util.c
> @@ -992,6 +992,42 @@ int ksm_use_zero_pages(void)
> return ret == 1 ? 0 : -EIO;
> }
>
> +int ksm_get_smart_scan(void)
> +{
> + int smart_scan_fd;
> + char buf;
> + ssize_t ret;
> +
> + smart_scan_fd = open("/sys/kernel/mm/ksm/smart_scan", O_RDONLY);
> + if (smart_scan_fd < 0)
> + return -errno;
> +
> + ret = pread(smart_scan_fd, &buf, 1, 0);
> + close(smart_scan_fd);
> + if (ret < 0)
> + return -errno;
> + if (ret != 1)
> + return -EIO;
> +
> + return buf == '1';
> +}
> +
> +int ksm_set_smart_scan(bool enable)
> +{
> + int smart_scan_fd;
> + ssize_t ret;
> +
> + smart_scan_fd = open("/sys/kernel/mm/ksm/smart_scan", O_WRONLY);
> + if (smart_scan_fd < 0)
> + return -errno;
> +
> + ret = write(smart_scan_fd, enable ? "1" : "0", 1);
> + close(smart_scan_fd);
> + if (ret < 0)
> + return -errno;
> + return ret == 1 ? 0 : -EIO;
> +}
> +
> int ksm_wait_full_scans(long nr)
> {
> long start_scans, end_scans;
> diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
> index 7e00030077d2f..ab1325dc65800 100644
> --- a/tools/testing/selftests/mm/vm_util.h
> +++ b/tools/testing/selftests/mm/vm_util.h
> @@ -163,6 +163,8 @@ long ksm_get_self_zero_pages(void);
> long ksm_get_self_merging_pages(void);
> long ksm_get_full_scans(void);
> int ksm_wait_full_scans(long nr);
> +int ksm_get_smart_scan(void);
> +int ksm_set_smart_scan(bool enable);
> int ksm_use_zero_pages(void);
> int ksm_start(void);
> int ksm_stop(void);
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 10+ messages in thread