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