staging: rtl8192u: remove redundant assignment to pointer crypt
[linux/fpc-iii.git] / tools / testing / selftests / cgroup / test_freezer.c
blob8219a30853d283fa65baa1be4f16036d7cf542a8
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #include <stdbool.h>
3 #include <linux/limits.h>
4 #include <sys/ptrace.h>
5 #include <sys/types.h>
6 #include <sys/mman.h>
7 #include <unistd.h>
8 #include <stdio.h>
9 #include <errno.h>
10 #include <poll.h>
11 #include <stdlib.h>
12 #include <sys/inotify.h>
13 #include <string.h>
14 #include <sys/wait.h>
16 #include "../kselftest.h"
17 #include "cgroup_util.h"
19 #define DEBUG
20 #ifdef DEBUG
21 #define debug(args...) fprintf(stderr, args)
22 #else
23 #define debug(args...)
24 #endif
27 * Check if the cgroup is frozen by looking at the cgroup.events::frozen value.
29 static int cg_check_frozen(const char *cgroup, bool frozen)
31 if (frozen) {
32 if (cg_read_strstr(cgroup, "cgroup.events", "frozen 1") != 0) {
33 debug("Cgroup %s isn't frozen\n", cgroup);
34 return -1;
36 } else {
38 * Check the cgroup.events::frozen value.
40 if (cg_read_strstr(cgroup, "cgroup.events", "frozen 0") != 0) {
41 debug("Cgroup %s is frozen\n", cgroup);
42 return -1;
46 return 0;
50 * Freeze the given cgroup.
52 static int cg_freeze_nowait(const char *cgroup, bool freeze)
54 return cg_write(cgroup, "cgroup.freeze", freeze ? "1" : "0");
58 * Prepare for waiting on cgroup.events file.
60 static int cg_prepare_for_wait(const char *cgroup)
62 int fd, ret = -1;
64 fd = inotify_init1(0);
65 if (fd == -1) {
66 debug("Error: inotify_init1() failed\n");
67 return fd;
70 ret = inotify_add_watch(fd, cg_control(cgroup, "cgroup.events"),
71 IN_MODIFY);
72 if (ret == -1) {
73 debug("Error: inotify_add_watch() failed\n");
74 close(fd);
77 return fd;
81 * Wait for an event. If there are no events for 10 seconds,
82 * treat this an error.
84 static int cg_wait_for(int fd)
86 int ret = -1;
87 struct pollfd fds = {
88 .fd = fd,
89 .events = POLLIN,
92 while (true) {
93 ret = poll(&fds, 1, 10000);
95 if (ret == -1) {
96 if (errno == EINTR)
97 continue;
98 debug("Error: poll() failed\n");
99 break;
102 if (ret > 0 && fds.revents & POLLIN) {
103 ret = 0;
104 break;
108 return ret;
112 * Attach a task to the given cgroup and wait for a cgroup frozen event.
113 * All transient events (e.g. populated) are ignored.
115 static int cg_enter_and_wait_for_frozen(const char *cgroup, int pid,
116 bool frozen)
118 int fd, ret = -1;
119 int attempts;
121 fd = cg_prepare_for_wait(cgroup);
122 if (fd < 0)
123 return fd;
125 ret = cg_enter(cgroup, pid);
126 if (ret)
127 goto out;
129 for (attempts = 0; attempts < 10; attempts++) {
130 ret = cg_wait_for(fd);
131 if (ret)
132 break;
134 ret = cg_check_frozen(cgroup, frozen);
135 if (ret)
136 continue;
139 out:
140 close(fd);
141 return ret;
145 * Freeze the given cgroup and wait for the inotify signal.
146 * If there are no events in 10 seconds, treat this as an error.
147 * Then check that the cgroup is in the desired state.
149 static int cg_freeze_wait(const char *cgroup, bool freeze)
151 int fd, ret = -1;
153 fd = cg_prepare_for_wait(cgroup);
154 if (fd < 0)
155 return fd;
157 ret = cg_freeze_nowait(cgroup, freeze);
158 if (ret) {
159 debug("Error: cg_freeze_nowait() failed\n");
160 goto out;
163 ret = cg_wait_for(fd);
164 if (ret)
165 goto out;
167 ret = cg_check_frozen(cgroup, freeze);
168 out:
169 close(fd);
170 return ret;
174 * A simple process running in a sleep loop until being
175 * re-parented.
177 static int child_fn(const char *cgroup, void *arg)
179 int ppid = getppid();
181 while (getppid() == ppid)
182 usleep(1000);
184 return getppid() == ppid;
188 * A simple test for the cgroup freezer: populated the cgroup with 100
189 * running processes and freeze it. Then unfreeze it. Then it kills all
190 * processes and destroys the cgroup.
192 static int test_cgfreezer_simple(const char *root)
194 int ret = KSFT_FAIL;
195 char *cgroup = NULL;
196 int i;
198 cgroup = cg_name(root, "cg_test_simple");
199 if (!cgroup)
200 goto cleanup;
202 if (cg_create(cgroup))
203 goto cleanup;
205 for (i = 0; i < 100; i++)
206 cg_run_nowait(cgroup, child_fn, NULL);
208 if (cg_wait_for_proc_count(cgroup, 100))
209 goto cleanup;
211 if (cg_check_frozen(cgroup, false))
212 goto cleanup;
214 if (cg_freeze_wait(cgroup, true))
215 goto cleanup;
217 if (cg_freeze_wait(cgroup, false))
218 goto cleanup;
220 ret = KSFT_PASS;
222 cleanup:
223 if (cgroup)
224 cg_destroy(cgroup);
225 free(cgroup);
226 return ret;
230 * The test creates the following hierarchy:
232 * / / \ \
233 * B E I K
234 * /\ |
235 * C D F
241 * with a process in C, H and 3 processes in K.
242 * Then it tries to freeze and unfreeze the whole tree.
244 static int test_cgfreezer_tree(const char *root)
246 char *cgroup[10] = {0};
247 int ret = KSFT_FAIL;
248 int i;
250 cgroup[0] = cg_name(root, "cg_test_tree_A");
251 if (!cgroup[0])
252 goto cleanup;
254 cgroup[1] = cg_name(cgroup[0], "B");
255 if (!cgroup[1])
256 goto cleanup;
258 cgroup[2] = cg_name(cgroup[1], "C");
259 if (!cgroup[2])
260 goto cleanup;
262 cgroup[3] = cg_name(cgroup[1], "D");
263 if (!cgroup[3])
264 goto cleanup;
266 cgroup[4] = cg_name(cgroup[0], "E");
267 if (!cgroup[4])
268 goto cleanup;
270 cgroup[5] = cg_name(cgroup[4], "F");
271 if (!cgroup[5])
272 goto cleanup;
274 cgroup[6] = cg_name(cgroup[5], "G");
275 if (!cgroup[6])
276 goto cleanup;
278 cgroup[7] = cg_name(cgroup[6], "H");
279 if (!cgroup[7])
280 goto cleanup;
282 cgroup[8] = cg_name(cgroup[0], "I");
283 if (!cgroup[8])
284 goto cleanup;
286 cgroup[9] = cg_name(cgroup[0], "K");
287 if (!cgroup[9])
288 goto cleanup;
290 for (i = 0; i < 10; i++)
291 if (cg_create(cgroup[i]))
292 goto cleanup;
294 cg_run_nowait(cgroup[2], child_fn, NULL);
295 cg_run_nowait(cgroup[7], child_fn, NULL);
296 cg_run_nowait(cgroup[9], child_fn, NULL);
297 cg_run_nowait(cgroup[9], child_fn, NULL);
298 cg_run_nowait(cgroup[9], child_fn, NULL);
301 * Wait until all child processes will enter
302 * corresponding cgroups.
305 if (cg_wait_for_proc_count(cgroup[2], 1) ||
306 cg_wait_for_proc_count(cgroup[7], 1) ||
307 cg_wait_for_proc_count(cgroup[9], 3))
308 goto cleanup;
311 * Freeze B.
313 if (cg_freeze_wait(cgroup[1], true))
314 goto cleanup;
317 * Freeze F.
319 if (cg_freeze_wait(cgroup[5], true))
320 goto cleanup;
323 * Freeze G.
325 if (cg_freeze_wait(cgroup[6], true))
326 goto cleanup;
329 * Check that A and E are not frozen.
331 if (cg_check_frozen(cgroup[0], false))
332 goto cleanup;
334 if (cg_check_frozen(cgroup[4], false))
335 goto cleanup;
338 * Freeze A. Check that A, B and E are frozen.
340 if (cg_freeze_wait(cgroup[0], true))
341 goto cleanup;
343 if (cg_check_frozen(cgroup[1], true))
344 goto cleanup;
346 if (cg_check_frozen(cgroup[4], true))
347 goto cleanup;
350 * Unfreeze B, F and G
352 if (cg_freeze_nowait(cgroup[1], false))
353 goto cleanup;
355 if (cg_freeze_nowait(cgroup[5], false))
356 goto cleanup;
358 if (cg_freeze_nowait(cgroup[6], false))
359 goto cleanup;
362 * Check that C and H are still frozen.
364 if (cg_check_frozen(cgroup[2], true))
365 goto cleanup;
367 if (cg_check_frozen(cgroup[7], true))
368 goto cleanup;
371 * Unfreeze A. Check that A, C and K are not frozen.
373 if (cg_freeze_wait(cgroup[0], false))
374 goto cleanup;
376 if (cg_check_frozen(cgroup[2], false))
377 goto cleanup;
379 if (cg_check_frozen(cgroup[9], false))
380 goto cleanup;
382 ret = KSFT_PASS;
384 cleanup:
385 for (i = 9; i >= 0 && cgroup[i]; i--) {
386 cg_destroy(cgroup[i]);
387 free(cgroup[i]);
390 return ret;
394 * A fork bomb emulator.
396 static int forkbomb_fn(const char *cgroup, void *arg)
398 int ppid;
400 fork();
401 fork();
403 ppid = getppid();
405 while (getppid() == ppid)
406 usleep(1000);
408 return getppid() == ppid;
412 * The test runs a fork bomb in a cgroup and tries to freeze it.
413 * Then it kills all processes and checks that cgroup isn't populated
414 * anymore.
416 static int test_cgfreezer_forkbomb(const char *root)
418 int ret = KSFT_FAIL;
419 char *cgroup = NULL;
421 cgroup = cg_name(root, "cg_forkbomb_test");
422 if (!cgroup)
423 goto cleanup;
425 if (cg_create(cgroup))
426 goto cleanup;
428 cg_run_nowait(cgroup, forkbomb_fn, NULL);
430 usleep(100000);
432 if (cg_freeze_wait(cgroup, true))
433 goto cleanup;
435 if (cg_killall(cgroup))
436 goto cleanup;
438 if (cg_wait_for_proc_count(cgroup, 0))
439 goto cleanup;
441 ret = KSFT_PASS;
443 cleanup:
444 if (cgroup)
445 cg_destroy(cgroup);
446 free(cgroup);
447 return ret;
451 * The test creates two nested cgroups, freezes the parent
452 * and removes the child. Then it checks that the parent cgroup
453 * remains frozen and it's possible to create a new child
454 * without unfreezing. The new child is frozen too.
456 static int test_cgfreezer_rmdir(const char *root)
458 int ret = KSFT_FAIL;
459 char *parent, *child = NULL;
461 parent = cg_name(root, "cg_test_rmdir_A");
462 if (!parent)
463 goto cleanup;
465 child = cg_name(parent, "cg_test_rmdir_B");
466 if (!child)
467 goto cleanup;
469 if (cg_create(parent))
470 goto cleanup;
472 if (cg_create(child))
473 goto cleanup;
475 if (cg_freeze_wait(parent, true))
476 goto cleanup;
478 if (cg_destroy(child))
479 goto cleanup;
481 if (cg_check_frozen(parent, true))
482 goto cleanup;
484 if (cg_create(child))
485 goto cleanup;
487 if (cg_check_frozen(child, true))
488 goto cleanup;
490 ret = KSFT_PASS;
492 cleanup:
493 if (child)
494 cg_destroy(child);
495 free(child);
496 if (parent)
497 cg_destroy(parent);
498 free(parent);
499 return ret;
503 * The test creates two cgroups: A and B, runs a process in A
504 * and performs several migrations:
505 * 1) A (running) -> B (frozen)
506 * 2) B (frozen) -> A (running)
507 * 3) A (frozen) -> B (frozen)
509 * On each step it checks the actual state of both cgroups.
511 static int test_cgfreezer_migrate(const char *root)
513 int ret = KSFT_FAIL;
514 char *cgroup[2] = {0};
515 int pid;
517 cgroup[0] = cg_name(root, "cg_test_migrate_A");
518 if (!cgroup[0])
519 goto cleanup;
521 cgroup[1] = cg_name(root, "cg_test_migrate_B");
522 if (!cgroup[1])
523 goto cleanup;
525 if (cg_create(cgroup[0]))
526 goto cleanup;
528 if (cg_create(cgroup[1]))
529 goto cleanup;
531 pid = cg_run_nowait(cgroup[0], child_fn, NULL);
532 if (pid < 0)
533 goto cleanup;
535 if (cg_wait_for_proc_count(cgroup[0], 1))
536 goto cleanup;
539 * Migrate from A (running) to B (frozen)
541 if (cg_freeze_wait(cgroup[1], true))
542 goto cleanup;
544 if (cg_enter_and_wait_for_frozen(cgroup[1], pid, true))
545 goto cleanup;
547 if (cg_check_frozen(cgroup[0], false))
548 goto cleanup;
551 * Migrate from B (frozen) to A (running)
553 if (cg_enter_and_wait_for_frozen(cgroup[0], pid, false))
554 goto cleanup;
556 if (cg_check_frozen(cgroup[1], true))
557 goto cleanup;
560 * Migrate from A (frozen) to B (frozen)
562 if (cg_freeze_wait(cgroup[0], true))
563 goto cleanup;
565 if (cg_enter_and_wait_for_frozen(cgroup[1], pid, true))
566 goto cleanup;
568 if (cg_check_frozen(cgroup[0], true))
569 goto cleanup;
571 ret = KSFT_PASS;
573 cleanup:
574 if (cgroup[0])
575 cg_destroy(cgroup[0]);
576 free(cgroup[0]);
577 if (cgroup[1])
578 cg_destroy(cgroup[1]);
579 free(cgroup[1]);
580 return ret;
584 * The test checks that ptrace works with a tracing process in a frozen cgroup.
586 static int test_cgfreezer_ptrace(const char *root)
588 int ret = KSFT_FAIL;
589 char *cgroup = NULL;
590 siginfo_t siginfo;
591 int pid;
593 cgroup = cg_name(root, "cg_test_ptrace");
594 if (!cgroup)
595 goto cleanup;
597 if (cg_create(cgroup))
598 goto cleanup;
600 pid = cg_run_nowait(cgroup, child_fn, NULL);
601 if (pid < 0)
602 goto cleanup;
604 if (cg_wait_for_proc_count(cgroup, 1))
605 goto cleanup;
607 if (cg_freeze_wait(cgroup, true))
608 goto cleanup;
610 if (ptrace(PTRACE_SEIZE, pid, NULL, NULL))
611 goto cleanup;
613 if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL))
614 goto cleanup;
616 waitpid(pid, NULL, 0);
619 * Cgroup has to remain frozen, however the test task
620 * is in traced state.
622 if (cg_check_frozen(cgroup, true))
623 goto cleanup;
625 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo))
626 goto cleanup;
628 if (ptrace(PTRACE_DETACH, pid, NULL, NULL))
629 goto cleanup;
631 if (cg_check_frozen(cgroup, true))
632 goto cleanup;
634 ret = KSFT_PASS;
636 cleanup:
637 if (cgroup)
638 cg_destroy(cgroup);
639 free(cgroup);
640 return ret;
644 * Check if the process is stopped.
646 static int proc_check_stopped(int pid)
648 char buf[PAGE_SIZE];
649 int len;
651 len = proc_read_text(pid, "stat", buf, sizeof(buf));
652 if (len == -1) {
653 debug("Can't get %d stat\n", pid);
654 return -1;
657 if (strstr(buf, "(test_freezer) T ") == NULL) {
658 debug("Process %d in the unexpected state: %s\n", pid, buf);
659 return -1;
662 return 0;
666 * Test that it's possible to freeze a cgroup with a stopped process.
668 static int test_cgfreezer_stopped(const char *root)
670 int pid, ret = KSFT_FAIL;
671 char *cgroup = NULL;
673 cgroup = cg_name(root, "cg_test_stopped");
674 if (!cgroup)
675 goto cleanup;
677 if (cg_create(cgroup))
678 goto cleanup;
680 pid = cg_run_nowait(cgroup, child_fn, NULL);
682 if (cg_wait_for_proc_count(cgroup, 1))
683 goto cleanup;
685 if (kill(pid, SIGSTOP))
686 goto cleanup;
688 if (cg_check_frozen(cgroup, false))
689 goto cleanup;
691 if (cg_freeze_wait(cgroup, true))
692 goto cleanup;
694 if (cg_freeze_wait(cgroup, false))
695 goto cleanup;
697 if (proc_check_stopped(pid))
698 goto cleanup;
700 ret = KSFT_PASS;
702 cleanup:
703 if (cgroup)
704 cg_destroy(cgroup);
705 free(cgroup);
706 return ret;
710 * Test that it's possible to freeze a cgroup with a ptraced process.
712 static int test_cgfreezer_ptraced(const char *root)
714 int pid, ret = KSFT_FAIL;
715 char *cgroup = NULL;
716 siginfo_t siginfo;
718 cgroup = cg_name(root, "cg_test_ptraced");
719 if (!cgroup)
720 goto cleanup;
722 if (cg_create(cgroup))
723 goto cleanup;
725 pid = cg_run_nowait(cgroup, child_fn, NULL);
727 if (cg_wait_for_proc_count(cgroup, 1))
728 goto cleanup;
730 if (ptrace(PTRACE_SEIZE, pid, NULL, NULL))
731 goto cleanup;
733 if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL))
734 goto cleanup;
736 waitpid(pid, NULL, 0);
738 if (cg_check_frozen(cgroup, false))
739 goto cleanup;
741 if (cg_freeze_wait(cgroup, true))
742 goto cleanup;
745 * cg_check_frozen(cgroup, true) will fail here,
746 * because the task in in the TRACEd state.
748 if (cg_freeze_wait(cgroup, false))
749 goto cleanup;
751 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo))
752 goto cleanup;
754 if (ptrace(PTRACE_DETACH, pid, NULL, NULL))
755 goto cleanup;
757 ret = KSFT_PASS;
759 cleanup:
760 if (cgroup)
761 cg_destroy(cgroup);
762 free(cgroup);
763 return ret;
766 static int vfork_fn(const char *cgroup, void *arg)
768 int pid = vfork();
770 if (pid == 0)
771 while (true)
772 sleep(1);
774 return pid;
778 * Test that it's possible to freeze a cgroup with a process,
779 * which called vfork() and is waiting for a child.
781 static int test_cgfreezer_vfork(const char *root)
783 int ret = KSFT_FAIL;
784 char *cgroup = NULL;
786 cgroup = cg_name(root, "cg_test_vfork");
787 if (!cgroup)
788 goto cleanup;
790 if (cg_create(cgroup))
791 goto cleanup;
793 cg_run_nowait(cgroup, vfork_fn, NULL);
795 if (cg_wait_for_proc_count(cgroup, 2))
796 goto cleanup;
798 if (cg_freeze_wait(cgroup, true))
799 goto cleanup;
801 ret = KSFT_PASS;
803 cleanup:
804 if (cgroup)
805 cg_destroy(cgroup);
806 free(cgroup);
807 return ret;
810 #define T(x) { x, #x }
811 struct cgfreezer_test {
812 int (*fn)(const char *root);
813 const char *name;
814 } tests[] = {
815 T(test_cgfreezer_simple),
816 T(test_cgfreezer_tree),
817 T(test_cgfreezer_forkbomb),
818 T(test_cgfreezer_rmdir),
819 T(test_cgfreezer_migrate),
820 T(test_cgfreezer_ptrace),
821 T(test_cgfreezer_stopped),
822 T(test_cgfreezer_ptraced),
823 T(test_cgfreezer_vfork),
825 #undef T
827 int main(int argc, char *argv[])
829 char root[PATH_MAX];
830 int i, ret = EXIT_SUCCESS;
832 if (cg_find_unified_root(root, sizeof(root)))
833 ksft_exit_skip("cgroup v2 isn't mounted\n");
834 for (i = 0; i < ARRAY_SIZE(tests); i++) {
835 switch (tests[i].fn(root)) {
836 case KSFT_PASS:
837 ksft_test_result_pass("%s\n", tests[i].name);
838 break;
839 case KSFT_SKIP:
840 ksft_test_result_skip("%s\n", tests[i].name);
841 break;
842 default:
843 ret = EXIT_FAILURE;
844 ksft_test_result_fail("%s\n", tests[i].name);
845 break;
849 return ret;