From 030c5ab9738a26904b820991fa0ab2c51ee5c2da Mon Sep 17 00:00:00 2001 From: Bui Quang Minh Date: Sun, 4 Sep 2022 15:55:24 +0700 Subject: zdtm: Check threads are restored into correct threaded controllers This test creates a process with 2 threads in different threaded controllers and check if CRIU restores these threads' cgroup controllers properly. Signed-off-by: Bui Quang Minh --- test/zdtm/static/Makefile | 3 + test/zdtm/static/cgroupv2_01.c | 180 +++++++++++++++++++++++++++++++++ test/zdtm/static/cgroupv2_01.checkskip | 11 ++ test/zdtm/static/cgroupv2_01.desc | 1 + test/zdtm/static/cgroupv2_01.hook | 24 +++++ 5 files changed, 219 insertions(+) create mode 100644 test/zdtm/static/cgroupv2_01.c create mode 100755 test/zdtm/static/cgroupv2_01.checkskip create mode 100644 test/zdtm/static/cgroupv2_01.desc create mode 100755 test/zdtm/static/cgroupv2_01.hook diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 915e565bd..edac92c83 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -387,6 +387,7 @@ TST_DIR = \ cgroup03 \ cgroup04 \ cgroupv2_00 \ + cgroupv2_01 \ cgroup_ifpriomap \ cgroup_ignore \ cgroup_stray \ @@ -679,6 +680,8 @@ sk-unix-listen02: CFLAGS += -DSK_UNIX_LISTEN02 sk-unix-listen03: CFLAGS += -DSK_UNIX_LISTEN03 sk-unix-listen04: CFLAGS += -DSK_UNIX_LISTEN02 -DSK_UNIX_LISTEN03 +cgroupv2_01: LDLIBS += -pthread + $(LIB): force $(Q) $(MAKE) -C $(LIBDIR) diff --git a/test/zdtm/static/cgroupv2_01.c b/test/zdtm/static/cgroupv2_01.c new file mode 100644 index 000000000..f3a6d18ba --- /dev/null +++ b/test/zdtm/static/cgroupv2_01.c @@ -0,0 +1,180 @@ +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check that cgroup-v2 threaded controllers"; +const char *test_author = "Bui Quang Minh "; + +char *dirname; +TEST_OPTION(dirname, string, "cgroup-v2 directory name", 1); +const char *cgname = "subcg01"; + +task_waiter_t t; + +#define gettid(code) syscall(__NR_gettid) + +void cleanup(void) +{ + char path[1024]; + + sprintf(path, "%s/%s/%s", dirname, cgname, "thread2"); + rmdir(path); + sprintf(path, "%s/%s/%s", dirname, cgname, "thread1"); + rmdir(path); + sprintf(path, "%s/%s", dirname, cgname); + rmdir(path); + sprintf(path, "%s", dirname); + umount(path); +} + +int is_in_cgroup(char *cgname) +{ + FILE *cgf; + char buffer[1024]; + + sprintf(buffer, "/proc/self/task/%ld/cgroup", gettid()); + cgf = fopen(buffer, "r"); + if (cgf == NULL) { + pr_err("Fail to open thread's cgroup procfs\n"); + return 0; + } + + while (fgets(buffer, sizeof(buffer), cgf)) { + if (strstr(buffer, cgname)) { + fclose(cgf); + return 1; + } + } + + fclose(cgf); + return 0; +} + +void *thread_func(void *arg) +{ + char path[1024], aux[1024]; + + sprintf(path, "%s/%s/%s/%s", dirname, cgname, "thread2", "cgroup.threads"); + sprintf(aux, "%ld", gettid()); + if (write_value(path, aux)) { + cleanup(); + exit(1); + } + + read_value(path, aux, sizeof(aux)); + + task_waiter_complete(&t, 1); + + /* Wait for restore */ + task_waiter_wait4(&t, 2); + + sprintf(path, "/%s/%s", cgname, "thread2"); + if (!is_in_cgroup(path)) { + fail("Thread2's cgroup is not restored"); + cleanup(); + exit(1); + } + + return NULL; +} + +int main(int argc, char **argv) +{ + char path[1024], aux[1024]; + pthread_t thread2; + int ret = 1; + + test_init(argc, argv); + task_waiter_init(&t); + + if (mkdir(dirname, 0700) < 0 && errno != EEXIST) { + pr_perror("Can't make dir"); + return -1; + } + + if (mount("cgroup2", dirname, "cgroup2", 0, NULL)) { + pr_perror("Can't mount cgroup-v2"); + return -1; + } + + sprintf(path, "%s/%s", dirname, cgname); + if (mkdir(path, 0700) < 0 && errno != EEXIST) { + pr_perror("Can't make dir"); + goto out; + } + + /* Make cpuset controllers available in children directory */ + sprintf(path, "%s/%s", dirname, "cgroup.subtree_control"); + sprintf(aux, "%s", "+cpuset"); + if (write_value(path, aux)) + goto out; + + sprintf(path, "%s/%s/%s", dirname, cgname, "cgroup.subtree_control"); + sprintf(aux, "%s", "+cpuset"); + if (write_value(path, aux)) + goto out; + + sprintf(path, "%s/%s/%s", dirname, cgname, "cgroup.procs"); + sprintf(aux, "%d", getpid()); + if (write_value(path, aux)) + goto out; + + sprintf(path, "%s/%s/%s", dirname, cgname, "thread1"); + if (mkdir(path, 0700) < 0 && errno != EEXIST) { + pr_perror("Can't make dir"); + goto out; + } + + sprintf(path, "%s/%s/%s/%s", dirname, cgname, "thread1", "cgroup.type"); + sprintf(aux, "%s", "threaded"); + if (write_value(path, aux)) + goto out; + + sprintf(path, "%s/%s/%s", dirname, cgname, "thread2"); + if (mkdir(path, 0700) < 0 && errno != EEXIST) { + pr_perror("Can't make dir"); + goto out; + } + + sprintf(path, "%s/%s/%s/%s", dirname, cgname, "thread2", "cgroup.type"); + sprintf(aux, "%s", "threaded"); + if (write_value(path, aux)) + goto out; + + ret = pthread_create(&thread2, NULL, thread_func, NULL); + if (ret < 0) { + pr_err("pthread_create %s\n", strerror(ret)); + ret = 1; + goto out; + } + + sprintf(path, "%s/%s/%s/%s", dirname, cgname, "thread1", "cgroup.threads"); + sprintf(aux, "%ld", gettid()); + if (write_value(path, aux)) + goto out; + + task_waiter_wait4(&t, 1); + + test_daemon(); + test_waitsig(); + + task_waiter_complete(&t, 2); + + sprintf(path, "/%s/%s", cgname, "thread1"); + if (!is_in_cgroup(path)) { + fail("Main thread's cgroup is not restored"); + cleanup(); + exit(1); + } + pthread_join(thread2, NULL); + pass(); + + ret = 0; + +out: + cleanup(); + return ret; +} diff --git a/test/zdtm/static/cgroupv2_01.checkskip b/test/zdtm/static/cgroupv2_01.checkskip new file mode 100755 index 000000000..375ed3564 --- /dev/null +++ b/test/zdtm/static/cgroupv2_01.checkskip @@ -0,0 +1,11 @@ +#!/bin/bash + +if [ -f /sys/fs/cgroup/cgroup.controllers ]; then + grep -q "cpuset" /sys/fs/cgroup/cgroup.controllers && exit 0 +fi + +if [ -d /sys/fs/cgroup/unified ]; then + grep -q "cpuset" /sys/fs/cgroup/unified/cgroup.controllers && exit 0 +fi + +exit 1 diff --git a/test/zdtm/static/cgroupv2_01.desc b/test/zdtm/static/cgroupv2_01.desc new file mode 100644 index 000000000..4bfd4b265 --- /dev/null +++ b/test/zdtm/static/cgroupv2_01.desc @@ -0,0 +1 @@ +{'flavor': 'h ns', 'flags': 'suid', 'opts': '--manage-cgroups=full'} diff --git a/test/zdtm/static/cgroupv2_01.hook b/test/zdtm/static/cgroupv2_01.hook new file mode 100755 index 000000000..2263fd014 --- /dev/null +++ b/test/zdtm/static/cgroupv2_01.hook @@ -0,0 +1,24 @@ +#!/bin/bash + +[ "$1" == "--clean" -o "$1" == "--pre-restore" ] || exit 0 + +set -e +cgname="subcg01" +tname=$(mktemp -d cgclean.XXXXXX) +mount -t cgroup2 cgroup2 $tname + +echo "Cleaning $tname" + +set +e +rmdir "$tname/$cgname/thread1" + +# When the test finishes, the cleanup() function removes this directory +# successfully because the thread in this controller exit and no other +# threads belong to this controller +if [ "$1" == "--pre-restore" ]; then + rmdir "$tname/$cgname/thread2" +fi + +rmdir "$tname/$cgname" +umount "$tname" +rmdir "$tname" -- cgit v1.2.3