1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) International Business Machines  Corp., 2001
4f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2001-2017
5f08c3bdfSopenharmony_ci *
6f08c3bdfSopenharmony_ci * DESCRIPTION
7f08c3bdfSopenharmony_ci *	hugeshmat01 - test that shmat() works correctly
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * ALGORITHM
10f08c3bdfSopenharmony_ci *	create a large shared memory resouce with read/write permissions
11f08c3bdfSopenharmony_ci *	loop if that option was specified
12f08c3bdfSopenharmony_ci *	call shmat() with the TEST() macro using three valid conditions
13f08c3bdfSopenharmony_ci *	check the return code
14f08c3bdfSopenharmony_ci *	  if failure, issue a FAIL message.
15f08c3bdfSopenharmony_ci *	otherwise,
16f08c3bdfSopenharmony_ci *	  if doing functionality testing
17f08c3bdfSopenharmony_ci *		check for the correct conditions after the call
18f08c3bdfSopenharmony_ci *		if correct,
19f08c3bdfSopenharmony_ci *			issue a PASS message
20f08c3bdfSopenharmony_ci *		otherwise
21f08c3bdfSopenharmony_ci *			issue a FAIL message
22f08c3bdfSopenharmony_ci *	call cleanup
23f08c3bdfSopenharmony_ci *
24f08c3bdfSopenharmony_ci * HISTORY
25f08c3bdfSopenharmony_ci *	03/2001 - Written by Wayne Boyer
26f08c3bdfSopenharmony_ci *	04/2004 - Updated by Robbie Williamson
27f08c3bdfSopenharmony_ci */
28f08c3bdfSopenharmony_ci
29f08c3bdfSopenharmony_ci#include <limits.h>
30f08c3bdfSopenharmony_ci#include "hugetlb.h"
31f08c3bdfSopenharmony_ci
32f08c3bdfSopenharmony_ci#define CASE0 10 /* values to write into the shared */
33f08c3bdfSopenharmony_ci#define CASE1 20 /* memory location.                */
34f08c3bdfSopenharmony_ci
35f08c3bdfSopenharmony_cistatic size_t shm_size;
36f08c3bdfSopenharmony_cistatic int shm_id_1 = -1;
37f08c3bdfSopenharmony_cistatic void *addr;
38f08c3bdfSopenharmony_ci
39f08c3bdfSopenharmony_cistatic struct tcase {
40f08c3bdfSopenharmony_ci	int *shmid;
41f08c3bdfSopenharmony_ci	void *addr;
42f08c3bdfSopenharmony_ci	int flags;
43f08c3bdfSopenharmony_ci} tcases[] = {
44f08c3bdfSopenharmony_ci	/* a straight forward read/write attach */
45f08c3bdfSopenharmony_ci	{&shm_id_1, 0, 0},
46f08c3bdfSopenharmony_ci	/*
47f08c3bdfSopenharmony_ci	 * an attach using non aligned memory
48f08c3bdfSopenharmony_ci	 * -1 will be replaced with an unaligned addr
49f08c3bdfSopenharmony_ci	 */
50f08c3bdfSopenharmony_ci	{&shm_id_1, (void *)-1, SHM_RND},
51f08c3bdfSopenharmony_ci	/* a read only attach */
52f08c3bdfSopenharmony_ci	{&shm_id_1, 0, SHM_RDONLY}
53f08c3bdfSopenharmony_ci};
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_cistatic void check_functionality(unsigned int i);
56f08c3bdfSopenharmony_ci
57f08c3bdfSopenharmony_cistatic void verify_hugeshmat(unsigned int i)
58f08c3bdfSopenharmony_ci{
59f08c3bdfSopenharmony_ci	struct tcase *tc = &tcases[i];
60f08c3bdfSopenharmony_ci
61f08c3bdfSopenharmony_ci	addr = shmat(*(tc->shmid), tc->addr, tc->flags);
62f08c3bdfSopenharmony_ci	if (addr == (void *)-1) {
63f08c3bdfSopenharmony_ci		tst_brk(TFAIL | TERRNO, "shmat");
64f08c3bdfSopenharmony_ci	} else {
65f08c3bdfSopenharmony_ci		check_functionality(i);
66f08c3bdfSopenharmony_ci	}
67f08c3bdfSopenharmony_ci
68f08c3bdfSopenharmony_ci	/*
69f08c3bdfSopenharmony_ci	 * addr in tcases[0] will be used to generate an unaligned
70f08c3bdfSopenharmony_ci	 * address for tcases[1]
71f08c3bdfSopenharmony_ci	 */
72f08c3bdfSopenharmony_ci	if (i == 0 && addr != (void *)-1)
73f08c3bdfSopenharmony_ci		tc[1].addr = (void *)(((unsigned long)addr &
74f08c3bdfSopenharmony_ci					~(SHMLBA - 1)) + SHMLBA - 1);
75f08c3bdfSopenharmony_ci	if (shmdt(addr) == -1)
76f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "shmdt");
77f08c3bdfSopenharmony_ci}
78f08c3bdfSopenharmony_ci
79f08c3bdfSopenharmony_ci/*
80f08c3bdfSopenharmony_ci * check_functionality - check various conditions to make sure they
81f08c3bdfSopenharmony_ci *			 are correct.
82f08c3bdfSopenharmony_ci */
83f08c3bdfSopenharmony_cistatic void check_functionality(unsigned int i)
84f08c3bdfSopenharmony_ci{
85f08c3bdfSopenharmony_ci	void *orig_add;
86f08c3bdfSopenharmony_ci	int *shared;
87f08c3bdfSopenharmony_ci	struct shmid_ds buf;
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_ci	shared = (int *)addr;
90f08c3bdfSopenharmony_ci
91f08c3bdfSopenharmony_ci	/* stat the shared memory ID */
92f08c3bdfSopenharmony_ci	if (shmctl(shm_id_1, IPC_STAT, &buf) == -1)
93f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "shmctl");
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_ci	/* check the number of attaches */
96f08c3bdfSopenharmony_ci	if (buf.shm_nattch != 1) {
97f08c3bdfSopenharmony_ci		tst_res(TFAIL, "# of attaches is incorrect");
98f08c3bdfSopenharmony_ci		return;
99f08c3bdfSopenharmony_ci	}
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_ci	/* check the size of the segment */
102f08c3bdfSopenharmony_ci	if (buf.shm_segsz != shm_size) {
103f08c3bdfSopenharmony_ci		tst_res(TFAIL, "segment size is incorrect");
104f08c3bdfSopenharmony_ci		return;
105f08c3bdfSopenharmony_ci	}
106f08c3bdfSopenharmony_ci
107f08c3bdfSopenharmony_ci	/* check for specific conditions depending on the type of attach */
108f08c3bdfSopenharmony_ci	switch (i) {
109f08c3bdfSopenharmony_ci	case 0:
110f08c3bdfSopenharmony_ci		/*
111f08c3bdfSopenharmony_ci		 * Check the functionality of the first call by simply
112f08c3bdfSopenharmony_ci		 * "writing" a value to the shared memory space.
113f08c3bdfSopenharmony_ci		 * If this fails the program will get a SIGSEGV, dump
114f08c3bdfSopenharmony_ci		 * core and exit.
115f08c3bdfSopenharmony_ci		 */
116f08c3bdfSopenharmony_ci		*shared = CASE0;
117f08c3bdfSopenharmony_ci		break;
118f08c3bdfSopenharmony_ci	case 1:
119f08c3bdfSopenharmony_ci		/*
120f08c3bdfSopenharmony_ci		 * Check the functionality of the second call by writing
121f08c3bdfSopenharmony_ci		 * a value to the shared memory space and then checking
122f08c3bdfSopenharmony_ci		 * that the original address given was rounded down as
123f08c3bdfSopenharmony_ci		 * specified in the man page.
124f08c3bdfSopenharmony_ci		 */
125f08c3bdfSopenharmony_ci		*shared = CASE1;
126f08c3bdfSopenharmony_ci		orig_add = addr + ((unsigned long)tcases[i].addr % SHMLBA);
127f08c3bdfSopenharmony_ci		if (orig_add != tcases[i].addr) {
128f08c3bdfSopenharmony_ci			tst_res(TFAIL, "shared memory address is not "
129f08c3bdfSopenharmony_ci				 "correct");
130f08c3bdfSopenharmony_ci			return;
131f08c3bdfSopenharmony_ci		}
132f08c3bdfSopenharmony_ci		break;
133f08c3bdfSopenharmony_ci	case 2:
134f08c3bdfSopenharmony_ci		/*
135f08c3bdfSopenharmony_ci		 * This time the shared memory is read only.  Read the value
136f08c3bdfSopenharmony_ci		 * and check that it is equal to the value set in case #2,
137f08c3bdfSopenharmony_ci		 * because shared memory is persistent.
138f08c3bdfSopenharmony_ci		 */
139f08c3bdfSopenharmony_ci		if (*shared != CASE1) {
140f08c3bdfSopenharmony_ci			tst_res(TFAIL, "shared memory value isn't correct");
141f08c3bdfSopenharmony_ci			return;
142f08c3bdfSopenharmony_ci		}
143f08c3bdfSopenharmony_ci		break;
144f08c3bdfSopenharmony_ci	}
145f08c3bdfSopenharmony_ci	tst_res(TPASS, "conditions and functionality are correct");
146f08c3bdfSopenharmony_ci}
147f08c3bdfSopenharmony_ci
148f08c3bdfSopenharmony_cistatic void setup(void)
149f08c3bdfSopenharmony_ci{
150f08c3bdfSopenharmony_ci	long hpage_size;
151f08c3bdfSopenharmony_ci
152f08c3bdfSopenharmony_ci	if (tst_hugepages == 0)
153f08c3bdfSopenharmony_ci		tst_brk(TCONF, "No enough hugepages for testing.");
154f08c3bdfSopenharmony_ci
155f08c3bdfSopenharmony_ci	hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024;
156f08c3bdfSopenharmony_ci
157f08c3bdfSopenharmony_ci	shm_size = hpage_size * tst_hugepages / 2;
158f08c3bdfSopenharmony_ci	update_shm_size(&shm_size);
159f08c3bdfSopenharmony_ci	shmkey = getipckey();
160f08c3bdfSopenharmony_ci	shm_id_1 = shmget(shmkey++, shm_size,
161f08c3bdfSopenharmony_ci			  SHM_HUGETLB | SHM_RW | IPC_CREAT | IPC_EXCL);
162f08c3bdfSopenharmony_ci	if (shm_id_1 == -1)
163f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "shmget");
164f08c3bdfSopenharmony_ci
165f08c3bdfSopenharmony_ci}
166f08c3bdfSopenharmony_ci
167f08c3bdfSopenharmony_cistatic void cleanup(void)
168f08c3bdfSopenharmony_ci{
169f08c3bdfSopenharmony_ci	rm_shm(shm_id_1);
170f08c3bdfSopenharmony_ci}
171f08c3bdfSopenharmony_ci
172f08c3bdfSopenharmony_cistatic struct tst_test test = {
173f08c3bdfSopenharmony_ci	.needs_root = 1,
174f08c3bdfSopenharmony_ci	.needs_tmpdir = 1,
175f08c3bdfSopenharmony_ci	.options = (struct tst_option[]) {
176f08c3bdfSopenharmony_ci		{"s:", &nr_opt, "Set the number of the been allocated hugepages"},
177f08c3bdfSopenharmony_ci		{}
178f08c3bdfSopenharmony_ci	},
179f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(tcases),
180f08c3bdfSopenharmony_ci	.test = verify_hugeshmat,
181f08c3bdfSopenharmony_ci	.setup = setup,
182f08c3bdfSopenharmony_ci	.cleanup = cleanup,
183f08c3bdfSopenharmony_ci	.hugepages = {128, TST_REQUEST},
184f08c3bdfSopenharmony_ci};
185