1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2001
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /*
21 * NAME
22 * hugeshmat01.c
23 *
24 * DESCRIPTION
25 * hugeshmat01 - test that shmat() works correctly
26 *
27 * ALGORITHM
28 * create a large shared memory resouce with read/write permissions
29 * loop if that option was specified
30 * call shmat() with the TEST() macro using three valid conditions
31 * check the return code
32 * if failure, issue a FAIL message.
33 * otherwise,
34 * if doing functionality testing
35 * check for the correct conditions after the call
36 * if correct,
37 * issue a PASS message
38 * otherwise
39 * issue a FAIL message
40 * call cleanup
41 *
42 * USAGE: <for command-line>
43 * hugeshmat01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
44 * where, -c n : Run n copies concurrently.
45 * -f : Turn off functionality Testing.
46 * -i n : Execute test n times.
47 * -I x : Execute test for x seconds.
48 * -P x : Pause for x seconds between iterations.
49 * -t : Turn on syscall timing.
50 *
51 * HISTORY
52 * 03/2001 - Written by Wayne Boyer
53 * 04/2004 - Updated by Robbie Williamson
54 *
55 * RESTRICTIONS
56 * none
57 */
58
59 #include "hugetlb.h"
60 #include "safe_macros.h"
61 #include "mem.h"
62
63 char *TCID = "hugeshmat01";
64 int TST_TOTAL = 3;
65
66 #define CASE0 10 /* values to write into the shared */
67 #define CASE1 20 /* memory location. */
68
69 static size_t shm_size;
70 static int shm_id_1 = -1;
71 static void *addr;
72
73 static long hugepages = 128;
74 static option_t options[] = {
75 {"s:", &sflag, &nr_opt},
76 {NULL, NULL, NULL}
77 };
78
79 struct test_case_t {
80 int *shmid;
81 void *addr;
82 int flags;
83 } TC[] = {
84 /* a straight forward read/write attach */
85 {
86 &shm_id_1, 0, 0},
87 /*
88 * an attach using non aligned memory
89 * -1 will be replaced with an unaligned addr
90 */
91 {
92 &shm_id_1, (void *)-1, SHM_RND},
93 /* a read only attach */
94 {
95 &shm_id_1, 0, SHM_RDONLY}
96 };
97
98 static void check_functionality(int i);
99
main(int ac,char ** av)100 int main(int ac, char **av)
101 {
102 int lc, i;
103
104 tst_parse_opts(ac, av, options, NULL);
105
106 if (sflag)
107 hugepages = SAFE_STRTOL(NULL, nr_opt, 0, LONG_MAX);
108
109 setup();
110
111 for (lc = 0; TEST_LOOPING(lc); lc++) {
112 tst_count = 0;
113
114 for (i = 0; i < TST_TOTAL; i++) {
115 addr = shmat(*(TC[i].shmid), TC[i].addr, TC[i].flags);
116 if (addr == (void *)-1) {
117 tst_brkm(TFAIL | TERRNO, cleanup, "shmat");
118 } else {
119 check_functionality(i);
120 }
121
122 /*
123 * addr in TC[0] will be used to generate an unaligned
124 * address for TC[1]
125 */
126 if (i == 0 && addr != (void *)-1)
127 TC[1].addr = (void *)(((unsigned long)addr &
128 ~(SHMLBA - 1)) + SHMLBA -
129 1);
130 if (shmdt(addr) == -1)
131 tst_brkm(TBROK | TERRNO, cleanup, "shmdt");
132 }
133 }
134 cleanup();
135 tst_exit();
136 }
137
138 /*
139 * check_functionality - check various conditions to make sure they
140 * are correct.
141 */
check_functionality(int i)142 static void check_functionality(int i)
143 {
144 void *orig_add;
145 int *shared;
146 struct shmid_ds buf;
147
148 shared = (int *)addr;
149
150 /* stat the shared memory ID */
151 if (shmctl(shm_id_1, IPC_STAT, &buf) == -1)
152 tst_brkm(TBROK | TERRNO, cleanup, "shmctl");
153
154 /* check the number of attaches */
155 if (buf.shm_nattch != 1) {
156 tst_resm(TFAIL, "# of attaches is incorrect");
157 return;
158 }
159
160 /* check the size of the segment */
161 if (buf.shm_segsz != shm_size) {
162 tst_resm(TFAIL, "segment size is incorrect");
163 return;
164 }
165
166 /* check for specific conditions depending on the type of attach */
167 switch (i) {
168 case 0:
169 /*
170 * Check the functionality of the first call by simply
171 * "writing" a value to the shared memory space.
172 * If this fails the program will get a SIGSEGV, dump
173 * core and exit.
174 */
175 *shared = CASE0;
176 break;
177 case 1:
178 /*
179 * Check the functionality of the second call by writing
180 * a value to the shared memory space and then checking
181 * that the original address given was rounded down as
182 * specified in the man page.
183 */
184 *shared = CASE1;
185 orig_add = addr + ((unsigned long)TC[i].addr % SHMLBA);
186 if (orig_add != TC[i].addr) {
187 tst_resm(TFAIL, "shared memory address is not "
188 "correct");
189 return;
190 }
191 break;
192 case 2:
193 /*
194 * This time the shared memory is read only. Read the value
195 * and check that it is equal to the value set in case #2,
196 * because shared memory is persistent.
197 */
198 if (*shared != CASE1) {
199 tst_resm(TFAIL, "shared memory value isn't correct");
200 return;
201 }
202 break;
203 }
204 tst_resm(TPASS, "conditions and functionality are correct");
205 }
206
setup(void)207 void setup(void)
208 {
209 long hpage_size;
210
211 tst_require_root();
212 check_hugepage();
213 tst_sig(NOFORK, DEF_HANDLER, cleanup);
214 tst_tmpdir();
215
216 orig_hugepages = get_sys_tune("nr_hugepages");
217 set_sys_tune("nr_hugepages", hugepages, 1);
218 hpage_size = read_meminfo("Hugepagesize:") * 1024;
219
220 shm_size = hpage_size * hugepages / 2;
221 update_shm_size(&shm_size);
222 shmkey = getipckey(cleanup);
223 shm_id_1 = shmget(shmkey++, shm_size,
224 SHM_HUGETLB | SHM_RW | IPC_CREAT | IPC_EXCL);
225 if (shm_id_1 == -1)
226 tst_brkm(TBROK | TERRNO, cleanup, "shmget");
227
228 TEST_PAUSE;
229 }
230
cleanup(void)231 void cleanup(void)
232 {
233 rm_shm(shm_id_1);
234
235 set_sys_tune("nr_hugepages", orig_hugepages, 0);
236
237 tst_rmdir();
238 }
239