| /* Copyright 2016 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include <errno.h> |
| |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include "test_harness.h" |
| |
| #include "container_cgroup.h" |
| |
| static const char CGNAME[] = "testcg"; |
| static const char CGPARENTNAME[] = "testparentcg"; |
| |
| static int check_is_dir(const char *path) |
| { |
| int rc; |
| struct stat st_buf; |
| |
| rc = stat(path, &st_buf); |
| if (rc) |
| return 0; |
| return S_ISDIR(st_buf.st_mode); |
| } |
| |
| static void create_file_with_content(const char *name, const char *content) |
| { |
| FILE *fp = fopen(name, "w"); |
| if (content) |
| fputs(content, fp); |
| fclose(fp); |
| } |
| |
| static void create_file(const char *name) |
| { |
| create_file_with_content(name, NULL); |
| } |
| |
| static int string_in_file(const char *path, const char *str) |
| { |
| FILE *fp = fopen(path, "r"); |
| char *buf = NULL; |
| size_t len; |
| |
| if (!fp) |
| return 0; |
| |
| while (getline(&buf, &len, fp) > 0) { |
| if (strstr(buf, str)) { |
| free(buf); |
| fclose(fp); |
| return 1; |
| } |
| } |
| free(buf); |
| fclose(fp); |
| return 0; |
| } |
| |
| static int file_has_line(const char *path, const char *line) |
| { |
| FILE *fp; |
| char *buf = NULL; |
| size_t len; |
| int found; |
| |
| fp = fopen(path, "r"); |
| if (!fp) |
| return 0; |
| |
| if (getline(&buf, &len, fp) <= 0) { |
| found = 0; |
| goto done_ret; |
| } |
| |
| found = !strcmp(buf, line); |
| |
| done_ret: |
| free(buf); |
| fclose(fp); |
| return found; |
| } |
| |
| TEST(cgroup_new_with_parent) { |
| struct container_cgroup *ccg = NULL; |
| |
| char *cgroup_root = NULL; |
| const char *cgroup_parent_name; |
| const char *cgroup_name; |
| char cpu_cg[256]; |
| char cpuacct_cg[256]; |
| char cpuset_cg[256]; |
| char devices_cg[256]; |
| char freezer_cg[256]; |
| |
| char temp_template[] = "/tmp/cgtestXXXXXX"; |
| char path[256]; |
| |
| cgroup_root = strdup(mkdtemp(temp_template)); |
| snprintf(path, sizeof(path), "rm -rf %s/*", cgroup_root); |
| EXPECT_EQ(0, system(path)); |
| |
| snprintf(path, sizeof(path), "%s/cpu", cgroup_root); |
| mkdir(path, S_IRWXU | S_IRWXG); |
| snprintf(path, sizeof(path), "%s/cpuacct", cgroup_root); |
| mkdir(path, S_IRWXU | S_IRWXG); |
| snprintf(path, sizeof(path), "%s/cpuset", cgroup_root); |
| mkdir(path, S_IRWXU | S_IRWXG); |
| snprintf(path, sizeof(path), "%s/devices", cgroup_root); |
| mkdir(path, S_IRWXU | S_IRWXG); |
| snprintf(path, sizeof(path), "%s/freezer", cgroup_root); |
| mkdir(path, S_IRWXU | S_IRWXG); |
| |
| cgroup_parent_name = CGPARENTNAME; |
| |
| snprintf(path, sizeof(path), "%s/cpu/%s", cgroup_root, |
| cgroup_parent_name); |
| mkdir(path, S_IRWXU | S_IRWXG); |
| snprintf(path, sizeof(path), "%s/cpuacct/%s", cgroup_root, |
| cgroup_parent_name); |
| mkdir(path, S_IRWXU | S_IRWXG); |
| snprintf(path, sizeof(path), "%s/cpuset/%s", cgroup_root, |
| cgroup_parent_name); |
| mkdir(path, S_IRWXU | S_IRWXG); |
| snprintf(path, sizeof(path), "%s/devices/%s", cgroup_root, |
| cgroup_parent_name); |
| mkdir(path, S_IRWXU | S_IRWXG); |
| snprintf(path, sizeof(path), "%s/freezer/%s", cgroup_root, |
| cgroup_parent_name); |
| mkdir(path, S_IRWXU | S_IRWXG); |
| |
| snprintf(path, sizeof(path), "%s/cpuset/%s/cpus", |
| cgroup_root, cgroup_parent_name); |
| create_file_with_content(path, "0-3"); |
| snprintf(path, sizeof(path), "%s/cpuset/%s/mems", |
| cgroup_root, cgroup_parent_name); |
| create_file_with_content(path, "0"); |
| |
| ccg = container_cgroup_new(CGNAME, cgroup_root, cgroup_parent_name, |
| 1000, 1000); |
| ASSERT_NE(NULL, ccg); |
| |
| cgroup_name = CGNAME; |
| |
| snprintf(cpu_cg, sizeof(cpu_cg), "%s/cpu/%s/%s", |
| cgroup_root, cgroup_parent_name, cgroup_name); |
| snprintf(cpuacct_cg, sizeof(cpuacct_cg), "%s/cpuacct/%s/%s", |
| cgroup_root, cgroup_parent_name, cgroup_name); |
| snprintf(cpuset_cg, sizeof(cpuset_cg), "%s/cpuset/%s/%s", |
| cgroup_root, cgroup_parent_name, cgroup_name); |
| snprintf(devices_cg, sizeof(devices_cg), "%s/devices/%s/%s", |
| cgroup_root, cgroup_parent_name, cgroup_name); |
| snprintf(freezer_cg, sizeof(freezer_cg), "%s/freezer/%s/%s", |
| cgroup_root, cgroup_parent_name, cgroup_name); |
| |
| EXPECT_TRUE(check_is_dir(cpu_cg)); |
| EXPECT_TRUE(check_is_dir(cpuacct_cg)); |
| EXPECT_TRUE(check_is_dir(cpuset_cg)); |
| EXPECT_TRUE(check_is_dir(devices_cg)); |
| EXPECT_TRUE(check_is_dir(freezer_cg)); |
| |
| char cmd[256]; |
| |
| snprintf(cmd, sizeof(cmd), "rm -rf %s/*", cgroup_root); |
| |
| free(cgroup_root); |
| container_cgroup_destroy(ccg); |
| |
| EXPECT_EQ(0, system(cmd)); |
| } |
| |
| FIXTURE(basic_manipulation) { |
| struct container_cgroup *ccg; |
| |
| char *cgroup_root; |
| const char *cgroup_name; |
| char cpu_cg[256]; |
| char cpuacct_cg[256]; |
| char cpuset_cg[256]; |
| char devices_cg[256]; |
| char freezer_cg[256]; |
| }; |
| |
| FIXTURE_SETUP(basic_manipulation) |
| { |
| char temp_template[] = "/tmp/cgtestXXXXXX"; |
| char path[256]; |
| |
| self->cgroup_root = strdup(mkdtemp(temp_template)); |
| snprintf(path, sizeof(path), "rm -rf %s/*", self->cgroup_root); |
| EXPECT_EQ(0, system(path)); |
| |
| snprintf(path, sizeof(path), "%s/cpu", self->cgroup_root); |
| mkdir(path, S_IRWXU | S_IRWXG); |
| snprintf(path, sizeof(path), "%s/cpuacct", self->cgroup_root); |
| mkdir(path, S_IRWXU | S_IRWXG); |
| snprintf(path, sizeof(path), "%s/cpuset", self->cgroup_root); |
| mkdir(path, S_IRWXU | S_IRWXG); |
| snprintf(path, sizeof(path), "%s/devices", self->cgroup_root); |
| mkdir(path, S_IRWXU | S_IRWXG); |
| snprintf(path, sizeof(path), "%s/freezer", self->cgroup_root); |
| mkdir(path, S_IRWXU | S_IRWXG); |
| |
| self->ccg = container_cgroup_new(CGNAME, self->cgroup_root, NULL, 0, 0); |
| ASSERT_NE(NULL, self->ccg); |
| |
| self->cgroup_name = CGNAME; |
| |
| snprintf(self->cpu_cg, sizeof(self->cpu_cg), "%s/cpu/%s", |
| self->cgroup_root, self->cgroup_name); |
| snprintf(self->cpuacct_cg, sizeof(self->cpuacct_cg), "%s/cpuacct/%s", |
| self->cgroup_root, self->cgroup_name); |
| snprintf(self->cpuset_cg, sizeof(self->cpuset_cg), "%s/cpuset/%s", |
| self->cgroup_root, self->cgroup_name); |
| snprintf(self->devices_cg, sizeof(self->devices_cg), "%s/devices/%s", |
| self->cgroup_root, self->cgroup_name); |
| snprintf(self->freezer_cg, sizeof(self->freezer_cg), "%s/freezer/%s", |
| self->cgroup_root, self->cgroup_name); |
| |
| EXPECT_TRUE(check_is_dir(self->cpu_cg)); |
| EXPECT_TRUE(check_is_dir(self->cpuacct_cg)); |
| EXPECT_TRUE(check_is_dir(self->cpuset_cg)); |
| EXPECT_TRUE(check_is_dir(self->devices_cg)); |
| EXPECT_TRUE(check_is_dir(self->freezer_cg)); |
| |
| snprintf(path, sizeof(path), "%s/tasks", self->cpu_cg); |
| create_file(path); |
| snprintf(path, sizeof(path), "%s/cpu.shares", self->cpu_cg); |
| create_file(path); |
| snprintf(path, sizeof(path), "%s/cpu.cfs_quota_us", self->cpu_cg); |
| create_file(path); |
| snprintf(path, sizeof(path), "%s/cpu.cfs_period_us", self->cpu_cg); |
| create_file(path); |
| snprintf(path, sizeof(path), "%s/cpu.rt_runtime_us", self->cpu_cg); |
| create_file(path); |
| snprintf(path, sizeof(path), "%s/cpu.rt_period_us", self->cpu_cg); |
| create_file(path); |
| snprintf(path, sizeof(path), "%s/tasks", self->cpuacct_cg); |
| create_file(path); |
| snprintf(path, sizeof(path), "%s/tasks", self->cpuset_cg); |
| create_file(path); |
| snprintf(path, sizeof(path), "%s/tasks", self->devices_cg); |
| create_file(path); |
| snprintf(path, sizeof(path), "%s/devices.allow", self->devices_cg); |
| create_file(path); |
| snprintf(path, sizeof(path), "%s/devices.deny", self->devices_cg); |
| create_file(path); |
| snprintf(path, sizeof(path), "%s/tasks", self->freezer_cg); |
| create_file(path); |
| snprintf(path, sizeof(path), "%s/freezer.state", self->freezer_cg); |
| create_file(path); |
| } |
| |
| FIXTURE_TEARDOWN(basic_manipulation) |
| { |
| char cmd[256]; |
| |
| snprintf(cmd, sizeof(cmd), "rm -rf %s/*", self->cgroup_root); |
| |
| free(self->cgroup_root); |
| container_cgroup_destroy(self->ccg); |
| |
| EXPECT_EQ(0, system(cmd)); |
| } |
| |
| TEST_F(basic_manipulation, freeze) |
| { |
| char path[256]; |
| EXPECT_EQ(0, self->ccg->ops->freeze(self->ccg)); |
| snprintf(path, sizeof(path), "%s/freezer.state", self->freezer_cg); |
| EXPECT_TRUE(string_in_file(path, "FROZEN")); |
| } |
| |
| TEST_F(basic_manipulation, thaw) |
| { |
| char path[256]; |
| EXPECT_EQ(0, self->ccg->ops->thaw(self->ccg)); |
| snprintf(path, sizeof(path), "%s/freezer.state", self->freezer_cg); |
| EXPECT_TRUE(string_in_file(path, "THAWED")); |
| } |
| |
| TEST_F(basic_manipulation, default_all_devs_disallow) |
| { |
| char path[256]; |
| ASSERT_EQ(0, self->ccg->ops->deny_all_devices(self->ccg)); |
| snprintf(path, sizeof(path), "%s/devices.deny", self->devices_cg); |
| EXPECT_TRUE(file_has_line(path, "a\n")); |
| } |
| |
| TEST_F(basic_manipulation, add_device_invalid_type) |
| { |
| EXPECT_NE(0, self->ccg->ops->add_device(self->ccg, 14, 3, 1, 1, 0, |
| 'x')); |
| } |
| |
| TEST_F(basic_manipulation, add_device_no_perms) |
| { |
| EXPECT_NE(0, self->ccg->ops->add_device(self->ccg, 14, 3, 0, 0, 0, |
| 'c')); |
| } |
| |
| TEST_F(basic_manipulation, add_device_rw) |
| { |
| char path[256]; |
| EXPECT_EQ(0, self->ccg->ops->add_device(self->ccg, 14, 3, 1, 1, 0, |
| 'c')); |
| snprintf(path, sizeof(path), "%s/devices.allow", self->devices_cg); |
| EXPECT_TRUE(file_has_line(path, "c 14:3 rw\n")); |
| } |
| |
| TEST_F(basic_manipulation, add_device_rwm) |
| { |
| char path[256]; |
| EXPECT_EQ(0, self->ccg->ops->add_device(self->ccg, 14, 3, 1, 1, 1, |
| 'c')); |
| snprintf(path, sizeof(path), "%s/devices.allow", self->devices_cg); |
| EXPECT_TRUE(file_has_line(path, "c 14:3 rwm\n")); |
| } |
| |
| TEST_F(basic_manipulation, add_device_ro) |
| { |
| char path[256]; |
| EXPECT_EQ(0, self->ccg->ops->add_device(self->ccg, 14, 3, 1, 0, 0, |
| 'c')); |
| snprintf(path, sizeof(path), "%s/devices.allow", self->devices_cg); |
| EXPECT_TRUE(file_has_line(path, "c 14:3 r\n")); |
| } |
| |
| TEST_F(basic_manipulation, add_device_wo) |
| { |
| char path[256]; |
| EXPECT_EQ(0, self->ccg->ops->add_device(self->ccg, 14, 3, 0, 1, 0, |
| 'c')); |
| snprintf(path, sizeof(path), "%s/devices.allow", self->devices_cg); |
| EXPECT_TRUE(file_has_line(path, "c 14:3 w\n")); |
| } |
| |
| TEST_F(basic_manipulation, add_device_major_wide) |
| { |
| char path[256]; |
| EXPECT_EQ(0, self->ccg->ops->add_device(self->ccg, 14, -1, 0, 1, 0, |
| 'c')); |
| snprintf(path, sizeof(path), "%s/devices.allow", self->devices_cg); |
| EXPECT_TRUE(file_has_line(path, "c 14:* w\n")); |
| } |
| |
| TEST_F(basic_manipulation, add_device_block) |
| { |
| char path[256]; |
| EXPECT_EQ(0, self->ccg->ops->add_device(self->ccg, 14, 3, 1, 1, 0, |
| 'b')); |
| snprintf(path, sizeof(path), "%s/devices.allow", self->devices_cg); |
| EXPECT_TRUE(file_has_line(path, "b 14:3 rw\n")); |
| } |
| |
| TEST_F(basic_manipulation, set_cpu_shares) |
| { |
| char path[256]; |
| EXPECT_EQ(0, self->ccg->ops->set_cpu_shares(self->ccg, 500)); |
| snprintf(path, sizeof(path), "%s/cpu.shares", self->cpu_cg); |
| EXPECT_TRUE(string_in_file(path, "500")); |
| } |
| |
| TEST_F(basic_manipulation, set_cpu_quota) |
| { |
| char path[256]; |
| EXPECT_EQ(0, self->ccg->ops->set_cpu_quota(self->ccg, 200000)); |
| snprintf(path, sizeof(path), "%s/cpu.cfs_quota_us", self->cpu_cg); |
| EXPECT_TRUE(string_in_file(path, "200000")); |
| } |
| |
| TEST_F(basic_manipulation, set_cpu_period) |
| { |
| char path[256]; |
| EXPECT_EQ(0, self->ccg->ops->set_cpu_period(self->ccg, 800000)); |
| snprintf(path, sizeof(path), "%s/cpu.cfs_period_us", self->cpu_cg); |
| EXPECT_TRUE(string_in_file(path, "800000")); |
| } |
| |
| TEST_F(basic_manipulation, set_cpu_rt_runtime) |
| { |
| char path[256]; |
| EXPECT_EQ(0, self->ccg->ops->set_cpu_rt_runtime(self->ccg, 100000)); |
| snprintf(path, sizeof(path), "%s/cpu.rt_runtime_us", self->cpu_cg); |
| EXPECT_TRUE(string_in_file(path, "100000")); |
| } |
| |
| TEST_F(basic_manipulation, set_cpu_rt_period) |
| { |
| char path[256]; |
| EXPECT_EQ(0, self->ccg->ops->set_cpu_rt_period(self->ccg, 500000)); |
| snprintf(path, sizeof(path), "%s/cpu.rt_period_us", self->cpu_cg); |
| EXPECT_TRUE(string_in_file(path, "500000")); |
| } |
| |
| TEST_HARNESS_MAIN |
| |