* [PATCH v4 0/3] selftests/mm: TAP output and global-state fixes
@ 2026-08-25 8:57 Song Hu
2026-08-25 8:57 ` [PATCH v4 1/3] selftests/mm: emit TAP header in uffd-wp-mremap Song Hu
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Song Hu @ 2026-08-25 8:57 UTC (permalink / raw)
To: akpm, usama.anjum
Cc: linux-mm, shuah, david, ljs, liam, vbabka, rppt, surenb, mhocko,
peterx, sarthak.sharma, linux-kselftest, linux-kernel, Song Hu
uffd-wp-mremap and mremap_test never print the TAP header (and mremap_test
skips with a bare exit(KSFT_SKIP) rather than a KTAP skip), so their output
is not valid KTAP; hugetlb-soft-offline toggles enable_soft_offline during
the run and leaves it disabled afterwards.
Tested on x86_64.
Song Hu (3):
selftests/mm: emit TAP header in uffd-wp-mremap
selftests/mm: emit TAP header and use TAP skip in mremap_test
selftests/mm: restore enable_soft_offline in hugetlb-soft-offline
tools/testing/selftests/mm/hugetlb-soft-offline.c | 49 +++++++++++++----------
tools/testing/selftests/mm/mremap_test.c | 43 +++++++++++++---------
tools/testing/selftests/mm/uffd-wp-mremap.c | 2 +
3 files changed, 55 insertions(+), 39 deletions(-)
---
Changes in v4, per review of v3 patch 3/3:
- hugetlb-soft-offline: the atexit restore handler no longer uses
write_num(); on failure it re-enters exit() through
ksft_exit_fail_msg(), undefined behavior from inside an atexit
handler. Restore with plain open()/write(), best effort.
Changes in v3, per Usama Anjum's review of v2 patch 2/3:
- mremap_test: cache mmap_min_addr in main() before ksft_set_plan(),
so the skip paths in get_mmap_min_addr() are taken before the plan
is set; a skip after the plan leaves the run with fewer tests than
planned.
Changes in v2, per review feedback from Mike Rapoport, Sarthak Sharma and
the Sashiko AI review Andrew Morton pointed at:
- mremap_test: save errno before fclose() in get_mmap_min_addr() so
strerror() reports the actual failure, and split the ksft_*() messages
embedding "\n\t" so continuation lines get the "# " prefix.
- hugetlb-soft-offline: restore enable_soft_offline from an atexit()
handler so it also runs on early exits, and use read_num()/write_num()
from vm_util instead of the hand-rolled helpers.
v3: https://lore.kernel.org/all/20260820061426.356869-1-husong@kylinos.cn/
v2: https://lore.kernel.org/all/20260815080716.3596514-1-husong@kylinos.cn/
v1: https://lore.kernel.org/all/20260812120821.523860-1-husong@kylinos.cn/
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 1/3] selftests/mm: emit TAP header in uffd-wp-mremap
2026-08-25 8:57 [PATCH v4 0/3] selftests/mm: TAP output and global-state fixes Song Hu
@ 2026-08-25 8:57 ` Song Hu
2026-09-10 9:28 ` David Hildenbrand (Arm)
2026-08-25 8:57 ` [PATCH v4 2/3] selftests/mm: emit TAP header and use TAP skip in mremap_test Song Hu
2026-08-25 8:57 ` [PATCH v4 3/3] selftests/mm: restore enable_soft_offline in hugetlb-soft-offline Song Hu
2 siblings, 1 reply; 9+ messages in thread
From: Song Hu @ 2026-08-25 8:57 UTC (permalink / raw)
To: akpm, usama.anjum
Cc: linux-mm, shuah, david, ljs, liam, vbabka, rppt, surenb, mhocko,
peterx, sarthak.sharma, linux-kselftest, linux-kernel, Song Hu
uffd-wp-mremap calls ksft_set_plan() without ksft_print_header(), so its
output is not valid KTAP. Add the header, like the sibling uffd tests
(uffd-stress, uffd-unit-tests).
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Reviewed-by: Sarthak Sharma <sarthak.sharma@arm.com>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Signed-off-by: Song Hu <husong@kylinos.cn>
---
tools/testing/selftests/mm/uffd-wp-mremap.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tools/testing/selftests/mm/uffd-wp-mremap.c b/tools/testing/selftests/mm/uffd-wp-mremap.c
index c973d6722720..572c2516e874 100644
--- a/tools/testing/selftests/mm/uffd-wp-mremap.c
+++ b/tools/testing/selftests/mm/uffd-wp-mremap.c
@@ -347,6 +347,8 @@ int main(int argc, char **argv)
struct thp_settings settings;
int i, j, plan = 0;
+ ksft_print_header();
+
hugepage_save_settings(true, true);
check_uffd_wp_feature_supported();
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 2/3] selftests/mm: emit TAP header and use TAP skip in mremap_test
2026-08-25 8:57 [PATCH v4 0/3] selftests/mm: TAP output and global-state fixes Song Hu
2026-08-25 8:57 ` [PATCH v4 1/3] selftests/mm: emit TAP header in uffd-wp-mremap Song Hu
@ 2026-08-25 8:57 ` Song Hu
2026-09-10 9:33 ` David Hildenbrand (Arm)
2026-08-25 8:57 ` [PATCH v4 3/3] selftests/mm: restore enable_soft_offline in hugetlb-soft-offline Song Hu
2 siblings, 1 reply; 9+ messages in thread
From: Song Hu @ 2026-08-25 8:57 UTC (permalink / raw)
To: akpm, usama.anjum
Cc: linux-mm, shuah, david, ljs, liam, vbabka, rppt, surenb, mhocko,
peterx, sarthak.sharma, linux-kselftest, linux-kernel, Song Hu
mremap_test calls ksft_set_plan() without ksft_print_header(), and its
get_mmap_min_addr() skip path uses a bare exit(KSFT_SKIP) that prints no
TAP line, so its output is not valid KTAP. Add the header and switch
the skip to ksft_exit_skip().
Also fix two more KTAP compliance issues spotted in review:
- get_mmap_min_addr() calls strerror(errno) after fclose(), which may
clobber errno; save errno before fclose() instead.
- Some ksft_*() messages embed "\n\t", so the text after each embedded
newline is printed without the "# " prefix. Split those into separate
messages.
And cache mmap_min_addr in main() before ksft_set_plan(), so that the
skip paths in get_mmap_min_addr() are taken before the plan is set; a
skip after the plan leaves the run with fewer tests than planned.
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Reviewed-by: Sarthak Sharma <sarthak.sharma@arm.com>
Reviewed-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: Song Hu <husong@kylinos.cn>
---
tools/testing/selftests/mm/mremap_test.c | 43 ++++++++++++++----------
1 file changed, 25 insertions(+), 18 deletions(-)
diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
index 131d9d6db867..ab5420f2e875 100644
--- a/tools/testing/selftests/mm/mremap_test.c
+++ b/tools/testing/selftests/mm/mremap_test.c
@@ -111,18 +111,17 @@ static unsigned long long get_mmap_min_addr(void)
return addr;
fp = fopen("/proc/sys/vm/mmap_min_addr", "r");
- if (fp == NULL) {
- ksft_print_msg("Failed to open /proc/sys/vm/mmap_min_addr: %s\n",
- strerror(errno));
- exit(KSFT_SKIP);
- }
+ if (!fp)
+ ksft_exit_skip("Failed to open /proc/sys/vm/mmap_min_addr: %s\n",
+ strerror(errno));
n_matched = fscanf(fp, "%llu", &addr);
if (n_matched != 1) {
- ksft_print_msg("Failed to read /proc/sys/vm/mmap_min_addr: %s\n",
- strerror(errno));
+ int err = errno;
+
fclose(fp);
- exit(KSFT_SKIP);
+ ksft_exit_skip("Failed to read /proc/sys/vm/mmap_min_addr: %s\n",
+ strerror(err));
}
fclose(fp);
@@ -1164,10 +1163,11 @@ static void run_mremap_test_case(struct test test_case, int *failures,
rand_addr);
if (remap_time < 0) {
- if (test_case.expect_failure)
- ksft_test_result_xfail("%s\n\tExpected mremap failure\n",
- test_case.name);
- else {
+ if (test_case.expect_failure) {
+ ksft_print_msg("%s: expected mremap failure\n",
+ test_case.name);
+ ksft_test_result_xfail("%s\n", test_case.name);
+ } else {
ksft_test_result_fail("%s\n", test_case.name);
*failures += 1;
}
@@ -1177,11 +1177,13 @@ static void run_mremap_test_case(struct test test_case, int *failures,
* was faulted in.
*/
if (threshold_mb == VALIDATION_NO_THRESHOLD ||
- test_case.config.region_size <= threshold_mb * _1MB)
- ksft_test_result_pass("%s\n\tmremap time: %12lldns\n",
- test_case.name, remap_time);
- else
+ test_case.config.region_size <= threshold_mb * _1MB) {
+ ksft_print_msg("%s: mremap time: %12lldns\n",
+ test_case.name, remap_time);
ksft_test_result_pass("%s\n", test_case.name);
+ } else {
+ ksft_test_result_pass("%s\n", test_case.name);
+ }
}
}
@@ -1250,13 +1252,18 @@ int main(int argc, char **argv)
time_t t;
FILE *maps_fp;
+ ksft_print_header();
+
+ get_mmap_min_addr();
+
pattern_seed = (unsigned int) time(&t);
if (parse_args(argc, argv, &threshold_mb, &pattern_seed) < 0)
exit(EXIT_FAILURE);
- ksft_print_msg("Test configs:\n\tthreshold_mb=%u\n\tpattern_seed=%u\n\n",
- threshold_mb, pattern_seed);
+ ksft_print_msg("Test configs:\n");
+ ksft_print_msg("threshold_mb=%u\n", threshold_mb);
+ ksft_print_msg("pattern_seed=%u\n", pattern_seed);
/*
* set preallocated random array according to test configs; see the
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 3/3] selftests/mm: restore enable_soft_offline in hugetlb-soft-offline
2026-08-25 8:57 [PATCH v4 0/3] selftests/mm: TAP output and global-state fixes Song Hu
2026-08-25 8:57 ` [PATCH v4 1/3] selftests/mm: emit TAP header in uffd-wp-mremap Song Hu
2026-08-25 8:57 ` [PATCH v4 2/3] selftests/mm: emit TAP header and use TAP skip in mremap_test Song Hu
@ 2026-08-25 8:57 ` Song Hu
2026-08-25 9:06 ` Song Hu
` (2 more replies)
2 siblings, 3 replies; 9+ messages in thread
From: Song Hu @ 2026-08-25 8:57 UTC (permalink / raw)
To: akpm, usama.anjum
Cc: linux-mm, shuah, david, ljs, liam, vbabka, rppt, surenb, mhocko,
peterx, sarthak.sharma, linux-kselftest, linux-kernel, Song Hu
hugetlb-soft-offline toggles /proc/sys/vm/enable_soft_offline between 1
and 0 (test_soft_offline_common(1) then (0)) and leaves it at 0 when it
finishes, silently disabling soft offlining for the whole system after
the run.
Save the original value before the test and restore it from an
atexit() handler, as hugepage_restore_settings_atexit() in
hugepage_settings.c already does. Use read_num()/write_num() from
vm_util instead of hand-rolled popen()/fopen() helpers.
The restore handler must not call write_num(): on failure it
re-enters exit() through ksft_exit_fail_msg(), which is undefined
behavior from inside an atexit handler. A non-root run hits it
directly - the restore write fails the same way the write that
triggered the exit did. Restore with plain open()/write(), best
effort.
Signed-off-by: Song Hu <husong@kylinos.cn>
---
Changes since v3: the restore handler no longer uses write_num(),
whose failure path calls exit() from inside an atexit handler -
undefined behavior on a non-root run. Restore with plain
open()/write(), best effort.
.../selftests/mm/hugetlb-soft-offline.c | 49 +++++++++++--------
1 file changed, 28 insertions(+), 21 deletions(-)
diff --git a/tools/testing/selftests/mm/hugetlb-soft-offline.c b/tools/testing/selftests/mm/hugetlb-soft-offline.c
index bc202e4ed2bd..4af9d3db7b5b 100644
--- a/tools/testing/selftests/mm/hugetlb-soft-offline.c
+++ b/tools/testing/selftests/mm/hugetlb-soft-offline.c
@@ -11,6 +11,7 @@
#define _GNU_SOURCE
#include <errno.h>
+#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -23,6 +24,7 @@
#include <sys/types.h>
#include "kselftest.h"
+#include "vm_util.h"
#include "hugepage_settings.h"
#ifndef MADV_SOFT_OFFLINE
@@ -31,6 +33,8 @@
#define EPREFIX " !!! "
+#define ENABLE_SOFT_OFFLINE_PATH "/proc/sys/vm/enable_soft_offline"
+
static int do_soft_offline(int fd, size_t len, int expect_errno)
{
char *filemap = NULL;
@@ -77,26 +81,29 @@ static int do_soft_offline(int fd, size_t len, int expect_errno)
return ret;
}
-static int set_enable_soft_offline(int value)
-{
- char cmd[256] = {0};
- FILE *cmdfile = NULL;
-
- if (value != 0 && value != 1)
- return -EINVAL;
+static unsigned long orig_enable_soft_offline = -1UL;
- sprintf(cmd, "echo %d > /proc/sys/vm/enable_soft_offline", value);
- cmdfile = popen(cmd, "r");
+/*
+ * Runs from an atexit handler, so it must not call anything that
+ * exits on failure: write_num() would re-enter exit() through
+ * ksft_exit_fail_msg().
+ */
+static void restore_enable_soft_offline(void)
+{
+ char buf[24];
+ int fd, len;
- if (cmdfile)
- ksft_print_msg("enable_soft_offline => %d\n", value);
- else {
- ksft_perror(EPREFIX "failed to set enable_soft_offline");
- return errno;
- }
+ if (orig_enable_soft_offline == -1UL)
+ return;
- pclose(cmdfile);
- return 0;
+ len = snprintf(buf, sizeof(buf), "%lu", orig_enable_soft_offline);
+ fd = open(ENABLE_SOFT_OFFLINE_PATH, O_WRONLY);
+ if (fd < 0)
+ return;
+ if (write(fd, buf, len) != len)
+ ksft_print_msg("failed to restore enable_soft_offline: %s\n",
+ strerror(errno));
+ close(fd);
}
static int create_hugetlbfs_file(struct statfs *file_stat)
@@ -145,10 +152,7 @@ static void test_soft_offline_common(int enable_soft_offline)
hugepagesize_kb = file_stat.f_bsize / 1024;
ksft_print_msg("Hugepagesize is %ldkB\n", hugepagesize_kb);
- if (set_enable_soft_offline(enable_soft_offline) != 0) {
- close(fd);
- ksft_exit_fail_msg("Failed to set enable_soft_offline\n");
- }
+ write_num(ENABLE_SOFT_OFFLINE_PATH, enable_soft_offline);
nr_hugepages_before = hugetlb_nr_default_pages();
@@ -192,6 +196,9 @@ int main(int argc, char **argv)
ksft_set_plan(2);
+ orig_enable_soft_offline = read_num(ENABLE_SOFT_OFFLINE_PATH);
+ atexit(restore_enable_soft_offline);
+
test_soft_offline_common(1);
test_soft_offline_common(0);
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 3/3] selftests/mm: restore enable_soft_offline in hugetlb-soft-offline
2026-08-25 8:57 ` [PATCH v4 3/3] selftests/mm: restore enable_soft_offline in hugetlb-soft-offline Song Hu
@ 2026-08-25 9:06 ` Song Hu
2026-08-25 9:24 ` Muhammad Usama Anjum
2026-09-10 9:36 ` David Hildenbrand (Arm)
2 siblings, 0 replies; 9+ messages in thread
From: Song Hu @ 2026-08-25 9:06 UTC (permalink / raw)
To: akpm, usama.anjum
Cc: husong, linux-mm, shuah, david, ljs, liam, vbabka, rppt, surenb,
mhocko, peterx, sarthak.sharma, linux-kselftest, linux-kernel
Hi Usama,
在 2026/8/25 16:57, Song Hu 写道:
> hugetlb-soft-offline toggles /proc/sys/vm/enable_soft_offline between 1
> and 0 (test_soft_offline_common(1) then (0)) and leaves it at 0 when it
> finishes, silently disabling soft offlining for the whole system after
> the run.
>
> Save the original value before the test and restore it from an
> atexit() handler, as hugepage_restore_settings_atexit() in
> hugepage_settings.c already does. Use read_num()/write_num() from
> vm_util instead of hand-rolled popen()/fopen() helpers.
>
> The restore handler must not call write_num(): on failure it
> re-enters exit() through ksft_exit_fail_msg(), which is undefined
> behavior from inside an atexit handler. A non-root run hits it
> directly - the restore write fails the same way the write that
> triggered the exit did. Restore with plain open()/write(), best
> effort.
>
Just a note on patch 3/3: v4 changed the restore handler, so your
Reviewed-by/Tested-by no longer apply and were dropped.
write_num() calls ksft_exit_fail_msg() on failure, which re-enters
exit() from inside the atexit handler - undefined behavior that a
non-root run hits directly. v4 restores with plain open()/write()
instead. Verified on 7.2.0-rc7-next-20260810: 2/2 pass and the sysctl
is restored afterwards.
Would you mind taking another look when you have time?
Thanks,
Song
> Signed-off-by: Song Hu <husong@kylinos.cn>
>
> ---
>
> Changes since v3: the restore handler no longer uses write_num(),
> whose failure path calls exit() from inside an atexit handler -
> undefined behavior on a non-root run. Restore with plain
> open()/write(), best effort.
>
> .../selftests/mm/hugetlb-soft-offline.c | 49 +++++++++++--------
> 1 file changed, 28 insertions(+), 21 deletions(-)
>
> diff --git a/tools/testing/selftests/mm/hugetlb-soft-offline.c b/tools/testing/selftests/mm/hugetlb-soft-offline.c
> index bc202e4ed2bd..4af9d3db7b5b 100644
> --- a/tools/testing/selftests/mm/hugetlb-soft-offline.c
> +++ b/tools/testing/selftests/mm/hugetlb-soft-offline.c
> @@ -11,6 +11,7 @@
>
> #define _GNU_SOURCE
> #include <errno.h>
> +#include <fcntl.h>
> #include <stdlib.h>
> #include <stdio.h>
> #include <string.h>
> @@ -23,6 +24,7 @@
> #include <sys/types.h>
>
> #include "kselftest.h"
> +#include "vm_util.h"
> #include "hugepage_settings.h"
>
> #ifndef MADV_SOFT_OFFLINE
> @@ -31,6 +33,8 @@
>
> #define EPREFIX " !!! "
>
> +#define ENABLE_SOFT_OFFLINE_PATH "/proc/sys/vm/enable_soft_offline"
> +
> static int do_soft_offline(int fd, size_t len, int expect_errno)
> {
> char *filemap = NULL;
> @@ -77,26 +81,29 @@ static int do_soft_offline(int fd, size_t len, int expect_errno)
> return ret;
> }
>
> -static int set_enable_soft_offline(int value)
> -{
> - char cmd[256] = {0};
> - FILE *cmdfile = NULL;
> -
> - if (value != 0 && value != 1)
> - return -EINVAL;
> +static unsigned long orig_enable_soft_offline = -1UL;
>
> - sprintf(cmd, "echo %d > /proc/sys/vm/enable_soft_offline", value);
> - cmdfile = popen(cmd, "r");
> +/*
> + * Runs from an atexit handler, so it must not call anything that
> + * exits on failure: write_num() would re-enter exit() through
> + * ksft_exit_fail_msg().
> + */
> +static void restore_enable_soft_offline(void)
> +{
> + char buf[24];
> + int fd, len;
>
> - if (cmdfile)
> - ksft_print_msg("enable_soft_offline => %d\n", value);
> - else {
> - ksft_perror(EPREFIX "failed to set enable_soft_offline");
> - return errno;
> - }
> + if (orig_enable_soft_offline == -1UL)
> + return;
>
> - pclose(cmdfile);
> - return 0;
> + len = snprintf(buf, sizeof(buf), "%lu", orig_enable_soft_offline);
> + fd = open(ENABLE_SOFT_OFFLINE_PATH, O_WRONLY);
> + if (fd < 0)
> + return;
> + if (write(fd, buf, len) != len)
> + ksft_print_msg("failed to restore enable_soft_offline: %s\n",
> + strerror(errno));
> + close(fd);
> }
>
> static int create_hugetlbfs_file(struct statfs *file_stat)
> @@ -145,10 +152,7 @@ static void test_soft_offline_common(int enable_soft_offline)
> hugepagesize_kb = file_stat.f_bsize / 1024;
> ksft_print_msg("Hugepagesize is %ldkB\n", hugepagesize_kb);
>
> - if (set_enable_soft_offline(enable_soft_offline) != 0) {
> - close(fd);
> - ksft_exit_fail_msg("Failed to set enable_soft_offline\n");
> - }
> + write_num(ENABLE_SOFT_OFFLINE_PATH, enable_soft_offline);
>
> nr_hugepages_before = hugetlb_nr_default_pages();
>
> @@ -192,6 +196,9 @@ int main(int argc, char **argv)
>
> ksft_set_plan(2);
>
> + orig_enable_soft_offline = read_num(ENABLE_SOFT_OFFLINE_PATH);
> + atexit(restore_enable_soft_offline);
> +
> test_soft_offline_common(1);
> test_soft_offline_common(0);
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 3/3] selftests/mm: restore enable_soft_offline in hugetlb-soft-offline
2026-08-25 8:57 ` [PATCH v4 3/3] selftests/mm: restore enable_soft_offline in hugetlb-soft-offline Song Hu
2026-08-25 9:06 ` Song Hu
@ 2026-08-25 9:24 ` Muhammad Usama Anjum
2026-09-10 9:36 ` David Hildenbrand (Arm)
2 siblings, 0 replies; 9+ messages in thread
From: Muhammad Usama Anjum @ 2026-08-25 9:24 UTC (permalink / raw)
To: Song Hu
Cc: usama.anjum, linux-mm, shuah, david, ljs, liam, vbabka, rppt,
surenb, mhocko, peterx, sarthak.sharma, linux-kselftest,
linux-kernel, akpm
On 25/08/2026 9:57 am, Song Hu wrote:
> hugetlb-soft-offline toggles /proc/sys/vm/enable_soft_offline between 1
> and 0 (test_soft_offline_common(1) then (0)) and leaves it at 0 when it
> finishes, silently disabling soft offlining for the whole system after
> the run.
>
> Save the original value before the test and restore it from an
> atexit() handler, as hugepage_restore_settings_atexit() in
> hugepage_settings.c already does. Use read_num()/write_num() from
> vm_util instead of hand-rolled popen()/fopen() helpers.
>
> The restore handler must not call write_num(): on failure it
> re-enters exit() through ksft_exit_fail_msg(), which is undefined
> behavior from inside an atexit handler. A non-root run hits it
> directly - the restore write fails the same way the write that
> triggered the exit did. Restore with plain open()/write(), best
> effort.
>
> Signed-off-by: Song Hu <husong@kylinos.cn>
>
> ---
>
> Changes since v3: the restore handler no longer uses write_num(),
> whose failure path calls exit() from inside an atexit handler -
> undefined behavior on a non-root run. Restore with plain
> open()/write(), best effort.
>
> .../selftests/mm/hugetlb-soft-offline.c | 49 +++++++++++--------
> 1 file changed, 28 insertions(+), 21 deletions(-)
>
> diff --git a/tools/testing/selftests/mm/hugetlb-soft-offline.c b/tools/testing/selftests/mm/hugetlb-soft-offline.c
> index bc202e4ed2bd..4af9d3db7b5b 100644
> --- a/tools/testing/selftests/mm/hugetlb-soft-offline.c
> +++ b/tools/testing/selftests/mm/hugetlb-soft-offline.c
> @@ -11,6 +11,7 @@
>
> #define _GNU_SOURCE
> #include <errno.h>
> +#include <fcntl.h>
> #include <stdlib.h>
> #include <stdio.h>
> #include <string.h>
> @@ -23,6 +24,7 @@
> #include <sys/types.h>
>
> #include "kselftest.h"
> +#include "vm_util.h"
> #include "hugepage_settings.h"
>
> #ifndef MADV_SOFT_OFFLINE
> @@ -31,6 +33,8 @@
>
> #define EPREFIX " !!! "
>
> +#define ENABLE_SOFT_OFFLINE_PATH "/proc/sys/vm/enable_soft_offline"
> +
> static int do_soft_offline(int fd, size_t len, int expect_errno)
> {
> char *filemap = NULL;
> @@ -77,26 +81,29 @@ static int do_soft_offline(int fd, size_t len, int expect_errno)
> return ret;
> }
>
> -static int set_enable_soft_offline(int value)
> -{
> - char cmd[256] = {0};
> - FILE *cmdfile = NULL;
> -
> - if (value != 0 && value != 1)
> - return -EINVAL;
> +static unsigned long orig_enable_soft_offline = -1UL;
>
> - sprintf(cmd, "echo %d > /proc/sys/vm/enable_soft_offline", value);
> - cmdfile = popen(cmd, "r");
> +/*
> + * Runs from an atexit handler, so it must not call anything that
> + * exits on failure: write_num() would re-enter exit() through
> + * ksft_exit_fail_msg().
> + */
> +static void restore_enable_soft_offline(void)
> +{
> + char buf[24];
> + int fd, len;
>
> - if (cmdfile)
> - ksft_print_msg("enable_soft_offline => %d\n", value);
> - else {
> - ksft_perror(EPREFIX "failed to set enable_soft_offline");
> - return errno;
> - }
> + if (orig_enable_soft_offline == -1UL)
> + return;
>
> - pclose(cmdfile);
> - return 0;
> + len = snprintf(buf, sizeof(buf), "%lu", orig_enable_soft_offline);
> + fd = open(ENABLE_SOFT_OFFLINE_PATH, O_WRONLY);
> + if (fd < 0)
> + return;
> + if (write(fd, buf, len) != len)
> + ksft_print_msg("failed to restore enable_soft_offline: %s\n",
> + strerror(errno));
> + close(fd);
> }
Looks good.
Reviewed-by: Muhammad Usama Anjum <usama.anjum@arm.com>
>
> static int create_hugetlbfs_file(struct statfs *file_stat)
> @@ -145,10 +152,7 @@ static void test_soft_offline_common(int enable_soft_offline)
> hugepagesize_kb = file_stat.f_bsize / 1024;
> ksft_print_msg("Hugepagesize is %ldkB\n", hugepagesize_kb);
>
> - if (set_enable_soft_offline(enable_soft_offline) != 0) {
> - close(fd);
> - ksft_exit_fail_msg("Failed to set enable_soft_offline\n");
> - }
> + write_num(ENABLE_SOFT_OFFLINE_PATH, enable_soft_offline);
>
> nr_hugepages_before = hugetlb_nr_default_pages();
>
> @@ -192,6 +196,9 @@ int main(int argc, char **argv)
>
> ksft_set_plan(2);
>
> + orig_enable_soft_offline = read_num(ENABLE_SOFT_OFFLINE_PATH);
> + atexit(restore_enable_soft_offline);
> +
> test_soft_offline_common(1);
> test_soft_offline_common(0);
>
--
Thanks,
Usama
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/3] selftests/mm: emit TAP header in uffd-wp-mremap
2026-08-25 8:57 ` [PATCH v4 1/3] selftests/mm: emit TAP header in uffd-wp-mremap Song Hu
@ 2026-09-10 9:28 ` David Hildenbrand (Arm)
0 siblings, 0 replies; 9+ messages in thread
From: David Hildenbrand (Arm) @ 2026-09-10 9:28 UTC (permalink / raw)
To: Song Hu, akpm, usama.anjum
Cc: linux-mm, shuah, ljs, liam, vbabka, rppt, surenb, mhocko, peterx,
sarthak.sharma, linux-kselftest, linux-kernel
On 8/25/26 10:57, Song Hu wrote:
> uffd-wp-mremap calls ksft_set_plan() without ksft_print_header(), so its
> output is not valid KTAP. Add the header, like the sibling uffd tests
> (uffd-stress, uffd-unit-tests).
>
> Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> Reviewed-by: Sarthak Sharma <sarthak.sharma@arm.com>
> Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> Reviewed-by: Muhammad Usama Anjum <usama.anjum@arm.com>
> Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
> Signed-off-by: Song Hu <husong@kylinos.cn>
> ---
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
--
Cheers,
David
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/3] selftests/mm: emit TAP header and use TAP skip in mremap_test
2026-08-25 8:57 ` [PATCH v4 2/3] selftests/mm: emit TAP header and use TAP skip in mremap_test Song Hu
@ 2026-09-10 9:33 ` David Hildenbrand (Arm)
0 siblings, 0 replies; 9+ messages in thread
From: David Hildenbrand (Arm) @ 2026-09-10 9:33 UTC (permalink / raw)
To: Song Hu, akpm, usama.anjum
Cc: linux-mm, shuah, ljs, liam, vbabka, rppt, surenb, mhocko, peterx,
sarthak.sharma, linux-kselftest, linux-kernel
On 8/25/26 10:57, Song Hu wrote:
> mremap_test calls ksft_set_plan() without ksft_print_header(), and its
> get_mmap_min_addr() skip path uses a bare exit(KSFT_SKIP) that prints no
> TAP line, so its output is not valid KTAP. Add the header and switch
> the skip to ksft_exit_skip().
>
> Also fix two more KTAP compliance issues spotted in review:
>
> - get_mmap_min_addr() calls strerror(errno) after fclose(), which may
> clobber errno; save errno before fclose() instead.
>
> - Some ksft_*() messages embed "\n\t", so the text after each embedded
> newline is printed without the "# " prefix. Split those into separate
> messages.
>
> And cache mmap_min_addr in main() before ksft_set_plan(), so that the
> skip paths in get_mmap_min_addr() are taken before the plan is set; a
> skip after the plan leaves the run with fewer tests than planned.
>
> Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> Reviewed-by: Sarthak Sharma <sarthak.sharma@arm.com>
> Reviewed-by: Muhammad Usama Anjum <usama.anjum@arm.com>
> Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
> Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> Signed-off-by: Song Hu <husong@kylinos.cn>
> ---
> tools/testing/selftests/mm/mremap_test.c | 43 ++++++++++++++----------
> 1 file changed, 25 insertions(+), 18 deletions(-)
>
> diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
> index 131d9d6db867..ab5420f2e875 100644
> --- a/tools/testing/selftests/mm/mremap_test.c
> +++ b/tools/testing/selftests/mm/mremap_test.c
> @@ -111,18 +111,17 @@ static unsigned long long get_mmap_min_addr(void)
> return addr;
>
> fp = fopen("/proc/sys/vm/mmap_min_addr", "r");
> - if (fp == NULL) {
> - ksft_print_msg("Failed to open /proc/sys/vm/mmap_min_addr: %s\n",
> - strerror(errno));
> - exit(KSFT_SKIP);
> - }
> + if (!fp)
> + ksft_exit_skip("Failed to open /proc/sys/vm/mmap_min_addr: %s\n",
> + strerror(errno));
>
> n_matched = fscanf(fp, "%llu", &addr);
> if (n_matched != 1) {
> - ksft_print_msg("Failed to read /proc/sys/vm/mmap_min_addr: %s\n",
> - strerror(errno));
> + int err = errno;
> +
> fclose(fp);
Why the local variable? And why the fclose() ?
ksft_exit_skip() will just exit the process and clean up, why clean up manually?
In other words, why not just drop the fclose?
> - exit(KSFT_SKIP);
> + ksft_exit_skip("Failed to read /proc/sys/vm/mmap_min_addr: %s\n",
> + strerror(err));
> }
>
> fclose(fp);
> @@ -1164,10 +1163,11 @@ static void run_mremap_test_case(struct test test_case, int *failures,
> rand_addr);
>
> if (remap_time < 0) {
> - if (test_case.expect_failure)
> - ksft_test_result_xfail("%s\n\tExpected mremap failure\n",
> - test_case.name);
Why can't we just drop the \n\t ?
> - else {
> + if (test_case.expect_failure) {
> + ksft_print_msg("%s: expected mremap failure\n",
> + test_case.name);
> + ksft_test_result_xfail("%s\n", test_case.name);
> + } else {
> ksft_test_result_fail("%s\n", test_case.name);
> *failures += 1;
> }
> @@ -1177,11 +1177,13 @@ static void run_mremap_test_case(struct test test_case, int *failures,
> * was faulted in.
> */
> if (threshold_mb == VALIDATION_NO_THRESHOLD ||
> - test_case.config.region_size <= threshold_mb * _1MB)
> - ksft_test_result_pass("%s\n\tmremap time: %12lldns\n",
> - test_case.name, remap_time);
Same question, why not drop the \n\t ?
--
Cheers,
David
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 3/3] selftests/mm: restore enable_soft_offline in hugetlb-soft-offline
2026-08-25 8:57 ` [PATCH v4 3/3] selftests/mm: restore enable_soft_offline in hugetlb-soft-offline Song Hu
2026-08-25 9:06 ` Song Hu
2026-08-25 9:24 ` Muhammad Usama Anjum
@ 2026-09-10 9:36 ` David Hildenbrand (Arm)
2 siblings, 0 replies; 9+ messages in thread
From: David Hildenbrand (Arm) @ 2026-09-10 9:36 UTC (permalink / raw)
To: Song Hu, akpm, usama.anjum
Cc: linux-mm, shuah, ljs, liam, vbabka, rppt, surenb, mhocko, peterx,
sarthak.sharma, linux-kselftest, linux-kernel
On 8/25/26 10:57, Song Hu wrote:
> hugetlb-soft-offline toggles /proc/sys/vm/enable_soft_offline between 1
> and 0 (test_soft_offline_common(1) then (0)) and leaves it at 0 when it
> finishes, silently disabling soft offlining for the whole system after
> the run.
>
> Save the original value before the test and restore it from an
> atexit() handler, as hugepage_restore_settings_atexit() in
> hugepage_settings.c already does. Use read_num()/write_num() from
> vm_util instead of hand-rolled popen()/fopen() helpers.
>
> The restore handler must not call write_num(): on failure it
> re-enters exit() through ksft_exit_fail_msg(), which is undefined
> behavior from inside an atexit handler. A non-root run hits it
> directly - the restore write fails the same way the write that
> triggered the exit did. Restore with plain open()/write(), best
> effort.
>
> Signed-off-by: Song Hu <husong@kylinos.cn>
>
> ---
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
--
Cheers,
David
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-09-10 9:36 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-25 8:57 [PATCH v4 0/3] selftests/mm: TAP output and global-state fixes Song Hu
2026-08-25 8:57 ` [PATCH v4 1/3] selftests/mm: emit TAP header in uffd-wp-mremap Song Hu
2026-09-10 9:28 ` David Hildenbrand (Arm)
2026-08-25 8:57 ` [PATCH v4 2/3] selftests/mm: emit TAP header and use TAP skip in mremap_test Song Hu
2026-09-10 9:33 ` David Hildenbrand (Arm)
2026-08-25 8:57 ` [PATCH v4 3/3] selftests/mm: restore enable_soft_offline in hugetlb-soft-offline Song Hu
2026-08-25 9:06 ` Song Hu
2026-08-25 9:24 ` Muhammad Usama Anjum
2026-09-10 9:36 ` David Hildenbrand (Arm)
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®