[LTP] cpuset_memory_spread: rewrite as a C test using the LTP cgroup library

linuxtestproject.agent@gmail.com linuxtestproject.agent@gmail.com
Wed Nov 4 04:30:39 CET 2026


Hi Changwei,

On Wed Nov 4 11:24:00 2026 +1100, Changwei Zou wrote:
> cpuset_memory_spread: rewrite as a C test using the LTP cgroup library

> + * where the file's pages landed. Instead of looking at the noisy global
> + * per-node page-cache counters in ``/sys``, it accounts for only the data
> + * file's own pages: after reading the file it mmaps it, faults every page
> + * in and uses ``move_pages()`` (with a NULL node array, so nothing is

Use :manpage:`move_pages(2)` instead of ``move_pages()`` in the doc comment.

> +/* Build the cpuset.cpus string listing all online CPUs of node 'nd'. */
> +static void node_cpus(int nd, char *cpus, size_t size)
> +{
> +	int ncpus = 0, i;
> +	long online;
> +	char path[PATH_MAX], buf[32];
> +
> +	while (tst_path_exists(PATH_SYS_SYSTEM "/cpu/cpu%d", ncpus))
> +		ncpus++;

numa_helper.h (linked via testcases/kernel/include/lib.mk) already provides
write_node_cpusets(), which gathers a node's online CPUs and sets
cpuset.cpus and cpuset.mems. Use write_node_cpusets() instead of duplicating
this helper.

> +	fd = SAFE_OPEN(DATAFILE, O_RDONLY);
> +	while ((ret = read(fd, buf, sizeof(buf))) > 0)
> +		;
> +	if (ret < 0)
> +		tst_brk(TBROK | TERRNO, "read %s", DATAFILE);
> +	SAFE_CLOSE(fd);

Use SAFE_READ(0, fd, buf, sizeof(buf)) in the loop instead of raw read() and
a manual error check.

> +static void run(void)
> +{
> +	int a = nodes[0];
> +	int b = nodes[1];
> +	const int expect_a[] = { a };
> +	const int expect_b[] = { b };
> +	const int expect_ab[] = { a, b };
> +
> +	do_spread_test(a, -1, 0, expect_a, 1,
> +		       "spread off, single node: local allocation");
> +	do_spread_test(a, -1, 1, expect_a, 1,
> +		       "spread on, single node: all on that node");
> +	do_spread_test(b, -1, 0, expect_b, 1,
> +		       "spread off, single node: local allocation");
> +	do_spread_test(b, -1, 1, expect_b, 1,
> +		       "spread on, single node: all on that node");
> +	do_spread_test(a, b, 0, expect_a, 1,
> +		       "spread off, two nodes: local allocation");
> +	do_spread_test(a, b, 1, expect_ab, 2,
> +		       "spread on, two nodes: even spread");
> +}

Define a struct tcase array and use .test + .tcnt = ARRAY_SIZE(tcases) in
struct tst_test instead of calling do_spread_test() multiple times from
.test_all. Also, in the original test_spread_page1(), cases 3 and 4 kept
cpuset.cpus on node a while setting cpuset.mems to node b to verify
non-local memory node allocation, whereas passing b as cpus_node here binds
both cpuset.cpus and cpuset.mems to node b and repeats cases 1 and 2.

> +	counts = SAFE_MALLOC(MAXNODES * sizeof(*counts));
> +
> +	tst_fill_file(DATAFILE, 0, 1024 * 1024, FILE_MB);
> +
> +	SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid());

tst_fill_file() does not call tst_brk() on failure; it unlinks DATAFILE and
returns -1, which later causes SAFE_OPEN(DATAFILE, O_RDONLY) to fail with
ENOENT. Check the return value of tst_fill_file() and call tst_brk(TBROK |
TERRNO, ...) on non-zero return.

> +	.test_all = run,
> +	.needs_cgroup_ctrls = (const char *const []){ "cpuset", NULL },
> +	.needs_cgroup_ver = TST_CG_V1,
> +};
> +
> +#else
> +	TST_TEST_TCONF(NUMA_ERROR_MSG);
> +#endif

Pass a literal string to TST_TEST_TCONF() (e.g.
TST_TEST_TCONF("test requires libnuma >= 2")) without leading indentation
instead of the NUMA_ERROR_MSG macro.

Verdict - Needs revision

---
Note:

The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.

Regards,
LTP AI Reviewer


More information about the ltp mailing list