1 /* SPDX-License-Identifier: GPL-2.0 */
4 #include <linux/limits.h>
5 #include <linux/sched.h>
18 #include "../kselftest.h"
19 #include "cgroup_util.h"
21 static int touch_anon(char *buf, size_t size)
26 fd = open("/dev/urandom", O_RDONLY);
31 ssize_t ret = read(fd, pos, size);
48 static int alloc_and_touch_anon_noexit(const char *cgroup, void *arg)
51 size_t size = (size_t)arg;
54 buf = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
56 if (buf == MAP_FAILED)
59 if (touch_anon((char *)buf, size)) {
64 while (getppid() == ppid)
72 * Create a child process that allocates and touches 100MB, then waits to be
73 * killed. Wait until the child is attached to the cgroup, kill all processes
74 * in that cgroup and wait until "cgroup.procs" is empty. At this point try to
75 * destroy the empty cgroup. The test helps detect race conditions between
76 * dying processes leaving the cgroup and cgroup destruction path.
78 static int test_cgcore_destroy(const char *root)
85 cg_test = cg_name(root, "cg_test");
90 for (int i = 0; i < 10; i++) {
91 if (cg_create(cg_test))
94 child_pid = cg_run_nowait(cg_test, alloc_and_touch_anon_noexit,
100 /* wait for the child to enter cgroup */
101 if (cg_wait_for_proc_count(cg_test, 1))
104 if (cg_killall(cg_test))
107 /* wait for cgroup to be empty */
109 if (cg_read(cg_test, "cgroup.procs", buf, sizeof(buf)))
119 if (waitpid(child_pid, NULL, 0) < 0)
134 * A, B and C's "populated" fields would be 1 while D's 0.
135 * test that after the one process in C is moved to root,
136 * A,B and C's "populated" fields would flip to "0" and file
137 * modified events will be generated on the
138 * "cgroup.events" files of both cgroups.
140 static int test_cgcore_populated(const char *root)
144 char *cg_test_a = NULL, *cg_test_b = NULL;
145 char *cg_test_c = NULL, *cg_test_d = NULL;
146 int cgroup_fd = -EBADF;
149 cg_test_a = cg_name(root, "cg_test_a");
150 cg_test_b = cg_name(root, "cg_test_a/cg_test_b");
151 cg_test_c = cg_name(root, "cg_test_a/cg_test_b/cg_test_c");
152 cg_test_d = cg_name(root, "cg_test_a/cg_test_b/cg_test_d");
154 if (!cg_test_a || !cg_test_b || !cg_test_c || !cg_test_d)
157 if (cg_create(cg_test_a))
160 if (cg_create(cg_test_b))
163 if (cg_create(cg_test_c))
166 if (cg_create(cg_test_d))
169 if (cg_enter_current(cg_test_c))
172 if (cg_read_strcmp(cg_test_a, "cgroup.events", "populated 1\n"))
175 if (cg_read_strcmp(cg_test_b, "cgroup.events", "populated 1\n"))
178 if (cg_read_strcmp(cg_test_c, "cgroup.events", "populated 1\n"))
181 if (cg_read_strcmp(cg_test_d, "cgroup.events", "populated 0\n"))
184 if (cg_enter_current(root))
187 if (cg_read_strcmp(cg_test_a, "cgroup.events", "populated 0\n"))
190 if (cg_read_strcmp(cg_test_b, "cgroup.events", "populated 0\n"))
193 if (cg_read_strcmp(cg_test_c, "cgroup.events", "populated 0\n"))
196 if (cg_read_strcmp(cg_test_d, "cgroup.events", "populated 0\n"))
199 /* Test that we can directly clone into a new cgroup. */
200 cgroup_fd = dirfd_open_opath(cg_test_d);
204 pid = clone_into_cgroup(cgroup_fd);
217 err = cg_read_strcmp(cg_test_d, "cgroup.events", "populated 1\n");
219 (void)clone_reap(pid, WSTOPPED);
220 (void)kill(pid, SIGCONT);
221 (void)clone_reap(pid, WEXITED);
226 if (cg_read_strcmp(cg_test_d, "cgroup.events", "populated 0\n"))
231 cg_destroy(cg_test_d);
236 pid = clone_into_cgroup(cgroup_fd);
241 (void)clone_reap(pid, WEXITED);
249 cg_destroy(cg_test_d);
251 cg_destroy(cg_test_c);
253 cg_destroy(cg_test_b);
255 cg_destroy(cg_test_a);
266 * A (domain threaded) - B (threaded) - C (domain)
268 * test that C can't be used until it is turned into a
269 * threaded cgroup. "cgroup.type" file will report "domain (invalid)" in
270 * these cases. Operations which fail due to invalid topology use
271 * EOPNOTSUPP as the errno.
273 static int test_cgcore_invalid_domain(const char *root)
276 char *grandparent = NULL, *parent = NULL, *child = NULL;
278 grandparent = cg_name(root, "cg_test_grandparent");
279 parent = cg_name(root, "cg_test_grandparent/cg_test_parent");
280 child = cg_name(root, "cg_test_grandparent/cg_test_parent/cg_test_child");
281 if (!parent || !child || !grandparent)
284 if (cg_create(grandparent))
287 if (cg_create(parent))
290 if (cg_create(child))
293 if (cg_write(parent, "cgroup.type", "threaded"))
296 if (cg_read_strcmp(child, "cgroup.type", "domain invalid\n"))
299 if (!cg_enter_current(child))
302 if (errno != EOPNOTSUPP)
305 if (!clone_into_cgroup_run_wait(child))
311 if (errno != EOPNOTSUPP)
318 cg_enter_current(root);
324 cg_destroy(grandparent);
332 * Test that when a child becomes threaded
333 * the parent type becomes domain threaded.
335 static int test_cgcore_parent_becomes_threaded(const char *root)
338 char *parent = NULL, *child = NULL;
340 parent = cg_name(root, "cg_test_parent");
341 child = cg_name(root, "cg_test_parent/cg_test_child");
342 if (!parent || !child)
345 if (cg_create(parent))
348 if (cg_create(child))
351 if (cg_write(child, "cgroup.type", "threaded"))
354 if (cg_read_strcmp(parent, "cgroup.type", "domain threaded\n"))
371 * Test that there's no internal process constrain on threaded cgroups.
372 * You can add threads/processes on a parent with a controller enabled.
374 static int test_cgcore_no_internal_process_constraint_on_threads(const char *root)
377 char *parent = NULL, *child = NULL;
379 if (cg_read_strstr(root, "cgroup.controllers", "cpu") ||
380 cg_write(root, "cgroup.subtree_control", "+cpu")) {
385 parent = cg_name(root, "cg_test_parent");
386 child = cg_name(root, "cg_test_parent/cg_test_child");
387 if (!parent || !child)
390 if (cg_create(parent))
393 if (cg_create(child))
396 if (cg_write(parent, "cgroup.type", "threaded"))
399 if (cg_write(child, "cgroup.type", "threaded"))
402 if (cg_write(parent, "cgroup.subtree_control", "+cpu"))
405 if (cg_enter_current(parent))
411 cg_enter_current(root);
412 cg_enter_current(root);
423 * Test that you can't enable a controller on a child if it's not enabled
426 static int test_cgcore_top_down_constraint_enable(const char *root)
429 char *parent = NULL, *child = NULL;
431 parent = cg_name(root, "cg_test_parent");
432 child = cg_name(root, "cg_test_parent/cg_test_child");
433 if (!parent || !child)
436 if (cg_create(parent))
439 if (cg_create(child))
442 if (!cg_write(child, "cgroup.subtree_control", "+memory"))
458 * Test that you can't disable a controller on a parent
459 * if it's enabled in a child.
461 static int test_cgcore_top_down_constraint_disable(const char *root)
464 char *parent = NULL, *child = NULL;
466 parent = cg_name(root, "cg_test_parent");
467 child = cg_name(root, "cg_test_parent/cg_test_child");
468 if (!parent || !child)
471 if (cg_create(parent))
474 if (cg_create(child))
477 if (cg_write(parent, "cgroup.subtree_control", "+memory"))
480 if (cg_write(child, "cgroup.subtree_control", "+memory"))
483 if (!cg_write(parent, "cgroup.subtree_control", "-memory"))
499 * Test internal process constraint.
500 * You can't add a pid to a domain parent if a controller is enabled.
502 static int test_cgcore_internal_process_constraint(const char *root)
505 char *parent = NULL, *child = NULL;
507 parent = cg_name(root, "cg_test_parent");
508 child = cg_name(root, "cg_test_parent/cg_test_child");
509 if (!parent || !child)
512 if (cg_create(parent))
515 if (cg_create(child))
518 if (cg_write(parent, "cgroup.subtree_control", "+memory"))
521 if (!cg_enter_current(parent))
524 if (!clone_into_cgroup_run_wait(parent))
539 static void *dummy_thread_fn(void *arg)
541 return (void *)(size_t)pause();
545 * Test threadgroup migration.
546 * All threads of a process are migrated together.
548 static int test_cgcore_proc_migration(const char *root)
551 int t, c_threads = 0, n_threads = 13;
552 char *src = NULL, *dst = NULL;
553 pthread_t threads[n_threads];
555 src = cg_name(root, "cg_src");
556 dst = cg_name(root, "cg_dst");
565 if (cg_enter_current(src))
568 for (c_threads = 0; c_threads < n_threads; ++c_threads) {
569 if (pthread_create(&threads[c_threads], NULL, dummy_thread_fn, NULL))
573 cg_enter_current(dst);
574 if (cg_read_lc(dst, "cgroup.threads") != n_threads + 1)
580 for (t = 0; t < c_threads; ++t) {
581 pthread_cancel(threads[t]);
584 for (t = 0; t < c_threads; ++t) {
585 pthread_join(threads[t], NULL);
588 cg_enter_current(root);
599 static void *migrating_thread_fn(void *arg)
601 int g, i, n_iterations = 1000;
603 char lines[3][PATH_MAX];
605 for (g = 1; g < 3; ++g)
606 snprintf(lines[g], sizeof(lines[g]), "0::%s", grps[g] + strlen(grps[0]));
608 for (i = 0; i < n_iterations; ++i) {
609 cg_enter_current_thread(grps[(i % 2) + 1]);
611 if (proc_read_strstr(0, 1, "cgroup", lines[(i % 2) + 1]))
618 * Test single thread migration.
619 * Threaded cgroups allow successful migration of a thread.
621 static int test_cgcore_thread_migration(const char *root)
626 char *grps[3] = { (char *)root, NULL, NULL };
630 dom = cg_name(root, "cg_dom");
631 grps[1] = cg_name(root, "cg_dom/cg_src");
632 grps[2] = cg_name(root, "cg_dom/cg_dst");
633 if (!grps[1] || !grps[2] || !dom)
638 if (cg_create(grps[1]))
640 if (cg_create(grps[2]))
643 if (cg_write(grps[1], "cgroup.type", "threaded"))
645 if (cg_write(grps[2], "cgroup.type", "threaded"))
648 if (cg_enter_current(grps[1]))
651 if (pthread_create(&thr, NULL, migrating_thread_fn, grps))
654 if (pthread_join(thr, &retval))
660 snprintf(line, sizeof(line), "0::%s", grps[1] + strlen(grps[0]));
661 if (proc_read_strstr(0, 1, "cgroup", line))
667 cg_enter_current(root);
681 * cgroup migration permission check should be performed based on the
682 * credentials at the time of open instead of write.
684 static int test_cgcore_lesser_euid_open(const char *root)
686 const uid_t test_euid = 65534; /* usually nobody, any !root is fine */
688 char *cg_test_a = NULL, *cg_test_b = NULL;
689 char *cg_test_a_procs = NULL, *cg_test_b_procs = NULL;
690 int cg_test_b_procs_fd = -1;
693 cg_test_a = cg_name(root, "cg_test_a");
694 cg_test_b = cg_name(root, "cg_test_b");
696 if (!cg_test_a || !cg_test_b)
699 cg_test_a_procs = cg_name(cg_test_a, "cgroup.procs");
700 cg_test_b_procs = cg_name(cg_test_b, "cgroup.procs");
702 if (!cg_test_a_procs || !cg_test_b_procs)
705 if (cg_create(cg_test_a) || cg_create(cg_test_b))
708 if (cg_enter_current(cg_test_a))
711 if (chown(cg_test_a_procs, test_euid, -1) ||
712 chown(cg_test_b_procs, test_euid, -1))
715 saved_uid = geteuid();
716 if (seteuid(test_euid))
719 cg_test_b_procs_fd = open(cg_test_b_procs, O_RDWR);
721 if (seteuid(saved_uid))
724 if (cg_test_b_procs_fd < 0)
727 if (write(cg_test_b_procs_fd, "0", 1) >= 0 || errno != EACCES)
733 cg_enter_current(root);
734 if (cg_test_b_procs_fd >= 0)
735 close(cg_test_b_procs_fd);
737 cg_destroy(cg_test_b);
739 cg_destroy(cg_test_a);
740 free(cg_test_b_procs);
741 free(cg_test_a_procs);
747 struct lesser_ns_open_thread_arg {
753 static int lesser_ns_open_thread_fn(void *arg)
755 struct lesser_ns_open_thread_arg *targ = arg;
757 targ->fd = open(targ->path, O_RDWR);
763 * cgroup migration permission check should be performed based on the cgroup
764 * namespace at the time of open instead of write.
766 static int test_cgcore_lesser_ns_open(const char *root)
768 static char stack[65536];
769 const uid_t test_euid = 65534; /* usually nobody, any !root is fine */
771 char *cg_test_a = NULL, *cg_test_b = NULL;
772 char *cg_test_a_procs = NULL, *cg_test_b_procs = NULL;
773 int cg_test_b_procs_fd = -1;
774 struct lesser_ns_open_thread_arg targ = { .fd = -1 };
778 cg_test_a = cg_name(root, "cg_test_a");
779 cg_test_b = cg_name(root, "cg_test_b");
781 if (!cg_test_a || !cg_test_b)
784 cg_test_a_procs = cg_name(cg_test_a, "cgroup.procs");
785 cg_test_b_procs = cg_name(cg_test_b, "cgroup.procs");
787 if (!cg_test_a_procs || !cg_test_b_procs)
790 if (cg_create(cg_test_a) || cg_create(cg_test_b))
793 if (cg_enter_current(cg_test_b))
796 if (chown(cg_test_a_procs, test_euid, -1) ||
797 chown(cg_test_b_procs, test_euid, -1))
800 targ.path = cg_test_b_procs;
801 pid = clone(lesser_ns_open_thread_fn, stack + sizeof(stack),
802 CLONE_NEWCGROUP | CLONE_FILES | CLONE_VM | SIGCHLD,
807 if (waitpid(pid, &status, 0) < 0)
810 if (!WIFEXITED(status))
813 cg_test_b_procs_fd = targ.fd;
814 if (cg_test_b_procs_fd < 0)
817 if (cg_enter_current(cg_test_a))
820 if ((status = write(cg_test_b_procs_fd, "0", 1)) >= 0 || errno != ENOENT)
826 cg_enter_current(root);
827 if (cg_test_b_procs_fd >= 0)
828 close(cg_test_b_procs_fd);
830 cg_destroy(cg_test_b);
832 cg_destroy(cg_test_a);
833 free(cg_test_b_procs);
834 free(cg_test_a_procs);
840 #define T(x) { x, #x }
842 int (*fn)(const char *root);
845 T(test_cgcore_internal_process_constraint),
846 T(test_cgcore_top_down_constraint_enable),
847 T(test_cgcore_top_down_constraint_disable),
848 T(test_cgcore_no_internal_process_constraint_on_threads),
849 T(test_cgcore_parent_becomes_threaded),
850 T(test_cgcore_invalid_domain),
851 T(test_cgcore_populated),
852 T(test_cgcore_proc_migration),
853 T(test_cgcore_thread_migration),
854 T(test_cgcore_destroy),
855 T(test_cgcore_lesser_euid_open),
856 T(test_cgcore_lesser_ns_open),
860 int main(int argc, char *argv[])
863 int i, ret = EXIT_SUCCESS;
865 if (cg_find_unified_root(root, sizeof(root)))
866 ksft_exit_skip("cgroup v2 isn't mounted\n");
868 if (cg_read_strstr(root, "cgroup.subtree_control", "memory"))
869 if (cg_write(root, "cgroup.subtree_control", "+memory"))
870 ksft_exit_skip("Failed to set memory controller\n");
872 for (i = 0; i < ARRAY_SIZE(tests); i++) {
873 switch (tests[i].fn(root)) {
875 ksft_test_result_pass("%s\n", tests[i].name);
878 ksft_test_result_skip("%s\n", tests[i].name);
882 ksft_test_result_fail("%s\n", tests[i].name);