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
);