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 bool nsdelegate;
23 static int touch_anon(char *buf, size_t size)
28 fd = open("/dev/urandom", O_RDONLY);
33 ssize_t ret = read(fd, pos, size);
50 static int alloc_and_touch_anon_noexit(const char *cgroup, void *arg)
53 size_t size = (size_t)arg;
56 buf = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
58 if (buf == MAP_FAILED)
61 if (touch_anon((char *)buf, size)) {
66 while (getppid() == ppid)
74 * Create a child process that allocates and touches 100MB, then waits to be
75 * killed. Wait until the child is attached to the cgroup, kill all processes
76 * in that cgroup and wait until "cgroup.procs" is empty. At this point try to
77 * destroy the empty cgroup. The test helps detect race conditions between
78 * dying processes leaving the cgroup and cgroup destruction path.
80 static int test_cgcore_destroy(const char *root)
87 cg_test = cg_name(root, "cg_test");
92 for (int i = 0; i < 10; i++) {
93 if (cg_create(cg_test))
96 child_pid = cg_run_nowait(cg_test, alloc_and_touch_anon_noexit,
102 /* wait for the child to enter cgroup */
103 if (cg_wait_for_proc_count(cg_test, 1))
106 if (cg_killall(cg_test))
109 /* wait for cgroup to be empty */
111 if (cg_read(cg_test, "cgroup.procs", buf, sizeof(buf)))
121 if (waitpid(child_pid, NULL, 0) < 0)
136 * A, B and C's "populated" fields would be 1 while D's 0.
137 * test that after the one process in C is moved to root,
138 * A,B and C's "populated" fields would flip to "0" and file
139 * modified events will be generated on the
140 * "cgroup.events" files of both cgroups.
142 static int test_cgcore_populated(const char *root)
146 char *cg_test_a = NULL, *cg_test_b = NULL;
147 char *cg_test_c = NULL, *cg_test_d = NULL;
148 int cgroup_fd = -EBADF;
151 cg_test_a = cg_name(root, "cg_test_a");
152 cg_test_b = cg_name(root, "cg_test_a/cg_test_b");
153 cg_test_c = cg_name(root, "cg_test_a/cg_test_b/cg_test_c");
154 cg_test_d = cg_name(root, "cg_test_a/cg_test_b/cg_test_d");
156 if (!cg_test_a || !cg_test_b || !cg_test_c || !cg_test_d)
159 if (cg_create(cg_test_a))
162 if (cg_create(cg_test_b))
165 if (cg_create(cg_test_c))
168 if (cg_create(cg_test_d))
171 if (cg_enter_current(cg_test_c))
174 if (cg_read_strcmp(cg_test_a, "cgroup.events", "populated 1\n"))
177 if (cg_read_strcmp(cg_test_b, "cgroup.events", "populated 1\n"))
180 if (cg_read_strcmp(cg_test_c, "cgroup.events", "populated 1\n"))
183 if (cg_read_strcmp(cg_test_d, "cgroup.events", "populated 0\n"))
186 if (cg_enter_current(root))
189 if (cg_read_strcmp(cg_test_a, "cgroup.events", "populated 0\n"))
192 if (cg_read_strcmp(cg_test_b, "cgroup.events", "populated 0\n"))
195 if (cg_read_strcmp(cg_test_c, "cgroup.events", "populated 0\n"))
198 if (cg_read_strcmp(cg_test_d, "cgroup.events", "populated 0\n"))
201 /* Test that we can directly clone into a new cgroup. */
202 cgroup_fd = dirfd_open_opath(cg_test_d);
206 pid = clone_into_cgroup(cgroup_fd);
219 err = cg_read_strcmp(cg_test_d, "cgroup.events", "populated 1\n");
221 (void)clone_reap(pid, WSTOPPED);
222 (void)kill(pid, SIGCONT);
223 (void)clone_reap(pid, WEXITED);
228 if (cg_read_strcmp(cg_test_d, "cgroup.events", "populated 0\n"))
233 cg_destroy(cg_test_d);
238 pid = clone_into_cgroup(cgroup_fd);
243 (void)clone_reap(pid, WEXITED);
251 cg_destroy(cg_test_d);
253 cg_destroy(cg_test_c);
255 cg_destroy(cg_test_b);
257 cg_destroy(cg_test_a);
268 * A (domain threaded) - B (threaded) - C (domain)
270 * test that C can't be used until it is turned into a
271 * threaded cgroup. "cgroup.type" file will report "domain (invalid)" in
272 * these cases. Operations which fail due to invalid topology use
273 * EOPNOTSUPP as the errno.
275 static int test_cgcore_invalid_domain(const char *root)
278 char *grandparent = NULL, *parent = NULL, *child = NULL;
280 grandparent = cg_name(root, "cg_test_grandparent");
281 parent = cg_name(root, "cg_test_grandparent/cg_test_parent");
282 child = cg_name(root, "cg_test_grandparent/cg_test_parent/cg_test_child");
283 if (!parent || !child || !grandparent)
286 if (cg_create(grandparent))
289 if (cg_create(parent))
292 if (cg_create(child))
295 if (cg_write(parent, "cgroup.type", "threaded"))
298 if (cg_read_strcmp(child, "cgroup.type", "domain invalid\n"))
301 if (!cg_enter_current(child))
304 if (errno != EOPNOTSUPP)
307 if (!clone_into_cgroup_run_wait(child))
313 if (errno != EOPNOTSUPP)
320 cg_enter_current(root);
326 cg_destroy(grandparent);
334 * Test that when a child becomes threaded
335 * the parent type becomes domain threaded.
337 static int test_cgcore_parent_becomes_threaded(const char *root)
340 char *parent = NULL, *child = NULL;
342 parent = cg_name(root, "cg_test_parent");
343 child = cg_name(root, "cg_test_parent/cg_test_child");
344 if (!parent || !child)
347 if (cg_create(parent))
350 if (cg_create(child))
353 if (cg_write(child, "cgroup.type", "threaded"))
356 if (cg_read_strcmp(parent, "cgroup.type", "domain threaded\n"))
373 * Test that there's no internal process constrain on threaded cgroups.
374 * You can add threads/processes on a parent with a controller enabled.
376 static int test_cgcore_no_internal_process_constraint_on_threads(const char *root)
379 char *parent = NULL, *child = NULL;
381 if (cg_read_strstr(root, "cgroup.controllers", "cpu") ||
382 cg_write(root, "cgroup.subtree_control", "+cpu")) {
387 parent = cg_name(root, "cg_test_parent");
388 child = cg_name(root, "cg_test_parent/cg_test_child");
389 if (!parent || !child)
392 if (cg_create(parent))
395 if (cg_create(child))
398 if (cg_write(parent, "cgroup.type", "threaded"))
401 if (cg_write(child, "cgroup.type", "threaded"))
404 if (cg_write(parent, "cgroup.subtree_control", "+cpu"))
407 if (cg_enter_current(parent))
413 cg_enter_current(root);
414 cg_enter_current(root);
425 * Test that you can't enable a controller on a child if it's not enabled
428 static int test_cgcore_top_down_constraint_enable(const char *root)
431 char *parent = NULL, *child = NULL;
433 parent = cg_name(root, "cg_test_parent");
434 child = cg_name(root, "cg_test_parent/cg_test_child");
435 if (!parent || !child)
438 if (cg_create(parent))
441 if (cg_create(child))
444 if (!cg_write(child, "cgroup.subtree_control", "+memory"))
460 * Test that you can't disable a controller on a parent
461 * if it's enabled in a child.
463 static int test_cgcore_top_down_constraint_disable(const char *root)
466 char *parent = NULL, *child = NULL;
468 parent = cg_name(root, "cg_test_parent");
469 child = cg_name(root, "cg_test_parent/cg_test_child");
470 if (!parent || !child)
473 if (cg_create(parent))
476 if (cg_create(child))
479 if (cg_write(parent, "cgroup.subtree_control", "+memory"))
482 if (cg_write(child, "cgroup.subtree_control", "+memory"))
485 if (!cg_write(parent, "cgroup.subtree_control", "-memory"))
501 * Test internal process constraint.
502 * You can't add a pid to a domain parent if a controller is enabled.
504 static int test_cgcore_internal_process_constraint(const char *root)
507 char *parent = NULL, *child = NULL;
509 parent = cg_name(root, "cg_test_parent");
510 child = cg_name(root, "cg_test_parent/cg_test_child");
511 if (!parent || !child)
514 if (cg_create(parent))
517 if (cg_create(child))
520 if (cg_write(parent, "cgroup.subtree_control", "+memory"))
523 if (!cg_enter_current(parent))
526 if (!clone_into_cgroup_run_wait(parent))
541 static void *dummy_thread_fn(void *arg)
543 return (void *)(size_t)pause();
547 * Test threadgroup migration.
548 * All threads of a process are migrated together.
550 static int test_cgcore_proc_migration(const char *root)
553 int t, c_threads = 0, n_threads = 13;
554 char *src = NULL, *dst = NULL;
555 pthread_t threads[n_threads];
557 src = cg_name(root, "cg_src");
558 dst = cg_name(root, "cg_dst");
567 if (cg_enter_current(src))
570 for (c_threads = 0; c_threads < n_threads; ++c_threads) {
571 if (pthread_create(&threads[c_threads], NULL, dummy_thread_fn, NULL))
575 cg_enter_current(dst);
576 if (cg_read_lc(dst, "cgroup.threads") != n_threads + 1)
582 for (t = 0; t < c_threads; ++t) {
583 pthread_cancel(threads[t]);
586 for (t = 0; t < c_threads; ++t) {
587 pthread_join(threads[t], NULL);
590 cg_enter_current(root);
601 static void *migrating_thread_fn(void *arg)
603 int g, i, n_iterations = 1000;
605 char lines[3][PATH_MAX];
607 for (g = 1; g < 3; ++g)
608 snprintf(lines[g], sizeof(lines[g]), "0::%s", grps[g] + strlen(grps[0]));
610 for (i = 0; i < n_iterations; ++i) {
611 cg_enter_current_thread(grps[(i % 2) + 1]);
613 if (proc_read_strstr(0, 1, "cgroup", lines[(i % 2) + 1]))
620 * Test single thread migration.
621 * Threaded cgroups allow successful migration of a thread.
623 static int test_cgcore_thread_migration(const char *root)
628 char *grps[3] = { (char *)root, NULL, NULL };
632 dom = cg_name(root, "cg_dom");
633 grps[1] = cg_name(root, "cg_dom/cg_src");
634 grps[2] = cg_name(root, "cg_dom/cg_dst");
635 if (!grps[1] || !grps[2] || !dom)
640 if (cg_create(grps[1]))
642 if (cg_create(grps[2]))
645 if (cg_write(grps[1], "cgroup.type", "threaded"))
647 if (cg_write(grps[2], "cgroup.type", "threaded"))
650 if (cg_enter_current(grps[1]))
653 if (pthread_create(&thr, NULL, migrating_thread_fn, grps))
656 if (pthread_join(thr, &retval))
662 snprintf(line, sizeof(line), "0::%s", grps[1] + strlen(grps[0]));
663 if (proc_read_strstr(0, 1, "cgroup", line))
669 cg_enter_current(root);
683 * cgroup migration permission check should be performed based on the
684 * credentials at the time of open instead of write.
686 static int test_cgcore_lesser_euid_open(const char *root)
688 const uid_t test_euid = TEST_UID;
690 char *cg_test_a = NULL, *cg_test_b = NULL;
691 char *cg_test_a_procs = NULL, *cg_test_b_procs = NULL;
692 int cg_test_b_procs_fd = -1;
695 cg_test_a = cg_name(root, "cg_test_a");
696 cg_test_b = cg_name(root, "cg_test_b");
698 if (!cg_test_a || !cg_test_b)
701 cg_test_a_procs = cg_name(cg_test_a, "cgroup.procs");
702 cg_test_b_procs = cg_name(cg_test_b, "cgroup.procs");
704 if (!cg_test_a_procs || !cg_test_b_procs)
707 if (cg_create(cg_test_a) || cg_create(cg_test_b))
710 if (cg_enter_current(cg_test_a))
713 if (chown(cg_test_a_procs, test_euid, -1) ||
714 chown(cg_test_b_procs, test_euid, -1))
717 saved_uid = geteuid();
718 if (seteuid(test_euid))
721 cg_test_b_procs_fd = open(cg_test_b_procs, O_RDWR);
723 if (seteuid(saved_uid))
726 if (cg_test_b_procs_fd < 0)
729 if (write(cg_test_b_procs_fd, "0", 1) >= 0 || errno != EACCES)
735 cg_enter_current(root);
736 if (cg_test_b_procs_fd >= 0)
737 close(cg_test_b_procs_fd);
739 cg_destroy(cg_test_b);
741 cg_destroy(cg_test_a);
742 free(cg_test_b_procs);
743 free(cg_test_a_procs);
749 struct lesser_ns_open_thread_arg {
755 static int lesser_ns_open_thread_fn(void *arg)
757 struct lesser_ns_open_thread_arg *targ = arg;
759 targ->fd = open(targ->path, O_RDWR);
765 * cgroup migration permission check should be performed based on the cgroup
766 * namespace at the time of open instead of write.
768 static int test_cgcore_lesser_ns_open(const char *root)
770 static char stack[65536];
771 const uid_t test_euid = 65534; /* usually nobody, any !root is fine */
773 char *cg_test_a = NULL, *cg_test_b = NULL;
774 char *cg_test_a_procs = NULL, *cg_test_b_procs = NULL;
775 int cg_test_b_procs_fd = -1;
776 struct lesser_ns_open_thread_arg targ = { .fd = -1 };
783 cg_test_a = cg_name(root, "cg_test_a");
784 cg_test_b = cg_name(root, "cg_test_b");
786 if (!cg_test_a || !cg_test_b)
789 cg_test_a_procs = cg_name(cg_test_a, "cgroup.procs");
790 cg_test_b_procs = cg_name(cg_test_b, "cgroup.procs");
792 if (!cg_test_a_procs || !cg_test_b_procs)
795 if (cg_create(cg_test_a) || cg_create(cg_test_b))
798 if (cg_enter_current(cg_test_b))
801 if (chown(cg_test_a_procs, test_euid, -1) ||
802 chown(cg_test_b_procs, test_euid, -1))
805 targ.path = cg_test_b_procs;
806 pid = clone(lesser_ns_open_thread_fn, stack + sizeof(stack),
807 CLONE_NEWCGROUP | CLONE_FILES | CLONE_VM | SIGCHLD,
812 if (waitpid(pid, &status, 0) < 0)
815 if (!WIFEXITED(status))
818 cg_test_b_procs_fd = targ.fd;
819 if (cg_test_b_procs_fd < 0)
822 if (cg_enter_current(cg_test_a))
825 if ((status = write(cg_test_b_procs_fd, "0", 1)) >= 0 || errno != ENOENT)
831 cg_enter_current(root);
832 if (cg_test_b_procs_fd >= 0)
833 close(cg_test_b_procs_fd);
835 cg_destroy(cg_test_b);
837 cg_destroy(cg_test_a);
838 free(cg_test_b_procs);
839 free(cg_test_a_procs);
845 #define T(x) { x, #x }
847 int (*fn)(const char *root);
850 T(test_cgcore_internal_process_constraint),
851 T(test_cgcore_top_down_constraint_enable),
852 T(test_cgcore_top_down_constraint_disable),
853 T(test_cgcore_no_internal_process_constraint_on_threads),
854 T(test_cgcore_parent_becomes_threaded),
855 T(test_cgcore_invalid_domain),
856 T(test_cgcore_populated),
857 T(test_cgcore_proc_migration),
858 T(test_cgcore_thread_migration),
859 T(test_cgcore_destroy),
860 T(test_cgcore_lesser_euid_open),
861 T(test_cgcore_lesser_ns_open),
865 int main(int argc, char *argv[])
868 int i, ret = EXIT_SUCCESS;
870 if (cg_find_unified_root(root, sizeof(root), &nsdelegate))
871 ksft_exit_skip("cgroup v2 isn't mounted\n");
873 if (cg_read_strstr(root, "cgroup.subtree_control", "memory"))
874 if (cg_write(root, "cgroup.subtree_control", "+memory"))
875 ksft_exit_skip("Failed to set memory controller\n");
877 for (i = 0; i < ARRAY_SIZE(tests); i++) {
878 switch (tests[i].fn(root)) {
880 ksft_test_result_pass("%s\n", tests[i].name);
883 ksft_test_result_skip("%s\n", tests[i].name);
887 ksft_test_result_fail("%s\n", tests[i].name);