Commit 95d6621c authored by Dmitry Safonov's avatar Dmitry Safonov Committed by Andrei Vagin

zdtm/cgroup: Add test for ifpriomap

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: 's avatarDmitry Safonov <dsafonov@virtuozzo.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent 0f9ed595
......@@ -277,6 +277,7 @@ TST_DIR = \
cgroup02 \
cgroup03 \
cgroup04 \
cgroup_ifpriomap \
cgroup_stray \
unlink_fstat04 \
mntns_remap \
......
#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@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;
}
{'flavor': 'h', 'flags': 'suid excl', 'opts': '--manage-cgroups=full'}
#!/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"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment