The test creates a tmpfs superblock with mpol=local and expects it to succeed on the host and to fail with -EINVAL in a VE. A tmpfs with size= is created in the VE as well, so the EINVAL can only come from the mpol= check, not from tmpfs being unavailable in the VE.
https://virtuozzo.atlassian.net/browse/VSTOR-153679 Feature: mm: prohibit NUMA API inside CT Signed-off-by: Konstantin Khorenko <[email protected]> --- tools/testing/selftests/ve/.gitignore | 1 + tools/testing/selftests/ve/Makefile | 1 + tools/testing/selftests/ve/ve_tmpfs_mpol_test.c | 123 ++++++++++++++++++++++++ 3 files changed, 125 insertions(+) diff --git a/tools/testing/selftests/ve/.gitignore b/tools/testing/selftests/ve/.gitignore index 5e07985c8fed3..2ff7669a393aa 100644 --- a/tools/testing/selftests/ve/.gitignore +++ b/tools/testing/selftests/ve/.gitignore @@ -5,3 +5,4 @@ ve_cpuid_override_test ve_vtty_stress ve_numa_migrate_test ve_numa_syscalls_prohibited_test +ve_tmpfs_mpol_test diff --git a/tools/testing/selftests/ve/Makefile b/tools/testing/selftests/ve/Makefile index 451a7e1cc17d1..cff4fc2a7639f 100644 --- a/tools/testing/selftests/ve/Makefile +++ b/tools/testing/selftests/ve/Makefile @@ -8,6 +8,7 @@ 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 +TEST_GEN_PROGS += ve_tmpfs_mpol_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_tmpfs_mpol_test.c b/tools/testing/selftests/ve/ve_tmpfs_mpol_test.c new file mode 100644 index 0000000000000..6254f95fadece --- /dev/null +++ b/tools/testing/selftests/ve/ve_tmpfs_mpol_test.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 +/* The tmpfs mpol= mount option works on the host and is rejected in a VE. */ +#define _GNU_SOURCE +#include <errno.h> +#include <sched.h> +#include <sys/mount.h> +#include <sys/syscall.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "../kselftest_harness.h" +#include "ve_selftest.h" + +/* Create a tmpfs superblock with one option set: 0 or the errno. */ +static int tmpfs_create(const char *key, const char *val) +{ + int fd, err = 0; + + fd = fsopen("tmpfs", FSOPEN_CLOEXEC); + if (fd < 0) + return errno; + if (fsconfig(fd, FSCONFIG_SET_STRING, key, val, 0) < 0 || + fsconfig(fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) + err = errno; + close(fd); + return err; +} + +struct tmpfs_result { + int size_err; + int mpol_err; +}; + +static void run_tmpfs(struct tmpfs_result *res) +{ + res->size_err = tmpfs_create("size", "1M"); + res->mpol_err = tmpfs_create("mpol", "local"); +} + +FIXTURE(tmpfs_mpol) +{ + int cgv2_fd; + int ctid; +}; + +FIXTURE_SETUP(tmpfs_mpol) +{ + long ret; + + self->cgv2_fd = -1; + + if (geteuid() != 0) + SKIP(return, "creating a ve cgroup needs root"); + + ret = syscall(__NR_get_mempolicy, NULL, NULL, 0UL, 0UL, 0UL); + if (ret == -1 && errno == ENOSYS) + SKIP(return, "no NUMA API on the host"); + ASSERT_EQ(ret, 0); + + 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(tmpfs_mpol) +{ + if (self->cgv2_fd >= 0) { + destroy_ve(self->cgv2_fd, self->ctid); + close(self->cgv2_fd); + } +} + +TEST_F(tmpfs_mpol, host_mpol_accepted) +{ + struct tmpfs_result res; + + run_tmpfs(&res); + EXPECT_EQ(res.size_err, 0) + TH_LOG("tmpfs size= on the host: %s", strerror(res.size_err)); + EXPECT_EQ(res.mpol_err, 0) + TH_LOG("tmpfs mpol= on the host: %s", strerror(res.mpol_err)); +} + +TEST_F(tmpfs_mpol, ve_mpol_rejected) +{ + struct tmpfs_result res; + int pipefd[2], status; + 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_tmpfs(&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]); + + EXPECT_EQ(res.size_err, 0) + TH_LOG("tmpfs size= in a VE: %s", strerror(res.size_err)); + EXPECT_EQ(res.mpol_err, EINVAL) + TH_LOG("tmpfs mpol= in a VE: %s, expected EINVAL", + strerror(res.mpol_err)); +} + +TEST_HARNESS_MAIN -- 2.43.0 _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
