diff --git a/.gitignore b/.gitignore index 068cac8486c64698e534ae390b34fd82411a5b30..5e50b521b78ae49458c1aff3d46a163e12543e5b 100644 --- a/.gitignore +++ b/.gitignore @@ -178,6 +178,7 @@ /tests/virauthconfigtest /tests/virbitmaptest /tests/virbuftest +/tests/vircgrouptest /tests/virdrivermoduletest /tests/virendiantest /tests/virhashtest diff --git a/cfg.mk b/cfg.mk index 394521e476aa074b35850d65771910562e2a1118..e60c4e31c1f87159b7d247bea360ff4267db7895 100644 --- a/cfg.mk +++ b/cfg.mk @@ -788,15 +788,16 @@ $(srcdir)/src/remote/remote_client_bodies.h: $(srcdir)/src/remote/remote_protoco exclude_file_name_regexp--sc_avoid_strcase = ^tools/virsh\.h$$ _src1=libvirt|fdstream|qemu/qemu_monitor|util/(vircommand|virutil)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller|locking/lock_daemon +_test1=shunloadtest|virnettlscontexttest|vircgroupmock exclude_file_name_regexp--sc_avoid_write = \ - ^(src/($(_src1))|daemon/libvirtd|tools/console|tests/(shunload|virnettlscontext)test)\.c$$ + ^(src/($(_src1))|daemon/libvirtd|tools/console|tests/($(_test1)))\.c$$ exclude_file_name_regexp--sc_bindtextdomain = ^(tests|examples)/ exclude_file_name_regexp--sc_copyright_address = \ ^COPYING\.LIB$$ -exclude_file_name_regexp--sc_flags_usage = ^(docs/|src/util/virnetdevtap\.c$$) +exclude_file_name_regexp--sc_flags_usage = ^(docs/|src/util/virnetdevtap\.c$$|tests/vircgroupmock\.c$$) exclude_file_name_regexp--sc_libvirt_unmarked_diagnostics = \ ^(src/rpc/gendispatch\.pl$$|tests/) @@ -812,10 +813,10 @@ exclude_file_name_regexp--sc_prohibit_always_true_header_tests = \ ^python/(libvirt-(lxc-|qemu-)?override|typewrappers)\.c$$ exclude_file_name_regexp--sc_prohibit_asprintf = \ - ^(bootstrap.conf$$|src/util/virutil\.c$$|examples/domain-events/events-c/event-test\.c$$) + ^(bootstrap.conf$$|src/util/virutil\.c$$|examples/domain-events/events-c/event-test\.c$$|tests/vircgroupmock\.c$$) exclude_file_name_regexp--sc_prohibit_close = \ - (\.p[yl]$$|^docs/|^(src/util/virfile\.c|src/libvirt\.c)$$) + (\.p[yl]$$|^docs/|^(src/util/virfile\.c|src/libvirt\.c|tests/vircgroupmock\.c)$$) exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \ (^tests/(qemuhelp|nodeinfo)data/|\.(gif|ico|png|diff)$$) @@ -836,7 +837,7 @@ exclude_file_name_regexp--sc_prohibit_nonreentrant = \ ^((po|tests)/|docs/.*(py|html\.in)|run.in$$) exclude_file_name_regexp--sc_prohibit_raw_allocation = \ - ^(docs/hacking\.html\.in)|(src/util/viralloc\.[ch]|examples/.*|tests/securityselinuxhelper.c)$$ + ^(docs/hacking\.html\.in)|(src/util/viralloc\.[ch]|examples/.*|tests/securityselinuxhelper\.c|tests/vircgroupmock\.c)$$ exclude_file_name_regexp--sc_prohibit_readlink = \ ^src/(util/virutil|lxc/lxc_container)\.c$$ diff --git a/tests/Makefile.am b/tests/Makefile.am index 7689453dde4ae17ca171e8348ffd8eafada5ed9a..68dbb273d7ca58b5a888c7176008a497056ee685 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -97,7 +97,9 @@ test_programs = virshtest sockettest \ utiltest shunloadtest \ virtimetest viruritest virkeyfiletest \ virauthconfigtest \ - virbitmaptest virendiantest \ + virbitmaptest \ + vircgrouptest \ + virendiantest \ viridentitytest \ virkeycodetest \ virlockspacetest \ @@ -249,6 +251,7 @@ EXTRA_DIST += $(test_scripts) test_libraries = libshunload.la \ libvirportallocatormock.la \ + vircgroupmock.la \ $(NULL) if WITH_QEMU test_libraries += libqemumonitortestutils.la @@ -598,6 +601,16 @@ libvirportallocatormock_la_CFLAGS = $(AM_CFLAGS) -DMOCK_HELPER=1 libvirportallocatormock_la_LDFLAGS = -module -avoid-version \ -rpath /evil/libtool/hack/to/force/shared/lib/creation +vircgrouptest_SOURCES = \ + vircgrouptest.c testutils.h testutils.c +vircgrouptest_LDADD = $(LDADDS) + +vircgroupmock_la_SOURCES = \ + vircgroupmock.c +vircgroupmock_la_CFLAGS = $(AM_CFLAGS) +vircgroupmock_la_LDFLAGS = -module -avoid-version \ + -rpath /evil/libtool/hack/to/force/shared/lib/creation + viruritest_SOURCES = \ viruritest.c testutils.h testutils.c diff --git a/tests/vircgroupmock.c b/tests/vircgroupmock.c new file mode 100644 index 0000000000000000000000000000000000000000..1d5d46b603f4541d416733da83cb470fa1ba2bc1 --- /dev/null +++ b/tests/vircgroupmock.c @@ -0,0 +1,452 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Author: Daniel P. Berrange + */ + +#include + +#ifdef __linux__ +# include "internal.h" + +# include +# include +# include +# include +# include +# include +# include + +static int (*realopen)(const char *path, int flags, ...); +static FILE *(*realfopen)(const char *path, const char *mode); +static int (*realaccess)(const char *path, int mode); +static int (*realmkdir)(const char *path, mode_t mode); +static char *fakesysfsdir; + + +# define SYSFS_PREFIX "/not/really/sys/fs/cgroup/" + +/* + * The plan: + * + * We fake out /proc/mounts, so make it look as is cgroups + * are mounted on /not/really/sys/fs/cgroup. We don't + * use /sys/fs/cgroup, because we want to make it easy to + * detect places where we've not mocked enough syscalls. + * + * In any open/acces/mkdir calls we look at path and if + * it starts with /not/really/sys/fs/cgroup, we rewrite + * the path to point at a temporary directory referred + * to by LIBVIRT_FAKE_SYSFS_DIR env variable that is + * set by the main test suite + * + * In mkdir() calls, we simulate the cgroups behaviour + * whereby creating the directory auto-creates a bunch + * of files beneath it + */ + +/* + * Intentionally missing the 'devices' mount. + * Co-mounting cpu & cpuacct controllers + * An anonymous controller for systemd + */ +const char *mounts = + "rootfs / rootfs rw 0 0\n" + "tmpfs /run tmpfs rw,seclabel,nosuid,nodev,mode=755 0 0\n" + "tmpfs /not/really/sys/fs/cgroup tmpfs rw,seclabel,nosuid,nodev,noexec,mode=755 0 0\n" + "cgroup /not/really/sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd 0 0\n" + "cgroup /not/really/sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0\n" + "cgroup /not/really/sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpuacct,cpu 0 0\n" + "cgroup /not/really/sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0\n" + "cgroup /not/really/sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0\n" + "cgroup /not/really/sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0\n" + "/dev/sda1 /boot ext4 rw,seclabel,relatime,data=ordered 0 0\n" + "tmpfs /tmp tmpfs rw,seclabel,relatime,size=1024000k 0 0\n"; + +const char *cgroups = + "115:memory:/\n" + "8:blkio:/\n" + "6:freezer:/\n" + "3:cpuacct,cpu:/system\n" + "2:cpuset:/\n" + "1:name=systemd:/user/berrange/123\n"; + +static int make_file(const char *path, + const char *name, + const char *value) +{ + int fd = -1; + int ret = -1; + char *filepath = NULL; + + if (asprintf(&filepath, "%s/%s", path, name) < 0) + return -1; + + if ((fd = realopen(filepath, O_CREAT|O_WRONLY, 0600)) < 0) + goto cleanup; + + if (write(fd, value, strlen(value)) != strlen(value)) + goto cleanup; + + ret = 0; +cleanup: + if (fd != -1 && close(fd) < 0) + ret = -1; + free(filepath); + + return ret; +} + +static int make_controller(const char *path, mode_t mode) +{ + int ret = -1; + const char *controller; + + if (!STRPREFIX(path, fakesysfsdir)) { + errno = EINVAL; + return -1; + } + controller = path + strlen(fakesysfsdir) + 1; + + if (STREQ(controller, "cpu")) + return symlink("cpu,cpuacct", path); + if (STREQ(controller, "cpuacct")) + return symlink("cpu,cpuacct", path); + + if (realmkdir(path, mode) < 0) + goto cleanup; + +# define MAKE_FILE(name, value) \ + do { \ + if (make_file(path, name, value) < 0) \ + goto cleanup; \ + } while (0) + + if (STRPREFIX(controller, "cpu,cpuacct")) { + MAKE_FILE("cpu.cfs_period_us", "100000\n"); + MAKE_FILE("cpu.cfs_quota_us", "-1\n"); + MAKE_FILE("cpu.rt_period_us", "1000000\n"); + MAKE_FILE("cpu.rt_runtime_us", "950000\n"); + MAKE_FILE("cpu.shares", "1024\n"); + MAKE_FILE("cpu.stat", + "nr_periods 0\n" + "nr_throttled 0\n" + "throttled_time 0\n"); + MAKE_FILE("cpuacct.stat", + "user 216687025\n" + "system 43421396\n"); + MAKE_FILE("cpuacct.usage", "2787788855799582\n"); + MAKE_FILE("cpuacct.usage_per_cpu", "1413142688153030 1374646168910542\n"); + } else if (STRPREFIX(controller, "cpuset")) { + MAKE_FILE("cpuset.cpu_exclusive", "1\n"); + if (STREQ(controller, "cpuset")) + MAKE_FILE("cpuset.cpus", "0-1"); + else + MAKE_FILE("cpuset.cpus", ""); /* Values don't inherit */ + MAKE_FILE("cpuset.mem_exclusive", "1\n"); + MAKE_FILE("cpuset.mem_hardwall", "0\n"); + MAKE_FILE("cpuset.memory_migrate", "0\n"); + MAKE_FILE("cpuset.memory_pressure", "0\n"); + MAKE_FILE("cpuset.memory_pressure_enabled", "0\n"); + MAKE_FILE("cpuset.memory_spread_page", "0\n"); + MAKE_FILE("cpuset.memory_spread_slab", "0\n"); + if (STREQ(controller, "cpuset")) + MAKE_FILE("cpuset.mems", "0"); + else + MAKE_FILE("cpuset.mems", ""); /* Values don't inherit */ + MAKE_FILE("cpuset.sched_load_balance", "1\n"); + MAKE_FILE("cpuset.sched_relax_domain_level", "-1\n"); + } else if (STRPREFIX(controller, "memory")) { + MAKE_FILE("memory.failcnt", "0\n"); + MAKE_FILE("memory.force_empty", ""); /* Write only */ + MAKE_FILE("memory.kmem.tcp.failcnt", "0\n"); + MAKE_FILE("memory.kmem.tcp.limit_in_bytes", "9223372036854775807\n"); + MAKE_FILE("memory.kmem.tcp.max_usage_in_bytes", "0\n"); + MAKE_FILE("memory.kmem.tcp.usage_in_bytes", "16384\n"); + MAKE_FILE("memory.limit_in_bytes", "9223372036854775807\n"); + MAKE_FILE("memory.max_usage_in_bytes", "0\n"); + MAKE_FILE("memory.memsw.failcnt", ""); /* Not supported */ + MAKE_FILE("memory.memsw.limit_in_bytes", ""); /* Not supported */ + MAKE_FILE("memory.memsw.max_usage_in_bytes", ""); /* Not supported */ + MAKE_FILE("memory.memsw.usage_in_bytes", ""); /* Not supported */ + MAKE_FILE("memory.move_charge_at_immigrate", "0\n"); + MAKE_FILE("memory.numa_stat", + "total=367664 N0=367664\n" + "file=314764 N0=314764\n" + "anon=51999 N0=51999\n" + "unevictable=901 N0=901\n"); + MAKE_FILE("memory.oom_control", + "oom_kill_disable 0\n" + "under_oom 0\n"); + MAKE_FILE("memory.soft_limit_in_bytes", "9223372036854775807\n"); + MAKE_FILE("memory.stat", + "cache 1336619008\n" + "rss 97792000\n" + "mapped_file 42090496\n" + "pgpgin 13022605027\n" + "pgpgout 13023820533\n" + "pgfault 54429417056\n" + "pgmajfault 315715\n" + "inactive_anon 145887232\n" + "active_anon 67100672\n" + "inactive_file 627400704\n" + "active_file 661872640\n" + "unevictable 3690496\n" + "hierarchical_memory_limit 9223372036854775807\n" + "total_cache 1336635392\n" + "total_rss 118689792\n" + "total_mapped_file 42106880\n" + "total_pgpgin 13022606816\n" + "total_pgpgout 13023820793\n" + "total_pgfault 54429422313\n" + "total_pgmajfault 315715\n" + "total_inactive_anon 145891328\n" + "total_active_anon 88010752\n" + "total_inactive_file 627400704\n" + "total_active_file 661872640\n" + "total_unevictable 3690496\n" + "recent_rotated_anon 112807028\n" + "recent_rotated_file 2547948\n" + "recent_scanned_anon 113796164\n" + "recent_scanned_file 8199863\n"); + MAKE_FILE("memory.swappiness", "60\n"); + MAKE_FILE("memory.usage_in_bytes", "1455321088\n"); + MAKE_FILE("memory.use_hierarchy", "0\n"); + } else if (STRPREFIX(controller, "freezer")) { + MAKE_FILE("freezer.state", "THAWED"); + } else if (STRPREFIX(controller, "blkio")) { + MAKE_FILE("blkio.io_merged", + "8:0 Read 1100949\n" + "8:0 Write 2248076\n" + "8:0 Sync 63063\n" + "8:0 Async 3285962\n" + "8:0 Total 3349025\n"); + MAKE_FILE("blkio.io_queued", + "8:0 Read 0\n" + "8:0 Write 0\n" + "8:0 Sync 0\n" + "8:0 Async 0\n" + "8:0 Total 0\n"); + MAKE_FILE("blkio.io_service_bytes", + "8:0 Read 59542078464\n" + "8:0 Write 397369182208\n" + "8:0 Sync 234080922624\n" + "8:0 Async 222830338048\n" + "8:0 Total 456911260672\n"); + MAKE_FILE("blkio.io_serviced", + "8:0 Read 3402504\n" + "8:0 Write 14966516\n" + "8:0 Sync 12064031\n" + "8:0 Async 6304989\n" + "8:0 Total 18369020\n"); + MAKE_FILE("blkio.io_service_time", + "8:0 Read 10747537542349\n" + "8:0 Write 9200028590575\n" + "8:0 Sync 6449319855381\n" + "8:0 Async 13498246277543\n" + "8:0 Total 19947566132924\n"); + MAKE_FILE("blkio.io_wait_time", + "8:0 Read 14687514824889\n" + "8:0 Write 357748452187691\n" + "8:0 Sync 55296974349413\n" + "8:0 Async 317138992663167\n" + "8:0 Total 372435967012580\n"); + MAKE_FILE("blkio.reset_stats", ""); /* Write only */ + MAKE_FILE("blkio.sectors", "8:0 892404806\n"); + MAKE_FILE("blkio.throttle.io_service_bytes", + "8:0 Read 59542107136\n" + "8:0 Write 411440480256\n" + "8:0 Sync 248486822912\n" + "8:0 Async 222495764480\n" + "8:0 Total 470982587392\n"); + MAKE_FILE("blkio.throttle.io_serviced", + "8:0 Read 4832583\n" + "8:0 Write 36641903\n" + "8:0 Sync 30723171\n" + "8:0 Async 10751315\n" + "8:0 Total 41474486\n"); + MAKE_FILE("blkio.throttle.read_bps_device", ""); + MAKE_FILE("blkio.throttle.read_iops_device", ""); + MAKE_FILE("blkio.throttle.write_bps_device", ""); + MAKE_FILE("blkio.throttle.write_iops_device", ""); + MAKE_FILE("blkio.time", "8:0 61019089\n"); + MAKE_FILE("blkio.weight", "1000\n"); + MAKE_FILE("blkio.weight_device", ""); + + } else { + errno = EINVAL; + goto cleanup; + } + + ret = 0; +cleanup: + return ret; +} + +static void init_syms(void) +{ + if (realfopen) + return; + +# define LOAD_SYM(name) \ + do { \ + if (!(real ## name = dlsym(RTLD_NEXT, #name))) { \ + fprintf(stderr, "Cannot find real '%s' symbol\n", #name); \ + abort(); \ + } \ + } while (0) + + LOAD_SYM(fopen); + LOAD_SYM(access); + LOAD_SYM(mkdir); + LOAD_SYM(open); +} + +static void init_sysfs(void) +{ + if (fakesysfsdir) + return; + + if (!(fakesysfsdir = getenv("LIBVIRT_FAKE_SYSFS_DIR"))) { + fprintf(stderr, "Missing LIBVIRT_FAKE_SYSFS_DIR env variable\n"); + abort(); + } + +# define MAKE_CONTROLLER(subpath) \ + do { \ + char *path; \ + if (asprintf(&path,"%s/%s", fakesysfsdir, subpath) < 0) \ + abort(); \ + if (make_controller(path, 0755) < 0) { \ + fprintf(stderr, "Cannot initialize %s\n", path); \ + abort(); \ + } \ + } while (0) + + MAKE_CONTROLLER("cpu"); + MAKE_CONTROLLER("cpuacct"); + MAKE_CONTROLLER("cpu,cpuacct"); + MAKE_CONTROLLER("cpu,cpuacct/system"); + MAKE_CONTROLLER("cpuset"); + MAKE_CONTROLLER("blkio"); + MAKE_CONTROLLER("memory"); + MAKE_CONTROLLER("freezer"); +} + + +FILE *fopen(const char *path, const char *mode) +{ + init_syms(); + + if (STREQ(path, "/proc/mounts")) { + if (STREQ(mode, "r")) { + return fmemopen((void *)mounts, strlen(mounts), mode); + } else { + errno = EACCES; + return NULL; + } + } + if (STREQ(path, "/proc/self/cgroup")) { + if (STREQ(mode, "r")) { + return fmemopen((void *)cgroups, strlen(cgroups), mode); + } else { + errno = EACCES; + return NULL; + } + } + + return realfopen(path, mode); +} + +int access(const char *path, int mode) +{ + int ret; + + init_syms(); + + if (STRPREFIX(path, SYSFS_PREFIX)) { + init_sysfs(); + char *newpath; + if (asprintf(&newpath, "%s/%s", + fakesysfsdir, + path + strlen(SYSFS_PREFIX)) < 0) { + errno = ENOMEM; + return -1; + } + ret = realaccess(newpath, mode); + free(newpath); + } else { + ret = realaccess(path, mode); + } + return ret; +} + +int mkdir(const char *path, mode_t mode) +{ + int ret; + + init_syms(); + + if (STRPREFIX(path, SYSFS_PREFIX)) { + init_sysfs(); + char *newpath; + if (asprintf(&newpath, "%s/%s", + fakesysfsdir, + path + strlen(SYSFS_PREFIX)) < 0) { + errno = ENOMEM; + return -1; + } + ret = make_controller(newpath, mode); + free(newpath); + } else { + ret = realmkdir(path, mode); + } + return ret; +} + +int open(const char *path, int flags, ...) +{ + int ret; + char *newpath = NULL; + + init_syms(); + + if (STRPREFIX(path, SYSFS_PREFIX)) { + init_sysfs(); + if (asprintf(&newpath, "%s/%s", + fakesysfsdir, + path + strlen(SYSFS_PREFIX)) < 0) { + errno = ENOMEM; + return -1; + } + } + if (flags & O_CREAT) { + va_list ap; + mode_t mode; + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + ret = realopen(newpath ? newpath : path, flags, mode); + } else { + ret = realopen(newpath ? newpath : path, flags); + } + free(newpath); + return ret; +} +#else +/* Nothing to override on non-__linux__ platforms */ +#endif diff --git a/tests/vircgrouptest.c b/tests/vircgrouptest.c new file mode 100644 index 0000000000000000000000000000000000000000..d03962421501373d48182ddefd775324e34781b3 --- /dev/null +++ b/tests/vircgrouptest.c @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Author: Daniel P. Berrange + */ + +#include + +#include "testutils.h" + +#ifdef __linux__ + +# include + +# define __VIR_CGROUP_ALLOW_INCLUDE_PRIV_H__ +# include "vircgrouppriv.h" +# include "virutil.h" +# include "virerror.h" +# include "virlog.h" +# include "virfile.h" + +# define VIR_FROM_THIS VIR_FROM_NONE + +static int validateCgroup(virCgroupPtr cgroup, + const char *expectPath, + const char **expectMountPoint, + const char **expectPlacement) +{ + int i; + + if (STRNEQ(cgroup->path, expectPath)) { + fprintf(stderr, "Wrong path '%s', expected '%s'\n", + cgroup->path, expectPath); + return -1; + } + + for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) { + if (STRNEQ_NULLABLE(expectMountPoint[i], + cgroup->controllers[i].mountPoint)) { + fprintf(stderr, "Wrong mount '%s', expected '%s' for '%s'\n", + cgroup->controllers[i].mountPoint, + expectMountPoint[i], + virCgroupControllerTypeToString(i)); + return -1; + } + if (STRNEQ_NULLABLE(expectPlacement[i], + cgroup->controllers[i].placement)) { + fprintf(stderr, "Wrong placement '%s', expected '%s' for '%s'\n", + cgroup->controllers[i].placement, + expectPlacement[i], + virCgroupControllerTypeToString(i)); + return -1; + } + } + + return 0; +} + +const char *mountsSmall[VIR_CGROUP_CONTROLLER_LAST] = { + [VIR_CGROUP_CONTROLLER_CPU] = "/not/really/sys/fs/cgroup/cpu,cpuacct", + [VIR_CGROUP_CONTROLLER_CPUACCT] = "/not/really/sys/fs/cgroup/cpu,cpuacct", + [VIR_CGROUP_CONTROLLER_CPUSET] = NULL, + [VIR_CGROUP_CONTROLLER_MEMORY] = "/not/really/sys/fs/cgroup/memory", + [VIR_CGROUP_CONTROLLER_DEVICES] = NULL, + [VIR_CGROUP_CONTROLLER_FREEZER] = NULL, + [VIR_CGROUP_CONTROLLER_BLKIO] = NULL, +}; +const char *mountsFull[VIR_CGROUP_CONTROLLER_LAST] = { + [VIR_CGROUP_CONTROLLER_CPU] = "/not/really/sys/fs/cgroup/cpu,cpuacct", + [VIR_CGROUP_CONTROLLER_CPUACCT] = "/not/really/sys/fs/cgroup/cpu,cpuacct", + [VIR_CGROUP_CONTROLLER_CPUSET] = "/not/really/sys/fs/cgroup/cpuset", + [VIR_CGROUP_CONTROLLER_MEMORY] = "/not/really/sys/fs/cgroup/memory", + [VIR_CGROUP_CONTROLLER_DEVICES] = NULL, + [VIR_CGROUP_CONTROLLER_FREEZER] = "/not/really/sys/fs/cgroup/freezer", + [VIR_CGROUP_CONTROLLER_BLKIO] = "/not/really/sys/fs/cgroup/blkio", +}; + +static int testCgroupNewForSelf(const void *args ATTRIBUTE_UNUSED) +{ + virCgroupPtr cgroup = NULL; + int ret = -1; + const char *placement[VIR_CGROUP_CONTROLLER_LAST] = { + [VIR_CGROUP_CONTROLLER_CPU] = "/system", + [VIR_CGROUP_CONTROLLER_CPUACCT] = "/system", + [VIR_CGROUP_CONTROLLER_CPUSET] = "", + [VIR_CGROUP_CONTROLLER_MEMORY] = "", + [VIR_CGROUP_CONTROLLER_DEVICES] = NULL, + [VIR_CGROUP_CONTROLLER_FREEZER] = "", + [VIR_CGROUP_CONTROLLER_BLKIO] = "", + }; + + if (virCgroupNewSelf(&cgroup) < 0) { + fprintf(stderr, "Cannot create cgroup for self\n"); + goto cleanup; + } + + ret = validateCgroup(cgroup, "/", mountsFull, placement); + +cleanup: + virCgroupFree(&cgroup); + return ret; +} + + +static int testCgroupNewForDriver(const void *args ATTRIBUTE_UNUSED) +{ + virCgroupPtr cgroup = NULL; + int ret = -1; + int rv; + const char *placement[VIR_CGROUP_CONTROLLER_LAST] = { + [VIR_CGROUP_CONTROLLER_CPU] = "/system", + [VIR_CGROUP_CONTROLLER_CPUACCT] = "/system", + [VIR_CGROUP_CONTROLLER_CPUSET] = "", + [VIR_CGROUP_CONTROLLER_MEMORY] = "", + [VIR_CGROUP_CONTROLLER_DEVICES] = NULL, + [VIR_CGROUP_CONTROLLER_FREEZER] = "", + [VIR_CGROUP_CONTROLLER_BLKIO] = "", + }; + + if ((rv = virCgroupNewDriver("lxc", true, false, -1, &cgroup)) != -ENOENT) { + fprintf(stderr, "Unexpected found LXC cgroup: %d\n", -rv); + goto cleanup; + } + + /* Asking for impossible combination since CPU is co-mounted */ + if ((rv = virCgroupNewDriver("lxc", true, true, + (1 << VIR_CGROUP_CONTROLLER_CPU), + &cgroup)) != -EINVAL) { + fprintf(stderr, "Should not have created LXC cgroup: %d\n", -rv); + goto cleanup; + } + + /* Asking for impossible combination since devices is not mounted */ + if ((rv = virCgroupNewDriver("lxc", true, true, + (1 << VIR_CGROUP_CONTROLLER_DEVICES), + &cgroup)) != -ENOENT) { + fprintf(stderr, "Should not have created LXC cgroup: %d\n", -rv); + goto cleanup; + } + + /* Asking for small combination since devices is not mounted */ + if ((rv = virCgroupNewDriver("lxc", true, true, + (1 << VIR_CGROUP_CONTROLLER_CPU) | + (1 << VIR_CGROUP_CONTROLLER_CPUACCT) | + (1 << VIR_CGROUP_CONTROLLER_MEMORY), + &cgroup)) != 0) { + fprintf(stderr, "Cannot create LXC cgroup: %d\n", -rv); + goto cleanup; + } + ret = validateCgroup(cgroup, "/libvirt/lxc", mountsSmall, placement); + virCgroupFree(&cgroup); + + if ((rv = virCgroupNewDriver("lxc", true, true, -1, &cgroup)) != 0) { + fprintf(stderr, "Cannot create LXC cgroup: %d\n", -rv); + goto cleanup; + } + ret = validateCgroup(cgroup, "/libvirt/lxc", mountsFull, placement); + +cleanup: + virCgroupFree(&cgroup); + return ret; +} + + +static int testCgroupNewForDomain(const void *args ATTRIBUTE_UNUSED) +{ + virCgroupPtr drivercgroup = NULL; + virCgroupPtr domaincgroup = NULL; + int ret = -1; + int rv; + const char *placement[VIR_CGROUP_CONTROLLER_LAST] = { + [VIR_CGROUP_CONTROLLER_CPU] = "/system", + [VIR_CGROUP_CONTROLLER_CPUACCT] = "/system", + [VIR_CGROUP_CONTROLLER_CPUSET] = "", + [VIR_CGROUP_CONTROLLER_MEMORY] = "", + [VIR_CGROUP_CONTROLLER_DEVICES] = NULL, + [VIR_CGROUP_CONTROLLER_FREEZER] = "", + [VIR_CGROUP_CONTROLLER_BLKIO] = "", + }; + + if ((rv = virCgroupNewDriver("lxc", true, false, -1, &drivercgroup)) != 0) { + fprintf(stderr, "Cannot find LXC cgroup: %d\n", -rv); + goto cleanup; + } + + if ((rv = virCgroupNewDomain(drivercgroup, "wibble", true, &domaincgroup)) != 0) { + fprintf(stderr, "Cannot create LXC cgroup: %d\n", -rv); + goto cleanup; + } + + ret = validateCgroup(domaincgroup, "/libvirt/lxc/wibble", mountsFull, placement); + +cleanup: + virCgroupFree(&drivercgroup); + virCgroupFree(&domaincgroup); + return ret; +} + + +# define FAKESYSFSDIRTEMPLATE abs_builddir "/fakesysfsdir-XXXXXX" + + + +static int +mymain(void) +{ + int ret = 0; + char *fakesysfsdir; + + if (!(fakesysfsdir = strdup(FAKESYSFSDIRTEMPLATE))) { + fprintf(stderr, "Out of memory\n"); + abort(); + } + + if (!mkdtemp(fakesysfsdir)) { + fprintf(stderr, "Cannot create fakesysfsdir"); + abort(); + } + + setenv("LIBVIRT_FAKE_SYSFS_DIR", fakesysfsdir, 1); + + if (virtTestRun("New cgroup for self", 1, testCgroupNewForSelf, NULL) < 0) + ret = -1; + + if (virtTestRun("New cgroup for driver", 1, testCgroupNewForDriver, NULL) < 0) + ret = -1; + + if (virtTestRun("New cgroup for domain", 1, testCgroupNewForDomain, NULL) < 0) + ret = -1; + + if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) + virFileDeleteTree(fakesysfsdir); + + VIR_FREE(fakesysfsdir); + + return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIRT_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/vircgroupmock.so") + +#else +int +main(void) +{ + return EXIT_AM_SKIP; +} +#endif