1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2014-2017
4f08c3bdfSopenharmony_ci *
5f08c3bdfSopenharmony_ci * DESCRIPTION
6f08c3bdfSopenharmony_ci *	hugeshmat04 - test for hugepage leak inspection.
7f08c3bdfSopenharmony_ci *
8f08c3bdfSopenharmony_ci *	It is a regression test for shared hugepage leak, when over 1GB
9f08c3bdfSopenharmony_ci *	shared memory was alocated in hugepage, the hugepage is not released
10f08c3bdfSopenharmony_ci *	though process finished.
11f08c3bdfSopenharmony_ci *
12f08c3bdfSopenharmony_ci *	You need more than 2GB memory in test job
13f08c3bdfSopenharmony_ci *
14f08c3bdfSopenharmony_ci * HISTORY
15f08c3bdfSopenharmony_ci * 	05/2014 - Written by Fujistu Corp.
16f08c3bdfSopenharmony_ci *	12/2014 - Port to LTP by Li Wang.
17f08c3bdfSopenharmony_ci *
18f08c3bdfSopenharmony_ci * RESTRICTIONS
19f08c3bdfSopenharmony_ci * 	test must be run at root
20f08c3bdfSopenharmony_ci */
21f08c3bdfSopenharmony_ci
22f08c3bdfSopenharmony_ci#include "hugetlb.h"
23f08c3bdfSopenharmony_ci
24f08c3bdfSopenharmony_ci#define SIZE	(1024 * 1024 * 1024)
25f08c3bdfSopenharmony_ci#define BOUNDARY (1024 * 1024 * 1024)
26f08c3bdfSopenharmony_ci#define BOUNDARY_MAX (3U * 1024 * 1024 * 1024)
27f08c3bdfSopenharmony_ci
28f08c3bdfSopenharmony_cistatic long huge_free;
29f08c3bdfSopenharmony_cistatic long huge_free2;
30f08c3bdfSopenharmony_ci
31f08c3bdfSopenharmony_cistatic void shared_hugepage(void);
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_cistatic void test_hugeshmat(unsigned int i LTP_ATTRIBUTE_UNUSED)
34f08c3bdfSopenharmony_ci{
35f08c3bdfSopenharmony_ci	huge_free = SAFE_READ_MEMINFO("HugePages_Free:");
36f08c3bdfSopenharmony_ci	shared_hugepage();
37f08c3bdfSopenharmony_ci	huge_free2 = SAFE_READ_MEMINFO("HugePages_Free:");
38f08c3bdfSopenharmony_ci
39f08c3bdfSopenharmony_ci	if (huge_free2 != huge_free)
40f08c3bdfSopenharmony_ci		tst_brk(TFAIL, "Test failed. Hugepage leak inspection.");
41f08c3bdfSopenharmony_ci	else
42f08c3bdfSopenharmony_ci		tst_res(TPASS, "No regression found.");
43f08c3bdfSopenharmony_ci}
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_cistatic void shared_hugepage(void)
46f08c3bdfSopenharmony_ci{
47f08c3bdfSopenharmony_ci	pid_t pid;
48f08c3bdfSopenharmony_ci	int status, shmid;
49f08c3bdfSopenharmony_ci	size_t size = (size_t)SIZE;
50f08c3bdfSopenharmony_ci	void *buf;
51f08c3bdfSopenharmony_ci	unsigned long boundary = BOUNDARY;
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_ci	shmid = shmget(IPC_PRIVATE, size, SHM_HUGETLB | IPC_CREAT | 0777);
54f08c3bdfSopenharmony_ci	if (shmid < 0)
55f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "shmget");
56f08c3bdfSopenharmony_ci
57f08c3bdfSopenharmony_ci	while (boundary <= BOUNDARY_MAX
58f08c3bdfSopenharmony_ci		&& range_is_mapped(boundary, boundary+SIZE))
59f08c3bdfSopenharmony_ci		boundary += 128*1024*1024;
60f08c3bdfSopenharmony_ci	if (boundary > BOUNDARY_MAX)
61f08c3bdfSopenharmony_ci		tst_brk(TCONF, "failed to find free unmapped range");
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_ci	tst_res(TINFO, "attaching at 0x%lx", boundary);
64f08c3bdfSopenharmony_ci	buf = shmat(shmid, (void *)boundary, SHM_RND | 0777);
65f08c3bdfSopenharmony_ci	if (buf == (void *)-1) {
66f08c3bdfSopenharmony_ci		shmctl(shmid, IPC_RMID, NULL);
67f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "shmat");
68f08c3bdfSopenharmony_ci	}
69f08c3bdfSopenharmony_ci
70f08c3bdfSopenharmony_ci	memset(buf, 2, size);
71f08c3bdfSopenharmony_ci	pid = SAFE_FORK();
72f08c3bdfSopenharmony_ci	if (pid == 0)
73f08c3bdfSopenharmony_ci		exit(1);
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_ci	wait(&status);
76f08c3bdfSopenharmony_ci	shmdt(buf);
77f08c3bdfSopenharmony_ci	shmctl(shmid, IPC_RMID, NULL);
78f08c3bdfSopenharmony_ci}
79f08c3bdfSopenharmony_ci
80f08c3bdfSopenharmony_cistatic void setup(void)
81f08c3bdfSopenharmony_ci{
82f08c3bdfSopenharmony_ci	long hpage_size, orig_hugepages;
83f08c3bdfSopenharmony_ci	unsigned long new_shmmax;
84f08c3bdfSopenharmony_ci
85f08c3bdfSopenharmony_ci	orig_hugepages = get_sys_tune("nr_hugepages");
86f08c3bdfSopenharmony_ci	SAFE_FILE_SCANF(PATH_SHMMAX, "%lu", &new_shmmax);
87f08c3bdfSopenharmony_ci
88f08c3bdfSopenharmony_ci	if (new_shmmax < SIZE)
89f08c3bdfSopenharmony_ci		tst_brk(TCONF,	"shmmax too low, have: %lu", new_shmmax);
90f08c3bdfSopenharmony_ci
91f08c3bdfSopenharmony_ci	hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024;
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_ci	struct tst_hugepage hp = { orig_hugepages + SIZE / hpage_size, TST_NEEDS };
94f08c3bdfSopenharmony_ci	tst_reserve_hugepages(&hp);
95f08c3bdfSopenharmony_ci}
96f08c3bdfSopenharmony_ci
97f08c3bdfSopenharmony_cistatic struct tst_test test = {
98f08c3bdfSopenharmony_ci	.tags = (const struct tst_tag[]) {
99f08c3bdfSopenharmony_ci		{"linux-git", "c5c99429fa57"},
100f08c3bdfSopenharmony_ci		{}
101f08c3bdfSopenharmony_ci	},
102f08c3bdfSopenharmony_ci	.needs_root = 1,
103f08c3bdfSopenharmony_ci	.forks_child = 1,
104f08c3bdfSopenharmony_ci	.needs_tmpdir = 1,
105f08c3bdfSopenharmony_ci	.tcnt = 3,
106f08c3bdfSopenharmony_ci	.test = test_hugeshmat,
107f08c3bdfSopenharmony_ci	.min_mem_avail = 2048,
108f08c3bdfSopenharmony_ci	.setup = setup,
109f08c3bdfSopenharmony_ci	.hugepages = {1, TST_NEEDS},
110f08c3bdfSopenharmony_ci	.save_restore = (const struct tst_path_val[]) {
111f08c3bdfSopenharmony_ci		{PATH_SHMMAX, "1073741824", TST_SR_TCONF_MISSING | TST_SR_TBROK_RO},
112f08c3bdfSopenharmony_ci		{}
113f08c3bdfSopenharmony_ci	},
114f08c3bdfSopenharmony_ci};
115