The ve selftests each keep their own copies of the same small pieces: a private cgroup2 mount, an openat based file write helper, a u64 file reader, a cgroup join helper, VE cgroup create and destroy, the CLONE_NEWVE fallback, the ctid search range, and the controller set a VE cgroup needs enabled. The new ve.proc_permissions test needs them too, so move them into a shared ve_selftest.h, the helpers made static inline so they can live in a header, and drop the copies from ve_ns_owner_test.
No functional change to the tests. The moved code keeps the same behaviour bar cosmetic reformatting. The shared destroy_ve additionally retries briefly on a busy cgroup, which only makes teardown more robust. https://virtuozzo.atlassian.net/browse/VSTOR-135286 Signed-off-by: Mirian Shilakadze <[email protected]> --- tools/testing/selftests/ve/ve_ns_owner_test.c | 111 +------------ tools/testing/selftests/ve/ve_selftest.h | 151 ++++++++++++++++++ 2 files changed, 158 insertions(+), 104 deletions(-) create mode 100644 tools/testing/selftests/ve/ve_selftest.h diff --git a/tools/testing/selftests/ve/ve_ns_owner_test.c b/tools/testing/selftests/ve/ve_ns_owner_test.c index b5b4f10be72b..82c31dff4b1b 100644 --- a/tools/testing/selftests/ve/ve_ns_owner_test.c +++ b/tools/testing/selftests/ve/ve_ns_owner_test.c @@ -43,13 +43,7 @@ #include <errno.h> #include "../kselftest_harness.h" - -#define CTID_MIN 108 -#define CTID_MAX 200 - -#ifndef CLONE_NEWVE -#define CLONE_NEWVE 0x00000040 -#endif +#include "ve_selftest.h" /* * Make ve.netns_avail_nr movements easy to detect: a small cap means @@ -57,81 +51,6 @@ */ #define VE_NETNS_MAX 3 -static int write_file_at(int dirfd, const char *path, const char *val) -{ - int fd, ret; - size_t len = strlen(val); - - fd = openat(dirfd, path, O_WRONLY); - if (fd < 0) - return -1; - - ret = write(fd, val, len); - close(fd); - return (ret == (int)len) ? 0 : -1; -} - -static int read_u64_at(int dirfd, const char *path, unsigned long long *out) -{ - char buf[32] = {0}; - int fd, ret; - - fd = openat(dirfd, path, O_RDONLY); - if (fd < 0) - return -1; - - ret = read(fd, buf, sizeof(buf) - 1); - close(fd); - if (ret <= 0) - return -1; - - *out = strtoull(buf, NULL, 10); - return 0; -} - -static int mount_cg2_fd(void) -{ - int fs_fd, mnt_fd; - - fs_fd = syscall(__NR_fsopen, "cgroup2", 0); - if (fs_fd < 0) - return -1; - - if (syscall(__NR_fsconfig, fs_fd, FSCONFIG_CMD_CREATE, - NULL, NULL, 0) < 0) { - close(fs_fd); - return -1; - } - - mnt_fd = syscall(__NR_fsmount, fs_fd, 0, 0); - close(fs_fd); - return mnt_fd; -} - -static int enter_cgroup(int cgv2_fd, int ctid) -{ - char cg_path[64]; - char pid_str[64]; - int fd; - int ret; - - if (ctid) - snprintf(cg_path, sizeof(cg_path), "%d/cgroup.procs", ctid); - else - snprintf(cg_path, sizeof(cg_path), "cgroup.procs"); - fd = openat(cgv2_fd, cg_path, O_WRONLY); - if (fd < 0) - return -1; - - snprintf(pid_str, sizeof(pid_str), "%d", getpid()); - ret = write(fd, pid_str, strlen(pid_str)); - if (ret < 0 || ret != (int)strlen(pid_str)) - ret = -1; - - close(fd); - return ret; -} - /* * Synchronisation across the clone() boundary: child does its setup, * tells parent it is ready, then blocks until parent acknowledges. @@ -199,7 +118,7 @@ static void check_new_ve_owner(struct __test_metadata *_metadata, int cgv2_fd, int ctid) { unsigned long long avail, mnt; - char path[64]; + char path[PATH_MAX]; snprintf(path, sizeof(path), "%d/ve.netns_avail_nr", ctid); ASSERT_EQ(read_u64_at(cgv2_fd, path, &avail), 0); @@ -219,15 +138,14 @@ FIXTURE(ve_ns_owner) FIXTURE_SETUP(ve_ns_owner) { unsigned long long initial_mnt_nr; - char ctid_str[16]; char val[16]; - char path[64]; + char path[PATH_MAX]; self->cgv2_fd = mount_cg2_fd(); ASSERT_GE(self->cgv2_fd, 0); ASSERT_EQ(write_file_at(self->cgv2_fd, "cgroup.subtree_control", - "+cpuset +cpu +cpuacct +io +memory +hugetlb +pids +rdma +misc +ve"), 0); + VE_CONTROLLERS), 0); ASSERT_EQ(write_file_at(self->cgv2_fd, "ve.default_sysfs_permissions", "/ rx"), 0); @@ -236,20 +154,8 @@ FIXTURE_SETUP(ve_ns_owner) ASSERT_EQ(write_file_at(self->cgv2_fd, "ve.default_sysfs_permissions", "fs/cgroup rw"), 0); - self->ctid = CTID_MIN; - while (self->ctid < CTID_MAX) { - snprintf(ctid_str, sizeof(ctid_str), "%d", self->ctid); - if (faccessat(self->cgv2_fd, ctid_str, F_OK, 0) != 0 && - errno == ENOENT) - break; - self->ctid++; - } - ASSERT_LT(self->ctid, CTID_MAX); - - ASSERT_EQ(mkdirat(self->cgv2_fd, ctid_str, 0755), 0); - - snprintf(path, sizeof(path), "%d/cgroup.controllers_hidden", self->ctid); - ASSERT_EQ(write_file_at(self->cgv2_fd, path, "-ve"), 0); + self->ctid = make_ve(self->cgv2_fd, CTID_MIN); + ASSERT_GE(self->ctid, 0); /* * ve.veid and ve.features are deliberately not configured: the @@ -279,11 +185,8 @@ FIXTURE_SETUP(ve_ns_owner) FIXTURE_TEARDOWN(ve_ns_owner) { - char path[64]; - enter_cgroup(self->cgv2_fd, 0); - snprintf(path, sizeof(path), "%d", self->ctid); - unlinkat(self->cgv2_fd, path, AT_REMOVEDIR); + destroy_ve(self->cgv2_fd, self->ctid); close(self->cgv2_fd); } diff --git a/tools/testing/selftests/ve/ve_selftest.h b/tools/testing/selftests/ve/ve_selftest.h new file mode 100644 index 000000000000..dddb09e948f9 --- /dev/null +++ b/tools/testing/selftests/ve/ve_selftest.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Shared helpers for the ve selftests: a private cgroup2 mount, small file and + * cgroup helpers, and VE cgroup create and destroy, used across the tests in + * this directory. + */ +#ifndef __SELFTESTS_VE_VE_SELFTEST_H +#define __SELFTESTS_VE_VE_SELFTEST_H + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <limits.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/mount.h> +#include <linux/mount.h> + +#ifndef CLONE_NEWVE +#define CLONE_NEWVE 0x00000040 +#endif + +/* VE cgroup id search range shared by the ve tests. */ +#define CTID_MIN 108 +#define CTID_MAX 200 + +/* Controllers a VE cgroup needs enabled in the root subtree_control. */ +#define VE_CONTROLLERS \ + "+cpuset +cpu +cpuacct +io +memory +hugetlb +pids +rdma +misc +ve" + +static inline int write_file_at(int dirfd, const char *path, const char *val) +{ + int fd, ret; + size_t len = strlen(val); + + fd = openat(dirfd, path, O_WRONLY); + if (fd < 0) + return -1; + + ret = write(fd, val, len); + close(fd); + return (ret == (int)len) ? 0 : -1; +} + +static inline int read_u64_at(int dirfd, const char *path, + unsigned long long *out) +{ + char buf[32] = {0}; + int fd, ret; + + fd = openat(dirfd, path, O_RDONLY); + if (fd < 0) + return -1; + + ret = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (ret <= 0) + return -1; + + *out = strtoull(buf, NULL, 10); + return 0; +} + +/* A fresh, private cgroup2 mount, returned as an fd to use with *at() calls. */ +static inline int mount_cg2_fd(void) +{ + int fs_fd, mnt_fd; + + fs_fd = syscall(__NR_fsopen, "cgroup2", 0); + if (fs_fd < 0) + return -1; + + if (syscall(__NR_fsconfig, fs_fd, FSCONFIG_CMD_CREATE, + NULL, NULL, 0) < 0) { + close(fs_fd); + return -1; + } + + mnt_fd = syscall(__NR_fsmount, fs_fd, 0, 0); + close(fs_fd); + return mnt_fd; +} + +/* Move the caller into cgroup @ctid (or the root when @ctid is 0). */ +static inline int enter_cgroup(int cgv2_fd, int ctid) +{ + char cg_path[PATH_MAX]; + char pid_str[64]; + int fd, ret; + + if (ctid) + snprintf(cg_path, sizeof(cg_path), "%d/cgroup.procs", ctid); + else + snprintf(cg_path, sizeof(cg_path), "cgroup.procs"); + fd = openat(cgv2_fd, cg_path, O_WRONLY); + if (fd < 0) + return -1; + + snprintf(pid_str, sizeof(pid_str), "%d", getpid()); + ret = write(fd, pid_str, strlen(pid_str)); + if (ret < 0 || ret != (int)strlen(pid_str)) + ret = -1; + + close(fd); + return ret; +} + +/* + * Create a fresh VE cgroup at the first free id at or after @from and unhide + * its ve.* control files. Return the new id, or -1. + */ +static inline int make_ve(int cgv2_fd, int from) +{ + char name[16], path[PATH_MAX]; + int id; + + for (id = from; id < CTID_MAX; id++) { + snprintf(name, sizeof(name), "%d", id); + if (faccessat(cgv2_fd, name, F_OK, 0) != 0 && errno == ENOENT) + break; + } + if (id >= CTID_MAX) + return -1; + if (mkdirat(cgv2_fd, name, 0755) != 0) + return -1; + snprintf(path, sizeof(path), "%d/cgroup.controllers_hidden", id); + if (write_file_at(cgv2_fd, path, "-ve") < 0) + return -1; + return id; +} + +/* Remove a VE cgroup, retrying briefly while it is still busy. */ +static inline void destroy_ve(int cgv2_fd, int id) +{ + char name[16]; + int i; + + if (id < 0) + return; + snprintf(name, sizeof(name), "%d", id); + for (i = 0; i < 100; i++) { + if (unlinkat(cgv2_fd, name, AT_REMOVEDIR) == 0 || errno != EBUSY) + break; + usleep(10000); + } +} + +#endif /* __SELFTESTS_VE_VE_SELFTEST_H */ -- 2.43.0 _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
