Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/checkpoint-restore/criu.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBui Quang Minh <minhquangbui99@gmail.com>2022-09-04 11:55:24 +0300
committerAndrei Vagin <avagin@gmail.com>2022-11-02 07:35:04 +0300
commit030c5ab9738a26904b820991fa0ab2c51ee5c2da (patch)
treea441bac113d15d7b1744fbcc11f2fb50a7af3d0e
parentda84213352ee4863e1739fd2b4da1e177426f98a (diff)
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 <minhquangbui99@gmail.com>
-rw-r--r--test/zdtm/static/Makefile3
-rw-r--r--test/zdtm/static/cgroupv2_01.c180
-rwxr-xr-xtest/zdtm/static/cgroupv2_01.checkskip11
-rw-r--r--test/zdtm/static/cgroupv2_01.desc1
-rwxr-xr-xtest/zdtm/static/cgroupv2_01.hook24
5 files changed, 219 insertions, 0 deletions
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 <sys/mount.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#include <syscall.h>
+
+#include "zdtmtst.h"
+
+const char *test_doc = "Check that cgroup-v2 threaded controllers";
+const char *test_author = "Bui Quang Minh <minhquangbui99@gmail.com>";
+
+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"