From: Konstantin Khorenko <khorenko@virtuozzo.com>
To: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>,
Vasileios Almpanis <vasileios.almpanis@virtuozzo.com>
Cc: devel@openvz.org
Subject: [Devel] [PATCH hci-8.1 2/2] selftests/ve: check that the NUMA API syscalls return ENOSYS in a VE
Date: Thu, 05 Nov 2026 19:48:45 +0100 [thread overview]
Message-ID: <20261105-b4-prep-khorenko-vstor-153679-mbind-ve-v1-2-b4fcd27c8001@virtuozzo.com> (raw)
In-Reply-To: <20261105-b4-prep-khorenko-vstor-153679-mbind-ve-v1-0-b4fcd27c8001@virtuozzo.com>
A CT must see a kernel without NUMA, so all six NUMA API syscalls
return -ENOSYS in a non-super VE.
The test makes each call with arguments that succeed on the host and
checks that the host gets 0, while a task in a VE gets -ENOSYS. The
host result shows that the ENOSYS can only come from the VE check, not
from a bad argument.
https://virtuozzo.atlassian.net/browse/VSTOR-153679
Feature: mm: prohibit NUMA API inside CT
Signed-off-by: Konstantin Khorenko <khorenko@virtuozzo.com>
---
tools/testing/selftests/ve/.gitignore | 1 +
tools/testing/selftests/ve/Makefile | 1 +
.../ve/ve_numa_syscalls_prohibited_test.c | 192 +++++++++++++++++++++
3 files changed, 194 insertions(+)
diff --git a/tools/testing/selftests/ve/.gitignore b/tools/testing/selftests/ve/.gitignore
index 3d1179bd2c5f4..5e07985c8fed3 100644
--- a/tools/testing/selftests/ve/.gitignore
+++ b/tools/testing/selftests/ve/.gitignore
@@ -4,3 +4,4 @@ ve_mount_accounting_test
ve_cpuid_override_test
ve_vtty_stress
ve_numa_migrate_test
+ve_numa_syscalls_prohibited_test
diff --git a/tools/testing/selftests/ve/Makefile b/tools/testing/selftests/ve/Makefile
index e96320a183844..451a7e1cc17d1 100644
--- a/tools/testing/selftests/ve/Makefile
+++ b/tools/testing/selftests/ve/Makefile
@@ -7,6 +7,7 @@ TEST_GEN_PROGS += ve_perms_test
TEST_GEN_PROGS += ve_mount_accounting_test
TEST_GEN_PROGS += ve_vtty_stress
TEST_GEN_PROGS += ve_numa_migrate_test
+TEST_GEN_PROGS += ve_numa_syscalls_prohibited_test
# CPUID faulting is x86-64 only. ARCH says "x86" for 32-bit too and lib.mk
# picks the clang target by its emptiness, so decide by the compiler.
diff --git a/tools/testing/selftests/ve/ve_numa_syscalls_prohibited_test.c b/tools/testing/selftests/ve/ve_numa_syscalls_prohibited_test.c
new file mode 100644
index 0000000000000..4cae1c74b46bc
--- /dev/null
+++ b/tools/testing/selftests/ve/ve_numa_syscalls_prohibited_test.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Every NUMA API syscall works on the host and returns ENOSYS in a VE. */
+#define _GNU_SOURCE
+#include <errno.h>
+#include <sched.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <linux/mempolicy.h>
+
+#include "../kselftest_harness.h"
+#include "ve_selftest.h"
+
+#define NODE_BITS 1024
+#define LONG_BITS (8 * sizeof(unsigned long))
+
+static unsigned long node_mask[NODE_BITS / LONG_BITS];
+static void *page;
+static size_t page_size;
+
+static long call_get_mempolicy(void)
+{
+ int mode;
+
+ return syscall(__NR_get_mempolicy, &mode, NULL, 0UL, 0UL, 0UL);
+}
+
+static long call_set_mempolicy(void)
+{
+ return syscall(__NR_set_mempolicy, MPOL_DEFAULT, NULL, 0UL);
+}
+
+static long call_mbind(void)
+{
+ return syscall(__NR_mbind, page, page_size, MPOL_BIND, node_mask,
+ NODE_BITS + 1UL, 0U);
+}
+
+static long call_set_mempolicy_home_node(void)
+{
+ unsigned long node;
+
+ for (node = 0; node < NODE_BITS; node++)
+ if (node_mask[node / LONG_BITS] & (1UL << (node % LONG_BITS)))
+ break;
+ return syscall(__NR_set_mempolicy_home_node, page, page_size, node, 0UL);
+}
+
+static long call_migrate_pages(void)
+{
+ unsigned long none[NODE_BITS / LONG_BITS] = { 0 };
+
+ return syscall(__NR_migrate_pages, 0, NODE_BITS + 1UL, none, node_mask);
+}
+
+static long call_move_pages(void)
+{
+ return syscall(__NR_move_pages, 0, 0UL, NULL, NULL, NULL, 0);
+}
+
+/* set_mempolicy_home_node() needs the MPOL_BIND policy mbind() installs. */
+static const struct numa_call {
+ const char *name;
+ long (*call)(void);
+} numa_calls[] = {
+ { "get_mempolicy", call_get_mempolicy },
+ { "set_mempolicy", call_set_mempolicy },
+ { "mbind", call_mbind },
+ { "set_mempolicy_home_node", call_set_mempolicy_home_node },
+ { "migrate_pages", call_migrate_pages },
+ { "move_pages", call_move_pages },
+};
+
+#define NR_CALLS ARRAY_SIZE(numa_calls)
+
+struct call_result {
+ long ret;
+ int err;
+};
+
+static void run_calls(struct call_result *res)
+{
+ unsigned int i;
+
+ for (i = 0; i < NR_CALLS; i++) {
+ errno = 0;
+ res[i].ret = numa_calls[i].call();
+ res[i].err = errno;
+ }
+}
+
+FIXTURE(numa_syscalls)
+{
+ int cgv2_fd;
+ int ctid;
+};
+
+FIXTURE_SETUP(numa_syscalls)
+{
+ unsigned long allowed[NODE_BITS / LONG_BITS] = { 0 };
+ unsigned int i;
+
+ self->cgv2_fd = -1;
+
+ if (geteuid() != 0)
+ SKIP(return, "creating a ve cgroup needs root");
+
+ page_size = getpagesize();
+ page = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ ASSERT_NE(page, MAP_FAILED);
+
+ ASSERT_EQ(syscall(__NR_get_mempolicy, NULL, allowed, NODE_BITS + 1UL,
+ 0UL, MPOL_F_MEMS_ALLOWED), 0);
+ for (i = 0; i < NODE_BITS; i++) {
+ if (allowed[i / LONG_BITS] & (1UL << (i % LONG_BITS))) {
+ node_mask[i / LONG_BITS] = 1UL << (i % LONG_BITS);
+ break;
+ }
+ }
+ ASSERT_LT(i, NODE_BITS);
+
+ self->cgv2_fd = mount_cg2_fd();
+ ASSERT_GE(self->cgv2_fd, 0);
+ ASSERT_EQ(write_file_at(self->cgv2_fd, "cgroup.subtree_control",
+ VE_CONTROLLERS), 0);
+
+ self->ctid = make_ve(self->cgv2_fd, CTID_MIN);
+ ASSERT_GE(self->ctid, 0);
+}
+
+FIXTURE_TEARDOWN(numa_syscalls)
+{
+ if (self->cgv2_fd >= 0) {
+ destroy_ve(self->cgv2_fd, self->ctid);
+ close(self->cgv2_fd);
+ }
+}
+
+TEST_F(numa_syscalls, host_calls_succeed)
+{
+ struct call_result res[NR_CALLS];
+ unsigned int i;
+
+ run_calls(res);
+ for (i = 0; i < NR_CALLS; i++) {
+ EXPECT_EQ(res[i].ret, 0)
+ TH_LOG("%s on the host: %s", numa_calls[i].name,
+ strerror(res[i].err));
+ }
+}
+
+TEST_F(numa_syscalls, ve_calls_return_enosys)
+{
+ struct call_result res[NR_CALLS];
+ int pipefd[2], status;
+ unsigned int i;
+ pid_t pid;
+
+ ASSERT_EQ(pipe(pipefd), 0);
+ pid = fork();
+ ASSERT_GE(pid, 0);
+ if (pid == 0) {
+ close(pipefd[0]);
+ if (enter_cgroup(self->cgv2_fd, self->ctid) < 0)
+ _exit(1);
+ if (unshare(CLONE_NEWVE) < 0)
+ _exit(2);
+ run_calls(res);
+ if (write(pipefd[1], res, sizeof(res)) != sizeof(res))
+ _exit(3);
+ _exit(0);
+ }
+ close(pipefd[1]);
+ ASSERT_EQ(waitpid(pid, &status, 0), pid);
+ ASSERT_TRUE(WIFEXITED(status));
+ ASSERT_EQ(WEXITSTATUS(status), 0)
+ TH_LOG("VE child setup failed at step %d", WEXITSTATUS(status));
+ ASSERT_EQ(read(pipefd[0], res, sizeof(res)), sizeof(res));
+ close(pipefd[0]);
+
+ for (i = 0; i < NR_CALLS; i++) {
+ EXPECT_TRUE(res[i].ret == -1 && res[i].err == ENOSYS)
+ TH_LOG("%s in a VE: returned %ld (%s), expected ENOSYS",
+ numa_calls[i].name, res[i].ret,
+ strerror(res[i].err));
+ }
+}
+
+TEST_HARNESS_MAIN
--
2.43.0
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel
next prev parent reply other threads:[~2026-11-05 18:50 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 18:48 [Devel] [PATCH hci-8.1 0/2] mempolicy: prohibit mbind and set_mempolicy_home_node in VE Konstantin Khorenko
2026-11-05 18:48 ` [Devel] [PATCH hci-8.1 1/2] " Konstantin Khorenko
2026-11-05 18:52 ` no-reply
2026-11-05 18:48 ` Konstantin Khorenko [this message]
2026-11-05 18:54 ` [Devel] [PATCH hci-8.1 2/2] selftests/ve: check that the NUMA API syscalls return ENOSYS in a VE no-reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261105-b4-prep-khorenko-vstor-153679-mbind-ve-v1-2-b4fcd27c8001@virtuozzo.com \
--to=khorenko@virtuozzo.com \
--cc=devel@openvz.org \
--cc=ptikhomirov@virtuozzo.com \
--cc=vasileios.almpanis@virtuozzo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.