xref: /linux/tools/testing/selftests/cgroup/test_freezer.c (revision 755fa5b4fb36627796af19932a432d343220ec63)
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 <stdlib.h>
11 #include <string.h>
12 #include <sys/wait.h>
13 
14 #include "../kselftest.h"
15 #include "cgroup_util.h"
16 
17 #define DEBUG
18 #ifdef DEBUG
19 #define debug(args...) fprintf(stderr, args)
20 #else
21 #define debug(args...)
22 #endif
23 
24 /*
25  * Check if the cgroup is frozen by looking at the cgroup.events::frozen value.
26  */
cg_check_frozen(const char * cgroup,bool frozen)27 static int cg_check_frozen(const char *cgroup, bool frozen)
28 {
29 	if (frozen) {
30 		if (cg_read_strstr(cgroup, "cgroup.events", "frozen 1") != 0) {
31 			debug("Cgroup %s isn't frozen\n", cgroup);
32 			return -1;
33 		}
34 	} else {
35 		/*
36 		 * Check the cgroup.events::frozen value.
37 		 */
38 		if (cg_read_strstr(cgroup, "cgroup.events", "frozen 0") != 0) {
39 			debug("Cgroup %s is frozen\n", cgroup);
40 			return -1;
41 		}
42 	}
43 
44 	return 0;
45 }
46 
47 /*
48  * Freeze the given cgroup.
49  */
cg_freeze_nowait(const char * cgroup,bool freeze)50 static int cg_freeze_nowait(const char *cgroup, bool freeze)
51 {
52 	return cg_write(cgroup, "cgroup.freeze", freeze ? "1" : "0");
53 }
54 
55 /*
56  * Attach a task to the given cgroup and wait for a cgroup frozen event.
57  * All transient events (e.g. populated) are ignored.
58  */
cg_enter_and_wait_for_frozen(const char * cgroup,int pid,bool frozen)59 static int cg_enter_and_wait_for_frozen(const char *cgroup, int pid,
60 					bool frozen)
61 {
62 	int fd, ret = -1;
63 	int attempts;
64 
65 	fd = cg_prepare_for_wait(cgroup);
66 	if (fd < 0)
67 		return fd;
68 
69 	ret = cg_enter(cgroup, pid);
70 	if (ret)
71 		goto out;
72 
73 	for (attempts = 0; attempts < 10; attempts++) {
74 		ret = cg_wait_for(fd);
75 		if (ret)
76 			break;
77 
78 		ret = cg_check_frozen(cgroup, frozen);
79 		if (ret)
80 			continue;
81 	}
82 
83 out:
84 	close(fd);
85 	return ret;
86 }
87 
88 /*
89  * Freeze the given cgroup and wait for the inotify signal.
90  * If there are no events in 10 seconds, treat this as an error.
91  * Then check that the cgroup is in the desired state.
92  */
cg_freeze_wait(const char * cgroup,bool freeze)93 static int cg_freeze_wait(const char *cgroup, bool freeze)
94 {
95 	int fd, ret = -1;
96 
97 	fd = cg_prepare_for_wait(cgroup);
98 	if (fd < 0)
99 		return fd;
100 
101 	ret = cg_freeze_nowait(cgroup, freeze);
102 	if (ret) {
103 		debug("Error: cg_freeze_nowait() failed\n");
104 		goto out;
105 	}
106 
107 	ret = cg_wait_for(fd);
108 	if (ret)
109 		goto out;
110 
111 	ret = cg_check_frozen(cgroup, freeze);
112 out:
113 	close(fd);
114 	return ret;
115 }
116 
117 /*
118  * A simple process running in a sleep loop until being
119  * re-parented.
120  */
child_fn(const char * cgroup,void * arg)121 static int child_fn(const char *cgroup, void *arg)
122 {
123 	int ppid = getppid();
124 
125 	while (getppid() == ppid)
126 		usleep(1000);
127 
128 	return getppid() == ppid;
129 }
130 
131 /*
132  * A simple test for the cgroup freezer: populated the cgroup with 100
133  * running processes and freeze it. Then unfreeze it. Then it kills all
134  * processes and destroys the cgroup.
135  */
test_cgfreezer_simple(const char * root)136 static int test_cgfreezer_simple(const char *root)
137 {
138 	int ret = KSFT_FAIL;
139 	char *cgroup = NULL;
140 	int i;
141 
142 	cgroup = cg_name(root, "cg_test_simple");
143 	if (!cgroup)
144 		goto cleanup;
145 
146 	if (cg_create(cgroup))
147 		goto cleanup;
148 
149 	for (i = 0; i < 100; i++)
150 		cg_run_nowait(cgroup, child_fn, NULL);
151 
152 	if (cg_wait_for_proc_count(cgroup, 100))
153 		goto cleanup;
154 
155 	if (cg_check_frozen(cgroup, false))
156 		goto cleanup;
157 
158 	if (cg_freeze_wait(cgroup, true))
159 		goto cleanup;
160 
161 	if (cg_freeze_wait(cgroup, false))
162 		goto cleanup;
163 
164 	ret = KSFT_PASS;
165 
166 cleanup:
167 	if (cgroup)
168 		cg_destroy(cgroup);
169 	free(cgroup);
170 	return ret;
171 }
172 
173 /*
174  * The test creates the following hierarchy:
175  *       A
176  *    / / \ \
177  *   B  E  I K
178  *  /\  |
179  * C  D F
180  *      |
181  *      G
182  *      |
183  *      H
184  *
185  * with a process in C, H and 3 processes in K.
186  * Then it tries to freeze and unfreeze the whole tree.
187  */
test_cgfreezer_tree(const char * root)188 static int test_cgfreezer_tree(const char *root)
189 {
190 	char *cgroup[10] = {0};
191 	int ret = KSFT_FAIL;
192 	int i;
193 
194 	cgroup[0] = cg_name(root, "cg_test_tree_A");
195 	if (!cgroup[0])
196 		goto cleanup;
197 
198 	cgroup[1] = cg_name(cgroup[0], "B");
199 	if (!cgroup[1])
200 		goto cleanup;
201 
202 	cgroup[2] = cg_name(cgroup[1], "C");
203 	if (!cgroup[2])
204 		goto cleanup;
205 
206 	cgroup[3] = cg_name(cgroup[1], "D");
207 	if (!cgroup[3])
208 		goto cleanup;
209 
210 	cgroup[4] = cg_name(cgroup[0], "E");
211 	if (!cgroup[4])
212 		goto cleanup;
213 
214 	cgroup[5] = cg_name(cgroup[4], "F");
215 	if (!cgroup[5])
216 		goto cleanup;
217 
218 	cgroup[6] = cg_name(cgroup[5], "G");
219 	if (!cgroup[6])
220 		goto cleanup;
221 
222 	cgroup[7] = cg_name(cgroup[6], "H");
223 	if (!cgroup[7])
224 		goto cleanup;
225 
226 	cgroup[8] = cg_name(cgroup[0], "I");
227 	if (!cgroup[8])
228 		goto cleanup;
229 
230 	cgroup[9] = cg_name(cgroup[0], "K");
231 	if (!cgroup[9])
232 		goto cleanup;
233 
234 	for (i = 0; i < 10; i++)
235 		if (cg_create(cgroup[i]))
236 			goto cleanup;
237 
238 	cg_run_nowait(cgroup[2], child_fn, NULL);
239 	cg_run_nowait(cgroup[7], child_fn, NULL);
240 	cg_run_nowait(cgroup[9], child_fn, NULL);
241 	cg_run_nowait(cgroup[9], child_fn, NULL);
242 	cg_run_nowait(cgroup[9], child_fn, NULL);
243 
244 	/*
245 	 * Wait until all child processes will enter
246 	 * corresponding cgroups.
247 	 */
248 
249 	if (cg_wait_for_proc_count(cgroup[2], 1) ||
250 	    cg_wait_for_proc_count(cgroup[7], 1) ||
251 	    cg_wait_for_proc_count(cgroup[9], 3))
252 		goto cleanup;
253 
254 	/*
255 	 * Freeze B.
256 	 */
257 	if (cg_freeze_wait(cgroup[1], true))
258 		goto cleanup;
259 
260 	/*
261 	 * Freeze F.
262 	 */
263 	if (cg_freeze_wait(cgroup[5], true))
264 		goto cleanup;
265 
266 	/*
267 	 * Freeze G.
268 	 */
269 	if (cg_freeze_wait(cgroup[6], true))
270 		goto cleanup;
271 
272 	/*
273 	 * Check that A and E are not frozen.
274 	 */
275 	if (cg_check_frozen(cgroup[0], false))
276 		goto cleanup;
277 
278 	if (cg_check_frozen(cgroup[4], false))
279 		goto cleanup;
280 
281 	/*
282 	 * Freeze A. Check that A, B and E are frozen.
283 	 */
284 	if (cg_freeze_wait(cgroup[0], true))
285 		goto cleanup;
286 
287 	if (cg_check_frozen(cgroup[1], true))
288 		goto cleanup;
289 
290 	if (cg_check_frozen(cgroup[4], true))
291 		goto cleanup;
292 
293 	/*
294 	 * Unfreeze B, F and G
295 	 */
296 	if (cg_freeze_nowait(cgroup[1], false))
297 		goto cleanup;
298 
299 	if (cg_freeze_nowait(cgroup[5], false))
300 		goto cleanup;
301 
302 	if (cg_freeze_nowait(cgroup[6], false))
303 		goto cleanup;
304 
305 	/*
306 	 * Check that C and H are still frozen.
307 	 */
308 	if (cg_check_frozen(cgroup[2], true))
309 		goto cleanup;
310 
311 	if (cg_check_frozen(cgroup[7], true))
312 		goto cleanup;
313 
314 	/*
315 	 * Unfreeze A. Check that A, C and K are not frozen.
316 	 */
317 	if (cg_freeze_wait(cgroup[0], false))
318 		goto cleanup;
319 
320 	if (cg_check_frozen(cgroup[2], false))
321 		goto cleanup;
322 
323 	if (cg_check_frozen(cgroup[9], false))
324 		goto cleanup;
325 
326 	ret = KSFT_PASS;
327 
328 cleanup:
329 	for (i = 9; i >= 0 && cgroup[i]; i--) {
330 		cg_destroy(cgroup[i]);
331 		free(cgroup[i]);
332 	}
333 
334 	return ret;
335 }
336 
337 /*
338  * A fork bomb emulator.
339  */
forkbomb_fn(const char * cgroup,void * arg)340 static int forkbomb_fn(const char *cgroup, void *arg)
341 {
342 	int ppid;
343 
344 	fork();
345 	fork();
346 
347 	ppid = getppid();
348 
349 	while (getppid() == ppid)
350 		usleep(1000);
351 
352 	return getppid() == ppid;
353 }
354 
355 /*
356  * The test runs a fork bomb in a cgroup and tries to freeze it.
357  * Then it kills all processes and checks that cgroup isn't populated
358  * anymore.
359  */
test_cgfreezer_forkbomb(const char * root)360 static int test_cgfreezer_forkbomb(const char *root)
361 {
362 	int ret = KSFT_FAIL;
363 	char *cgroup = NULL;
364 
365 	cgroup = cg_name(root, "cg_forkbomb_test");
366 	if (!cgroup)
367 		goto cleanup;
368 
369 	if (cg_create(cgroup))
370 		goto cleanup;
371 
372 	cg_run_nowait(cgroup, forkbomb_fn, NULL);
373 
374 	usleep(100000);
375 
376 	if (cg_freeze_wait(cgroup, true))
377 		goto cleanup;
378 
379 	if (cg_killall(cgroup))
380 		goto cleanup;
381 
382 	if (cg_wait_for_proc_count(cgroup, 0))
383 		goto cleanup;
384 
385 	ret = KSFT_PASS;
386 
387 cleanup:
388 	if (cgroup)
389 		cg_destroy(cgroup);
390 	free(cgroup);
391 	return ret;
392 }
393 
394 /*
395  * The test creates a cgroups and freezes it. Then it creates a child cgroup
396  * and populates it with a task. After that it checks that the child cgroup
397  * is frozen and the parent cgroup remains frozen too.
398  */
test_cgfreezer_mkdir(const char * root)399 static int test_cgfreezer_mkdir(const char *root)
400 {
401 	int ret = KSFT_FAIL;
402 	char *parent, *child = NULL;
403 	int pid;
404 
405 	parent = cg_name(root, "cg_test_mkdir_A");
406 	if (!parent)
407 		goto cleanup;
408 
409 	child = cg_name(parent, "cg_test_mkdir_B");
410 	if (!child)
411 		goto cleanup;
412 
413 	if (cg_create(parent))
414 		goto cleanup;
415 
416 	if (cg_freeze_wait(parent, true))
417 		goto cleanup;
418 
419 	if (cg_create(child))
420 		goto cleanup;
421 
422 	pid = cg_run_nowait(child, child_fn, NULL);
423 	if (pid < 0)
424 		goto cleanup;
425 
426 	if (cg_wait_for_proc_count(child, 1))
427 		goto cleanup;
428 
429 	if (cg_check_frozen(child, true))
430 		goto cleanup;
431 
432 	if (cg_check_frozen(parent, true))
433 		goto cleanup;
434 
435 	ret = KSFT_PASS;
436 
437 cleanup:
438 	if (child)
439 		cg_destroy(child);
440 	free(child);
441 	if (parent)
442 		cg_destroy(parent);
443 	free(parent);
444 	return ret;
445 }
446 
447 /*
448  * The test creates two nested cgroups, freezes the parent
449  * and removes the child. Then it checks that the parent cgroup
450  * remains frozen and it's possible to create a new child
451  * without unfreezing. The new child is frozen too.
452  */
test_cgfreezer_rmdir(const char * root)453 static int test_cgfreezer_rmdir(const char *root)
454 {
455 	int ret = KSFT_FAIL;
456 	char *parent, *child = NULL;
457 
458 	parent = cg_name(root, "cg_test_rmdir_A");
459 	if (!parent)
460 		goto cleanup;
461 
462 	child = cg_name(parent, "cg_test_rmdir_B");
463 	if (!child)
464 		goto cleanup;
465 
466 	if (cg_create(parent))
467 		goto cleanup;
468 
469 	if (cg_create(child))
470 		goto cleanup;
471 
472 	if (cg_freeze_wait(parent, true))
473 		goto cleanup;
474 
475 	if (cg_destroy(child))
476 		goto cleanup;
477 
478 	if (cg_check_frozen(parent, true))
479 		goto cleanup;
480 
481 	if (cg_create(child))
482 		goto cleanup;
483 
484 	if (cg_check_frozen(child, true))
485 		goto cleanup;
486 
487 	ret = KSFT_PASS;
488 
489 cleanup:
490 	if (child)
491 		cg_destroy(child);
492 	free(child);
493 	if (parent)
494 		cg_destroy(parent);
495 	free(parent);
496 	return ret;
497 }
498 
499 /*
500  * The test creates two cgroups: A and B, runs a process in A
501  * and performs several migrations:
502  * 1) A (running) -> B (frozen)
503  * 2) B (frozen) -> A (running)
504  * 3) A (frozen) -> B (frozen)
505  *
506  * On each step it checks the actual state of both cgroups.
507  */
test_cgfreezer_migrate(const char * root)508 static int test_cgfreezer_migrate(const char *root)
509 {
510 	int ret = KSFT_FAIL;
511 	char *cgroup[2] = {0};
512 	int pid;
513 
514 	cgroup[0] = cg_name(root, "cg_test_migrate_A");
515 	if (!cgroup[0])
516 		goto cleanup;
517 
518 	cgroup[1] = cg_name(root, "cg_test_migrate_B");
519 	if (!cgroup[1])
520 		goto cleanup;
521 
522 	if (cg_create(cgroup[0]))
523 		goto cleanup;
524 
525 	if (cg_create(cgroup[1]))
526 		goto cleanup;
527 
528 	pid = cg_run_nowait(cgroup[0], child_fn, NULL);
529 	if (pid < 0)
530 		goto cleanup;
531 
532 	if (cg_wait_for_proc_count(cgroup[0], 1))
533 		goto cleanup;
534 
535 	/*
536 	 * Migrate from A (running) to B (frozen)
537 	 */
538 	if (cg_freeze_wait(cgroup[1], true))
539 		goto cleanup;
540 
541 	if (cg_enter_and_wait_for_frozen(cgroup[1], pid, true))
542 		goto cleanup;
543 
544 	if (cg_check_frozen(cgroup[0], false))
545 		goto cleanup;
546 
547 	/*
548 	 * Migrate from B (frozen) to A (running)
549 	 */
550 	if (cg_enter_and_wait_for_frozen(cgroup[0], pid, false))
551 		goto cleanup;
552 
553 	if (cg_check_frozen(cgroup[1], true))
554 		goto cleanup;
555 
556 	/*
557 	 * Migrate from A (frozen) to B (frozen)
558 	 */
559 	if (cg_freeze_wait(cgroup[0], true))
560 		goto cleanup;
561 
562 	if (cg_enter_and_wait_for_frozen(cgroup[1], pid, true))
563 		goto cleanup;
564 
565 	if (cg_check_frozen(cgroup[0], true))
566 		goto cleanup;
567 
568 	ret = KSFT_PASS;
569 
570 cleanup:
571 	if (cgroup[0])
572 		cg_destroy(cgroup[0]);
573 	free(cgroup[0]);
574 	if (cgroup[1])
575 		cg_destroy(cgroup[1]);
576 	free(cgroup[1]);
577 	return ret;
578 }
579 
580 /*
581  * The test checks that ptrace works with a tracing process in a frozen cgroup.
582  */
test_cgfreezer_ptrace(const char * root)583 static int test_cgfreezer_ptrace(const char *root)
584 {
585 	int ret = KSFT_FAIL;
586 	char *cgroup = NULL;
587 	siginfo_t siginfo;
588 	int pid;
589 
590 	cgroup = cg_name(root, "cg_test_ptrace");
591 	if (!cgroup)
592 		goto cleanup;
593 
594 	if (cg_create(cgroup))
595 		goto cleanup;
596 
597 	pid = cg_run_nowait(cgroup, child_fn, NULL);
598 	if (pid < 0)
599 		goto cleanup;
600 
601 	if (cg_wait_for_proc_count(cgroup, 1))
602 		goto cleanup;
603 
604 	if (cg_freeze_wait(cgroup, true))
605 		goto cleanup;
606 
607 	if (ptrace(PTRACE_SEIZE, pid, NULL, NULL))
608 		goto cleanup;
609 
610 	if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL))
611 		goto cleanup;
612 
613 	waitpid(pid, NULL, 0);
614 
615 	/*
616 	 * Cgroup has to remain frozen, however the test task
617 	 * is in traced state.
618 	 */
619 	if (cg_check_frozen(cgroup, true))
620 		goto cleanup;
621 
622 	if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo))
623 		goto cleanup;
624 
625 	if (ptrace(PTRACE_DETACH, pid, NULL, NULL))
626 		goto cleanup;
627 
628 	if (cg_check_frozen(cgroup, true))
629 		goto cleanup;
630 
631 	ret = KSFT_PASS;
632 
633 cleanup:
634 	if (cgroup)
635 		cg_destroy(cgroup);
636 	free(cgroup);
637 	return ret;
638 }
639 
640 /*
641  * Check if the process is stopped.
642  */
proc_check_stopped(int pid)643 static int proc_check_stopped(int pid)
644 {
645 	char buf[PAGE_SIZE];
646 	int len;
647 
648 	len = proc_read_text(pid, 0, "stat", buf, sizeof(buf));
649 	if (len == -1) {
650 		debug("Can't get %d stat\n", pid);
651 		return -1;
652 	}
653 
654 	if (strstr(buf, "(test_freezer) T ") == NULL) {
655 		debug("Process %d in the unexpected state: %s\n", pid, buf);
656 		return -1;
657 	}
658 
659 	return 0;
660 }
661 
662 /*
663  * Test that it's possible to freeze a cgroup with a stopped process.
664  */
test_cgfreezer_stopped(const char * root)665 static int test_cgfreezer_stopped(const char *root)
666 {
667 	int pid, ret = KSFT_FAIL;
668 	char *cgroup = NULL;
669 
670 	cgroup = cg_name(root, "cg_test_stopped");
671 	if (!cgroup)
672 		goto cleanup;
673 
674 	if (cg_create(cgroup))
675 		goto cleanup;
676 
677 	pid = cg_run_nowait(cgroup, child_fn, NULL);
678 
679 	if (cg_wait_for_proc_count(cgroup, 1))
680 		goto cleanup;
681 
682 	if (kill(pid, SIGSTOP))
683 		goto cleanup;
684 
685 	if (cg_check_frozen(cgroup, false))
686 		goto cleanup;
687 
688 	if (cg_freeze_wait(cgroup, true))
689 		goto cleanup;
690 
691 	if (cg_freeze_wait(cgroup, false))
692 		goto cleanup;
693 
694 	if (proc_check_stopped(pid))
695 		goto cleanup;
696 
697 	ret = KSFT_PASS;
698 
699 cleanup:
700 	if (cgroup)
701 		cg_destroy(cgroup);
702 	free(cgroup);
703 	return ret;
704 }
705 
706 /*
707  * Test that it's possible to freeze a cgroup with a ptraced process.
708  */
test_cgfreezer_ptraced(const char * root)709 static int test_cgfreezer_ptraced(const char *root)
710 {
711 	int pid, ret = KSFT_FAIL;
712 	char *cgroup = NULL;
713 	siginfo_t siginfo;
714 
715 	cgroup = cg_name(root, "cg_test_ptraced");
716 	if (!cgroup)
717 		goto cleanup;
718 
719 	if (cg_create(cgroup))
720 		goto cleanup;
721 
722 	pid = cg_run_nowait(cgroup, child_fn, NULL);
723 
724 	if (cg_wait_for_proc_count(cgroup, 1))
725 		goto cleanup;
726 
727 	if (ptrace(PTRACE_SEIZE, pid, NULL, NULL))
728 		goto cleanup;
729 
730 	if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL))
731 		goto cleanup;
732 
733 	waitpid(pid, NULL, 0);
734 
735 	if (cg_check_frozen(cgroup, false))
736 		goto cleanup;
737 
738 	if (cg_freeze_wait(cgroup, true))
739 		goto cleanup;
740 
741 	/*
742 	 * cg_check_frozen(cgroup, true) will fail here,
743 	 * because the task is in the TRACEd state.
744 	 */
745 	if (cg_freeze_wait(cgroup, false))
746 		goto cleanup;
747 
748 	if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo))
749 		goto cleanup;
750 
751 	if (ptrace(PTRACE_DETACH, pid, NULL, NULL))
752 		goto cleanup;
753 
754 	ret = KSFT_PASS;
755 
756 cleanup:
757 	if (cgroup)
758 		cg_destroy(cgroup);
759 	free(cgroup);
760 	return ret;
761 }
762 
vfork_fn(const char * cgroup,void * arg)763 static int vfork_fn(const char *cgroup, void *arg)
764 {
765 	int pid = vfork();
766 
767 	if (pid == 0)
768 		while (true)
769 			sleep(1);
770 
771 	return pid;
772 }
773 
774 /*
775  * Test that it's possible to freeze a cgroup with a process,
776  * which called vfork() and is waiting for a child.
777  */
test_cgfreezer_vfork(const char * root)778 static int test_cgfreezer_vfork(const char *root)
779 {
780 	int ret = KSFT_FAIL;
781 	char *cgroup = NULL;
782 
783 	cgroup = cg_name(root, "cg_test_vfork");
784 	if (!cgroup)
785 		goto cleanup;
786 
787 	if (cg_create(cgroup))
788 		goto cleanup;
789 
790 	cg_run_nowait(cgroup, vfork_fn, NULL);
791 
792 	if (cg_wait_for_proc_count(cgroup, 2))
793 		goto cleanup;
794 
795 	if (cg_freeze_wait(cgroup, true))
796 		goto cleanup;
797 
798 	ret = KSFT_PASS;
799 
800 cleanup:
801 	if (cgroup)
802 		cg_destroy(cgroup);
803 	free(cgroup);
804 	return ret;
805 }
806 
807 /*
808  * Get the current frozen_usec for the cgroup.
809  */
cg_check_freezetime(const char * cgroup)810 static long cg_check_freezetime(const char *cgroup)
811 {
812 	return cg_read_key_long(cgroup, "cgroup.stat.local",
813 				"frozen_usec ");
814 }
815 
816 /*
817  * Test that the freeze time will behave as expected for an empty cgroup.
818  */
test_cgfreezer_time_empty(const char * root)819 static int test_cgfreezer_time_empty(const char *root)
820 {
821 	int ret = KSFT_FAIL;
822 	char *cgroup = NULL;
823 	long prev, curr;
824 
825 	cgroup = cg_name(root, "cg_time_test_empty");
826 	if (!cgroup)
827 		goto cleanup;
828 
829 	/*
830 	 * 1) Create an empty cgroup and check that its freeze time
831 	 *    is 0.
832 	 */
833 	if (cg_create(cgroup))
834 		goto cleanup;
835 
836 	curr = cg_check_freezetime(cgroup);
837 	if (curr < 0) {
838 		ret = KSFT_SKIP;
839 		goto cleanup;
840 	}
841 	if (curr > 0) {
842 		debug("Expect time (%ld) to be 0\n", curr);
843 		goto cleanup;
844 	}
845 
846 	if (cg_freeze_nowait(cgroup, true))
847 		goto cleanup;
848 
849 	/*
850 	 * 2) Sleep for 1000 us. Check that the freeze time is at
851 	 *    least 1000 us.
852 	 */
853 	usleep(1000);
854 	curr = cg_check_freezetime(cgroup);
855 	if (curr < 1000) {
856 		debug("Expect time (%ld) to be at least 1000 us\n",
857 		      curr);
858 		goto cleanup;
859 	}
860 
861 	/*
862 	 * 3) Unfreeze the cgroup. Check that the freeze time is
863 	 *    larger than at 2).
864 	 */
865 	if (cg_freeze_nowait(cgroup, false))
866 		goto cleanup;
867 	prev = curr;
868 	curr = cg_check_freezetime(cgroup);
869 	if (curr <= prev) {
870 		debug("Expect time (%ld) to be more than previous check (%ld)\n",
871 		      curr, prev);
872 		goto cleanup;
873 	}
874 
875 	/*
876 	 * 4) Check the freeze time again to ensure that it has not
877 	 *    changed.
878 	 */
879 	prev = curr;
880 	curr = cg_check_freezetime(cgroup);
881 	if (curr != prev) {
882 		debug("Expect time (%ld) to be unchanged from previous check (%ld)\n",
883 		      curr, prev);
884 		goto cleanup;
885 	}
886 
887 	ret = KSFT_PASS;
888 
889 cleanup:
890 	if (cgroup)
891 		cg_destroy(cgroup);
892 	free(cgroup);
893 	return ret;
894 }
895 
896 /*
897  * A simple test for cgroup freezer time accounting. This test follows
898  * the same flow as test_cgfreezer_time_empty, but with a single process
899  * in the cgroup.
900  */
test_cgfreezer_time_simple(const char * root)901 static int test_cgfreezer_time_simple(const char *root)
902 {
903 	int ret = KSFT_FAIL;
904 	char *cgroup = NULL;
905 	long prev, curr;
906 
907 	cgroup = cg_name(root, "cg_time_test_simple");
908 	if (!cgroup)
909 		goto cleanup;
910 
911 	/*
912 	 * 1) Create a cgroup and check that its freeze time is 0.
913 	 */
914 	if (cg_create(cgroup))
915 		goto cleanup;
916 
917 	curr = cg_check_freezetime(cgroup);
918 	if (curr < 0) {
919 		ret = KSFT_SKIP;
920 		goto cleanup;
921 	}
922 	if (curr > 0) {
923 		debug("Expect time (%ld) to be 0\n", curr);
924 		goto cleanup;
925 	}
926 
927 	/*
928 	 * 2) Populate the cgroup with one child and check that the
929 	 *    freeze time is still 0.
930 	 */
931 	cg_run_nowait(cgroup, child_fn, NULL);
932 	prev = curr;
933 	curr = cg_check_freezetime(cgroup);
934 	if (curr > prev) {
935 		debug("Expect time (%ld) to be 0\n", curr);
936 		goto cleanup;
937 	}
938 
939 	if (cg_freeze_nowait(cgroup, true))
940 		goto cleanup;
941 
942 	/*
943 	 * 3) Sleep for 1000 us. Check that the freeze time is at
944 	 *    least 1000 us.
945 	 */
946 	usleep(1000);
947 	prev = curr;
948 	curr = cg_check_freezetime(cgroup);
949 	if (curr < 1000) {
950 		debug("Expect time (%ld) to be at least 1000 us\n",
951 		      curr);
952 		goto cleanup;
953 	}
954 
955 	/*
956 	 * 4) Unfreeze the cgroup. Check that the freeze time is
957 	 *    larger than at 3).
958 	 */
959 	if (cg_freeze_nowait(cgroup, false))
960 		goto cleanup;
961 	prev = curr;
962 	curr = cg_check_freezetime(cgroup);
963 	if (curr <= prev) {
964 		debug("Expect time (%ld) to be more than previous check (%ld)\n",
965 		      curr, prev);
966 		goto cleanup;
967 	}
968 
969 	/*
970 	 * 5) Sleep for 1000 us. Check that the freeze time is the
971 	 *    same as at 4).
972 	 */
973 	usleep(1000);
974 	prev = curr;
975 	curr = cg_check_freezetime(cgroup);
976 	if (curr != prev) {
977 		debug("Expect time (%ld) to be unchanged from previous check (%ld)\n",
978 		      curr, prev);
979 		goto cleanup;
980 	}
981 
982 	ret = KSFT_PASS;
983 
984 cleanup:
985 	if (cgroup)
986 		cg_destroy(cgroup);
987 	free(cgroup);
988 	return ret;
989 }
990 
991 /*
992  * Test that freezer time accounting works as expected, even while we're
993  * populating a cgroup with processes.
994  */
test_cgfreezer_time_populate(const char * root)995 static int test_cgfreezer_time_populate(const char *root)
996 {
997 	int ret = KSFT_FAIL;
998 	char *cgroup = NULL;
999 	long prev, curr;
1000 	int i;
1001 
1002 	cgroup = cg_name(root, "cg_time_test_populate");
1003 	if (!cgroup)
1004 		goto cleanup;
1005 
1006 	if (cg_create(cgroup))
1007 		goto cleanup;
1008 
1009 	curr = cg_check_freezetime(cgroup);
1010 	if (curr < 0) {
1011 		ret = KSFT_SKIP;
1012 		goto cleanup;
1013 	}
1014 	if (curr > 0) {
1015 		debug("Expect time (%ld) to be 0\n", curr);
1016 		goto cleanup;
1017 	}
1018 
1019 	/*
1020 	 * 1) Populate the cgroup with 100 processes. Check that
1021 	 *    the freeze time is 0.
1022 	 */
1023 	for (i = 0; i < 100; i++)
1024 		cg_run_nowait(cgroup, child_fn, NULL);
1025 	prev = curr;
1026 	curr = cg_check_freezetime(cgroup);
1027 	if (curr != prev) {
1028 		debug("Expect time (%ld) to be 0\n", curr);
1029 		goto cleanup;
1030 	}
1031 
1032 	/*
1033 	 * 2) Wait for the group to become fully populated. Check
1034 	 *    that the freeze time is 0.
1035 	 */
1036 	if (cg_wait_for_proc_count(cgroup, 100))
1037 		goto cleanup;
1038 	prev = curr;
1039 	curr = cg_check_freezetime(cgroup);
1040 	if (curr != prev) {
1041 		debug("Expect time (%ld) to be 0\n", curr);
1042 		goto cleanup;
1043 	}
1044 
1045 	/*
1046 	 * 3) Freeze the cgroup and then populate it with 100 more
1047 	 *    processes. Check that the freeze time continues to grow.
1048 	 */
1049 	if (cg_freeze_nowait(cgroup, true))
1050 		goto cleanup;
1051 	prev = curr;
1052 	curr = cg_check_freezetime(cgroup);
1053 	if (curr <= prev) {
1054 		debug("Expect time (%ld) to be more than previous check (%ld)\n",
1055 		      curr, prev);
1056 		goto cleanup;
1057 	}
1058 
1059 	for (i = 0; i < 100; i++)
1060 		cg_run_nowait(cgroup, child_fn, NULL);
1061 	prev = curr;
1062 	curr = cg_check_freezetime(cgroup);
1063 	if (curr <= prev) {
1064 		debug("Expect time (%ld) to be more than previous check (%ld)\n",
1065 		      curr, prev);
1066 		goto cleanup;
1067 	}
1068 
1069 	/*
1070 	 * 4) Wait for the group to become fully populated. Check
1071 	 *    that the freeze time is larger than at 3).
1072 	 */
1073 	if (cg_wait_for_proc_count(cgroup, 200))
1074 		goto cleanup;
1075 	prev = curr;
1076 	curr = cg_check_freezetime(cgroup);
1077 	if (curr <= prev) {
1078 		debug("Expect time (%ld) to be more than previous check (%ld)\n",
1079 		      curr, prev);
1080 		goto cleanup;
1081 	}
1082 
1083 	/*
1084 	 * 5) Unfreeze the cgroup. Check that the freeze time is
1085 	 *    larger than at 4).
1086 	 */
1087 	if (cg_freeze_nowait(cgroup, false))
1088 		goto cleanup;
1089 	prev = curr;
1090 	curr = cg_check_freezetime(cgroup);
1091 	if (curr <= prev) {
1092 		debug("Expect time (%ld) to be more than previous check (%ld)\n",
1093 		      curr, prev);
1094 		goto cleanup;
1095 	}
1096 
1097 	/*
1098 	 * 6) Kill the processes. Check that the freeze time is the
1099 	 *    same as it was at 5).
1100 	 */
1101 	if (cg_killall(cgroup))
1102 		goto cleanup;
1103 	prev = curr;
1104 	curr = cg_check_freezetime(cgroup);
1105 	if (curr != prev) {
1106 		debug("Expect time (%ld) to be unchanged from previous check (%ld)\n",
1107 		      curr, prev);
1108 		goto cleanup;
1109 	}
1110 
1111 	/*
1112 	 * 7) Freeze and unfreeze the cgroup. Check that the freeze
1113 	 *    time is larger than it was at 6).
1114 	 */
1115 	if (cg_freeze_nowait(cgroup, true))
1116 		goto cleanup;
1117 	if (cg_freeze_nowait(cgroup, false))
1118 		goto cleanup;
1119 	prev = curr;
1120 	curr = cg_check_freezetime(cgroup);
1121 	if (curr <= prev) {
1122 		debug("Expect time (%ld) to be more than previous check (%ld)\n",
1123 		      curr, prev);
1124 		goto cleanup;
1125 	}
1126 
1127 	ret = KSFT_PASS;
1128 
1129 cleanup:
1130 	if (cgroup)
1131 		cg_destroy(cgroup);
1132 	free(cgroup);
1133 	return ret;
1134 }
1135 
1136 /*
1137  * Test that frozen time for a cgroup continues to work as expected,
1138  * even as processes are migrated. Frozen cgroup A's freeze time should
1139  * continue to increase and running cgroup B's should stay 0.
1140  */
test_cgfreezer_time_migrate(const char * root)1141 static int test_cgfreezer_time_migrate(const char *root)
1142 {
1143 	long prev_A, curr_A, curr_B;
1144 	char *cgroup[2] = {0};
1145 	int ret = KSFT_FAIL;
1146 	int pid;
1147 
1148 	cgroup[0] = cg_name(root, "cg_time_test_migrate_A");
1149 	if (!cgroup[0])
1150 		goto cleanup;
1151 
1152 	cgroup[1] = cg_name(root, "cg_time_test_migrate_B");
1153 	if (!cgroup[1])
1154 		goto cleanup;
1155 
1156 	if (cg_create(cgroup[0]))
1157 		goto cleanup;
1158 
1159 	if (cg_check_freezetime(cgroup[0]) < 0) {
1160 		ret = KSFT_SKIP;
1161 		goto cleanup;
1162 	}
1163 
1164 	if (cg_create(cgroup[1]))
1165 		goto cleanup;
1166 
1167 	pid = cg_run_nowait(cgroup[0], child_fn, NULL);
1168 	if (pid < 0)
1169 		goto cleanup;
1170 
1171 	if (cg_wait_for_proc_count(cgroup[0], 1))
1172 		goto cleanup;
1173 
1174 	curr_A = cg_check_freezetime(cgroup[0]);
1175 	if (curr_A) {
1176 		debug("Expect time (%ld) to be 0\n", curr_A);
1177 		goto cleanup;
1178 	}
1179 	curr_B = cg_check_freezetime(cgroup[1]);
1180 	if (curr_B) {
1181 		debug("Expect time (%ld) to be 0\n", curr_B);
1182 		goto cleanup;
1183 	}
1184 
1185 	/*
1186 	 * Freeze cgroup A.
1187 	 */
1188 	if (cg_freeze_wait(cgroup[0], true))
1189 		goto cleanup;
1190 	prev_A = curr_A;
1191 	curr_A = cg_check_freezetime(cgroup[0]);
1192 	if (curr_A <= prev_A) {
1193 		debug("Expect time (%ld) to be > 0\n", curr_A);
1194 		goto cleanup;
1195 	}
1196 
1197 	/*
1198 	 * Migrate from A (frozen) to B (running).
1199 	 */
1200 	if (cg_enter(cgroup[1], pid))
1201 		goto cleanup;
1202 
1203 	usleep(1000);
1204 	curr_B = cg_check_freezetime(cgroup[1]);
1205 	if (curr_B) {
1206 		debug("Expect time (%ld) to be 0\n", curr_B);
1207 		goto cleanup;
1208 	}
1209 
1210 	prev_A = curr_A;
1211 	curr_A = cg_check_freezetime(cgroup[0]);
1212 	if (curr_A <= prev_A) {
1213 		debug("Expect time (%ld) to be more than previous check (%ld)\n",
1214 		      curr_A, prev_A);
1215 		goto cleanup;
1216 	}
1217 
1218 	ret = KSFT_PASS;
1219 
1220 cleanup:
1221 	if (cgroup[0])
1222 		cg_destroy(cgroup[0]);
1223 	free(cgroup[0]);
1224 	if (cgroup[1])
1225 		cg_destroy(cgroup[1]);
1226 	free(cgroup[1]);
1227 	return ret;
1228 }
1229 
1230 /*
1231  * The test creates a cgroup and freezes it. Then it creates a child cgroup.
1232  * After that it checks that the child cgroup has a non-zero freeze time
1233  * that is less than the parent's. Next, it freezes the child, unfreezes
1234  * the parent, and sleeps. Finally, it checks that the child's freeze
1235  * time has grown larger than the parent's.
1236  */
test_cgfreezer_time_parent(const char * root)1237 static int test_cgfreezer_time_parent(const char *root)
1238 {
1239 	char *parent, *child = NULL;
1240 	int ret = KSFT_FAIL;
1241 	long ptime, ctime;
1242 
1243 	parent = cg_name(root, "cg_test_parent_A");
1244 	if (!parent)
1245 		goto cleanup;
1246 
1247 	child = cg_name(parent, "cg_test_parent_B");
1248 	if (!child)
1249 		goto cleanup;
1250 
1251 	if (cg_create(parent))
1252 		goto cleanup;
1253 
1254 	if (cg_check_freezetime(parent) < 0) {
1255 		ret = KSFT_SKIP;
1256 		goto cleanup;
1257 	}
1258 
1259 	if (cg_freeze_wait(parent, true))
1260 		goto cleanup;
1261 
1262 	usleep(1000);
1263 	if (cg_create(child))
1264 		goto cleanup;
1265 
1266 	if (cg_check_frozen(child, true))
1267 		goto cleanup;
1268 
1269 	/*
1270 	 * Since the parent was frozen the entire time the child cgroup
1271 	 * was being created, we expect the parent's freeze time to be
1272 	 * larger than the child's.
1273 	 *
1274 	 * Ideally, we would be able to check both times simultaneously,
1275 	 * but here we get the child's after we get the parent's.
1276 	 */
1277 	ptime = cg_check_freezetime(parent);
1278 	ctime = cg_check_freezetime(child);
1279 	if (ptime <= ctime) {
1280 		debug("Expect ptime (%ld) > ctime (%ld)\n", ptime, ctime);
1281 		goto cleanup;
1282 	}
1283 
1284 	if (cg_freeze_nowait(child, true))
1285 		goto cleanup;
1286 
1287 	if (cg_freeze_wait(parent, false))
1288 		goto cleanup;
1289 
1290 	if (cg_check_frozen(child, true))
1291 		goto cleanup;
1292 
1293 	usleep(100000);
1294 
1295 	ctime = cg_check_freezetime(child);
1296 	ptime = cg_check_freezetime(parent);
1297 
1298 	if (ctime <= ptime) {
1299 		debug("Expect ctime (%ld) > ptime (%ld)\n", ctime, ptime);
1300 		goto cleanup;
1301 	}
1302 
1303 	ret = KSFT_PASS;
1304 
1305 cleanup:
1306 	if (child)
1307 		cg_destroy(child);
1308 	free(child);
1309 	if (parent)
1310 		cg_destroy(parent);
1311 	free(parent);
1312 	return ret;
1313 }
1314 
1315 /*
1316  * The test creates a parent cgroup and a child cgroup. Then, it freezes
1317  * the child and checks that the child's freeze time is greater than the
1318  * parent's, which should be zero.
1319  */
test_cgfreezer_time_child(const char * root)1320 static int test_cgfreezer_time_child(const char *root)
1321 {
1322 	char *parent, *child = NULL;
1323 	int ret = KSFT_FAIL;
1324 	long ptime, ctime;
1325 
1326 	parent = cg_name(root, "cg_test_child_A");
1327 	if (!parent)
1328 		goto cleanup;
1329 
1330 	child = cg_name(parent, "cg_test_child_B");
1331 	if (!child)
1332 		goto cleanup;
1333 
1334 	if (cg_create(parent))
1335 		goto cleanup;
1336 
1337 	if (cg_check_freezetime(parent) < 0) {
1338 		ret = KSFT_SKIP;
1339 		goto cleanup;
1340 	}
1341 
1342 	if (cg_create(child))
1343 		goto cleanup;
1344 
1345 	if (cg_freeze_wait(child, true))
1346 		goto cleanup;
1347 
1348 	ctime = cg_check_freezetime(child);
1349 	ptime = cg_check_freezetime(parent);
1350 	if (ptime != 0) {
1351 		debug("Expect ptime (%ld) to be 0\n", ptime);
1352 		goto cleanup;
1353 	}
1354 
1355 	if (ctime <= ptime) {
1356 		debug("Expect ctime (%ld) <= ptime (%ld)\n", ctime, ptime);
1357 		goto cleanup;
1358 	}
1359 
1360 	ret = KSFT_PASS;
1361 
1362 cleanup:
1363 	if (child)
1364 		cg_destroy(child);
1365 	free(child);
1366 	if (parent)
1367 		cg_destroy(parent);
1368 	free(parent);
1369 	return ret;
1370 }
1371 
1372 /*
1373  * The test creates the following hierarchy:
1374  *    A
1375  *    |
1376  *    B
1377  *    |
1378  *    C
1379  *
1380  * Then it freezes the cgroups in the order C, B, A.
1381  * Then it unfreezes the cgroups in the order A, B, C.
1382  * Then it checks that C's freeze time is larger than B's and
1383  * that B's is larger than A's.
1384  */
test_cgfreezer_time_nested(const char * root)1385 static int test_cgfreezer_time_nested(const char *root)
1386 {
1387 	char *cgroup[3] = {0};
1388 	int ret = KSFT_FAIL;
1389 	long time[3] = {0};
1390 	int i;
1391 
1392 	cgroup[0] = cg_name(root, "cg_test_time_A");
1393 	if (!cgroup[0])
1394 		goto cleanup;
1395 
1396 	cgroup[1] = cg_name(cgroup[0], "B");
1397 	if (!cgroup[1])
1398 		goto cleanup;
1399 
1400 	cgroup[2] = cg_name(cgroup[1], "C");
1401 	if (!cgroup[2])
1402 		goto cleanup;
1403 
1404 	if (cg_create(cgroup[0]))
1405 		goto cleanup;
1406 
1407 	if (cg_check_freezetime(cgroup[0]) < 0) {
1408 		ret = KSFT_SKIP;
1409 		goto cleanup;
1410 	}
1411 
1412 	if (cg_create(cgroup[1]))
1413 		goto cleanup;
1414 
1415 	if (cg_create(cgroup[2]))
1416 		goto cleanup;
1417 
1418 	if (cg_freeze_nowait(cgroup[2], true))
1419 		goto cleanup;
1420 
1421 	if (cg_freeze_nowait(cgroup[1], true))
1422 		goto cleanup;
1423 
1424 	if (cg_freeze_nowait(cgroup[0], true))
1425 		goto cleanup;
1426 
1427 	usleep(1000);
1428 
1429 	if (cg_freeze_nowait(cgroup[0], false))
1430 		goto cleanup;
1431 
1432 	if (cg_freeze_nowait(cgroup[1], false))
1433 		goto cleanup;
1434 
1435 	if (cg_freeze_nowait(cgroup[2], false))
1436 		goto cleanup;
1437 
1438 	time[2] = cg_check_freezetime(cgroup[2]);
1439 	time[1] = cg_check_freezetime(cgroup[1]);
1440 	time[0] = cg_check_freezetime(cgroup[0]);
1441 
1442 	if (time[2] <= time[1]) {
1443 		debug("Expect C's time (%ld) > B's time (%ld)", time[2], time[1]);
1444 		goto cleanup;
1445 	}
1446 
1447 	if (time[1] <= time[0]) {
1448 		debug("Expect B's time (%ld) > A's time (%ld)", time[1], time[0]);
1449 		goto cleanup;
1450 	}
1451 
1452 	ret = KSFT_PASS;
1453 
1454 cleanup:
1455 	for (i = 2; i >= 0 && cgroup[i]; i--) {
1456 		cg_destroy(cgroup[i]);
1457 		free(cgroup[i]);
1458 	}
1459 
1460 	return ret;
1461 }
1462 
1463 #define T(x) { x, #x }
1464 struct cgfreezer_test {
1465 	int (*fn)(const char *root);
1466 	const char *name;
1467 } tests[] = {
1468 	T(test_cgfreezer_simple),
1469 	T(test_cgfreezer_tree),
1470 	T(test_cgfreezer_forkbomb),
1471 	T(test_cgfreezer_mkdir),
1472 	T(test_cgfreezer_rmdir),
1473 	T(test_cgfreezer_migrate),
1474 	T(test_cgfreezer_ptrace),
1475 	T(test_cgfreezer_stopped),
1476 	T(test_cgfreezer_ptraced),
1477 	T(test_cgfreezer_vfork),
1478 	T(test_cgfreezer_time_empty),
1479 	T(test_cgfreezer_time_simple),
1480 	T(test_cgfreezer_time_populate),
1481 	T(test_cgfreezer_time_migrate),
1482 	T(test_cgfreezer_time_parent),
1483 	T(test_cgfreezer_time_child),
1484 	T(test_cgfreezer_time_nested),
1485 };
1486 #undef T
1487 
main(int argc,char * argv[])1488 int main(int argc, char *argv[])
1489 {
1490 	char root[PATH_MAX];
1491 	int i, ret = EXIT_SUCCESS;
1492 
1493 	if (cg_find_unified_root(root, sizeof(root), NULL))
1494 		ksft_exit_skip("cgroup v2 isn't mounted\n");
1495 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
1496 		switch (tests[i].fn(root)) {
1497 		case KSFT_PASS:
1498 			ksft_test_result_pass("%s\n", tests[i].name);
1499 			break;
1500 		case KSFT_SKIP:
1501 			ksft_test_result_skip("%s\n", tests[i].name);
1502 			break;
1503 		default:
1504 			ret = EXIT_FAILURE;
1505 			ksft_test_result_fail("%s\n", tests[i].name);
1506 			break;
1507 		}
1508 	}
1509 
1510 	return ret;
1511 }
1512