Linux Test Project
 help / color / mirror / Atom feed
From: Yeswanth Krishna Tellakula <yeswanth@linux.ibm.com>
To: ltp@lists.linux.it
Cc: Yeswanth Krishna Tellakula <yeswanth@linux.ibm.com>
Subject: [LTP] [PATCH] cgroup/cgroup_core03: convert to new LTP API with parameterised subtests
Date: Fri, 31 Jul 2026 09:49:49 +0530	[thread overview]
Message-ID: <20260731041949.26465-1-yeswanth@linux.ibm.com> (raw)

The test used the old .test_all single-function style. Convert it to
the new parameterised .test/.tcnt API, splitting the three inline
checks into named subtest functions with explicit tst_res() reporting.

Changes:
- Replace .test_all with .test/tcnt=3 (new LTP API)
- Split run() into test_cg_kill_procs_count(), test_cg_kill_trigger(),
  test_cg_kill_empty() for per-subtest PASS/FAIL granularity
- Move cg_child lifecycle and SAFE_CG_HAS() check into setup()/cleanup()
  to ensure cgroup is cleaned up on any abort path
- Promote pids[] and num_pids to file scope so they survive across
  parameterised subtest calls
- Fix BUF_LEN to use compile-time MAX_PID_NUM instead of runtime PID_NUM
- Replace TST_EXP_VAL/TST_EXP_PASS_SILENT with tst_res(TPASS/TFAIL)
  with descriptive diagnostic messages
- Fix sizeof(*data_ptr) for type safety over sizeof(uintptr_t)
- Add .needs_root, .taint_check and increase .timeout to 30

No functional behaviour change.

Signed-off-by: Yeswanth Krishna Tellakula <yeswanth@linux.ibm.com>
---
 .../kernel/controllers/cgroup/cgroup_core03.c | 202 +++++++++++++-----
 1 file changed, 152 insertions(+), 50 deletions(-)

diff --git a/testcases/kernel/controllers/cgroup/cgroup_core03.c b/testcases/kernel/controllers/cgroup/cgroup_core03.c
index 846c00f29..44e1ac44a 100644
--- a/testcases/kernel/controllers/cgroup/cgroup_core03.c
+++ b/testcases/kernel/controllers/cgroup/cgroup_core03.c
@@ -2,15 +2,28 @@
 /*
  * Copyright (c) 2012 Christian Brauner <brauner-AT-kernel.org>
  * Copyright (c) 2023 SUSE LLC <wegao@suse.com>
+ * Copyright (c) 2024 Linux Test Project
  */
 
 /*\
- * This test is copied from kselftest
- * tools/testing/selftests/cgroup/test_kill.c.
+ * [Description]
  *
- * Only simple test implemented within current case, the other cases such
- * as test_cgkill_tree and test_cgkill_forkbomb can be created later.
+ * Functional test for cgroup.kill interface (cgroupv2).
  *
+ * Derived from kselftest tools/testing/selftests/cgroup/test_kill.c
+ * (test_cgkill_simple subcase).
+ *
+ * The test verifies the following sequence:
+ *   1. Fork PID_NUM child processes, each joining a dedicated child cgroup.
+ *   2. Confirm all PID_NUM processes are visible in cgroup.procs.
+ *   3. Write 1 to cgroup.kill; confirm every process exits with a signal.
+ *   4. Confirm cgroup.procs is empty after the kill.
+ *
+ * [Algorithm]
+ *
+ * - Subtest 1: all forked pids appear in cgroup.procs before kill.
+ * - Subtest 2: writing 1 to cgroup.kill terminates every member process.
+ * - Subtest 3: cgroup.procs count reaches 0 after kill completes.
  */
 
 #include <sys/wait.h>
@@ -18,14 +31,24 @@
 #include "lapi/syscalls.h"
 #include "tst_test.h"
 
-#define MAX_PID_NUM 100
-#define PID_NUM MIN(MAX_PID_NUM, (tst_ncpus_available() + 1))
-#define BUF_LEN (20 * PID_NUM)
+#define MAX_PID_NUM	100
+#define PID_NUM		MIN(MAX_PID_NUM, (tst_ncpus_available() + 1))
+#define BUF_LEN		(20 * MAX_PID_NUM)
 
 static tst_atomic_t *data_ptr;
 static char *buf;
-static struct tst_cg_group *cg_child_test_simple;
+static struct tst_cg_group *cg_child;
+static pid_t pids[MAX_PID_NUM];
+static int num_pids;
+
+/* ------------------------------------------------------------------ */
+/* Helpers                                                              */
+/* ------------------------------------------------------------------ */
 
+/*
+ * wait_for_pid() - wait for a single pid and verify it was killed by signal.
+ * Returns 0 on success (process was signalled), -1 otherwise.
+ */
 static int wait_for_pid(pid_t pid)
 {
 	int status, ret;
@@ -35,95 +58,174 @@ again:
 	if (ret == -1) {
 		if (errno == EINTR)
 			goto again;
-
 		return -1;
 	}
 
-	if (WIFSIGNALED(status))
-		return 0;
+	return WIFSIGNALED(status) ? 0 : -1;
+}
+
+/*
+ * cg_count_procs() - count newline-separated PIDs in cgroup.procs.
+ */
+static int cg_count_procs(const struct tst_cg_group *cg)
+{
+	char *ptr;
+	int nr = 0;
+
+	SAFE_CG_READ(cg, "cgroup.procs", buf, BUF_LEN);
+	for (ptr = buf; *ptr; ptr++)
+		if (*ptr == '\n')
+			nr++;
 
-	return -1;
+	return nr;
 }
 
-static int cg_run_nowait(const struct tst_cg_group *const cg)
+/*
+ * cg_run_nowait() - fork a child, move it into cg, then pause.
+ * Returns the child pid to the parent.
+ */
+static pid_t cg_run_nowait(const struct tst_cg_group *cg)
 {
-	int pid;
+	pid_t pid;
 
 	pid = SAFE_FORK();
 	if (pid == 0) {
 		SAFE_CG_PRINTF(cg, "cgroup.procs", "%d", getpid());
-		if (tst_atomic_inc(data_ptr) == PID_NUM)
+		if (tst_atomic_inc(data_ptr) == num_pids)
 			TST_CHECKPOINT_WAKE(0);
 		pause();
+		exit(0);
 	}
 
 	return pid;
 }
 
-static int cg_count_procs(const struct tst_cg_group *cg)
+/* ------------------------------------------------------------------ */
+/* Sub-tests                                                            */
+/* ------------------------------------------------------------------ */
+
+/*
+ * test_cg_kill_procs_count - verify PID_NUM processes are inside the cgroup
+ * before cgroup.kill is triggered.
+ */
+static void test_cg_kill_procs_count(void)
 {
-	char *ptr;
+	int actual;
+
+	actual = cg_count_procs(cg_child);
+	if (actual == num_pids)
+		tst_res(TPASS, "cgroup.procs has %d entries as expected", actual);
+	else
+		tst_res(TFAIL, "cgroup.procs has %d entries, expected %d",
+			actual, num_pids);
+}
 
-	int nr = 0;
+/*
+ * test_cg_kill_trigger - write 1 to cgroup.kill and confirm every forked
+ * process exits via a signal.
+ */
+static void test_cg_kill_trigger(void)
+{
+	int i, failed = 0;
 
-	SAFE_CG_READ(cg, "cgroup.procs", buf, BUF_LEN);
+	SAFE_CG_PRINTF(cg_child, "cgroup.kill", "%d", 1);
 
-	for (ptr = buf; *ptr; ptr++)
-		if (*ptr == '\n')
-			nr++;
+	for (i = 0; i < num_pids; i++) {
+		if (wait_for_pid(pids[i]) != 0) {
+			tst_res(TFAIL, "pid[%d]=%d did not exit via signal",
+				i, pids[i]);
+			failed++;
+		}
+	}
 
-	return nr;
+	if (!failed)
+		tst_res(TPASS, "all %d processes were killed by cgroup.kill",
+			num_pids);
 }
 
-static void run(void)
+/*
+ * test_cg_kill_empty - verify cgroup.procs is empty after cgroup.kill.
+ */
+static void test_cg_kill_empty(void)
 {
-	pid_t pids[MAX_PID_NUM];
-	int i;
-	*data_ptr = 0;
-
-	cg_child_test_simple = tst_cg_group_mk(tst_cg, "cg_test_simple");
-
-	if (!SAFE_CG_HAS(cg_child_test_simple, "cgroup.kill")) {
-		cg_child_test_simple = tst_cg_group_rm(cg_child_test_simple);
-		tst_brk(TCONF, "cgroup.kill is not supported on your distribution");
-	}
+	int actual;
+
+	actual = cg_count_procs(cg_child);
+	if (actual == 0)
+		tst_res(TPASS, "cgroup.procs is empty after cgroup.kill");
+	else
+		tst_res(TFAIL, "cgroup.procs still has %d entries after kill",
+			actual);
+}
 
-	memset(buf, 0, BUF_LEN);
+/*
+ * run() - dispatch sub-tests; fork wave happens once before test 1.
+ */
+static void run(unsigned int n)
+{
+	int i;
 
-	for (i = 0; i < PID_NUM; i++)
-		pids[i] = cg_run_nowait(cg_child_test_simple);
+	/* Fork wave: only needed before the first subtest. */
+	if (n == 0) {
+		*data_ptr = 0;
+		num_pids = PID_NUM;
 
-	TST_CHECKPOINT_WAIT(0);
-	TST_EXP_VAL(cg_count_procs(cg_child_test_simple), PID_NUM);
-	SAFE_CG_PRINTF(cg_child_test_simple, "cgroup.kill", "%d", 1);
+		for (i = 0; i < num_pids; i++)
+			pids[i] = cg_run_nowait(cg_child);
 
-	for (i = 0; i < PID_NUM; i++)
-		TST_EXP_PASS_SILENT(wait_for_pid(pids[i]));
+		TST_CHECKPOINT_WAIT(0);
+	}
 
-	TST_EXP_VAL(cg_count_procs(cg_child_test_simple), 0);
-	cg_child_test_simple = tst_cg_group_rm(cg_child_test_simple);
+	switch (n) {
+	case 0:
+		test_cg_kill_procs_count();
+		break;
+	case 1:
+		test_cg_kill_trigger();
+		break;
+	case 2:
+		test_cg_kill_empty();
+		break;
+	}
 }
 
+/* ------------------------------------------------------------------ */
+/* Setup / Cleanup                                                      */
+/* ------------------------------------------------------------------ */
+
 static void setup(void)
 {
 	buf = tst_alloc(BUF_LEN);
-	data_ptr = SAFE_MMAP(NULL, sizeof(uintptr_t), PROT_READ | PROT_WRITE,
-						 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+	data_ptr = SAFE_MMAP(NULL, sizeof(*data_ptr), PROT_READ | PROT_WRITE,
+			     MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+
+	cg_child = tst_cg_group_mk(tst_cg, "cg_test_simple");
+
+	if (!SAFE_CG_HAS(cg_child, "cgroup.kill")) {
+		cg_child = tst_cg_group_rm(cg_child);
+		tst_brk(TCONF, "cgroup.kill is not supported on this kernel");
+	}
 }
 
 static void cleanup(void)
 {
+	if (cg_child)
+		cg_child = tst_cg_group_rm(cg_child);
+
 	if (data_ptr)
-		SAFE_MUNMAP(data_ptr, sizeof(uintptr_t));
+		SAFE_MUNMAP(data_ptr, sizeof(*data_ptr));
 }
 
 static struct tst_test test = {
-	.test_all = run,
+	.test = run,
+	.tcnt = 3,
 	.setup = setup,
 	.cleanup = cleanup,
 	.forks_child = 1,
-	.timeout = 20,
+	.needs_root = 1,
+	.needs_checkpoints = 1,
+	.timeout = 30,
+	.taint_check = TST_TAINT_W | TST_TAINT_D,
 	.needs_cgroup_ctrls = (const char *const []){ "base", NULL },
 	.needs_cgroup_ver = TST_CG_V2,
-	.needs_checkpoints = 1,
 };
-- 
2.50.1 (Apple Git-155)


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

             reply	other threads:[~2026-08-01  7:19 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-31  4:19 Yeswanth Krishna Tellakula [this message]
2026-08-01  7:30 ` [LTP] cgroup/cgroup_core03: convert to new LTP API with parameterised subtests linuxtestproject.agent
  -- strict thread matches above, loose matches on Subject: below --
2026-07-31  4:42 [LTP] [PATCH] " Yeswanth Krishna Tellakula
2026-07-30 20:39 Yeswanth Krishna Tellakula

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260731041949.26465-1-yeswanth@linux.ibm.com \
    --to=yeswanth@linux.ibm.com \
    --cc=ltp@lists.linux.it \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox