File Index
Files and directories
Sign in
FILE

test_freezer.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/cgroup/test_freezer.c C
   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 */
  27static 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 */
  50static 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 */
  59static 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
  83out:
  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 */
  93static 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);
 112out:
 113	close(fd);
 114	return ret;
 115}
 116
 117/*
 118 * A simple process running in a sleep loop until being
 119 * re-parented.
 120 */
 121static 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 */
 136static 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
 166cleanup:
 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 */
 188static 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
 328cleanup:
 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 */
 340static 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 */
 360static 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
 387cleanup:
 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 */
 399static 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
 437cleanup:
 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 */
 453static 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
 489cleanup:
 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 */
 508static 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
 570cleanup:
 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 */
 583static 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
 633cleanup:
 634	if (cgroup)
 635		cg_destroy(cgroup);
 636	free(cgroup);
 637	return ret;
 638}
 639
 640/*
 641 * Check if the process is stopped.
 642 */
 643static 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 */
 665static 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
 699cleanup:
 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 */
 709static 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
 756cleanup:
 757	if (cgroup)
 758		cg_destroy(cgroup);
 759	free(cgroup);
 760	return ret;
 761}
 762
 763static 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 */
 778static 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
 800cleanup:
 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 */
 810static 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 */
 819static 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
 889cleanup:
 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 */
 901static 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
 984cleanup:
 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 */
 995static 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
1129cleanup:
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 */
1141static 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
1220cleanup:
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 */
1237static 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
1305cleanup:
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 */
1320static 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
1362cleanup:
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 */
1385static 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
1454cleanup:
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 }
1464struct 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
1488int main(int argc, char *argv[])
1489{
1490	char root[PATH_MAX];
1491	int i;
1492
1493	ksft_print_header();
1494	ksft_set_plan(ARRAY_SIZE(tests));
1495	if (cg_find_unified_root(root, sizeof(root), NULL))
1496		ksft_exit_skip("cgroup v2 isn't mounted\n");
1497	for (i = 0; i < ARRAY_SIZE(tests); i++) {
1498		switch (tests[i].fn(root)) {
1499		case KSFT_PASS:
1500			ksft_test_result_pass("%s\n", tests[i].name);
1501			break;
1502		case KSFT_SKIP:
1503			ksft_test_result_skip("%s\n", tests[i].name);
1504			break;
1505		default:
1506			ksft_test_result_fail("%s\n", tests[i].name);
1507			break;
1508		}
1509	}
1510
1511	ksft_finished();
1512}
~/ Read-only file preview.