1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2002
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 /* 11/19/2002	Port to LTP	robbiew@us.ibm.com */
21 /* 06/30/2001	Port to Linux	nsharoff@us.ibm.com */
22 
23 /*
24  * NAME
25  *	stack_space.c - stack test
26  *
27  *	Test VM for set of stack-space intensive programs.
28  *	This code very similar to tdat.c, only uses stack-based "file".
29  *
30  */
31 
32 #include <stdio.h>
33 #include <sys/types.h>
34 #include <signal.h>
35 #include <errno.h>
36 #include <sys/wait.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <string.h>
40 
41 /** LTP Port **/
42 #include "test.h"
43 
44 #define FAILED 0
45 #define PASSED 1
46 
47 int local_flag = PASSED;
48 int block_number;
49 
50 char *TCID = "stack_space";	/* Test program identifier.    */
51 int TST_TOTAL = 1;		/* Total number of test cases. */
52 /**************/
53 
54 #define MAXCHILD	100	/* max # kids */
55 #define K_1		1024
56 #define K_2		2048
57 #define K_4		4096
58 #define MAXSIZE         10*K_1
59 
60 int nchild;			/* # kids */
61 int csize;			/* chunk size */
62 int iterations;			/* # total iterations */
63 int parent_pid;
64 
65 int usage(char *);
66 int bd_arg(char *);
67 int runtest();
68 int dotest(int, int);
69 int bfill(char *, char, int);
70 int dumpbuf(char *);
71 void dumpbits(char *, int);
72 
73 char *prog;			/* invoked name */
74 
usage(char * prog)75 int usage(char *prog)
76 {
77 	tst_resm(TCONF, "Usage: %s <nchild> <chunk_size> <iterations>", prog);
78 	tst_brkm(TCONF, NULL, "DEFAULTS: 20 1024 50");
79 }
80 
main(argc,argv)81 int main(argc, argv)
82 int argc;
83 char *argv[];
84 {
85 	register int i;
86 	void term();
87 
88 	prog = argv[0];
89 	parent_pid = getpid();
90 
91 	if (signal(SIGTERM, term) == SIG_ERR) {
92 		tst_brkm(TBROK, NULL, "first sigset failed");
93 
94 	}
95 
96 	if (argc == 1) {
97 		nchild = 20;
98 		csize = K_1;
99 		iterations = 50;
100 	} else if (argc == 4) {
101 		i = 1;
102 		if (sscanf(argv[i++], "%d", &nchild) != 1)
103 			bd_arg(argv[i - 1]);
104 		if (nchild > MAXCHILD) {
105 			tst_brkm(TBROK, NULL,
106 				 "Too many children, max is %d\n",
107 				 MAXCHILD);
108 		}
109 		if (sscanf(argv[i++], "%d", &csize) != 1)
110 			bd_arg(argv[i - 1]);
111 		if (csize > MAXSIZE) {
112 			tst_brkm(TBROK, NULL,
113 				 "Chunk size too large , max is %d\n",
114 				 MAXSIZE);
115 		}
116 		if (sscanf(argv[i++], "%d", &iterations) != 1)
117 			bd_arg(argv[i - 1]);
118 	} else
119 		usage(prog);
120 
121 	tst_tmpdir();
122 	runtest();
123 	/**NOT REACHED**/
124 	return 0;
125 
126 }
127 
bd_arg(str)128 int bd_arg(str)
129 char *str;
130 {
131 	tst_brkm(TCONF, NULL,
132 		 "Bad argument - %s - could not parse as number.\n",
133 		 str);
134 }
135 
runtest()136 int runtest()
137 {
138 	register int i;
139 	int child;
140 	int status;
141 	int count;
142 
143 	for (i = 0; i < nchild; i++) {
144 		if ((child = fork()) == 0) {	/* child */
145 			dotest(nchild, i);	/* do it! */
146 			exit(0);	/* when done, exit */
147 		}
148 		if (child < 0) {
149 			tst_resm(TBROK,
150 				 "Fork failed (may be OK if under stress)");
151 			tst_resm(TINFO, "System resource may be too low.\n");
152 			tst_brkm(TBROK, tst_rmdir, "Reason: %s\n",
153 				 strerror(errno));
154 
155 		}
156 	}
157 
158 	/*
159 	 * Wait for children to finish.
160 	 */
161 
162 	count = 0;
163 	while ((child = wait(&status)) > 0) {
164 #ifdef DEBUG
165 		tst_resm(TINFO, "\t%s[%d] exited status = 0x%x\n", prog, child,
166 			 status);
167 #endif
168 		if (status) {
169 			tst_resm(TINFO, "\tFailed - expected 0 exit status.\n");
170 			local_flag = FAILED;
171 		}
172 		++count;
173 	}
174 
175 	/*
176 	 * Should have collected all children.
177 	 */
178 
179 	if (count != nchild) {
180 		tst_resm(TINFO, "\tWrong # children waited on, count = %d\n",
181 			 count);
182 		local_flag = FAILED;
183 	}
184 
185 	(local_flag == FAILED) ? tst_resm(TFAIL, "Test failed")
186 	    : tst_resm(TPASS, "Test passed");
187 	sync();			/* safeness */
188 	tst_rmdir();
189 	tst_exit();
190 
191 }
192 
193 /*
194  * dotest()
195  *	Children execute this.
196  *
197  * Randomly read/mod/write chunks with known pattern and check.
198  * When fill sectors, iterate.
199  */
200 
201 int nchunks;
202 
203 #define	CHUNK(i)	((i) * csize)
204 
dotest(int testers,int me)205 int dotest(int testers, int me)
206 {
207 	char *bits;
208 	char *val_buf;
209 	char *zero_buf;
210 	char *buf;
211 	int count;
212 	int collide;
213 	char val;
214 	int chunk;
215 	char mondobuf[MAXSIZE];
216 
217 	nchunks = MAXSIZE / csize;
218 	bits = malloc((nchunks + 7) / 8);
219 	val_buf = (char *)(malloc(csize));
220 	zero_buf = (char *)(malloc(csize));
221 
222 	if (bits == 0 || val_buf == 0 || zero_buf == 0) {
223 		tst_brkm(TFAIL, NULL, "\tmalloc failed, pid: %d\n", getpid());
224 	}
225 
226 	/*
227 	 * No init sectors; allow file to be sparse.
228 	 */
229 
230 	val = (64 / testers) * me + 1;
231 
232 	/*
233 	 * For each iteration:
234 	 *      zap bits array
235 	 *      loop:
236 	 *              pick random chunk.
237 	 *              if corresponding bit off {
238 	 *                      verify == 0. (sparse file)
239 	 *                      ++count;
240 	 *              } else
241 	 *                      verify == val.
242 	 *              write "val" on it.
243 	 *              repeat until count = nchunks.
244 	 *      ++val.
245 	 *      Fill-in those chunks not yet seen.
246 	 */
247 
248 	bfill(zero_buf, 0, csize);
249 	bfill(mondobuf, 0, MAXSIZE);
250 
251 	srand(getpid());
252 	while (iterations-- > 0) {
253 		bfill(bits, 0, (nchunks + 7) / 8);
254 		bfill(val_buf, val, csize);
255 		count = 0;
256 		collide = 0;
257 		while (count < nchunks) {
258 			chunk = rand() % nchunks;
259 			buf = mondobuf + CHUNK(chunk);
260 
261 			/*
262 			 * If bit off, haven't seen it yet.
263 			 * Else, have.  Verify values.
264 			 */
265 
266 			if ((bits[chunk / 8] & (1 << (chunk % 8))) == 0) {
267 				if (memcmp(buf, zero_buf, csize)) {
268 					tst_resm(TFAIL,
269 						 "%s[%d] bad verify @ %d (%p) for val %d count %d, should be 0.\n",
270 						 prog, me, chunk, buf, val,
271 						 count);
272 					tst_resm(TINFO, "Prev ");
273 					dumpbuf(buf - csize);
274 					dumpbuf(buf);
275 					tst_resm(TINFO, "Next ");
276 					dumpbuf(buf + csize);
277 					dumpbits(bits, (nchunks + 7) / 8);
278 					tst_exit();
279 				}
280 				bits[chunk / 8] |= (1 << (chunk % 8));
281 				++count;
282 			} else {
283 				++collide;
284 				if (memcmp(buf, val_buf, csize)) {
285 					tst_resm(TFAIL,
286 						 "%s[%d] bad verify @ %d (%p) for val %d count %d.\n",
287 						 prog, me, chunk, buf, val,
288 						 count);
289 					tst_resm(TINFO, "Prev ");
290 					dumpbuf(buf - csize);
291 					dumpbuf(buf);
292 					tst_resm(TINFO, "Next ");
293 					dumpbuf(buf + csize);
294 					dumpbits(bits, (nchunks + 7) / 8);
295 					tst_exit();
296 				}
297 			}
298 
299 			/*
300 			 * Write it.
301 			 */
302 
303 			bfill(buf, val, csize);
304 
305 			if (count + collide > 2 * nchunks)
306 				break;
307 		}
308 
309 		/*
310 		 * End of iteration, maybe before doing all chunks.
311 		 */
312 
313 		for (chunk = 0; chunk < nchunks; chunk++) {
314 			if ((bits[chunk / 8] & (1 << (chunk % 8))) == 0)
315 				bfill(mondobuf + CHUNK(chunk), val, csize);
316 		}
317 		bfill(zero_buf, val, csize);
318 		++val;
319 	}
320 	free(bits);
321 	free(val_buf);
322 	free(zero_buf);
323 
324 	return 0;
325 }
326 
bfill(buf,val,size)327 int bfill(buf, val, size)
328 register char *buf;
329 char val;
330 register int size;
331 {
332 	register int i;
333 
334 	for (i = 0; i < size; i++)
335 		buf[i] = val;
336 	return 0;
337 }
338 
339 /*
340  * dumpbuf
341  *	Dump the buffer.
342  */
343 
dumpbuf(buf)344 int dumpbuf(buf)
345 register char *buf;
346 {
347 	register int i;
348 	char val;
349 	int idx;
350 	int nout;
351 
352 #ifdef DEBUG
353 	tst_resm(TINFO, "Buf: ... ");
354 	for (i = -10; i < 0; i++)
355 		tst_resm(TINFO, "%x, ", buf[i]);
356 	tst_resm(TINFO, "\n");
357 #endif
358 
359 	nout = 0;
360 	idx = 0;
361 	val = buf[0];
362 	for (i = 0; i < csize; i++) {
363 		if (buf[i] != val) {
364 #ifdef DEBUG
365 			if (i == idx + 1)
366 				tst_resm(TINFO, "%x, ", buf[idx] & 0xff);
367 			else
368 				tst_resm(TINFO, "%d*%x, ", i - idx,
369 					 buf[idx] & 0xff);
370 #endif
371 			idx = i;
372 			val = buf[i];
373 			++nout;
374 		}
375 		if (nout > 10) {
376 #ifdef DEBUG
377 			tst_resm(TINFO, " ... more\n");
378 #endif
379 			return 0;
380 		}
381 	}
382 #ifdef DEBUG
383 	if (i == idx + 1)
384 		tst_resm(TINFO, "%x\n", buf[idx] & 0xff);
385 	else
386 		tst_resm(TINFO, "%d*%x\n", i - idx, buf[idx]);
387 #endif
388 	return 0;
389 
390 }
391 
392 /*
393  * dumpbits
394  *	Dump the bit-map.
395  */
396 
dumpbits(bits,size)397 void dumpbits(bits, size)
398 char *bits;
399 register int size;
400 {
401 #ifdef DEBUG
402 	register char *buf;
403 
404 	tst_resm(TINFO, "Bits array:");
405 	for (buf = bits; size > 0; --size, ++buf) {
406 		if ((buf - bits) % 16 == 0)
407 			tst_resm(TINFO, "\n%04x:\t", 8 * (buf - bits));
408 		tst_resm(TINFO, "%02x ", (int)*buf & 0xff);
409 	}
410 	tst_resm(TINFO, "\n");
411 #endif
412 
413 }
414 
term()415 void term()
416 {
417 
418 	if (getpid() == parent_pid) {
419 #ifdef DEBUG
420 		tst_resm(TINFO, "term - parent - got SIGTERM.\n");
421 #endif
422 	} else {
423 #ifdef DEBUG
424 		tst_resm(TINFO, "term1 - child - exiting\n");
425 #endif
426 		exit(0);
427 	}
428 }
429