mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-09 05:18:08 -04:00
The predicates in test expect event counting from73e75e6fc3("cgroup/pids: Separate semantics of pids.events related to pids.max") and the test would fail on older kernels. We want to have one version of tests for all, so detect the feature and skip the test on old kernels. (The test could even switch to check v1 semantics based on the flag but keep it simple for now.) Fixes:9f34c56602("selftests: cgroup: Add basic tests for pids controller") Signed-off-by: Michal Koutný <mkoutny@suse.com> Tested-by: Sebastian Chlad <sebastian.chlad@suse.com> Signed-off-by: Tejun Heo <tj@kernel.org>
182 lines
3.5 KiB
C
182 lines
3.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#define _GNU_SOURCE
|
|
|
|
#include <errno.h>
|
|
#include <linux/limits.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include "../kselftest.h"
|
|
#include "cgroup_util.h"
|
|
|
|
static int run_success(const char *cgroup, void *arg)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int run_pause(const char *cgroup, void *arg)
|
|
{
|
|
return pause();
|
|
}
|
|
|
|
/*
|
|
* This test checks that pids.max prevents forking new children above the
|
|
* specified limit in the cgroup.
|
|
*/
|
|
static int test_pids_max(const char *root)
|
|
{
|
|
int ret = KSFT_FAIL;
|
|
char *cg_pids;
|
|
int pid;
|
|
|
|
cg_pids = cg_name(root, "pids_test");
|
|
if (!cg_pids)
|
|
goto cleanup;
|
|
|
|
if (cg_create(cg_pids))
|
|
goto cleanup;
|
|
|
|
if (cg_read_strcmp(cg_pids, "pids.max", "max\n"))
|
|
goto cleanup;
|
|
|
|
if (cg_write(cg_pids, "pids.max", "2"))
|
|
goto cleanup;
|
|
|
|
if (cg_enter_current(cg_pids))
|
|
goto cleanup;
|
|
|
|
pid = cg_run_nowait(cg_pids, run_pause, NULL);
|
|
if (pid < 0)
|
|
goto cleanup;
|
|
|
|
if (cg_run_nowait(cg_pids, run_success, NULL) != -1 || errno != EAGAIN)
|
|
goto cleanup;
|
|
|
|
if (kill(pid, SIGINT))
|
|
goto cleanup;
|
|
|
|
ret = KSFT_PASS;
|
|
|
|
cleanup:
|
|
cg_enter_current(root);
|
|
cg_destroy(cg_pids);
|
|
free(cg_pids);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* This test checks that pids.events are counted in cgroup associated with pids.max
|
|
*/
|
|
static int test_pids_events(const char *root)
|
|
{
|
|
int ret = KSFT_FAIL;
|
|
char *cg_parent = NULL, *cg_child = NULL;
|
|
int pid;
|
|
|
|
if (cgroup_feature("pids_localevents") <= 0)
|
|
return KSFT_SKIP;
|
|
|
|
cg_parent = cg_name(root, "pids_parent");
|
|
cg_child = cg_name(cg_parent, "pids_child");
|
|
if (!cg_parent || !cg_child)
|
|
goto cleanup;
|
|
|
|
if (cg_create(cg_parent))
|
|
goto cleanup;
|
|
if (cg_write(cg_parent, "cgroup.subtree_control", "+pids"))
|
|
goto cleanup;
|
|
if (cg_create(cg_child))
|
|
goto cleanup;
|
|
|
|
if (cg_write(cg_parent, "pids.max", "2"))
|
|
goto cleanup;
|
|
|
|
if (cg_read_strcmp(cg_child, "pids.max", "max\n"))
|
|
goto cleanup;
|
|
|
|
if (cg_enter_current(cg_child))
|
|
goto cleanup;
|
|
|
|
pid = cg_run_nowait(cg_child, run_pause, NULL);
|
|
if (pid < 0)
|
|
goto cleanup;
|
|
|
|
if (cg_run_nowait(cg_child, run_success, NULL) != -1 || errno != EAGAIN)
|
|
goto cleanup;
|
|
|
|
if (kill(pid, SIGINT))
|
|
goto cleanup;
|
|
|
|
if (cg_read_key_long(cg_child, "pids.events", "max ") != 0)
|
|
goto cleanup;
|
|
if (cg_read_key_long(cg_parent, "pids.events", "max ") != 1)
|
|
goto cleanup;
|
|
|
|
|
|
ret = KSFT_PASS;
|
|
|
|
cleanup:
|
|
cg_enter_current(root);
|
|
if (cg_child)
|
|
cg_destroy(cg_child);
|
|
if (cg_parent)
|
|
cg_destroy(cg_parent);
|
|
free(cg_child);
|
|
free(cg_parent);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
#define T(x) { x, #x }
|
|
struct pids_test {
|
|
int (*fn)(const char *root);
|
|
const char *name;
|
|
} tests[] = {
|
|
T(test_pids_max),
|
|
T(test_pids_events),
|
|
};
|
|
#undef T
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
char root[PATH_MAX];
|
|
|
|
ksft_print_header();
|
|
ksft_set_plan(ARRAY_SIZE(tests));
|
|
if (cg_find_unified_root(root, sizeof(root), NULL))
|
|
ksft_exit_skip("cgroup v2 isn't mounted\n");
|
|
|
|
/*
|
|
* Check that pids controller is available:
|
|
* pids is listed in cgroup.controllers
|
|
*/
|
|
if (cg_read_strstr(root, "cgroup.controllers", "pids"))
|
|
ksft_exit_skip("pids controller isn't available\n");
|
|
|
|
if (cg_read_strstr(root, "cgroup.subtree_control", "pids"))
|
|
if (cg_write(root, "cgroup.subtree_control", "+pids"))
|
|
ksft_exit_skip("Failed to set pids controller\n");
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(tests); i++) {
|
|
switch (tests[i].fn(root)) {
|
|
case KSFT_PASS:
|
|
ksft_test_result_pass("%s\n", tests[i].name);
|
|
break;
|
|
case KSFT_SKIP:
|
|
ksft_test_result_skip("%s\n", tests[i].name);
|
|
break;
|
|
default:
|
|
ksft_test_result_fail("%s\n", tests[i].name);
|
|
break;
|
|
}
|
|
}
|
|
|
|
ksft_finished();
|
|
}
|