[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