* [PATCH v2 1/3] selftests/mm: handle EINVAL when configuring gigantic hugepages
2026-06-30 9:32 [PATCH v2 0/3] selftests/mm: avoid false failures in hugetlb and KSM tests Sayali Patil
@ 2026-06-30 9:32 ` Sayali Patil
2026-06-30 10:45 ` David Hildenbrand (Arm)
2026-06-30 9:32 ` [PATCH v2 2/3] selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes Sayali Patil
2026-06-30 9:32 ` [PATCH v2 3/3] selftests/mm: fix ternary operator precedence in ksm_tests Sayali Patil
2 siblings, 1 reply; 8+ messages in thread
From: Sayali Patil @ 2026-06-30 9:32 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
Some MM selftests attempt to configure the amount of
HugeTLB pages of different sizes by writing to nr_hugepages.
PowerPC hash MMU pSeries systems advertise gigantic hugepage sizes
but do not support runtime allocation of such pages, writes
to the corresponding nr_hugepages file fail with -EINVAL.
This causes the test to bail out even though the failure is due
to a platform limitation rather than the
functionality being tested.
Treat -EINVAL from the sysfs write as a skipped configuration request
and continue running the test instead of failing.
Before patch:
-------------------------
running ./hugetlb-madvise
-------------------------
TAP version 13
1..1
[INFO] detected hugetlb page size: 16777216 KiB
[INFO] detected hugetlb page size: 16384 KiB
ok 1 MADV_DONTNEED and MADV_REMOVE on hugetlb
Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
Bail out! /sys/kernel/mm/hugepages/hugepages-16777216kB/nr_hugepages
write(0) failed: Invalid argument
Totals: pass:0 fail:0 xfail:0 xpass:0 skip:0 error:0
[FAIL]
After patch:
-------------------------
running ./hugetlb-madvise
-------------------------
TAP version 13
1..1
[INFO] detected hugetlb page size: 16777216 KiB
[INFO] detected hugetlb page size: 16384 KiB
ok 1 MADV_DONTNEED and MADV_REMOVE on hugetlb
Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
/sys/kernel/mm/hugepages/hugepages-16777216kB/nr_hugepages
write(0) failed: Invalid argument
[PASS]
Fixes: 27477b28b74f ("selftests/mm: hugepage_settings: add APIs to get and set nr_hugepages")
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
.../testing/selftests/mm/hugepage_settings.c | 32 ++++++++++++++++++-
.../testing/selftests/mm/hugepage_settings.h | 1 +
2 files changed, 32 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/mm/hugepage_settings.c b/tools/testing/selftests/mm/hugepage_settings.c
index 2eab2110ac6a..ce38ae3da01a 100644
--- a/tools/testing/selftests/mm/hugepage_settings.c
+++ b/tools/testing/selftests/mm/hugepage_settings.c
@@ -422,6 +422,36 @@ static void hugetlb_sysfs_path(char *buf, size_t buflen,
size / 1024, attr);
}
+void hugetlb_write_num(const char *path, unsigned long num)
+{
+ int fd, saved_errno;
+ ssize_t numwritten;
+ char buf[21];
+
+ sprintf(buf, "%lu", num);
+
+ fd = open(path, O_WRONLY);
+ if (fd == -1)
+ ksft_exit_fail_msg("%s open failed: %s\n", path, strerror(errno));
+
+ numwritten = write(fd, buf, strlen(buf));
+ saved_errno = errno;
+ close(fd);
+ errno = saved_errno;
+
+ /* Treat EINVAL as a skipped configuration (e.g., unsupported gigantic pages) */
+ if (numwritten < 0 && errno == EINVAL) {
+ ksft_print_msg("%s write(%s) failed: %s\n", path, buf, strerror(errno));
+ return;
+ }
+
+ if (numwritten < 0)
+ ksft_exit_fail_msg("%s write(%s) failed: %s\n", path, buf, strerror(errno));
+ if (numwritten != strlen(buf))
+ ksft_exit_fail_msg("%s write(%s) is truncated, expected %zu bytes, got %zd bytes\n",
+ path, buf, strlen(buf), numwritten);
+}
+
unsigned long hugetlb_nr_pages(unsigned long size)
{
char path[PATH_MAX];
@@ -437,7 +467,7 @@ void hugetlb_set_nr_pages(unsigned long size, unsigned long nr)
hugetlb_sysfs_path(path, sizeof(path), size, "nr_hugepages");
- write_num(path, nr);
+ hugetlb_write_num(path, nr);
}
unsigned long hugetlb_free_pages(unsigned long size)
diff --git a/tools/testing/selftests/mm/hugepage_settings.h b/tools/testing/selftests/mm/hugepage_settings.h
index 726c73c43c05..390fcc483b9e 100644
--- a/tools/testing/selftests/mm/hugepage_settings.h
+++ b/tools/testing/selftests/mm/hugepage_settings.h
@@ -95,6 +95,7 @@ bool thp_is_enabled(void);
int detect_hugetlb_page_sizes(unsigned long sizes[], int max);
unsigned long default_huge_page_size(void);
+void hugetlb_write_num(const char *path, unsigned long num);
unsigned long hugetlb_nr_pages(unsigned long size);
void hugetlb_set_nr_pages(unsigned long size, unsigned long nr);
unsigned long hugetlb_free_pages(unsigned long size);
--
2.52.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH v2 1/3] selftests/mm: handle EINVAL when configuring gigantic hugepages
2026-06-30 9:32 ` [PATCH v2 1/3] selftests/mm: handle EINVAL when configuring gigantic hugepages Sayali Patil
@ 2026-06-30 10:45 ` David Hildenbrand (Arm)
2026-06-30 20:20 ` Sayali Patil
0 siblings, 1 reply; 8+ messages in thread
From: David Hildenbrand (Arm) @ 2026-06-30 10:45 UTC (permalink / raw)
To: Sayali Patil, Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: Zi Yan, Michal Hocko, Oscar Salvador, Lorenzo Stoakes, Dev Jain,
Liam.Howlett, linuxppc-dev, Miaohe Lin, Venkat Rao Bagalkote
On 6/30/26 11:32, Sayali Patil wrote:
> Some MM selftests attempt to configure the amount of
> HugeTLB pages of different sizes by writing to nr_hugepages.
>
> PowerPC hash MMU pSeries systems advertise gigantic hugepage sizes
> but do not support runtime allocation of such pages, writes
> to the corresponding nr_hugepages file fail with -EINVAL.
> This causes the test to bail out even though the failure is due
> to a platform limitation rather than the
> functionality being tested.
>
> Treat -EINVAL from the sysfs write as a skipped configuration request
> and continue running the test instead of failing.
>
> Before patch:
> -------------------------
> running ./hugetlb-madvise
> -------------------------
> TAP version 13
> 1..1
> [INFO] detected hugetlb page size: 16777216 KiB
> [INFO] detected hugetlb page size: 16384 KiB
> ok 1 MADV_DONTNEED and MADV_REMOVE on hugetlb
> Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
> Bail out! /sys/kernel/mm/hugepages/hugepages-16777216kB/nr_hugepages
> write(0) failed: Invalid argument
> Totals: pass:0 fail:0 xfail:0 xpass:0 skip:0 error:0
> [FAIL]
>
> After patch:
> -------------------------
> running ./hugetlb-madvise
> -------------------------
> TAP version 13
> 1..1
> [INFO] detected hugetlb page size: 16777216 KiB
> [INFO] detected hugetlb page size: 16384 KiB
> ok 1 MADV_DONTNEED and MADV_REMOVE on hugetlb
> Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
> /sys/kernel/mm/hugepages/hugepages-16777216kB/nr_hugepages
> write(0) failed: Invalid argument
> [PASS]
>
> Fixes: 27477b28b74f ("selftests/mm: hugepage_settings: add APIs to get and set nr_hugepages")
> Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
> ---
> .../testing/selftests/mm/hugepage_settings.c | 32 ++++++++++++++++++-
> .../testing/selftests/mm/hugepage_settings.h | 1 +
> 2 files changed, 32 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/selftests/mm/hugepage_settings.c b/tools/testing/selftests/mm/hugepage_settings.c
> index 2eab2110ac6a..ce38ae3da01a 100644
> --- a/tools/testing/selftests/mm/hugepage_settings.c
> +++ b/tools/testing/selftests/mm/hugepage_settings.c
> @@ -422,6 +422,36 @@ static void hugetlb_sysfs_path(char *buf, size_t buflen,
> size / 1024, attr);
> }
>
> +void hugetlb_write_num(const char *path, unsigned long num)
> +{
> + int fd, saved_errno;
> + ssize_t numwritten;
> + char buf[21];
> +
> + sprintf(buf, "%lu", num);
> +
> + fd = open(path, O_WRONLY);
> + if (fd == -1)
> + ksft_exit_fail_msg("%s open failed: %s\n", path, strerror(errno));
> +
> + numwritten = write(fd, buf, strlen(buf));
> + saved_errno = errno;
> + close(fd);
> + errno = saved_errno;
> +
> + /* Treat EINVAL as a skipped configuration (e.g., unsupported gigantic pages) */
> + if (numwritten < 0 && errno == EINVAL) {
> + ksft_print_msg("%s write(%s) failed: %s\n", path, buf, strerror(errno));
Should we even print anything here? Rather confusing. It's just like we cannot
allocate anything (no memory).
In general, you are copy-pasting a lot of write_num()+write_file() content,
which is really suboptimal.
All you want is an option for write_num -> write_file to skip on -EINVAL, correct?
There are not that many write_num / write_file users ...
--
Cheers,
David
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH v2 1/3] selftests/mm: handle EINVAL when configuring gigantic hugepages
2026-06-30 10:45 ` David Hildenbrand (Arm)
@ 2026-06-30 20:20 ` Sayali Patil
0 siblings, 0 replies; 8+ messages in thread
From: Sayali Patil @ 2026-06-30 20:20 UTC (permalink / raw)
To: David Hildenbrand (Arm), Andrew Morton, Shuah Khan, linux-mm,
linux-kernel, linux-kselftest, Ritesh Harjani
Cc: Zi Yan, Michal Hocko, Oscar Salvador, Lorenzo Stoakes, Dev Jain,
Liam.Howlett, linuxppc-dev, Miaohe Lin, Venkat Rao Bagalkote
On 30/06/26 16:15, David Hildenbrand (Arm) wrote:
> On 6/30/26 11:32, Sayali Patil wrote:
>> Some MM selftests attempt to configure the amount of
>> HugeTLB pages of different sizes by writing to nr_hugepages.
>>
>> PowerPC hash MMU pSeries systems advertise gigantic hugepage sizes
>> but do not support runtime allocation of such pages, writes
>> to the corresponding nr_hugepages file fail with -EINVAL.
>> This causes the test to bail out even though the failure is due
>> to a platform limitation rather than the
>> functionality being tested.
>>
>> Treat -EINVAL from the sysfs write as a skipped configuration request
>> and continue running the test instead of failing.
>>
>> Before patch:
>> -------------------------
>> running ./hugetlb-madvise
>> -------------------------
>> TAP version 13
>> 1..1
>> [INFO] detected hugetlb page size: 16777216 KiB
>> [INFO] detected hugetlb page size: 16384 KiB
>> ok 1 MADV_DONTNEED and MADV_REMOVE on hugetlb
>> Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
>> Bail out! /sys/kernel/mm/hugepages/hugepages-16777216kB/nr_hugepages
>> write(0) failed: Invalid argument
>> Totals: pass:0 fail:0 xfail:0 xpass:0 skip:0 error:0
>> [FAIL]
>>
>> After patch:
>> -------------------------
>> running ./hugetlb-madvise
>> -------------------------
>> TAP version 13
>> 1..1
>> [INFO] detected hugetlb page size: 16777216 KiB
>> [INFO] detected hugetlb page size: 16384 KiB
>> ok 1 MADV_DONTNEED and MADV_REMOVE on hugetlb
>> Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
>> /sys/kernel/mm/hugepages/hugepages-16777216kB/nr_hugepages
>> write(0) failed: Invalid argument
>> [PASS]
>>
>> Fixes: 27477b28b74f ("selftests/mm: hugepage_settings: add APIs to get and set nr_hugepages")
>> Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
>> ---
>> .../testing/selftests/mm/hugepage_settings.c | 32 ++++++++++++++++++-
>> .../testing/selftests/mm/hugepage_settings.h | 1 +
>> 2 files changed, 32 insertions(+), 1 deletion(-)
>>
>> diff --git a/tools/testing/selftests/mm/hugepage_settings.c b/tools/testing/selftests/mm/hugepage_settings.c
>> index 2eab2110ac6a..ce38ae3da01a 100644
>> --- a/tools/testing/selftests/mm/hugepage_settings.c
>> +++ b/tools/testing/selftests/mm/hugepage_settings.c
>> @@ -422,6 +422,36 @@ static void hugetlb_sysfs_path(char *buf, size_t buflen,
>> size / 1024, attr);
>> }
>>
>> +void hugetlb_write_num(const char *path, unsigned long num)
>> +{
>> + int fd, saved_errno;
>> + ssize_t numwritten;
>> + char buf[21];
>> +
>> + sprintf(buf, "%lu", num);
>> +
>> + fd = open(path, O_WRONLY);
>> + if (fd == -1)
>> + ksft_exit_fail_msg("%s open failed: %s\n", path, strerror(errno));
>> +
>> + numwritten = write(fd, buf, strlen(buf));
>> + saved_errno = errno;
>> + close(fd);
>> + errno = saved_errno;
>> +
>> + /* Treat EINVAL as a skipped configuration (e.g., unsupported gigantic pages) */
>> + if (numwritten < 0 && errno == EINVAL) {
>> + ksft_print_msg("%s write(%s) failed: %s\n", path, buf, strerror(errno));
>
> Should we even print anything here? Rather confusing. It's just like we cannot
> allocate anything (no memory).
>
> In general, you are copy-pasting a lot of write_num()+write_file() content,
> which is really suboptimal.
>
> All you want is an option for write_num -> write_file to skip on -EINVAL, correct?
>
> There are not that many write_num / write_file users ...
>
Hi David,
Yes, all I need is to ignore the expected -EINVAL when attempting to
configure gigantic hugepages via nr_hugepages.
I looked at extending write_num()/write_file() for this as in v1
(https://lore.kernel.org/all/8bfa921e30eb94072685103f6496784aa23bb166.1782365671.git.sayalip@linux.ibm.com/),
but these helpers are shared by several other selftests.
For example, write_file() is used by split_huge_page_test setup and by
khugepaged tests for drop_caches, and is also used for various THP and
khugepaged settings where -EINVAL would indicate a genuine setup
failure. This concern was also raised during the v1 review.
Because the expected -EINVAL is specific to gigantic hugepage runtime
allocation, I kept the handling local to the hugetlb setup path rather
than changing the semantics of the common helpers.
I also agree that printing a message is not particularly useful in this
case, and we can simply return without emitting any output.
Please let me know if you would prefer a different approach.
Thanks,
Sayali
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 2/3] selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes
2026-06-30 9:32 [PATCH v2 0/3] selftests/mm: avoid false failures in hugetlb and KSM tests Sayali Patil
2026-06-30 9:32 ` [PATCH v2 1/3] selftests/mm: handle EINVAL when configuring gigantic hugepages Sayali Patil
@ 2026-06-30 9:32 ` Sayali Patil
2026-06-30 10:45 ` Sayali Patil
2026-06-30 9:32 ` [PATCH v2 3/3] selftests/mm: fix ternary operator precedence in ksm_tests Sayali Patil
2 siblings, 1 reply; 8+ messages in thread
From: Sayali Patil @ 2026-06-30 9:32 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
The KSM NUMA merge test allocates identical pages on different NUMA
nodes and verifies KSM behavior with merge_across_nodes enabled and
disabled.
On systems with memoryless NUMA nodes, for example:
#numactl -H
available: 2 nodes (0,4)
.....
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
node 0 size: 14825 MB
node 0 free: 1382 MB
node 4 cpus:
node 4 size: 0 MB
node 4 free: 0 MB
the test may attempt to allocate memory on a node without memory,
causing numa_alloc_onnode() to fail and resulting in a spurious test
failure.
The test currently checks numa_num_configured_nodes() to determine
whether sufficient NUMA nodes are available. However, configured nodes
do not necessarily have memory.
Reuse the existing get_first_mem_node() and get_next_mem_node()
helpers to locate NUMA nodes that actually contain memory, and skip
the test when fewer than two such nodes are available.
Before patch:
---------------------------
running ./ksm_tests -N -m 1
---------------------------
mbind: Invalid argument
ok 1 KSM NUMA merging
Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
[PASS]
ok 1 ksm_tests -N -m 1
---------------------------
running ./ksm_tests -N -m 0
---------------------------
mbind: Invalid argument
not ok 1 KSM NUMA merging
Totals: pass:0 fail:1 xfail:0 xpass:0 skip:0 error:0
[FAIL]
not ok 2 ksm_tests -N -m 0 # exit=1
After patch:
---------------------------
running ./ksm_tests -N -m 1
---------------------------
At least 2 NUMA nodes with memory must be available
ok 1
SKIP KSM NUMA merging
Totals: pass:0 fail:0 xfail:0 xpass:0 skip:1 error:0
[PASS]
ok 1 ksm_tests -N -m 1
---------------------------
running ./ksm_tests -N -m 0
---------------------------
At least 2 NUMA nodes with memory must be available
ok 1
SKIP KSM NUMA merging
Totals: pass:0 fail:0 xfail:0 xpass:0 skip:1 error:0
[PASS]
ok 2 ksm_tests -N -m 0
Fixes: e3820ab252dd ("selftest/vm: fix ksm selftest to run with different NUMA topologies")
Co-developed-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
tools/testing/selftests/mm/ksm_tests.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/tools/testing/selftests/mm/ksm_tests.c b/tools/testing/selftests/mm/ksm_tests.c
index a050f4840cfa..2ebbb544c671 100644
--- a/tools/testing/selftests/mm/ksm_tests.c
+++ b/tools/testing/selftests/mm/ksm_tests.c
@@ -440,9 +440,9 @@ static int get_next_mem_node(int node)
mem_node = i % (max_node + 1);
node_size = numa_node_size(mem_node, NULL);
if (node_size > 0)
- break;
+ return mem_node;
}
- return mem_node;
+ return -ENODEV;
}
static int get_first_mem_node(void)
@@ -455,8 +455,8 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeo
{
void *numa1_map_ptr, *numa2_map_ptr;
struct timespec start_time;
+ int first_node, second_node;
int page_count = 2;
- int first_node;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time)) {
ksft_perror("clock_gettime");
@@ -467,17 +467,19 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeo
ksft_print_msg("NUMA support not enabled\n");
return KSFT_SKIP;
}
- if (numa_num_configured_nodes() <= 1) {
- ksft_print_msg("At least 2 NUMA nodes must be available\n");
+ first_node = get_first_mem_node();
+ second_node = get_next_mem_node(first_node);
+
+ if (second_node < 0) {
+ ksft_print_msg("At least 2 NUMA nodes with memory must be available\n");
return KSFT_SKIP;
}
if (ksm_write_sysfs(KSM_FP("merge_across_nodes"), merge_across_nodes))
return KSFT_FAIL;
/* allocate 2 pages in 2 different NUMA nodes and fill them with the same data */
- first_node = get_first_mem_node();
numa1_map_ptr = numa_alloc_onnode(page_size, first_node);
- numa2_map_ptr = numa_alloc_onnode(page_size, get_next_mem_node(first_node));
+ numa2_map_ptr = numa_alloc_onnode(page_size, second_node);
if (!numa1_map_ptr || !numa2_map_ptr) {
ksft_perror("numa_alloc_onnode");
return KSFT_FAIL;
--
2.52.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH v2 2/3] selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes
2026-06-30 9:32 ` [PATCH v2 2/3] selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes Sayali Patil
@ 2026-06-30 10:45 ` Sayali Patil
0 siblings, 0 replies; 8+ messages in thread
From: Sayali Patil @ 2026-06-30 10:45 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote
On 30/06/26 15:02, Sayali Patil wrote:
> The KSM NUMA merge test allocates identical pages on different NUMA
> nodes and verifies KSM behavior with merge_across_nodes enabled and
> disabled.
>
> On systems with memoryless NUMA nodes, for example:
> #numactl -H
> available: 2 nodes (0,4)
> .....
> node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
> node 0 size: 14825 MB
> node 0 free: 1382 MB
> node 4 cpus:
> node 4 size: 0 MB
> node 4 free: 0 MB
>
> the test may attempt to allocate memory on a node without memory,
> causing numa_alloc_onnode() to fail and resulting in a spurious test
> failure.
>
> The test currently checks numa_num_configured_nodes() to determine
> whether sufficient NUMA nodes are available. However, configured nodes
> do not necessarily have memory.
>
> Reuse the existing get_first_mem_node() and get_next_mem_node()
> helpers to locate NUMA nodes that actually contain memory, and skip
> the test when fewer than two such nodes are available.
>
> Before patch:
> ---------------------------
> running ./ksm_tests -N -m 1
> ---------------------------
> mbind: Invalid argument
> ok 1 KSM NUMA merging
> Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
> [PASS]
> ok 1 ksm_tests -N -m 1
> ---------------------------
> running ./ksm_tests -N -m 0
> ---------------------------
> mbind: Invalid argument
> not ok 1 KSM NUMA merging
> Totals: pass:0 fail:1 xfail:0 xpass:0 skip:0 error:0
> [FAIL]
> not ok 2 ksm_tests -N -m 0 # exit=1
>
> After patch:
> ---------------------------
> running ./ksm_tests -N -m 1
> ---------------------------
> At least 2 NUMA nodes with memory must be available
> ok 1
> SKIP KSM NUMA merging
> Totals: pass:0 fail:0 xfail:0 xpass:0 skip:1 error:0
> [PASS]
> ok 1 ksm_tests -N -m 1
> ---------------------------
> running ./ksm_tests -N -m 0
> ---------------------------
> At least 2 NUMA nodes with memory must be available
> ok 1
> SKIP KSM NUMA merging
> Totals: pass:0 fail:0 xfail:0 xpass:0 skip:1 error:0
> [PASS]
> ok 2 ksm_tests -N -m 0
>
> Fixes: e3820ab252dd ("selftest/vm: fix ksm selftest to run with different NUMA topologies")
> Co-developed-by: David Hildenbrand (Arm) <david@kernel.org>
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
> Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
> ---
> tools/testing/selftests/mm/ksm_tests.c | 16 +++++++++-------
> 1 file changed, 9 insertions(+), 7 deletions(-)
>
> diff --git a/tools/testing/selftests/mm/ksm_tests.c b/tools/testing/selftests/mm/ksm_tests.c
> index a050f4840cfa..2ebbb544c671 100644
> --- a/tools/testing/selftests/mm/ksm_tests.c
> +++ b/tools/testing/selftests/mm/ksm_tests.c
> @@ -440,9 +440,9 @@ static int get_next_mem_node(int node)
> mem_node = i % (max_node + 1);
> node_size = numa_node_size(mem_node, NULL);
> if (node_size > 0)
> - break;
> + return mem_node;
> }
> - return mem_node;
> + return -ENODEV;
> }
>
> static int get_first_mem_node(void)
> @@ -455,8 +455,8 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeo
> {
> void *numa1_map_ptr, *numa2_map_ptr;
> struct timespec start_time;
> + int first_node, second_node;
> int page_count = 2;
> - int first_node;
>
> if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time)) {
> ksft_perror("clock_gettime");
> @@ -467,17 +467,19 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeo
> ksft_print_msg("NUMA support not enabled\n");
> return KSFT_SKIP;
> }
> - if (numa_num_configured_nodes() <= 1) {
> - ksft_print_msg("At least 2 NUMA nodes must be available\n");
> + first_node = get_first_mem_node();
> + second_node = get_next_mem_node(first_node);
> +
> + if (second_node < 0) {
> + ksft_print_msg("At least 2 NUMA nodes with memory must be available\n");
> return KSFT_SKIP;
> }
> if (ksm_write_sysfs(KSM_FP("merge_across_nodes"), merge_across_nodes))
> return KSFT_FAIL;
>
> /* allocate 2 pages in 2 different NUMA nodes and fill them with the same data */
> - first_node = get_first_mem_node();
> numa1_map_ptr = numa_alloc_onnode(page_size, first_node);
> - numa2_map_ptr = numa_alloc_onnode(page_size, get_next_mem_node(first_node));
> + numa2_map_ptr = numa_alloc_onnode(page_size, second_node);
> if (!numa1_map_ptr || !numa2_map_ptr) {
> ksft_perror("numa_alloc_onnode");
> return KSFT_FAIL;
AI review comment:
> If get_first_mem_node() doesn't find a node with memory, will it
> return -ENODEV and pass it directly into get_next_mem_node()?
> Looking at get_next_mem_node() with a negative node parameter:
> tools/testing/selftests/mm/ksm_tests.c:get_next_mem_node() {
> ...
> for (i = node + 1; i <= max_node + node; i++) {
> mem_node = i % (max_node + 1);
> node_size = numa_node_size(mem_node, NULL);
> ...
> }
> Because the modulo operator preserves the sign of a negative dividend,
> starting the loop with a negative node value causes mem_node to become
> negative. This means a negative node ID is then passed into libnuma's
> numa_node_size() function.
> Could we check if first_node is valid before attempting to find the
> second node?
The additional check for get_first_mem_node() is not needed. After
numa_available() succeeds, a running system should always have at least
one NUMA node with memory, so get_first_mem_node() is expected to return
a valid node ID. The actual prerequisite for this test is the presence
of two NUMA nodes with memory, which is already validated by checking
the return value of get_next_mem_node().
Thanks,
Sayali
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 3/3] selftests/mm: fix ternary operator precedence in ksm_tests
2026-06-30 9:32 [PATCH v2 0/3] selftests/mm: avoid false failures in hugetlb and KSM tests Sayali Patil
2026-06-30 9:32 ` [PATCH v2 1/3] selftests/mm: handle EINVAL when configuring gigantic hugepages Sayali Patil
2026-06-30 9:32 ` [PATCH v2 2/3] selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes Sayali Patil
@ 2026-06-30 9:32 ` Sayali Patil
2026-06-30 10:33 ` David Hildenbrand (Arm)
2 siblings, 1 reply; 8+ messages in thread
From: Sayali Patil @ 2026-06-30 9:32 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
The KSM selftest uses conditional expressions to skip accesses to
merge_across_nodes on systems without NUMA support. However, the
ternary operator is combined with logical OR without parentheses:
a || numa_available() ? 0 : b || c
Due to operator precedence rules, this is parsed as:
(a || numa_available()) ? 0 : (b || c)
instead of the intended:
a || (numa_available() ? 0 : b) || c
Add parentheses around the conditional expressions to ensure the
correct evaluation order.
Fixes: 9aa1af954db0 ("selftests: vm: check numa_available() before operating "merge_across_nodes" in ksm_tests")
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
tools/testing/selftests/mm/ksm_tests.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/tools/testing/selftests/mm/ksm_tests.c b/tools/testing/selftests/mm/ksm_tests.c
index 2ebbb544c671..5fd7792a0d47 100644
--- a/tools/testing/selftests/mm/ksm_tests.c
+++ b/tools/testing/selftests/mm/ksm_tests.c
@@ -288,8 +288,8 @@ static bool assert_ksm_pages_count(long dupl_page_count)
static int ksm_save_def(struct ksm_sysfs *ksm_sysfs)
{
if (ksm_read_sysfs(KSM_FP("max_page_sharing"), &ksm_sysfs->max_page_sharing) ||
- numa_available() ? 0 :
- ksm_read_sysfs(KSM_FP("merge_across_nodes"), &ksm_sysfs->merge_across_nodes) ||
+ (numa_available() ? 0 :
+ ksm_read_sysfs(KSM_FP("merge_across_nodes"), &ksm_sysfs->merge_across_nodes)) ||
ksm_read_sysfs(KSM_FP("sleep_millisecs"), &ksm_sysfs->sleep_millisecs) ||
ksm_read_sysfs(KSM_FP("pages_to_scan"), &ksm_sysfs->pages_to_scan) ||
ksm_read_sysfs(KSM_FP("run"), &ksm_sysfs->run) ||
@@ -304,8 +304,8 @@ static int ksm_save_def(struct ksm_sysfs *ksm_sysfs)
static int ksm_restore(struct ksm_sysfs *ksm_sysfs)
{
if (ksm_write_sysfs(KSM_FP("max_page_sharing"), ksm_sysfs->max_page_sharing) ||
- numa_available() ? 0 :
- ksm_write_sysfs(KSM_FP("merge_across_nodes"), ksm_sysfs->merge_across_nodes) ||
+ (numa_available() ? 0 :
+ ksm_write_sysfs(KSM_FP("merge_across_nodes"), ksm_sysfs->merge_across_nodes)) ||
ksm_write_sysfs(KSM_FP("pages_to_scan"), ksm_sysfs->pages_to_scan) ||
ksm_write_sysfs(KSM_FP("run"), ksm_sysfs->run) ||
ksm_write_sysfs(KSM_FP("sleep_millisecs"), ksm_sysfs->sleep_millisecs) ||
@@ -846,8 +846,8 @@ int main(int argc, char *argv[])
if (ksm_write_sysfs(KSM_FP("run"), 2) ||
ksm_write_sysfs(KSM_FP("sleep_millisecs"), 0) ||
- numa_available() ? 0 :
- ksm_write_sysfs(KSM_FP("merge_across_nodes"), 1) ||
+ (numa_available() ? 0 :
+ ksm_write_sysfs(KSM_FP("merge_across_nodes"), 1)) ||
ksm_write_sysfs(KSM_FP("pages_to_scan"), page_count))
ksft_exit_fail_msg("Cannot set up KSM tunables\n");
--
2.52.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH v2 3/3] selftests/mm: fix ternary operator precedence in ksm_tests
2026-06-30 9:32 ` [PATCH v2 3/3] selftests/mm: fix ternary operator precedence in ksm_tests Sayali Patil
@ 2026-06-30 10:33 ` David Hildenbrand (Arm)
0 siblings, 0 replies; 8+ messages in thread
From: David Hildenbrand (Arm) @ 2026-06-30 10:33 UTC (permalink / raw)
To: Sayali Patil, Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: Zi Yan, Michal Hocko, Oscar Salvador, Lorenzo Stoakes, Dev Jain,
Liam.Howlett, linuxppc-dev, Miaohe Lin, Venkat Rao Bagalkote
On 6/30/26 11:32, Sayali Patil wrote:
> The KSM selftest uses conditional expressions to skip accesses to
> merge_across_nodes on systems without NUMA support. However, the
> ternary operator is combined with logical OR without parentheses:
>
> a || numa_available() ? 0 : b || c
>
> Due to operator precedence rules, this is parsed as:
>
> (a || numa_available()) ? 0 : (b || c)
>
> instead of the intended:
>
> a || (numa_available() ? 0 : b) || c
>
> Add parentheses around the conditional expressions to ensure the
> correct evaluation order.
>
> Fixes: 9aa1af954db0 ("selftests: vm: check numa_available() before operating "merge_across_nodes" in ksm_tests")
> Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
> ---
LGTM, although the code is a bit ugly (already before your changes).
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
--
Cheers,
David
^ permalink raw reply [flat|nested] 8+ messages in thread