Linux Kernel Selftest development
 help / color / mirror / Atom feed
* [PATCH v5 0/2] support kselftest on nommu platform
@ 2026-10-06  8:56 Hajime Tazaki
  2026-10-06  8:56 ` [PATCH v5 1/2] selftests: run tests on nommu architecture Hajime Tazaki
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Hajime Tazaki @ 2026-10-06  8:56 UTC (permalink / raw)
  To: linux-mm, liam, rbm, akpm, luto, brendan.jackman, david,
	liuhangbin, corbet, kees, ljs, broonie, mhocko, rppt, shuah,
	surenb, vbabka, wad, linux-doc, linux-kselftest, linux-um
  Cc: geert, daniel, Hajime Tazaki

This patchset adds an ability to execute kselftest on nommu platforms.

Currently there are several issues if we wish to run kselftests on nommu
targets:

- it cannot compile/build test binaries because the current files mainly
  assume to build with glibc,
- some of the tests are not able to run on nommu targets as there are no
  fork(2) syscall.

The first issue can be avoided if we can build static PIE binaries (if
targets support it), but in our case (build on ubuntu/glibc and run on
alpine/musl-libc), it fails to invoke due to lack of the GNU ifunc
mechanism.  Thus, we need to cross-compile with musl toolchain, which
needs to be solved the first issue.

The second issue is the lack of fork(2) syscall on those platforms.
Especially the test harness helper (kselftest_harness.h) uses the
syscall, which cannot be simply with vfork(2).  `timeout` command used
in `runner.sh` never works for nommu platform as it uses fork(2).

nommu component in the mm subsystem has several known issues and having
test cases should help this situation, thus this patchset is very first
step toward enriching test environment which has not been well tested
for a while.  The test cases is implemented based on the document
(Documentation/admin-guide/mm/nommu-mmap.rst).

Initial shape for this patches is implemented as an opt-in TARGET, not
built/invoked automatically if users don't specify this nommu target.

--

- v4:
https://lore.kernel.org/all/20260929235711.2287931-1-thehajime@gmail.com/
- v3:
https://lore.kernel.org/linux-mm/20260926010819.604346-1-thehajime@gmail.com/
- v2:
https://lore.kernel.org/linux-mm/20260825015945.141739-1-thehajime@gmail.com/
- rfc:
https://lore.kernel.org/linux-mm/20260813063401.1786548-1-thehajime@gmail.com/

Hajime Tazaki (2):
  selftests: run tests on nommu architecture
  selftests/nommu: add nommu mmap and mremap behavior tests

 Documentation/dev-tools/kselftest.rst         |  18 +
 tools/testing/selftests/kselftest/runner.sh   |  11 +-
 tools/testing/selftests/nommu/Makefile        |   7 +
 tools/testing/selftests/nommu/nommu.h         |  33 ++
 .../testing/selftests/nommu/nommu_mmap_test.c | 264 +++++++++++++
 .../selftests/nommu/nommu_mremap_test.c       | 356 ++++++++++++++++++
 6 files changed, 688 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/nommu/Makefile
 create mode 100644 tools/testing/selftests/nommu/nommu.h
 create mode 100644 tools/testing/selftests/nommu/nommu_mmap_test.c
 create mode 100644 tools/testing/selftests/nommu/nommu_mremap_test.c


base-commit: e8d0f6a1b2a447d02845984fa6288787543cb03c
-- 
2.52.0


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

* [PATCH v5 1/2] selftests: run tests on nommu architecture
  2026-10-06  8:56 [PATCH v5 0/2] support kselftest on nommu platform Hajime Tazaki
@ 2026-10-06  8:56 ` Hajime Tazaki
  2026-10-06  8:56 ` [PATCH v5 2/2] selftests/nommu: add nommu mmap and mremap behavior tests Hajime Tazaki
  2026-10-07 19:30 ` [PATCH v5 0/2] support kselftest on nommu platform Andrew Morton
  2 siblings, 0 replies; 4+ messages in thread
From: Hajime Tazaki @ 2026-10-06  8:56 UTC (permalink / raw)
  To: linux-mm, liam, rbm, akpm, luto, brendan.jackman, david,
	liuhangbin, corbet, kees, ljs, broonie, mhocko, rppt, shuah,
	surenb, vbabka, wad, linux-doc, linux-kselftest, linux-um
  Cc: geert, daniel, Hajime Tazaki

Architectures lacking MMU don't support fork(2) syscall and only
vfork(2) is available with limitations.  Thus, we cannot run kselftest
on nommu architecture as is.

This commit addresses this issue with the following changes:

- Detect NOMMU at runtime from the MmapCopy field in /proc/meminfo
  and avoid timeout, which requires fork(2).
- Document how to build and run the NOMMU tests, including the procfs
  prerequisite for runtime detection.

Build and run the tests with:

 $ make ARCH=um O=build kselftest-all TARGETS=nommu
 $ make ARCH=um O=build kselftest-install TARGETS=nommu
 $ ./build/kselftest/kselftest_install/run_kselftest.sh -p -c nommu

Cc: Shuah Khan <shuah@kernel.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Kees Cook <kees@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Will Drewry <wad@chromium.org>
Cc: Mark Brown <broonie@kernel.org>
Cc: Brendan Jackman <brendan.jackman@linux.dev>
Cc: Hangbin Liu <liuhangbin@gmail.com>
Cc: "Ricardo B. Marliere" <rbm@suse.com>
Cc: linux-kselftest@vger.kernel.org
Cc: linux-um@lists.infradead.org
Cc: linux-mm@kvack.org
Cc: linux-doc@vger.kernel.org
Closes: https://sashiko.dev/#/patchset/20260813063401.1786548-1-thehajime%40gmail.com
Signed-off-by: Hajime Tazaki <thehajime@gmail.com>

--

v4 => v5
- remove build-time selection and detect NOMMU at runtime

v3 => v4
- fix typos in commit message

v2 => v3
- remove unnecessary modification
- new target is moved from TARGETS=mm/nommu to TARGETS=nommu
- rename CONFIG_NOMMU to NOMMU to avoid confusion to kernel config

rfc => v2
- reformat ktap header, reported by Sashiko review
- https://lore.kernel.org/linux-mm/20260825015945.141739-2-thehajime@gmail.com/

rfc: https://lore.kernel.org/linux-mm/20260813063401.1786548-1-thehajime@gmail.com/
---
 Documentation/dev-tools/kselftest.rst       | 18 ++++++++++++++++++
 tools/testing/selftests/kselftest/runner.sh | 11 ++++++++++-
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/Documentation/dev-tools/kselftest.rst b/Documentation/dev-tools/kselftest.rst
index 64c0ec742..fc4dc1f9d 100644
--- a/Documentation/dev-tools/kselftest.rst
+++ b/Documentation/dev-tools/kselftest.rst
@@ -230,6 +230,24 @@ section::
 
 .. _tar's auto-compress: https://www.gnu.org/software/tar/manual/html_node/gzip.html#auto_002dcompress
 
+Build and test on nommu target
+==============================
+
+The nommu selftests detect NOMMU at runtime by checking for the ``MmapCopy``
+entry in ``/proc/meminfo``. Ensure procfs is mounted at ``/proc`` before
+building and running the tests.
+
+::
+
+  $ make ARCH=um O=build kselftest-all TARGETS=nommu  # <= build-only
+  $ make ARCH=um O=build kselftest-install TARGETS=nommu
+  $ ./build/kselftest/kselftest_install/run_kselftest.sh -p -c nommu
+
+The C tests report a skip if ``/proc/meminfo`` is unavailable. On a NOMMU
+system, the runner needs that file to avoid wrapping the tests in ``timeout``
+before they can report a skip. Mounting procfs is therefore a prerequisite
+for running this target through the kselftest runner.
+
 Contributing new tests
 ======================
 
diff --git a/tools/testing/selftests/kselftest/runner.sh b/tools/testing/selftests/kselftest/runner.sh
index 311811dc5..45fb8ec38 100644
--- a/tools/testing/selftests/kselftest/runner.sh
+++ b/tools/testing/selftests/kselftest/runner.sh
@@ -36,10 +36,19 @@ tap_prefix()
 	fi
 }
 
+is_nommu()
+{
+	grep -q '^MmapCopy:' /proc/meminfo 2>/dev/null
+}
+
 tap_timeout()
 {
+	# nommu doesn't support timeout command (missing fork(2))
+	if is_nommu; then
+		echo "timeout isn't supported for NOMMU"
+		$1
 	# Make sure tests will time out if utility is available.
-	if [ -x /usr/bin/timeout ] ; then
+	elif [ -x /usr/bin/timeout ]; then
 		/usr/bin/timeout --foreground "$kselftest_timeout" \
 			/usr/bin/timeout "$kselftest_timeout" $1
 	else
-- 
2.52.0


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

* [PATCH v5 2/2] selftests/nommu: add nommu mmap and mremap behavior tests
  2026-10-06  8:56 [PATCH v5 0/2] support kselftest on nommu platform Hajime Tazaki
  2026-10-06  8:56 ` [PATCH v5 1/2] selftests: run tests on nommu architecture Hajime Tazaki
@ 2026-10-06  8:56 ` Hajime Tazaki
  2026-10-07 19:30 ` [PATCH v5 0/2] support kselftest on nommu platform Andrew Morton
  2 siblings, 0 replies; 4+ messages in thread
From: Hajime Tazaki @ 2026-10-06  8:56 UTC (permalink / raw)
  To: linux-mm, liam, rbm, akpm, luto, brendan.jackman, david,
	liuhangbin, corbet, kees, ljs, broonie, mhocko, rppt, shuah,
	surenb, vbabka, wad, linux-doc, linux-kselftest, linux-um
  Cc: geert, daniel, Hajime Tazaki

Introduce a kselftest utility to validate memory mapping capabilities
under nommu kernels, aligned with
Documentation/admin-guide/mm/nommu-mmap.rst.

The test implements basic checks into a generic architecture-agnostic
test matrix applicable across nommu targets. It evaluates:

1. MAP_FIXED allocation rejections.
2. Standard MAP_PRIVATE and MAP_ANONYMOUS allocation resilience.
3. Regular file mappings via standard filesystem storage.
4. Block device subsystem mappings (gracefully skipping if node is
   missing).
5. Shared vs Private backing discrepancies under nommu conditions.
6. mremap limits, ensuring non-expandable restrictions behave properly.

Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: "Liam R. Howlett" <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: linux-kselftest@vger.kernel.org
Cc: linux-mm@kvack.org
Cc: linux-um@lists.infradead.org
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260825015945.141739-1-thehajime@gmail.com
Assisted-by: Gemini:Pro [AI_Reviewer] [Sashiko_Linter]
Assisted-by: cubic.dev:unspecified
Signed-off-by: Hajime Tazaki <thehajime@gmail.com>

--

v4 => v5
- remove #ifdef NOMMU and use a global variable detected from /proc/meminfo

v3 => v4
- clean up messages

v2 => v3
- remove unnecessary modifications
- address Sashiko review

rfc => v2
- prepare a different TARGETS for tests (mm/nommu)
- drop shrink fix tests
- drop mmap /dev/zero tests
- https://lore.kernel.org/linux-mm/20260825015945.141739-3-thehajime@gmail.com/

rfc:
- https://lore.kernel.org/linux-mm/20260813063401.1786548-1-thehajime@gmail.com/
---
 tools/testing/selftests/nommu/Makefile        |   7 +
 tools/testing/selftests/nommu/nommu.h         |  33 ++
 .../testing/selftests/nommu/nommu_mmap_test.c | 264 +++++++++++++
 .../selftests/nommu/nommu_mremap_test.c       | 356 ++++++++++++++++++
 4 files changed, 660 insertions(+)
 create mode 100644 tools/testing/selftests/nommu/Makefile
 create mode 100644 tools/testing/selftests/nommu/nommu.h
 create mode 100644 tools/testing/selftests/nommu/nommu_mmap_test.c
 create mode 100644 tools/testing/selftests/nommu/nommu_mremap_test.c

diff --git a/tools/testing/selftests/nommu/Makefile b/tools/testing/selftests/nommu/Makefile
new file mode 100644
index 000000000..87bc3bbfa
--- /dev/null
+++ b/tools/testing/selftests/nommu/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for nommu selftests
+
+TEST_GEN_PROGS += nommu_mmap_test
+TEST_GEN_PROGS += nommu_mremap_test
+
+include ../lib.mk
diff --git a/tools/testing/selftests/nommu/nommu.h b/tools/testing/selftests/nommu/nommu.h
new file mode 100644
index 000000000..2c9a2f4e0
--- /dev/null
+++ b/tools/testing/selftests/nommu/nommu.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef NOMMU_H
+#define NOMMU_H
+
+#include <stdio.h>
+#include <string.h>
+
+/* Returns 1 for NOMMU, 0 for MMU, and -1 if /proc/meminfo is unavailable. */
+static inline int ksft_is_nommu(void)
+{
+	FILE *fp;
+	char line[256];
+	int nommu = 0;
+
+	fp = fopen("/proc/meminfo", "r");
+	if (!fp)
+		return -1;
+
+	while (fgets(line, sizeof(line), fp)) {
+		if (strncmp(line, "MmapCopy:", sizeof("MmapCopy:") - 1) == 0) {
+			nommu = 1;
+			break;
+		}
+	}
+
+	if (ferror(fp))
+		nommu = -1;
+	fclose(fp);
+
+	return nommu;
+}
+
+#endif
diff --git a/tools/testing/selftests/nommu/nommu_mmap_test.c b/tools/testing/selftests/nommu/nommu_mmap_test.c
new file mode 100644
index 000000000..2b3639cf7
--- /dev/null
+++ b/tools/testing/selftests/nommu/nommu_mmap_test.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include "kselftest.h"
+#include "nommu.h"
+
+#include <sys/vfs.h>
+#ifndef RAMFS_MAGIC
+#define RAMFS_MAGIC 0x858458f6
+#endif
+
+static size_t ps;
+static int nommu;
+
+struct test_case_t {
+	const char *name;
+	const char *pathname;
+	int open_flags;
+	int mmap_prot;
+	int mmap_flags;
+	int exp_err;
+	int (*resolve_exp_err)(const char *path);
+};
+
+static int get_shm_expected_error(const char *path)
+{
+	struct statfs fs;
+
+	if (!nommu)
+		return 0;
+
+	if (statfs(path, &fs) == 0) {
+		if (fs.f_type == RAMFS_MAGIC)
+			return 0; /* ramfs succeed with contiguous memory */
+	}
+	 /* hostfs, etc returns ENODEV due to lack of contiguous allocation */
+	return ENODEV;
+}
+
+static struct test_case_t test_cases[] = {
+	{
+		.name = "anonymous private allocation",
+		.pathname = NULL,
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ | PROT_WRITE,
+		.mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE,
+		.exp_err = 0,
+		.resolve_exp_err = NULL,
+	},
+	{
+		.name = "non-anonymous private file mapping (rw-)",
+		.pathname = "/tmp/ksft.nommu-reg-XXXXXX",
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ | PROT_WRITE,
+		.mmap_flags = MAP_PRIVATE,
+		.exp_err = 0,
+		.resolve_exp_err = NULL,
+	},
+	{
+		.name = "non-anonymous private file mapping (r--)",
+		.pathname = "/tmp/ksft.nommu-reg-XXXXXX",
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ,
+		.mmap_flags = MAP_PRIVATE,
+		.exp_err = 0,
+		.resolve_exp_err = NULL,
+	},
+	{
+		.name = "non-anonymous shared file mapping (rw-)",
+		.pathname = "/tmp/ksft.nommu-shm-XXXXXX",
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ | PROT_WRITE,
+		.mmap_flags = MAP_SHARED,
+		.exp_err = 0,
+		.resolve_exp_err = get_shm_expected_error,
+	},
+	{
+		.name = "non-anonymous shared file mapping (r--)",
+		.pathname = "/tmp/ksft.nommu-shm-XXXXXX",
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ,
+		.mmap_flags = MAP_SHARED,
+		.exp_err = 0,
+		.resolve_exp_err = get_shm_expected_error,
+	},
+};
+
+static int run_mapping_matrix_test(struct test_case_t *tcase)
+{
+	int fd;
+	void *ptr = MAP_FAILED;
+	char path_buf[PATH_MAX];
+	const char *path = tcase->pathname;
+	int rc = KSFT_PASS;
+	int expected_error;
+
+	ksft_print_msg("[RUN] %s\n", tcase->name);
+
+	if (tcase->pathname == NULL) {
+		fd = -1;
+	} else if (strstr(tcase->pathname, "XXXXXX")) {
+		strncpy(path_buf, tcase->pathname, sizeof(path_buf) - 1);
+		path_buf[sizeof(path_buf) - 1] = '\0';
+		fd = mkstemp(path_buf);
+		if (fd < 0) {
+			ksft_print_msg("Failed to setup temp node: %s\n",
+				tcase->pathname);
+			ksft_test_result_skip("%s\n", tcase->name);
+			return KSFT_SKIP;
+		}
+		if (ftruncate(fd, ps) != 0) {
+			ksft_print_msg("ftruncate failed for: %s\n", tcase->pathname);
+			rc = KSFT_FAIL;
+			goto cleanup;
+		}
+		path = path_buf;
+	} else {
+		fd = open(tcase->pathname, tcase->open_flags, 0600);
+		if (fd < 0) {
+			ksft_print_msg("Device node not accessible: %s\n",
+				       tcase->pathname);
+			ksft_test_result_skip("%s\n", tcase->name);
+			return KSFT_SKIP;
+		}
+	}
+
+	expected_error = tcase->exp_err;
+	if (tcase->resolve_exp_err && fd >= 0)
+		expected_error = tcase->resolve_exp_err(path);
+
+	ptr = mmap(NULL, ps, tcase->mmap_prot, tcase->mmap_flags, fd, 0);
+
+	if (expected_error != 0) {
+		if (ptr != MAP_FAILED) {
+			ksft_print_msg("mmap unexpectedly succeeded (exp error %d)\n",
+					      expected_error);
+			rc = KSFT_FAIL;
+			goto cleanup;
+		}
+		if (errno != expected_error) {
+			ksft_print_msg("mmap failed with %d (%s), but expected %d\n",
+				errno, strerror(errno), expected_error);
+			rc = KSFT_FAIL;
+			goto cleanup;
+		}
+		ksft_print_msg("Correctly rejected with expected error %s(%d)\n",
+			strerror(expected_error), expected_error);
+		rc = KSFT_PASS;
+		goto cleanup;
+	}
+
+	if (ptr == MAP_FAILED) {
+		ksft_print_msg("mmap failed unexpectedly: %s\n", strerror(errno));
+		rc = KSFT_FAIL;
+		goto cleanup;
+	}
+
+cleanup:
+	if (ptr != MAP_FAILED && munmap(ptr, ps)) {
+		ksft_print_msg("munmap failed: %s\n", strerror(errno));
+		rc = KSFT_FAIL;
+	}
+	if (fd >= 0) {
+		close(fd);
+		if (tcase->pathname && strstr(tcase->pathname, "XXXXXX") &&
+		    unlink(path_buf)) {
+			ksft_print_msg("unlink failed for %s: %s\n",
+				       path_buf, strerror(errno));
+			rc = KSFT_FAIL;
+		}
+	}
+	ksft_test_result_report(rc, "%s\n", tcase->name);
+	return rc;
+}
+
+static int test_map_fixed(void)
+{
+	void *fixed_addr;
+	void *ptr;
+
+	ksft_print_msg("[RUN] %s\n", __func__);
+
+	fixed_addr = mmap(NULL, ps, PROT_READ | PROT_WRITE,
+			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	if (fixed_addr == MAP_FAILED) {
+		ksft_print_msg("Unable to reserve test address: %s\n",
+				strerror(errno));
+		ksft_test_result_skip("MAP_FIXED behavior\n");
+		return KSFT_SKIP;
+	}
+
+	if (munmap(fixed_addr, ps)) {
+		ksft_print_msg("Unable to release test address: %s\n",
+			strerror(errno));
+		ksft_test_result_fail("MAP_FIXED behavior\n");
+		return KSFT_FAIL;
+	}
+
+	ptr = mmap(fixed_addr, ps, PROT_READ | PROT_WRITE,
+		MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+
+	if (nommu) {
+		if (ptr == MAP_FAILED && (errno == ENODEV || errno == EINVAL)) {
+			ksft_print_msg("MAP_FIXED correctly rejected under nommu\n");
+			ksft_test_result_pass("MAP_FIXED behavior\n");
+			return KSFT_PASS;
+		}
+		if (ptr != MAP_FAILED) {
+			ksft_print_msg("MAP_FIXED unexpectedly allowed under nommu\n");
+			ksft_test_result_fail("MAP_FIXED behavior\n");
+			if (munmap(ptr, ps))
+				ksft_print_msg("munmap failed: %s\n", strerror(errno));
+			return KSFT_FAIL;
+		}
+		ksft_print_msg("MAP_FIXED failed under NOMMU: %s\n",
+				      strerror(errno));
+		ksft_test_result_fail("MAP_FIXED behavior\n");
+		return KSFT_FAIL;
+	}
+	if (ptr != MAP_FAILED) {
+		ksft_print_msg("MAP_FIXED successfully allocated under MMU\n");
+		if (munmap(ptr, ps)) {
+			ksft_print_msg("munmap failed: %s\n", strerror(errno));
+			ksft_test_result_fail("MAP_FIXED behavior\n");
+			return KSFT_FAIL;
+		}
+		ksft_test_result_pass("MAP_FIXED behavior\n");
+		return KSFT_PASS;
+	}
+	ksft_print_msg("MAP_FIXED failed allocation under MMU\n");
+	ksft_test_result_fail("MAP_FIXED behavior\n");
+	return KSFT_FAIL;
+}
+
+int main(int argc, char **argv)
+{
+	int i;
+
+	nommu = ksft_is_nommu();
+	if (nommu < 0)
+		ksft_exit_skip("Cannot read /proc/meminfo; mount procfs at /proc\n");
+
+	ps = sysconf(_SC_PAGESIZE);
+	ksft_print_header();
+	ksft_set_plan(ARRAY_SIZE(test_cases) + 1);
+
+	if (nommu)
+		ksft_print_msg("Running strict MMAP test criteria under nommu architecture\n");
+	else
+		ksft_print_msg("Running MMAP test criteria under MMU architecture\n");
+
+	test_map_fixed();
+	for (i = 0; i < (int)ARRAY_SIZE(test_cases); i++)
+		run_mapping_matrix_test(&test_cases[i]);
+
+	ksft_finished();
+}
diff --git a/tools/testing/selftests/nommu/nommu_mremap_test.c b/tools/testing/selftests/nommu/nommu_mremap_test.c
new file mode 100644
index 000000000..6ee89cb25
--- /dev/null
+++ b/tools/testing/selftests/nommu/nommu_mremap_test.c
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include "kselftest.h"
+#include "nommu.h"
+
+#include <sys/vfs.h>
+#ifndef RAMFS_MAGIC
+#define RAMFS_MAGIC 0x858458f6
+#endif
+
+static size_t ps;
+static int nommu;
+
+static long get_fs_type(const char *path)
+{
+	struct statfs fs;
+
+	if (statfs(path, &fs) == 0)
+		return fs.f_type;
+
+	return 0;
+}
+
+static void munmap_shrink_test(void)
+{
+	void *addr;
+	int ret;
+
+	/* munmap shrink test */
+	for (int i = 0; i < 4; i++) {
+		addr = mmap(NULL, ps * 4, PROT_READ | PROT_WRITE,
+			    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+		if (addr == MAP_FAILED) {
+			ksft_print_msg("mmap failed: %s(%d)\n", strerror(errno), errno);
+			ksft_test_result_fail("munmap shrink\n");
+			return;
+		}
+		ret = munmap((char *)addr + ps * i, ps);
+		if (ret != 0) {
+			ksft_print_msg("memory %p isn't unmapped at %p\n",
+				addr, (char *)addr + ps * i);
+			goto error;
+		}
+
+		if (i == 0) {
+			if (munmap(addr +  ps, ps * 3))
+				goto error;
+		} else if (i == 1) {
+			if (munmap(addr, ps) || munmap(addr + (ps * 2), ps * 2))
+				goto error;
+		} else if (i == 2) {
+			if (munmap(addr, ps * 2) || munmap(addr + (ps * 3), ps))
+				goto error;
+		} else if (i == 3) {
+			if (munmap(addr, ps * 3))
+				goto error;
+		}
+	}
+
+	ksft_test_result_pass("munmap shrink\n");
+	return;
+error:
+	for (int j = 0; j < 4; j++) {
+		if (munmap((char *)addr + j * ps, ps))
+			ksft_print_msg("cleanup munmap failed: %s\n", strerror(errno));
+	}
+	ksft_print_msg("clean up failures\n");
+	ksft_test_result_fail("munmap shrink\n");
+}
+
+static size_t page_align(size_t len)
+{
+	return (len + ps - 1) / ps * ps;
+}
+
+static void mremap_shrink_test(void)
+{
+	void *addr, *addr2;
+	size_t current_len;
+	size_t old_len, new_len;
+	struct param {
+		size_t old;
+		size_t new;
+	} params[] = {
+		/* should not happen any shrink */
+		{ .old = ps * 4 - 1, .new = ps * 4 - 2 },
+		/* should not happen any shrink */
+		{ .old = ps * 4 - 1, .new = ps * 4 },
+		{ .old = ps * 4, .new = ps * 2 },
+		/* should not happen any shrink */
+		{ .old = ps * 2, .new = ps * 2 - 2 },
+		{ .old = ps * 2 - 2, .new = ps * 1 },
+	};
+
+	/* mremap shrink test */
+	current_len = page_align(ps * 4 - 1);
+	addr = mmap(NULL, ps * 4 - 1, PROT_READ | PROT_WRITE,
+		    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	if (addr == MAP_FAILED) {
+		ksft_print_msg("mmap failed: %s(%d)\n", strerror(errno), errno);
+		ksft_test_result_fail("mremap shrink\n");
+		return;
+	}
+
+	for (int i = 0; i < ARRAY_SIZE(params); i++) {
+		old_len = params[i].old;
+		new_len = params[i].new;
+		current_len = page_align(new_len);
+		addr2 = mremap(addr, old_len, new_len, MREMAP_MAYMOVE);
+		if (addr2 == MAP_FAILED) {
+			ksft_print_msg("memory %p isn't remapped at %p\n", addr, addr2);
+			ksft_test_result_fail("mremap shrink\n");
+			munmap(addr, page_align(old_len));
+			return;
+		}
+
+		addr = addr2;
+	}
+
+	if (munmap(addr, current_len)) {
+		ksft_print_msg("cleanup failed: %s\n", strerror(errno));
+		ksft_test_result_fail("mremap shrink\n");
+		return;
+	}
+	ksft_test_result_pass("mremap shrink\n");
+}
+
+static int get_shared_writable_file_expected_error(const char *path)
+{
+	if (nommu && get_fs_type(path) == RAMFS_MAGIC)
+		return EPERM; /* ramfs failed */
+
+	return 0;
+}
+
+struct mremap_case_t {
+	const char *name;
+	const char *pathname;
+	int open_flags;
+	int mmap_prot;
+	int mmap_flags;
+	int exp_err;
+	int nommu_exp_err;
+	int (*resolve_exp_err)(const char *path);
+	unsigned int old_pages;
+	unsigned int new_pages;
+};
+
+static struct mremap_case_t mremap_cases[] = {
+	{
+		.name = "anonymous shrink (r--)",
+		.pathname = NULL,
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ,
+		.mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE,
+		.exp_err = 0,
+		.resolve_exp_err = 0,
+	},
+	{
+		.name = "shared file shrink (r--)",
+		.pathname = "/tmp/ksft.nommu-remap-XXXXXX",
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ,
+		.mmap_flags = MAP_SHARED,
+		.exp_err = 0,
+		.resolve_exp_err = get_shared_writable_file_expected_error,
+	},
+	{
+		.name = "private file unchanged length (r-)",
+		.pathname = "/tmp/ksft.nommu-remap-XXXXXX",
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ,
+		.mmap_flags = MAP_PRIVATE,
+		.exp_err = 0,
+		.nommu_exp_err = EPERM,
+		.resolve_exp_err = 0,
+		.old_pages = 4,
+		.new_pages = 4,
+	},
+	{
+		.name = "private file unchanged length (rw-)",
+		.pathname = "/tmp/ksft.nommu-remap-XXXXXX",
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ | PROT_WRITE,
+		.mmap_flags = MAP_PRIVATE,
+		.exp_err = 0,
+		.resolve_exp_err = 0,
+		.old_pages = 4,
+		.new_pages = 4,
+	},
+	{
+		.name = "private file growth (r-)",
+		.pathname = "/tmp/ksft.nommu-remap-XXXXXX",
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ,
+		.mmap_flags = MAP_PRIVATE,
+		.exp_err = 0,
+		.nommu_exp_err = EPERM,
+		.resolve_exp_err = 0,
+		.old_pages = 4,
+		.new_pages = 8,
+	},
+	{
+		.name = "private file growth (rw-)",
+		.pathname = "/tmp/ksft.nommu-remap-XXXXXX",
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ | PROT_WRITE,
+		.mmap_flags = MAP_PRIVATE,
+		.exp_err = 0,
+		.nommu_exp_err = ENOMEM,
+		.resolve_exp_err = 0,
+		.old_pages = 4,
+		.new_pages = 8,
+	},
+};
+
+static int run_mremap_test(struct mremap_case_t *tcase)
+{
+	int fd = -1;
+	void *addr, *addr2;
+	char pb[PATH_MAX];
+	const char *path = tcase->pathname;
+	int rc = KSFT_PASS;
+	int expected_error;
+	unsigned int old_pages = tcase->old_pages ?: 4;
+	unsigned int new_pages = tcase->new_pages ?: 2;
+	unsigned int file_pages = old_pages > new_pages ?
+				  old_pages : new_pages;
+
+	ksft_print_msg("[RUN] Testing mremap: %s\n", tcase->name);
+
+	if (tcase->pathname && strstr(tcase->pathname, "XXXXXX")) {
+		strncpy(pb, tcase->pathname, sizeof(pb) - 1);
+		pb[sizeof(pb) - 1] = '\0';
+		fd = mkstemp(pb);
+		if (fd < 0) {
+			ksft_print_msg("Failed to setup file backing\n");
+			ksft_test_result_skip("%s\n", tcase->name);
+			return KSFT_SKIP;
+		}
+		if (ftruncate(fd, ps * file_pages) != 0) {
+			ksft_print_msg("Failed to setup file backing\n");
+			rc = KSFT_FAIL;
+			goto out;
+		}
+
+		if (nommu && (tcase->mmap_flags & MAP_SHARED) &&
+		    get_fs_type(pb) != RAMFS_MAGIC) {
+			ksft_print_msg("Skip the test under non-ramfs filesystem (%s)\n",
+				pb);
+			rc = KSFT_SKIP;
+			goto out;
+		}
+		path = pb;
+	} else if (tcase->pathname) {
+		fd = open(tcase->pathname, tcase->open_flags, 0600);
+		if (fd < 0) {
+			ksft_print_msg("Backing node not accessible\n");
+			ksft_test_result_skip("%s\n", tcase->name);
+			return KSFT_SKIP;
+		}
+
+		if (nommu && (tcase->mmap_flags & MAP_SHARED) &&
+		    get_fs_type(tcase->pathname) != RAMFS_MAGIC) {
+			ksft_print_msg("Skip the test under non-ramfs filesystem (%s)\n",
+					      tcase->pathname);
+			rc = KSFT_SKIP;
+			goto out;
+		}
+	}
+
+	addr = mmap(NULL, ps * old_pages, tcase->mmap_prot,
+		    tcase->mmap_flags, fd, 0);
+	if (addr == MAP_FAILED) {
+		ksft_print_msg("mmap mapping failed %s(%d)\n", strerror(errno), errno);
+		rc = KSFT_FAIL;
+		goto out;
+	}
+
+	expected_error = nommu ? tcase->nommu_exp_err : tcase->exp_err;
+	if (tcase->resolve_exp_err && fd >= 0)
+		expected_error = tcase->resolve_exp_err(path);
+
+	addr2 = mremap(addr, ps * old_pages, ps * new_pages,
+		       MREMAP_MAYMOVE);
+
+	if (expected_error != 0) {
+		if (addr2 != MAP_FAILED) {
+			ksft_print_msg("Expected error %d, but mremap unexpectedly succeeded\n",
+				       expected_error);
+			rc = KSFT_FAIL;
+		} else if (errno != expected_error) {
+			ksft_print_msg("Expected error %d, got %s(%d)\n",
+				       expected_error, strerror(errno), errno);
+			rc = KSFT_FAIL;
+		} else {
+			ksft_print_msg("%s: Handled expected error path (errno=%d)\n",
+				       tcase->name, expected_error);
+		}
+	} else if (addr2 == MAP_FAILED) {
+		ksft_print_msg("mremap shrink failed unexpectedly: %s\n",
+			       strerror(errno));
+		rc = KSFT_FAIL;
+	} else {
+		ksft_print_msg("%s step successful\n", tcase->name);
+	}
+
+	/* clean up */
+	if (munmap(addr2 == MAP_FAILED ? addr : addr2,
+		   addr2 == MAP_FAILED ? ps * old_pages : ps * new_pages)) {
+		ksft_print_msg("munmap failed: %s\n", strerror(errno));
+		rc = KSFT_FAIL;
+	}
+
+out:
+	if (fd >= 0) {
+		close(fd);
+		if (tcase->pathname && strstr(tcase->pathname, "XXXXXX") &&
+		    unlink(pb)) {
+			ksft_print_msg("unlink failed for %s: %s\n", pb, strerror(errno));
+			rc = KSFT_FAIL;
+		}
+	}
+
+	ksft_test_result_report(rc, "%s\n", tcase->name);
+	return rc;
+}
+
+int main(int argc, char **argv)
+{
+	int i;
+
+	nommu = ksft_is_nommu();
+	if (nommu < 0)
+		ksft_exit_skip("Cannot read /proc/meminfo; mount procfs at /proc\n");
+
+	ps = sysconf(_SC_PAGESIZE);
+	ksft_print_header();
+	ksft_set_plan(ARRAY_SIZE(mremap_cases) + 2);
+
+	munmap_shrink_test();
+	mremap_shrink_test();
+
+	for (i = 0; i < (int)ARRAY_SIZE(mremap_cases); i++)
+		run_mremap_test(&mremap_cases[i]);
+
+	ksft_finished();
+}
-- 
2.52.0


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

* Re: [PATCH v5 0/2] support kselftest on nommu platform
  2026-10-06  8:56 [PATCH v5 0/2] support kselftest on nommu platform Hajime Tazaki
  2026-10-06  8:56 ` [PATCH v5 1/2] selftests: run tests on nommu architecture Hajime Tazaki
  2026-10-06  8:56 ` [PATCH v5 2/2] selftests/nommu: add nommu mmap and mremap behavior tests Hajime Tazaki
@ 2026-10-07 19:30 ` Andrew Morton
  2 siblings, 0 replies; 4+ messages in thread
From: Andrew Morton @ 2026-10-07 19:30 UTC (permalink / raw)
  To: Hajime Tazaki
  Cc: linux-mm, liam, rbm, luto, brendan.jackman, david, liuhangbin,
	corbet, kees, ljs, broonie, mhocko, rppt, shuah, surenb, vbabka,
	wad, linux-doc, linux-kselftest, linux-um, geert, daniel

On Tue,  6 Oct 2026 17:56:40 +0900 Hajime Tazaki <thehajime@gmail.com> wrote:

> This patchset adds an ability to execute kselftest on nommu platforms.
> 
> Currently there are several issues if we wish to run kselftests on nommu
> targets:
> 
> - it cannot compile/build test binaries because the current files mainly
>   assume to build with glibc,
> - some of the tests are not able to run on nommu targets as there are no
>   fork(2) syscall.
> 
> The first issue can be avoided if we can build static PIE binaries (if
> targets support it), but in our case (build on ubuntu/glibc and run on
> alpine/musl-libc), it fails to invoke due to lack of the GNU ifunc
> mechanism.  Thus, we need to cross-compile with musl toolchain, which
> needs to be solved the first issue.
> 
> The second issue is the lack of fork(2) syscall on those platforms.
> Especially the test harness helper (kselftest_harness.h) uses the
> syscall, which cannot be simply with vfork(2).  `timeout` command used
> in `runner.sh` never works for nommu platform as it uses fork(2).
> 
> nommu component in the mm subsystem has several known issues and having
> test cases should help this situation, thus this patchset is very first
> step toward enriching test environment which has not been well tested
> for a while.  The test cases is implemented based on the document
> (Documentation/admin-guide/mm/nommu-mmap.rst).
> 
> Initial shape for this patches is implemented as an opt-in TARGET, not
> built/invoked automatically if users don't specify this nommu target.

Thanks, I've updated mm.git's mm-unstable branch with this version.

Then I moved the series down into the tail of the mm-unstable branch,
in preparation for excluding it from the 7.3-rcX queue.

It's changing a lot and it isn't converging quickly and review hasn't
happened and everyone's traveling so I'll likely hold this series over
for 7.4-rcX.

Hang in there - it's great that you're caring for nommu!

> --

That should be --- (in the patches too).

<grabs the v4->v5 logging from the individual patches>

> v4 => v5
> - remove build-time selection and detect NOMMU at runtime
> - remove #ifdef NOMMU and use a global variable detected from /proc/meminfo

Here's how v5 altered mm.git:



 Documentation/dev-tools/kselftest.rst             |   18 +-
 tools/testing/selftests/kselftest/runner.sh       |    9 -
 tools/testing/selftests/nommu/Makefile            |    1 
 tools/testing/selftests/nommu/local.mk            |    7 
 tools/testing/selftests/nommu/nommu.h             |   33 ++++
 tools/testing/selftests/nommu/nommu_mmap_test.c   |   91 ++++++------
 tools/testing/selftests/nommu/nommu_mremap_test.c |   72 ++++-----
 7 files changed, 129 insertions(+), 102 deletions(-)

--- a/Documentation/dev-tools/kselftest.rst~b
+++ a/Documentation/dev-tools/kselftest.rst
@@ -233,16 +233,20 @@ section::
 Build and test on nommu target
 ==============================
 
-If you (cross-)build kselftests for nommu targets, or run tests on nommu targets, use
-``NOMMU=1`` as a make variable/environment setting to tell build system to do the additional
-checks.  These nommu targets may differ in several ways, such as not supporting fork(2) or
-using musl or another libc.  Set this variable to apply the necessary build and test adjustments.
+The nommu selftests detect NOMMU at runtime by checking for the ``MmapCopy``
+entry in ``/proc/meminfo``. Ensure procfs is mounted at ``/proc`` before
+building and running the tests.
 
 ::
 
-  $ make ARCH=um NOMMU=1 O=build kselftest-all TARGETS=nommu  # <= build-only
-  $ make ARCH=um NOMMU=1 O=build kselftest-install TARGETS=nommu
-  $ NOMMU=1 ./build/kselftest/kselftest_install/run_kselftest.sh -p -c nommu
+  $ make ARCH=um O=build kselftest-all TARGETS=nommu  # <= build-only
+  $ make ARCH=um O=build kselftest-install TARGETS=nommu
+  $ ./build/kselftest/kselftest_install/run_kselftest.sh -p -c nommu
+
+The C tests report a skip if ``/proc/meminfo`` is unavailable. On a NOMMU
+system, the runner needs that file to avoid wrapping the tests in ``timeout``
+before they can report a skip. Mounting procfs is therefore a prerequisite
+for running this target through the kselftest runner.
 
 Contributing new tests
 ======================
--- a/tools/testing/selftests/kselftest/runner.sh~b
+++ a/tools/testing/selftests/kselftest/runner.sh
@@ -36,14 +36,19 @@ tap_prefix()
 	fi
 }
 
+is_nommu()
+{
+	grep -q '^MmapCopy:' /proc/meminfo 2>/dev/null
+}
+
 tap_timeout()
 {
 	# nommu doesn't support timeout command (missing fork(2))
-	if [ "$NOMMU" = "1" ] ; then
+	if is_nommu; then
 		echo "timeout isn't supported for NOMMU"
 		$1
 	# Make sure tests will time out if utility is available.
-	elif [ -x /usr/bin/timeout ] ; then
+	elif [ -x /usr/bin/timeout ]; then
 		/usr/bin/timeout --foreground "$kselftest_timeout" \
 			/usr/bin/timeout "$kselftest_timeout" $1
 	else
diff --git a/tools/testing/selftests/nommu/local.mk a/tools/testing/selftests/nommu/local.mk
deleted file mode 100644
--- a/tools/testing/selftests/nommu/local.mk
+++ /dev/null
@@ -1,7 +0,0 @@
-# detect if users request NOMMU build or not
-# User can set NOMMU to 1 to build/test for NOMMU platforms
-NOMMU ?= 0
-ifeq ($(NOMMU),1)
-CFLAGS += -DNOMMU
-export NOMMU
-endif
--- a/tools/testing/selftests/nommu/Makefile~b
+++ a/tools/testing/selftests/nommu/Makefile
@@ -5,4 +5,3 @@ TEST_GEN_PROGS += nommu_mmap_test
 TEST_GEN_PROGS += nommu_mremap_test
 
 include ../lib.mk
-include local.mk
diff --git a/tools/testing/selftests/nommu/nommu.h a/tools/testing/selftests/nommu/nommu.h
new file mode 100644
--- /dev/null
+++ a/tools/testing/selftests/nommu/nommu.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef NOMMU_H
+#define NOMMU_H
+
+#include <stdio.h>
+#include <string.h>
+
+/* Returns 1 for NOMMU, 0 for MMU, and -1 if /proc/meminfo is unavailable. */
+static inline int ksft_is_nommu(void)
+{
+	FILE *fp;
+	char line[256];
+	int nommu = 0;
+
+	fp = fopen("/proc/meminfo", "r");
+	if (!fp)
+		return -1;
+
+	while (fgets(line, sizeof(line), fp)) {
+		if (strncmp(line, "MmapCopy:", sizeof("MmapCopy:") - 1) == 0) {
+			nommu = 1;
+			break;
+		}
+	}
+
+	if (ferror(fp))
+		nommu = -1;
+	fclose(fp);
+
+	return nommu;
+}
+
+#endif
--- a/tools/testing/selftests/nommu/nommu_mmap_test.c~b
+++ a/tools/testing/selftests/nommu/nommu_mmap_test.c
@@ -9,6 +9,7 @@
 #include <string.h>
 #include <limits.h>
 #include "kselftest.h"
+#include "nommu.h"
 
 #include <sys/vfs.h>
 #ifndef RAMFS_MAGIC
@@ -16,6 +17,7 @@
 #endif
 
 static size_t ps;
+static int nommu;
 
 struct test_case_t {
 	const char *name;
@@ -31,6 +33,9 @@ static int get_shm_expected_error(const
 {
 	struct statfs fs;
 
+	if (!nommu)
+		return 0;
+
 	if (statfs(path, &fs) == 0) {
 		if (fs.f_type == RAMFS_MAGIC)
 			return 0; /* ramfs succeed with contiguous memory */
@@ -74,11 +79,7 @@ static struct test_case_t test_cases[] =
 		.mmap_prot = PROT_READ | PROT_WRITE,
 		.mmap_flags = MAP_SHARED,
 		.exp_err = 0,
-#ifdef NOMMU
 		.resolve_exp_err = get_shm_expected_error,
-#else
-		.resolve_exp_err = NULL,
-#endif
 	},
 	{
 		.name = "non-anonymous shared file mapping (r--)",
@@ -87,18 +88,14 @@ static struct test_case_t test_cases[] =
 		.mmap_prot = PROT_READ,
 		.mmap_flags = MAP_SHARED,
 		.exp_err = 0,
-#ifdef NOMMU
 		.resolve_exp_err = get_shm_expected_error,
-#else
-		.resolve_exp_err = 0,
-#endif
 	},
 };
 
 static int run_mapping_matrix_test(struct test_case_t *tcase)
 {
 	int fd;
-	void *ptr;
+	void *ptr = MAP_FAILED;
 	char path_buf[PATH_MAX];
 	const char *path = tcase->pathname;
 	int rc = KSFT_PASS;
@@ -120,10 +117,8 @@ static int run_mapping_matrix_test(struc
 		}
 		if (ftruncate(fd, ps) != 0) {
 			ksft_print_msg("ftruncate failed for: %s\n", tcase->pathname);
-			ksft_test_result_fail("%s\n", tcase->name);
-			close(fd);
-			unlink(path_buf);
-			return KSFT_FAIL;
+			rc = KSFT_FAIL;
+			goto cleanup;
 		}
 		path = path_buf;
 	} else {
@@ -146,41 +141,42 @@ static int run_mapping_matrix_test(struc
 		if (ptr != MAP_FAILED) {
 			ksft_print_msg("mmap unexpectedly succeeded (exp error %d)\n",
 					      expected_error);
-			ksft_test_result_fail("%s\n", tcase->name);
-			munmap(ptr, ps);
 			rc = KSFT_FAIL;
 			goto cleanup;
 		}
 		if (errno != expected_error) {
 			ksft_print_msg("mmap failed with %d (%s), but expected %d\n",
 				errno, strerror(errno), expected_error);
-			ksft_test_result_fail("%s\n", tcase->name);
 			rc = KSFT_FAIL;
 			goto cleanup;
 		}
 		ksft_print_msg("Correctly rejected with expected error %s(%d)\n",
 			strerror(expected_error), expected_error);
-		ksft_test_result_pass("%s\n", tcase->name);
 		rc = KSFT_PASS;
 		goto cleanup;
 	}
 
 	if (ptr == MAP_FAILED) {
 		ksft_print_msg("mmap failed unexpectedly: %s\n", strerror(errno));
-		ksft_test_result_fail("%s\n", tcase->name);
 		rc = KSFT_FAIL;
 		goto cleanup;
 	}
 
-	ksft_test_result_pass("%s\n", tcase->name);
-	munmap(ptr, ps);
-
 cleanup:
+	if (ptr != MAP_FAILED && munmap(ptr, ps)) {
+		ksft_print_msg("munmap failed: %s\n", strerror(errno));
+		rc = KSFT_FAIL;
+	}
 	if (fd >= 0) {
 		close(fd);
-		if (tcase->pathname && strstr(tcase->pathname, "XXXXXX"))
-			unlink(path_buf);
+		if (tcase->pathname && strstr(tcase->pathname, "XXXXXX") &&
+		    unlink(path_buf)) {
+			ksft_print_msg("unlink failed for %s: %s\n",
+				       path_buf, strerror(errno));
+			rc = KSFT_FAIL;
+		}
 	}
+	ksft_test_result_report(rc, "%s\n", tcase->name);
 	return rc;
 }
 
@@ -210,48 +206,55 @@ static int test_map_fixed(void)
 	ptr = mmap(fixed_addr, ps, PROT_READ | PROT_WRITE,
 		MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
 
-#ifdef NOMMU
-	if (ptr == MAP_FAILED && (errno == ENODEV || errno == EINVAL)) {
-		ksft_print_msg("MAP_FIXED correctly rejected under nommu\n");
-		ksft_test_result_pass("MAP_FIXED behavior\n");
-		return KSFT_PASS;
-	}
-	if (ptr != MAP_FAILED) {
-		ksft_print_msg("MAP_FIXED unexpectedly allowed under nommu\n");
+	if (nommu) {
+		if (ptr == MAP_FAILED && (errno == ENODEV || errno == EINVAL)) {
+			ksft_print_msg("MAP_FIXED correctly rejected under nommu\n");
+			ksft_test_result_pass("MAP_FIXED behavior\n");
+			return KSFT_PASS;
+		}
+		if (ptr != MAP_FAILED) {
+			ksft_print_msg("MAP_FIXED unexpectedly allowed under nommu\n");
+			ksft_test_result_fail("MAP_FIXED behavior\n");
+			if (munmap(ptr, ps))
+				ksft_print_msg("munmap failed: %s\n", strerror(errno));
+			return KSFT_FAIL;
+		}
+		ksft_print_msg("MAP_FIXED failed under NOMMU: %s\n",
+				      strerror(errno));
 		ksft_test_result_fail("MAP_FIXED behavior\n");
-		munmap(ptr, ps);
 		return KSFT_FAIL;
 	}
-	ksft_print_msg("MAP_FIXED failed under NOMMU: %s\n",
-			      strerror(errno));
-	ksft_test_result_fail("MAP_FIXED behavior\n");
-	return KSFT_FAIL;
-#else
 	if (ptr != MAP_FAILED) {
 		ksft_print_msg("MAP_FIXED successfully allocated under MMU\n");
+		if (munmap(ptr, ps)) {
+			ksft_print_msg("munmap failed: %s\n", strerror(errno));
+			ksft_test_result_fail("MAP_FIXED behavior\n");
+			return KSFT_FAIL;
+		}
 		ksft_test_result_pass("MAP_FIXED behavior\n");
-		munmap(ptr, ps);
 		return KSFT_PASS;
 	}
 	ksft_print_msg("MAP_FIXED failed allocation under MMU\n");
 	ksft_test_result_fail("MAP_FIXED behavior\n");
 	return KSFT_FAIL;
-#endif
 }
 
 int main(int argc, char **argv)
 {
 	int i;
 
+	nommu = ksft_is_nommu();
+	if (nommu < 0)
+		ksft_exit_skip("Cannot read /proc/meminfo; mount procfs at /proc\n");
+
 	ps = sysconf(_SC_PAGESIZE);
 	ksft_print_header();
 	ksft_set_plan(ARRAY_SIZE(test_cases) + 1);
 
-#ifdef NOMMU
-	ksft_print_msg("Running strict MMAP test criteria under nommu architecture\n");
-#else
-	ksft_print_msg("Running MMAP test criteria under MMU architecture\n");
-#endif
+	if (nommu)
+		ksft_print_msg("Running strict MMAP test criteria under nommu architecture\n");
+	else
+		ksft_print_msg("Running MMAP test criteria under MMU architecture\n");
 
 	test_map_fixed();
 	for (i = 0; i < (int)ARRAY_SIZE(test_cases); i++)
--- a/tools/testing/selftests/nommu/nommu_mremap_test.c~b
+++ a/tools/testing/selftests/nommu/nommu_mremap_test.c
@@ -9,6 +9,7 @@
 #include <string.h>
 #include <limits.h>
 #include "kselftest.h"
+#include "nommu.h"
 
 #include <sys/vfs.h>
 #ifndef RAMFS_MAGIC
@@ -16,6 +17,7 @@
 #endif
 
 static size_t ps;
+static int nommu;
 
 static long get_fs_type(const char *path)
 {
@@ -45,8 +47,7 @@ static void munmap_shrink_test(void)
 		if (ret != 0) {
 			ksft_print_msg("memory %p isn't unmapped at %p\n",
 				addr, (char *)addr + ps * i);
-			ksft_test_result_fail("munmap shrink\n");
-			return;
+			goto error;
 		}
 
 		if (i == 0) {
@@ -67,8 +68,10 @@ static void munmap_shrink_test(void)
 	ksft_test_result_pass("munmap shrink\n");
 	return;
 error:
-	for (int j = 0; j < 4; j++)
-		munmap((char *)addr + j * ps, ps);
+	for (int j = 0; j < 4; j++) {
+		if (munmap((char *)addr + j * ps, ps))
+			ksft_print_msg("cleanup munmap failed: %s\n", strerror(errno));
+	}
 	ksft_print_msg("clean up failures\n");
 	ksft_test_result_fail("munmap shrink\n");
 }
@@ -132,7 +135,7 @@ static void mremap_shrink_test(void)
 
 static int get_shared_writable_file_expected_error(const char *path)
 {
-	if (get_fs_type(path) == RAMFS_MAGIC)
+	if (nommu && get_fs_type(path) == RAMFS_MAGIC)
 		return EPERM; /* ramfs failed */
 
 	return 0;
@@ -145,6 +148,7 @@ struct mremap_case_t {
 	int mmap_prot;
 	int mmap_flags;
 	int exp_err;
+	int nommu_exp_err;
 	int (*resolve_exp_err)(const char *path);
 	unsigned int old_pages;
 	unsigned int new_pages;
@@ -167,11 +171,7 @@ static struct mremap_case_t mremap_cases
 		.mmap_prot = PROT_READ,
 		.mmap_flags = MAP_SHARED,
 		.exp_err = 0,
-#ifdef NOMMU
 		.resolve_exp_err = get_shared_writable_file_expected_error,
-#else
-		.resolve_exp_err = 0,
-#endif
 	},
 	{
 		.name = "private file unchanged length (r-)",
@@ -179,11 +179,8 @@ static struct mremap_case_t mremap_cases
 		.open_flags = O_CREAT | O_RDWR | O_EXCL,
 		.mmap_prot = PROT_READ,
 		.mmap_flags = MAP_PRIVATE,
-#ifdef NOMMU
-		.exp_err = EPERM,
-#else
 		.exp_err = 0,
-#endif
+		.nommu_exp_err = EPERM,
 		.resolve_exp_err = 0,
 		.old_pages = 4,
 		.new_pages = 4,
@@ -205,11 +202,8 @@ static struct mremap_case_t mremap_cases
 		.open_flags = O_CREAT | O_RDWR | O_EXCL,
 		.mmap_prot = PROT_READ,
 		.mmap_flags = MAP_PRIVATE,
-#ifdef NOMMU
-		.exp_err = EPERM,
-#else
 		.exp_err = 0,
-#endif
+		.nommu_exp_err = EPERM,
 		.resolve_exp_err = 0,
 		.old_pages = 4,
 		.new_pages = 8,
@@ -220,11 +214,8 @@ static struct mremap_case_t mremap_cases
 		.open_flags = O_CREAT | O_RDWR | O_EXCL,
 		.mmap_prot = PROT_READ | PROT_WRITE,
 		.mmap_flags = MAP_PRIVATE,
-#ifdef NOMMU
-		.exp_err = ENOMEM,
-#else
 		.exp_err = 0,
-#endif
+		.nommu_exp_err = ENOMEM,
 		.resolve_exp_err = 0,
 		.old_pages = 4,
 		.new_pages = 8,
@@ -257,22 +248,17 @@ static int run_mremap_test(struct mremap
 		}
 		if (ftruncate(fd, ps * file_pages) != 0) {
 			ksft_print_msg("Failed to setup file backing\n");
-			ksft_test_result_fail("%s\n", tcase->name);
-			close(fd);
-			unlink(pb);
-			return KSFT_FAIL;
+			rc = KSFT_FAIL;
+			goto out;
 		}
 
-#ifdef NOMMU
-		if ((tcase->mmap_flags & MAP_SHARED) && get_fs_type(pb) != RAMFS_MAGIC) {
+		if (nommu && (tcase->mmap_flags & MAP_SHARED) &&
+		    get_fs_type(pb) != RAMFS_MAGIC) {
 			ksft_print_msg("Skip the test under non-ramfs filesystem (%s)\n",
 				pb);
-			ksft_test_result_skip("%s\n", tcase->name);
-			close(fd);
-			unlink(pb);
-			return KSFT_SKIP;
+			rc = KSFT_SKIP;
+			goto out;
 		}
-#endif
 		path = pb;
 	} else if (tcase->pathname) {
 		fd = open(tcase->pathname, tcase->open_flags, 0600);
@@ -282,16 +268,13 @@ static int run_mremap_test(struct mremap
 			return KSFT_SKIP;
 		}
 
-#ifdef NOMMU
-		if ((tcase->mmap_flags & MAP_SHARED) &&
+		if (nommu && (tcase->mmap_flags & MAP_SHARED) &&
 		    get_fs_type(tcase->pathname) != RAMFS_MAGIC) {
 			ksft_print_msg("Skip the test under non-ramfs filesystem (%s)\n",
 					      tcase->pathname);
-			ksft_test_result_skip("%s\n", tcase->name);
-			close(fd);
-			return KSFT_SKIP;
+			rc = KSFT_SKIP;
+			goto out;
 		}
-#endif
 	}
 
 	addr = mmap(NULL, ps * old_pages, tcase->mmap_prot,
@@ -302,7 +285,7 @@ static int run_mremap_test(struct mremap
 		goto out;
 	}
 
-	expected_error = tcase->exp_err;
+	expected_error = nommu ? tcase->nommu_exp_err : tcase->exp_err;
 	if (tcase->resolve_exp_err && fd >= 0)
 		expected_error = tcase->resolve_exp_err(path);
 
@@ -340,8 +323,11 @@ static int run_mremap_test(struct mremap
 out:
 	if (fd >= 0) {
 		close(fd);
-		if (tcase->pathname && strstr(tcase->pathname, "XXXXXX"))
-			unlink(pb);
+		if (tcase->pathname && strstr(tcase->pathname, "XXXXXX") &&
+		    unlink(pb)) {
+			ksft_print_msg("unlink failed for %s: %s\n", pb, strerror(errno));
+			rc = KSFT_FAIL;
+		}
 	}
 
 	ksft_test_result_report(rc, "%s\n", tcase->name);
@@ -352,6 +338,10 @@ int main(int argc, char **argv)
 {
 	int i;
 
+	nommu = ksft_is_nommu();
+	if (nommu < 0)
+		ksft_exit_skip("Cannot read /proc/meminfo; mount procfs at /proc\n");
+
 	ps = sysconf(_SC_PAGESIZE);
 	ksft_print_header();
 	ksft_set_plan(ARRAY_SIZE(mremap_cases) + 2);
_


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

end of thread, other threads:[~2026-10-07 19:30 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-06  8:56 [PATCH v5 0/2] support kselftest on nommu platform Hajime Tazaki
2026-10-06  8:56 ` [PATCH v5 1/2] selftests: run tests on nommu architecture Hajime Tazaki
2026-10-06  8:56 ` [PATCH v5 2/2] selftests/nommu: add nommu mmap and mremap behavior tests Hajime Tazaki
2026-10-07 19:30 ` [PATCH v5 0/2] support kselftest on nommu platform Andrew Morton

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