Path: blob/master/tools/testing/selftests/cgroup/test_pids.c
29270 views
// SPDX-License-Identifier: GPL-2.01#define _GNU_SOURCE23#include <errno.h>4#include <linux/limits.h>5#include <signal.h>6#include <string.h>7#include <sys/stat.h>8#include <sys/types.h>9#include <unistd.h>1011#include "../kselftest.h"12#include "cgroup_util.h"1314static int run_success(const char *cgroup, void *arg)15{16return 0;17}1819static int run_pause(const char *cgroup, void *arg)20{21return pause();22}2324/*25* This test checks that pids.max prevents forking new children above the26* specified limit in the cgroup.27*/28static int test_pids_max(const char *root)29{30int ret = KSFT_FAIL;31char *cg_pids;32int pid;3334cg_pids = cg_name(root, "pids_test");35if (!cg_pids)36goto cleanup;3738if (cg_create(cg_pids))39goto cleanup;4041if (cg_read_strcmp(cg_pids, "pids.max", "max\n"))42goto cleanup;4344if (cg_write(cg_pids, "pids.max", "2"))45goto cleanup;4647if (cg_enter_current(cg_pids))48goto cleanup;4950pid = cg_run_nowait(cg_pids, run_pause, NULL);51if (pid < 0)52goto cleanup;5354if (cg_run_nowait(cg_pids, run_success, NULL) != -1 || errno != EAGAIN)55goto cleanup;5657if (kill(pid, SIGINT))58goto cleanup;5960ret = KSFT_PASS;6162cleanup:63cg_enter_current(root);64cg_destroy(cg_pids);65free(cg_pids);6667return ret;68}6970/*71* This test checks that pids.events are counted in cgroup associated with pids.max72*/73static int test_pids_events(const char *root)74{75int ret = KSFT_FAIL;76char *cg_parent = NULL, *cg_child = NULL;77int pid;7879if (cgroup_feature("pids_localevents") <= 0)80return KSFT_SKIP;8182cg_parent = cg_name(root, "pids_parent");83cg_child = cg_name(cg_parent, "pids_child");84if (!cg_parent || !cg_child)85goto cleanup;8687if (cg_create(cg_parent))88goto cleanup;89if (cg_write(cg_parent, "cgroup.subtree_control", "+pids"))90goto cleanup;91if (cg_create(cg_child))92goto cleanup;9394if (cg_write(cg_parent, "pids.max", "2"))95goto cleanup;9697if (cg_read_strcmp(cg_child, "pids.max", "max\n"))98goto cleanup;99100if (cg_enter_current(cg_child))101goto cleanup;102103pid = cg_run_nowait(cg_child, run_pause, NULL);104if (pid < 0)105goto cleanup;106107if (cg_run_nowait(cg_child, run_success, NULL) != -1 || errno != EAGAIN)108goto cleanup;109110if (kill(pid, SIGINT))111goto cleanup;112113if (cg_read_key_long(cg_child, "pids.events", "max ") != 0)114goto cleanup;115if (cg_read_key_long(cg_parent, "pids.events", "max ") != 1)116goto cleanup;117118119ret = KSFT_PASS;120121cleanup:122cg_enter_current(root);123if (cg_child)124cg_destroy(cg_child);125if (cg_parent)126cg_destroy(cg_parent);127free(cg_child);128free(cg_parent);129130return ret;131}132133134135#define T(x) { x, #x }136struct pids_test {137int (*fn)(const char *root);138const char *name;139} tests[] = {140T(test_pids_max),141T(test_pids_events),142};143#undef T144145int main(int argc, char **argv)146{147char root[PATH_MAX];148149ksft_print_header();150ksft_set_plan(ARRAY_SIZE(tests));151if (cg_find_unified_root(root, sizeof(root), NULL))152ksft_exit_skip("cgroup v2 isn't mounted\n");153154/*155* Check that pids controller is available:156* pids is listed in cgroup.controllers157*/158if (cg_read_strstr(root, "cgroup.controllers", "pids"))159ksft_exit_skip("pids controller isn't available\n");160161if (cg_read_strstr(root, "cgroup.subtree_control", "pids"))162if (cg_write(root, "cgroup.subtree_control", "+pids"))163ksft_exit_skip("Failed to set pids controller\n");164165for (int i = 0; i < ARRAY_SIZE(tests); i++) {166switch (tests[i].fn(root)) {167case KSFT_PASS:168ksft_test_result_pass("%s\n", tests[i].name);169break;170case KSFT_SKIP:171ksft_test_result_skip("%s\n", tests[i].name);172break;173default:174ksft_test_result_fail("%s\n", tests[i].name);175break;176}177}178179ksft_finished();180}181182183