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