179 lines · c
1// SPDX-License-Identifier: GPL-2.02#define _GNU_SOURCE3 4#include <errno.h>5#include <linux/limits.h>6#include <signal.h>7#include <string.h>8#include <sys/stat.h>9#include <sys/types.h>10#include <unistd.h>11 12#include "../kselftest.h"13#include "cgroup_util.h"14 15static int run_success(const char *cgroup, void *arg)16{17 return 0;18}19 20static int run_pause(const char *cgroup, void *arg)21{22 return pause();23}24 25/*26 * This test checks that pids.max prevents forking new children above the27 * specified limit in the cgroup.28 */29static int test_pids_max(const char *root)30{31 int ret = KSFT_FAIL;32 char *cg_pids;33 int pid;34 35 cg_pids = cg_name(root, "pids_test");36 if (!cg_pids)37 goto cleanup;38 39 if (cg_create(cg_pids))40 goto cleanup;41 42 if (cg_read_strcmp(cg_pids, "pids.max", "max\n"))43 goto cleanup;44 45 if (cg_write(cg_pids, "pids.max", "2"))46 goto cleanup;47 48 if (cg_enter_current(cg_pids))49 goto cleanup;50 51 pid = cg_run_nowait(cg_pids, run_pause, NULL);52 if (pid < 0)53 goto cleanup;54 55 if (cg_run_nowait(cg_pids, run_success, NULL) != -1 || errno != EAGAIN)56 goto cleanup;57 58 if (kill(pid, SIGINT))59 goto cleanup;60 61 ret = KSFT_PASS;62 63cleanup:64 cg_enter_current(root);65 cg_destroy(cg_pids);66 free(cg_pids);67 68 return ret;69}70 71/*72 * This test checks that pids.events are counted in cgroup associated with pids.max73 */74static int test_pids_events(const char *root)75{76 int ret = KSFT_FAIL;77 char *cg_parent = NULL, *cg_child = NULL;78 int pid;79 80 cg_parent = cg_name(root, "pids_parent");81 cg_child = cg_name(cg_parent, "pids_child");82 if (!cg_parent || !cg_child)83 goto cleanup;84 85 if (cg_create(cg_parent))86 goto cleanup;87 if (cg_write(cg_parent, "cgroup.subtree_control", "+pids"))88 goto cleanup;89 if (cg_create(cg_child))90 goto cleanup;91 92 if (cg_write(cg_parent, "pids.max", "2"))93 goto cleanup;94 95 if (cg_read_strcmp(cg_child, "pids.max", "max\n"))96 goto cleanup;97 98 if (cg_enter_current(cg_child))99 goto cleanup;100 101 pid = cg_run_nowait(cg_child, run_pause, NULL);102 if (pid < 0)103 goto cleanup;104 105 if (cg_run_nowait(cg_child, run_success, NULL) != -1 || errno != EAGAIN)106 goto cleanup;107 108 if (kill(pid, SIGINT))109 goto cleanup;110 111 if (cg_read_key_long(cg_child, "pids.events", "max ") != 0)112 goto cleanup;113 if (cg_read_key_long(cg_parent, "pids.events", "max ") != 1)114 goto cleanup;115 116 117 ret = KSFT_PASS;118 119cleanup:120 cg_enter_current(root);121 if (cg_child)122 cg_destroy(cg_child);123 if (cg_parent)124 cg_destroy(cg_parent);125 free(cg_child);126 free(cg_parent);127 128 return ret;129}130 131 132 133#define T(x) { x, #x }134struct pids_test {135 int (*fn)(const char *root);136 const char *name;137} tests[] = {138 T(test_pids_max),139 T(test_pids_events),140};141#undef T142 143int main(int argc, char **argv)144{145 char root[PATH_MAX];146 147 ksft_print_header();148 ksft_set_plan(ARRAY_SIZE(tests));149 if (cg_find_unified_root(root, sizeof(root), NULL))150 ksft_exit_skip("cgroup v2 isn't mounted\n");151 152 /*153 * Check that pids controller is available:154 * pids is listed in cgroup.controllers155 */156 if (cg_read_strstr(root, "cgroup.controllers", "pids"))157 ksft_exit_skip("pids controller isn't available\n");158 159 if (cg_read_strstr(root, "cgroup.subtree_control", "pids"))160 if (cg_write(root, "cgroup.subtree_control", "+pids"))161 ksft_exit_skip("Failed to set pids controller\n");162 163 for (int i = 0; i < ARRAY_SIZE(tests); i++) {164 switch (tests[i].fn(root)) {165 case KSFT_PASS:166 ksft_test_result_pass("%s\n", tests[i].name);167 break;168 case KSFT_SKIP:169 ksft_test_result_skip("%s\n", tests[i].name);170 break;171 default:172 ksft_test_result_fail("%s\n", tests[i].name);173 break;174 }175 }176 177 ksft_finished();178}179