mirror of
https://github.com/torvalds/linux.git
synced 2026-09-12 20:53:03 +02:00
selftests/cgroup: test clone3() into a previously killed cgroup
Once cgroup.kill had been written to a cgroup, a stale kill_seq snapshot (taken in cgroup_css_set_fork() before the target cgroup was resolved) caused every child subsequently cloned into that cgroup with clone3(CLONE_INTO_CGROUP) to be SIGKILLed on the spot. Add a regression test: create a cgroup, kill it while it is empty, then clone a child into it and check that the child runs and exits cleanly. On a kernel without the fix, the test fails: not ok 4 test_cgkill_clone_into_killed The test is skipped on kernels without clone3() or without CLONE_INTO_CGROUP. Cc: Shakeel Butt <shakeel.butt@linux.dev> Assisted-by: LLM Signed-off-by: Etienne Perot <eperot@google.com> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
parent
8e35992021
commit
3f4b7d1a49
|
|
@ -7,6 +7,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "kselftest.h"
|
||||
|
|
@ -261,6 +262,59 @@ static int test_cgkill_forkbomb(const char *root)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that a cgroup that was killed in the past can still be the target
|
||||
* of clone3(CLONE_INTO_CGROUP): writing cgroup.kill must only kill the
|
||||
* tasks in the cgroup at the time of the write, not tasks cloned into
|
||||
* it afterwards.
|
||||
*/
|
||||
static int test_cgkill_clone_into_killed(const char *root)
|
||||
{
|
||||
pid_t pid;
|
||||
int cgroup_fd = -EBADF;
|
||||
int ret = KSFT_FAIL;
|
||||
char *cgroup = NULL;
|
||||
|
||||
cgroup = cg_name(root, "cg_test_clone_into_killed");
|
||||
if (!cgroup)
|
||||
goto cleanup;
|
||||
|
||||
if (cg_create(cgroup))
|
||||
goto cleanup;
|
||||
|
||||
/* Kill the cgroup while it is still empty. */
|
||||
if (cg_write(cgroup, "cgroup.kill", "1"))
|
||||
goto cleanup;
|
||||
|
||||
cgroup_fd = dirfd_open_opath(cgroup);
|
||||
if (cgroup_fd < 0)
|
||||
goto cleanup;
|
||||
|
||||
pid = clone_into_cgroup(cgroup_fd);
|
||||
if (pid < 0) {
|
||||
if (errno == ENOSYS)
|
||||
ret = KSFT_SKIP;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (pid == 0)
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
/* The child must not be SIGKILLed; it has to exit cleanly. */
|
||||
if (clone_reap(pid, WEXITED) != EXIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
ret = KSFT_PASS;
|
||||
|
||||
cleanup:
|
||||
if (cgroup_fd >= 0)
|
||||
close(cgroup_fd);
|
||||
if (cgroup)
|
||||
cg_destroy(cgroup);
|
||||
free(cgroup);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define T(x) { x, #x }
|
||||
struct cgkill_test {
|
||||
int (*fn)(const char *root);
|
||||
|
|
@ -269,6 +323,7 @@ struct cgkill_test {
|
|||
T(test_cgkill_simple),
|
||||
T(test_cgkill_tree),
|
||||
T(test_cgkill_forkbomb),
|
||||
T(test_cgkill_clone_into_killed),
|
||||
};
|
||||
#undef T
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user