[CRIU] [PATCH 11/11] zdtm/cgroup: Add test for ifpriomap
Dmitry Safonov
dsafonov at virtuozzo.com
Wed Jul 26 00:08:16 MSK 2017
A test to check C/R of multiline cgroup net_prio.ifpriomap.
Before this patches set restoring of this file failed as
it's a multiline cgroup property and kernel can read it
only line-by-line.
Signed-off-by: Dmitry Safonov <dsafonov at virtuozzo.com>
---
test/zdtm/static/Makefile | 1 +
test/zdtm/static/cgroup_ifpriomap.c | 271 +++++++++++++++++++++++++++++++++
test/zdtm/static/cgroup_ifpriomap.desc | 1 +
test/zdtm/static/cgroup_ifpriomap.hook | 15 ++
4 files changed, 288 insertions(+)
create mode 100644 test/zdtm/static/cgroup_ifpriomap.c
create mode 100644 test/zdtm/static/cgroup_ifpriomap.desc
create mode 100755 test/zdtm/static/cgroup_ifpriomap.hook
diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
index b3b5fae26585..ae42ca51b871 100644
--- a/test/zdtm/static/Makefile
+++ b/test/zdtm/static/Makefile
@@ -276,6 +276,7 @@ TST_DIR = \
cgroup02 \
cgroup03 \
cgroup04 \
+ cgroup_ifpriomap \
cgroup_stray \
unlink_fstat04 \
mntns_remap \
diff --git a/test/zdtm/static/cgroup_ifpriomap.c b/test/zdtm/static/cgroup_ifpriomap.c
new file mode 100644
index 000000000000..d14508060194
--- /dev/null
+++ b/test/zdtm/static/cgroup_ifpriomap.c
@@ -0,0 +1,271 @@
+#include <fcntl.h>
+#include <linux/limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include "zdtmtst.h"
+
+const char *test_doc = "Check preserving multiline cgroup controller's property net_prio/net_prio.ifpriomap";
+const char *test_author = "Dmitry Safonov <dsafonov at virtuozzo.com>";
+
+char *dirname;
+TEST_OPTION(dirname, string, "cgroup directory name", 1);
+
+static const char *cgname = "zdtmtst";
+
+#define BUF_SZ 1024
+#define PRIOMAPS_SZ 40
+
+struct ifpriomap_t {
+ char *ifname;
+ uint32_t prio;
+};
+struct ifpriomap_t maps[PRIOMAPS_SZ], new_maps[PRIOMAPS_SZ];
+
+static int mount_cg(const char *controller)
+{
+ char mnt_point[BUF_SZ], subdir[BUF_SZ];
+ char tasks_path[BUF_SZ], pid_str[BUF_SZ];
+ int fd;
+
+ sprintf(mnt_point, "%s/%s", dirname, controller);
+ sprintf(subdir, "%s/%s/%s", dirname, controller, cgname);
+ sprintf(pid_str, "%d", getpid());
+ sprintf(tasks_path, "%s/%s/%s/tasks", dirname, controller, cgname);
+
+ if (mkdir(dirname, 0700) < 0 && errno != EEXIST) {
+ pr_perror("Can't make dir");
+ return -1;
+ }
+ if (mkdir(mnt_point, 0700) < 0) {
+ pr_perror("Can't make dir `%s'", mnt_point);
+ return -1;
+ }
+ if (mount("none", mnt_point, "cgroup", 0, controller)) {
+ pr_perror("Can't mount cgroups");
+ goto err_rm;
+ }
+ if (mkdir(subdir, 0700) < 0 && errno != EEXIST) {
+ pr_perror("Can't make dir `%s'", subdir);
+ goto err_umount;
+ }
+
+ /* Add self to newly created cgroup */
+ fd = open(tasks_path, O_WRONLY);
+ if (fd < 0) {
+ pr_perror("Failed to open `%s'", tasks_path);
+ goto err_controller;
+ }
+ if (write(fd, pid_str, strlen(pid_str)) != strlen(pid_str)) {
+ pr_perror("failed to write `%s' to `%s'", pid_str, tasks_path);
+ close(fd);
+ goto err_controller;
+ }
+
+ close(fd);
+ return 0;
+
+err_controller:
+ rmdir(subdir);
+err_umount:
+ umount(mnt_point);
+err_rm:
+ rmdir(mnt_point);
+ return -1;
+}
+
+static int umount_cg(const char *controller)
+{
+ char mnt_point[BUF_SZ], subdir[BUF_SZ];
+
+ sprintf(mnt_point, "%s/%s", dirname, controller);
+ sprintf(subdir, "%s/%s/%s", dirname, controller, cgname);
+
+ rmdir(subdir);
+
+ return umount(mnt_point);
+}
+
+static int read_one_priomap(char *prop_line, struct ifpriomap_t *out)
+{
+ char *space;
+ size_t len;
+
+ space = strchr(prop_line, ' ');
+ if (!space) {
+ pr_err("Broken ifpriomap file line: `%s'\n", prop_line);
+ return -1;
+ }
+ len = space - prop_line;
+
+ out->ifname = malloc(len + 1);
+ strncpy(out->ifname, prop_line, len);
+ out->ifname[len] = '\0'; /* poor man's strlcpy() */
+ out->prio = (uint32_t)strtol(space + 1, NULL, 10);
+
+ return 0;
+}
+
+static int read_map(const char *path, struct ifpriomap_t *out, size_t out_sz)
+{
+ char buf[BUF_SZ];
+ FILE *fpriomap;
+ size_t i;
+
+ fpriomap = fopen(path, "r");
+ if (!fpriomap) {
+ pr_perror("Failed to open `%s'", path);
+ return -1;
+ }
+
+ for (i = 0; i < out_sz; i++) {
+ if (!fgets(buf, BUF_SZ, fpriomap))
+ break;
+
+ if (read_one_priomap(buf, &out[i])) {
+ fclose(fpriomap);
+ return -1;
+ }
+ }
+
+ if (fclose(fpriomap)) {
+ pr_perror("Failed to close `%s'", path);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_map(const char *path, struct ifpriomap_t *out, size_t out_sz)
+{
+ char buf[BUF_SZ];
+ ssize_t written;
+ size_t i;
+ int fd;
+
+ fd = open(path, O_WRONLY);
+ if (fd < 0) {
+ pr_perror("Failed to open `%s'", path);
+ return -1;
+ }
+
+ for (i = 0; i < out_sz; i++) {
+ struct ifpriomap_t *p = &out[i];
+
+ if (!p->ifname)
+ break;
+
+ snprintf(buf, BUF_SZ, "%s %lu",
+ p->ifname, (unsigned long)p->prio);
+
+ written = write(fd, buf, strlen(buf));
+ if (written < 0) {
+ pr_perror("Failed to write `%s' to `%s'", buf, path);
+ close(fd);
+ return -1;
+ }
+ }
+
+ if (close(fd)) {
+ pr_perror("Failed to close `%s'", path);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void randomize_map(struct ifpriomap_t *out, size_t out_sz)
+{
+ size_t i;
+
+ for (i = 0; i < out_sz; i++) {
+ struct ifpriomap_t *p = &out[i];
+
+ if (!p->ifname)
+ return;
+
+ p->prio += rand();
+ }
+}
+
+static int compare_maps(void)
+{
+ size_t i, j;
+
+ for (i = 0; i < PRIOMAPS_SZ; i++) {
+ struct ifpriomap_t *a = &maps[i];
+
+ if (!a->ifname)
+ return 0;
+
+ for (j = 0; j < PRIOMAPS_SZ; j++) {
+ struct ifpriomap_t *b = &new_maps[j];
+
+ if (!b->ifname)
+ break;
+
+ if (strcmp(a->ifname, b->ifname) == 0) {
+ if (a->prio != b->prio) {
+ pr_err("`%s' prio: %lu != %lu\n",
+ a->ifname,
+ (unsigned long)a->prio,
+ (unsigned long)b->prio);
+ return -1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ char subdir[PATH_MAX];
+ char path[PATH_MAX];
+ int ret = -1;
+
+ srand(time(NULL));
+
+ test_init(argc, argv);
+
+ if (mount_cg("net_prio") < 0)
+ return -1;
+
+ sprintf(path, "%s/net_prio/%s/net_prio.ifpriomap", dirname, cgname);
+
+ if (read_map(path, maps, PRIOMAPS_SZ))
+ goto out_umount;
+
+ randomize_map(maps, PRIOMAPS_SZ);
+
+ if (write_map(path, maps, PRIOMAPS_SZ))
+ goto out_umount;
+
+ test_daemon();
+ test_waitsig();
+
+ if (read_map(path, new_maps, PRIOMAPS_SZ)) {
+ fail("Can't read ifpriomap after C/R");
+ goto out_umount;
+ }
+
+ if (!compare_maps()) {
+ ret = 0;
+ pass();
+ } else {
+ fail("ifpriomap differs before/after C/R");
+ }
+
+out_umount:
+ sprintf(subdir, "%s/%s/%s", dirname, "net_prio", cgname);
+ rmdir(subdir);
+ umount_cg("net_prio");
+
+ return ret;
+}
diff --git a/test/zdtm/static/cgroup_ifpriomap.desc b/test/zdtm/static/cgroup_ifpriomap.desc
new file mode 100644
index 000000000000..5fa9d5079040
--- /dev/null
+++ b/test/zdtm/static/cgroup_ifpriomap.desc
@@ -0,0 +1 @@
+{'flavor': 'h', 'flags': 'suid excl', 'opts': '--manage-cgroups=full'}
diff --git a/test/zdtm/static/cgroup_ifpriomap.hook b/test/zdtm/static/cgroup_ifpriomap.hook
new file mode 100755
index 000000000000..692c5ebe26a6
--- /dev/null
+++ b/test/zdtm/static/cgroup_ifpriomap.hook
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+[ "$1" == "--clean" -o "$1" == "--pre-restore" ] || exit 0
+
+tname=$(mktemp -d cgclean.XXXXXX)
+mount -t cgroup none $tname -o "net_prio"
+
+echo "Cleaning $tname"
+
+set +e
+rmdir "$tname/zdtmtst"
+set -e
+
+umount "$tname"
+rmdir "$tname"
--
2.13.3
More information about the CRIU
mailing list