1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0
2f08c3bdfSopenharmony_ci/*\
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * [Description]
5f08c3bdfSopenharmony_ci *
6f08c3bdfSopenharmony_ci * Conversion of second kself test in cgroup/test_memcontrol.c.
7f08c3bdfSopenharmony_ci *
8f08c3bdfSopenharmony_ci * Original description:
9f08c3bdfSopenharmony_ci * "This test creates a memory cgroup, allocates some anonymous memory
10f08c3bdfSopenharmony_ci * and some pagecache and check memory.current and some memory.stat
11f08c3bdfSopenharmony_ci * values."
12f08c3bdfSopenharmony_ci *
13f08c3bdfSopenharmony_ci * Note that the V1 rss and cache counters were renamed to anon and
14f08c3bdfSopenharmony_ci * file in V2. Besides error reporting, this test differs from the
15f08c3bdfSopenharmony_ci * kselftest in the following ways:
16f08c3bdfSopenharmony_ci *
17f08c3bdfSopenharmony_ci * . It supports V1.
18f08c3bdfSopenharmony_ci * . It writes instead of reads to fill the page cache. Because no
19f08c3bdfSopenharmony_ci *   pages were allocated on tmpfs.
20f08c3bdfSopenharmony_ci * . It runs on most filesystems available
21f08c3bdfSopenharmony_ci * . On EXFAT and extN we change the margin of error between all and file
22f08c3bdfSopenharmony_ci *   memory to 50%. Because these allocate non-page-cache memory during writes.
23f08c3bdfSopenharmony_ci */
24f08c3bdfSopenharmony_ci#define _GNU_SOURCE
25f08c3bdfSopenharmony_ci
26f08c3bdfSopenharmony_ci#include "memcontrol_common.h"
27f08c3bdfSopenharmony_ci
28f08c3bdfSopenharmony_cistatic size_t page_size;
29f08c3bdfSopenharmony_cistatic struct tst_cg_group *cg_child;
30f08c3bdfSopenharmony_cistatic int fd;
31f08c3bdfSopenharmony_cistatic int file_to_all_error = 10;
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_cistatic void alloc_anon_50M_check(void)
34f08c3bdfSopenharmony_ci{
35f08c3bdfSopenharmony_ci	const ssize_t size = MB(50);
36f08c3bdfSopenharmony_ci	char *buf, *ptr;
37f08c3bdfSopenharmony_ci	ssize_t anon, current;
38f08c3bdfSopenharmony_ci	const char *const anon_key_fmt =
39f08c3bdfSopenharmony_ci		TST_CG_VER_IS_V1(tst_cg, "memory") ? "rss %zd" : "anon %zd";
40f08c3bdfSopenharmony_ci
41f08c3bdfSopenharmony_ci	buf = SAFE_MALLOC(size);
42f08c3bdfSopenharmony_ci	for (ptr = buf; ptr < buf + size; ptr += page_size)
43f08c3bdfSopenharmony_ci		*ptr = 0;
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_ci	SAFE_CG_SCANF(cg_child, "memory.current", "%zd", &current);
46f08c3bdfSopenharmony_ci	TST_EXP_EXPR(current >= size,
47f08c3bdfSopenharmony_ci		     "(memory.current=%zd) >= (size=%zd)", current, size);
48f08c3bdfSopenharmony_ci
49f08c3bdfSopenharmony_ci	SAFE_CG_LINES_SCANF(cg_child, "memory.stat", anon_key_fmt, &anon);
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_ci	TST_EXP_EXPR(anon > 0, "(memory.stat.anon=%zd) > 0", anon);
52f08c3bdfSopenharmony_ci	TST_EXP_EXPR(values_close(size, anon, 3),
53f08c3bdfSopenharmony_ci		     "(size=%zd) ~= (memory.stat.anon=%zd)", size, anon);
54f08c3bdfSopenharmony_ci	TST_EXP_EXPR(values_close(anon, current, 3),
55f08c3bdfSopenharmony_ci		     "(memory.current=%zd) ~= (memory.stat.anon=%zd)",
56f08c3bdfSopenharmony_ci		     current, anon);
57f08c3bdfSopenharmony_ci}
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_cistatic void alloc_pagecache_50M_check(void)
60f08c3bdfSopenharmony_ci{
61f08c3bdfSopenharmony_ci	const size_t size = MB(50);
62f08c3bdfSopenharmony_ci	size_t current, file;
63f08c3bdfSopenharmony_ci	const char *const file_key_fmt =
64f08c3bdfSopenharmony_ci		TST_CG_VER_IS_V1(tst_cg, "memory") ? "cache %zd" : "file %zd";
65f08c3bdfSopenharmony_ci
66f08c3bdfSopenharmony_ci	fd = SAFE_OPEN(TMPDIR"/tmpfile", O_RDWR | O_CREAT, 0600);
67f08c3bdfSopenharmony_ci
68f08c3bdfSopenharmony_ci	SAFE_CG_SCANF(cg_child, "memory.current", "%zu", &current);
69f08c3bdfSopenharmony_ci	tst_res(TINFO, "Created temp file: memory.current=%zu", current);
70f08c3bdfSopenharmony_ci
71f08c3bdfSopenharmony_ci	alloc_pagecache(fd, size);
72f08c3bdfSopenharmony_ci
73f08c3bdfSopenharmony_ci	SAFE_CG_SCANF(cg_child, "memory.current", "%zu", &current);
74f08c3bdfSopenharmony_ci	TST_EXP_EXPR(current >= size,
75f08c3bdfSopenharmony_ci			 "(memory.current=%zu) >= (size=%zu)", current, size);
76f08c3bdfSopenharmony_ci
77f08c3bdfSopenharmony_ci	SAFE_CG_LINES_SCANF(cg_child, "memory.stat", file_key_fmt, &file);
78f08c3bdfSopenharmony_ci	TST_EXP_EXPR(file > 0, "(memory.stat.file=%zd) > 0", file);
79f08c3bdfSopenharmony_ci
80f08c3bdfSopenharmony_ci	TST_EXP_EXPR(values_close(file, current, file_to_all_error),
81f08c3bdfSopenharmony_ci			 "(memory.current=%zd) ~= (memory.stat.file=%zd)",
82f08c3bdfSopenharmony_ci			 current, file);
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_ci	SAFE_CLOSE(fd);
85f08c3bdfSopenharmony_ci}
86f08c3bdfSopenharmony_ci
87f08c3bdfSopenharmony_cistatic void test_memcg_current(unsigned int n)
88f08c3bdfSopenharmony_ci{
89f08c3bdfSopenharmony_ci	size_t current;
90f08c3bdfSopenharmony_ci
91f08c3bdfSopenharmony_ci	cg_child = tst_cg_group_mk(tst_cg, "child");
92f08c3bdfSopenharmony_ci	SAFE_CG_SCANF(cg_child, "memory.current", "%zu", &current);
93f08c3bdfSopenharmony_ci	TST_EXP_EXPR(current == 0, "(current=%zu) == 0", current);
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_ci	if (!SAFE_FORK()) {
96f08c3bdfSopenharmony_ci		SAFE_CG_PRINTF(cg_child, "cgroup.procs", "%d", getpid());
97f08c3bdfSopenharmony_ci
98f08c3bdfSopenharmony_ci		SAFE_CG_SCANF(cg_child, "memory.current", "%zu", &current);
99f08c3bdfSopenharmony_ci		tst_res(TINFO, "Added proc to memcg: memory.current=%zu",
100f08c3bdfSopenharmony_ci			current);
101f08c3bdfSopenharmony_ci
102f08c3bdfSopenharmony_ci		if (!n)
103f08c3bdfSopenharmony_ci			alloc_anon_50M_check();
104f08c3bdfSopenharmony_ci		else
105f08c3bdfSopenharmony_ci			alloc_pagecache_50M_check();
106f08c3bdfSopenharmony_ci	} else {
107f08c3bdfSopenharmony_ci		tst_reap_children();
108f08c3bdfSopenharmony_ci		cg_child = tst_cg_group_rm(cg_child);
109f08c3bdfSopenharmony_ci	}
110f08c3bdfSopenharmony_ci}
111f08c3bdfSopenharmony_ci
112f08c3bdfSopenharmony_cistatic void setup(void)
113f08c3bdfSopenharmony_ci{
114f08c3bdfSopenharmony_ci	page_size = SAFE_SYSCONF(_SC_PAGESIZE);
115f08c3bdfSopenharmony_ci
116f08c3bdfSopenharmony_ci	switch (tst_fs_type(TMPDIR)) {
117f08c3bdfSopenharmony_ci	case TST_VFAT_MAGIC:
118f08c3bdfSopenharmony_ci	case TST_EXFAT_MAGIC:
119f08c3bdfSopenharmony_ci	case TST_EXT234_MAGIC:
120f08c3bdfSopenharmony_ci		file_to_all_error = 50;
121f08c3bdfSopenharmony_ci		break;
122f08c3bdfSopenharmony_ci	}
123f08c3bdfSopenharmony_ci}
124f08c3bdfSopenharmony_ci
125f08c3bdfSopenharmony_cistatic void cleanup(void)
126f08c3bdfSopenharmony_ci{
127f08c3bdfSopenharmony_ci	if (cg_child)
128f08c3bdfSopenharmony_ci		cg_child = tst_cg_group_rm(cg_child);
129f08c3bdfSopenharmony_ci}
130f08c3bdfSopenharmony_ci
131f08c3bdfSopenharmony_cistatic struct tst_test test = {
132f08c3bdfSopenharmony_ci	.setup = setup,
133f08c3bdfSopenharmony_ci	.cleanup = cleanup,
134f08c3bdfSopenharmony_ci	.tcnt = 2,
135f08c3bdfSopenharmony_ci	.test = test_memcg_current,
136f08c3bdfSopenharmony_ci	.mount_device = 1,
137f08c3bdfSopenharmony_ci	.dev_min_size = 256,
138f08c3bdfSopenharmony_ci	.mntpoint = TMPDIR,
139f08c3bdfSopenharmony_ci	.all_filesystems = 1,
140f08c3bdfSopenharmony_ci	.forks_child = 1,
141f08c3bdfSopenharmony_ci	.needs_root = 1,
142f08c3bdfSopenharmony_ci	.needs_cgroup_ctrls = (const char *const []){ "memory", NULL },
143f08c3bdfSopenharmony_ci};
144