• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Disktest
3 * Copyright (c) International Business Machines Corp., 2001
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 *  Please send e-mail to yardleyb@us.ibm.com if you have
21 *  questions or comments.
22 *
23 *  Project Website:  TBD
24 *
25 * $Id: main.c,v 1.11 2009/02/26 12:14:53 subrata_modak Exp $
26 *
27 */
28 #include <stdio.h>
29 #ifdef WINDOWS
30 #include <windows.h>
31 #include <winioctl.h>
32 #include <io.h>
33 #include <process.h>
34 #include <sys/stat.h>
35 #include "getopt.h"
36 #else
37 #include <pthread.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40 #endif
41 #include <stdlib.h>
42 #include <stdarg.h>
43 #include <stdint.h>
44 #include <signal.h>
45 #include <time.h>
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <string.h>
49 #include <ctype.h>
50 
51 #include "defs.h"
52 #include "globals.h"
53 #include "main.h"
54 #include "usage.h"
55 #include "sfunc.h"
56 #include "parse.h"
57 #include "childmain.h"
58 #include "threading.h"
59 #include "dump.h"
60 #include "timer.h"
61 #include "stats.h"
62 #include "signals.h"
63 
64 /* global */
65 child_args_t cleanArgs;
66 test_env_t cleanEnv;
67 char hostname[HOSTNAME_SIZE];	/* global system hostname */
68 
linear_read_write_test(test_ll_t * test)69 void linear_read_write_test(test_ll_t * test)
70 {
71 	OFF_T *pVal1 = (OFF_T *) test->env->shared_mem;
72 	int i;
73 
74 	if (test->args->flags & CLD_FLG_W) {
75 		test->env->bContinue = TRUE;
76 		*(pVal1 + OFF_WLBA) = test->args->start_lba;
77 		test->args->test_state = DIRCT_INC(test->args->test_state);
78 		test->env->lastAction.oper = WRITER;
79 		test->args->test_state = SET_OPER_W(test->args->test_state);
80 		test->args->test_state = SET_wFST_TIME(test->args->test_state);
81 //              srand(test->args->seed);        /* reseed so we can re create the same random transfers */
82 		memset(test->env->action_list, 0,
83 		       sizeof(action_t) * test->args->t_kids);
84 		test->env->action_list_entry = 0;
85 		test->env->wcount = 0;
86 		test->env->rcount = 0;
87 		if (test->args->flags & CLD_FLG_CYC)
88 			if (test->args->cycles == 0) {
89 				pMsg(INFO, test->args,
90 				     "Starting write pass, cycle %lu\n",
91 				     (unsigned long)test->env->pass_count);
92 			} else {
93 				pMsg(INFO, test->args,
94 				     "Starting write pass, cycle %lu of %lu\n",
95 				     (unsigned long)test->env->pass_count,
96 				     test->args->cycles);
97 		} else {
98 			pMsg(INFO, test->args, "Starting write pass\n");
99 		}
100 		CreateTestChild(ChildTimer, test);
101 		for (i = 0; i < test->args->t_kids; i++) {
102 			CreateTestChild(ChildMain, test);
103 		}
104 		/* Wait for the writers to finish */
105 		cleanUpTestChildren(test);
106 	}
107 
108 	/* If the write test failed don't start the read test */
109 	if (!(TST_STS(test->args->test_state))) {
110 		return;
111 	}
112 
113 	if (test->args->flags & CLD_FLG_R) {
114 		test->env->bContinue = TRUE;
115 		*(pVal1 + OFF_RLBA) = test->args->start_lba;
116 		test->args->test_state = DIRCT_INC(test->args->test_state);
117 		test->env->lastAction.oper = READER;
118 		test->args->test_state = SET_OPER_R(test->args->test_state);
119 		test->args->test_state = SET_rFST_TIME(test->args->test_state);
120 //              srand(test->args->seed);        /* reseed so we can re create the same random transfers */
121 		memset(test->env->action_list, 0,
122 		       sizeof(action_t) * test->args->t_kids);
123 		test->env->action_list_entry = 0;
124 		test->env->wcount = 0;
125 		test->env->rcount = 0;
126 		if (test->args->flags & CLD_FLG_CYC)
127 			if (test->args->cycles == 0) {
128 				pMsg(INFO, test->args,
129 				     "Starting read pass, cycle %lu\n",
130 				     (unsigned long)test->env->pass_count);
131 			} else {
132 				pMsg(INFO, test->args,
133 				     "Starting read pass, cycle %lu of %lu\n",
134 				     (unsigned long)test->env->pass_count,
135 				     test->args->cycles);
136 		} else {
137 			pMsg(INFO, test->args, "Starting read pass\n");
138 		}
139 		CreateTestChild(ChildTimer, test);
140 		for (i = 0; i < test->args->t_kids; i++) {
141 			CreateTestChild(ChildMain, test);
142 		}
143 		/* Wait for the readers to finish */
144 		cleanUpTestChildren(test);
145 	}
146 }
147 
init_data(test_ll_t * test,unsigned char ** data_buffer_unaligned)148 unsigned long init_data(test_ll_t * test, unsigned char **data_buffer_unaligned)
149 {
150 	int i;
151 	OFF_T *pVal1;
152 
153 	unsigned long data_buffer_size;
154 
155 #ifdef WINDOWS
156 	if (CreateMutex(NULL, FALSE, "gbl") == NULL) {
157 		pMsg(ERR, test->args,
158 		     "Failed to create semaphore, error = %u\n",
159 		     GetLastError());
160 		return (GetLastError());
161 	}
162 	if ((test->env->mutexs.MutexACTION =
163 	     CreateMutex(NULL, FALSE, NULL)) == NULL) {
164 		pMsg(ERR, test->args,
165 		     "Failed to create semaphore, error = %u\n",
166 		     GetLastError());
167 		return (GetLastError());
168 	}
169 	if ((test->env->mutexs.MutexIO =
170 	     CreateMutex(NULL, FALSE, NULL)) == NULL) {
171 		pMsg(ERR, test->args,
172 		     "Failed to create semaphore, error = %u\n",
173 		     GetLastError());
174 		return (GetLastError());
175 	}
176 #else
177 
178 	mutexs_t mutexs =
179 	    { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER };
180 	test->env->mutexs = mutexs;
181 
182 #endif
183 
184 	if (test->args->seed == 0)
185 		test->args->seed = test->args->pid;
186 	srand(test->args->seed);
187 
188 	/* create bitmap to hold write/read context: each bit is an LBA */
189 	/* the stuff before BMP_OFFSET is the data for child/thread shared context */
190 	test->env->bmp_siz =
191 	    (((((size_t) test->args->vsiz)) / 8) ==
192 	     0) ? 1 : ((((size_t) test->args->vsiz)) / 8);
193 	if ((test->args->vsiz / 8) != 0)
194 		test->env->bmp_siz += 1;	/* account for rounding error */
195 
196 	/* We use that same data buffer for static data, so alloc here. */
197 	data_buffer_size = ((test->args->htrsiz * BLK_SIZE) * 2);
198 	if ((*data_buffer_unaligned =
199 	     (unsigned char *)ALLOC(data_buffer_size + ALIGNSIZE)) == NULL) {
200 		pMsg(ERR, test->args,
201 		     "Failed to allocate static data buffer memory.\n");
202 		return (-1);
203 	}
204 	/* create list to hold lbas currently be written */
205 	if ((test->env->action_list =
206 	     (action_t *) ALLOC(sizeof(action_t) * test->args->t_kids)) ==
207 	    NULL) {
208 		pMsg(ERR, test->args,
209 		     "Failed to allocate static data buffer memory.\n");
210 		return (-1);
211 	}
212 
213 	test->env->data_buffer =
214 	    (unsigned char *)BUFALIGN(*data_buffer_unaligned);
215 
216 	if ((test->env->shared_mem =
217 	     (void *)ALLOC(test->env->bmp_siz + BMP_OFFSET)) == NULL) {
218 		pMsg(ERR, test->args, "Failed to allocate bitmap memory\n");
219 		return (-1);
220 	}
221 
222 	memset(test->env->shared_mem, 0, test->env->bmp_siz + BMP_OFFSET);
223 	memset(test->env->data_buffer, 0, data_buffer_size);
224 	memset(test->env->action_list, 0,
225 	       sizeof(action_t) * test->args->t_kids);
226 	test->env->action_list_entry = 0;
227 
228 	pVal1 = (OFF_T *) test->env->shared_mem;
229 	*(pVal1 + OFF_WLBA) = test->args->start_lba;
230 	*(pVal1 + OFF_RLBA) = test->args->start_lba;
231 	test->args->test_state = SET_STS_PASS(test->args->test_state);
232 	test->args->test_state = SET_wFST_TIME(test->args->test_state);
233 	test->args->test_state = SET_rFST_TIME(test->args->test_state);
234 	test->args->test_state = DIRCT_INC(test->args->test_state);
235 	if (test->args->flags & CLD_FLG_W) {
236 		test->env->lastAction.oper = WRITER;
237 		test->args->test_state = SET_OPER_W(test->args->test_state);
238 	} else {
239 		test->env->lastAction.oper = READER;
240 		test->args->test_state = SET_OPER_R(test->args->test_state);
241 	}
242 
243 	/* prefill the data buffer with data for compares and writes */
244 	switch (test->args->flags & CLD_FLG_PTYPS) {
245 	case CLD_FLG_FPTYPE:
246 		for (i = 0; i < sizeof(test->args->pattern); i++) {
247 			if ((test->args->
248 			     pattern & (((OFF_T) 0xff) <<
249 					(((sizeof(test->args->pattern) - 1) -
250 					  i) * 8))) != 0)
251 				break;
252 		}
253 		/* special case for pattern = 0 */
254 		if (i == sizeof(test->args->pattern))
255 			i = 0;
256 		fill_buffer(test->env->data_buffer, data_buffer_size,
257 			    &test->args->pattern,
258 			    sizeof(test->args->pattern) - i, CLD_FLG_FPTYPE);
259 		break;
260 	case CLD_FLG_RPTYPE:
261 		fill_buffer(test->env->data_buffer, data_buffer_size, NULL, 0,
262 			    CLD_FLG_RPTYPE);
263 		break;
264 	case CLD_FLG_CPTYPE:
265 		fill_buffer(test->env->data_buffer, data_buffer_size, 0, 0,
266 			    CLD_FLG_CPTYPE);
267 	case CLD_FLG_LPTYPE:
268 		break;
269 	default:
270 		pMsg(WARN, test->args, "Unknown fill pattern\n");
271 		return (-1);
272 	}
273 
274 	return 0;
275 }
276 
277 #ifdef WINDOWS
threadedMain(test_ll_t * test)278 DWORD WINAPI threadedMain(test_ll_t * test)
279 #else
280 void *threadedMain(void *vtest)
281 #endif
282 {
283 #ifndef WINDOWS
284 	test_ll_t *test = (test_ll_t *) vtest;
285 #endif
286 
287 	OFF_T *pVal1;
288 	unsigned char *data_buffer_unaligned = NULL;
289 	unsigned long ulRV;
290 	int i;
291 	unsigned char *sharedMem;
292 
293 	extern unsigned short glb_run;
294 	extern int signal_action;
295 
296 	test->args->pid = GETPID();
297 
298 	init_gbl_data(test->env);
299 
300 	if (make_assumptions(test->args) < 0) {
301 		TEXIT((uintptr_t) GETLASTERROR());
302 	}
303 	if (check_conclusions(test->args) < 0) {
304 		TEXIT((uintptr_t) GETLASTERROR());
305 	}
306 	if (test->args->flags & CLD_FLG_DUMP) {
307 		/*
308 		 * All we are doing is dumping filespec data to STDOUT, so
309 		 * we will do this here and be done.
310 		 */
311 		do_dump(test->args);
312 		TEXIT((uintptr_t) GETLASTERROR());
313 	} else {
314 		ulRV = init_data(test, &data_buffer_unaligned);
315 		if (ulRV != 0) {
316 			TEXIT(ulRV);
317 		}
318 		pVal1 = (OFF_T *) test->env->shared_mem;
319 	}
320 
321 	pMsg(START, test->args, "Start args: %s\n", test->args->argstr);
322 
323 	/*
324 	 * This loop takes care of passes
325 	 */
326 	do {
327 		test->env->pass_count++;
328 		test->env->start_time = time(NULL);
329 		if (test->args->flags & CLD_FLG_RPTYPE) {	/* force random data to be different each cycle */
330 			fill_buffer(test->env->data_buffer,
331 				    ((test->args->htrsiz * BLK_SIZE) * 2), NULL,
332 				    0, CLD_FLG_RPTYPE);
333 		}
334 		sharedMem = test->env->shared_mem;
335 		memset(sharedMem + BMP_OFFSET, 0, test->env->bmp_siz);
336 		if ((test->args->flags & CLD_FLG_LINEAR)
337 		    && !(test->args->flags & CLD_FLG_NTRLVD)) {
338 			linear_read_write_test(test);
339 		} else {
340 			/* we only reset the end time if not running a linear read / write test */
341 			test->env->end_time =
342 			    test->env->start_time + test->args->run_time;
343 			test->env->bContinue = TRUE;
344 			*(pVal1 + OFF_WLBA) = test->args->start_lba;
345 			test->args->test_state =
346 			    DIRCT_INC(test->args->test_state);
347 			test->args->test_state =
348 			    SET_wFST_TIME(test->args->test_state);
349 			test->args->test_state =
350 			    SET_rFST_TIME(test->args->test_state);
351 			if (test->args->flags & CLD_FLG_W) {
352 				test->env->lastAction.oper = WRITER;
353 				test->args->test_state =
354 				    SET_OPER_W(test->args->test_state);
355 			} else {
356 				test->env->lastAction.oper = READER;
357 				test->args->test_state =
358 				    SET_OPER_R(test->args->test_state);
359 			}
360 			memset(test->env->action_list, 0,
361 			       sizeof(action_t) * test->args->t_kids);
362 			test->env->action_list_entry = 0;
363 			test->env->wcount = 0;
364 			test->env->rcount = 0;
365 
366 			if (test->args->flags & CLD_FLG_CYC)
367 				if (test->args->cycles == 0) {
368 					pMsg(INFO, test->args,
369 					     "Starting pass %lu\n",
370 					     (unsigned long)test->env->
371 					     pass_count);
372 				} else {
373 					pMsg(INFO, test->args,
374 					     "Starting pass %lu of %lu\n",
375 					     (unsigned long)test->env->
376 					     pass_count, test->args->cycles);
377 			} else {
378 				pMsg(INFO, test->args, "Starting pass\n");
379 			}
380 
381 			CreateTestChild(ChildTimer, test);
382 			for (i = 0; i < test->args->t_kids; i++) {
383 				CreateTestChild(ChildMain, test);
384 			}
385 			/* Wait for the children to finish */
386 			cleanUpTestChildren(test);
387 		}
388 
389 		update_cyc_stats(test->env);
390 		if ((test->args->flags & CLD_FLG_CYC)
391 		    && (test->args->flags & CLD_FLG_PCYC)) {
392 			print_stats(test->args, test->env, CYCLE);
393 		}
394 		update_gbl_stats(test->env);
395 
396 		if (signal_action & SIGNAL_STOP) {
397 			break;
398 		}		/* user request to stop */
399 		if ((glb_run == 0)) {
400 			break;
401 		}
402 		/* global request to stop */
403 		if (!(test->args->flags & CLD_FLG_CYC)) {
404 			break;	/* leave, unless cycle testing */
405 		} else {
406 			if ((test->args->cycles > 0)
407 			    && (test->env->pass_count >= test->args->cycles)) {
408 				break;	/* leave, cycle testing complete */
409 			}
410 		}
411 	} while (TST_STS(test->args->test_state));
412 	print_stats(test->args, test->env, TOTAL);
413 
414 	FREE(data_buffer_unaligned);
415 	FREE(test->env->shared_mem);
416 #ifdef WINDOWS
417 	CloseHandle(OpenMutex(SYNCHRONIZE, TRUE, "gbl"));
418 	CloseHandle(OpenMutex(SYNCHRONIZE, TRUE, "data"));
419 #endif
420 
421 	if (TST_STS(test->args->test_state)) {
422 		if (signal_action & SIGNAL_STOP) {
423 			pMsg(END, test->args,
424 			     "User Interrupt: Test Done (Passed)\n");
425 		} else {
426 			pMsg(END, test->args, "Test Done (Passed)\n");
427 		}
428 	} else {
429 		if (signal_action & SIGNAL_STOP) {
430 			pMsg(END, test->args,
431 			     "User Interrupt: Test Done (Failed)\n");
432 		} else {
433 			pMsg(END, test->args, "Test Done (Failed)\n");
434 		}
435 	}
436 	TEXIT((uintptr_t) GETLASTERROR());
437 }
438 
439 /*
440  * Creates a new test structure and adds it to the list of
441  * test structures already available.  Allocate all memory
442  * needed by the new test.
443  *
444  * Returns the newly created test structure
445  */
getNewTest(test_ll_t * testList)446 test_ll_t *getNewTest(test_ll_t * testList)
447 {
448 	test_ll_t *pNewTest;
449 
450 	if ((pNewTest = (test_ll_t *) ALLOC(sizeof(test_ll_t))) == NULL) {
451 		pMsg(ERR, &cleanArgs,
452 		     "%d : Could not allocate memory for new test.\n",
453 		     GETLASTERROR());
454 		return NULL;
455 	}
456 
457 	memset(pNewTest, 0, sizeof(test_ll_t));
458 
459 	if ((pNewTest->args =
460 	     (child_args_t *) ALLOC(sizeof(child_args_t))) == NULL) {
461 		pMsg(ERR, &cleanArgs,
462 		     "%d : Could not allocate memory for new test.\n",
463 		     GETLASTERROR());
464 		FREE(pNewTest);
465 		return NULL;
466 	}
467 	if ((pNewTest->env = (test_env_t *) ALLOC(sizeof(test_env_t))) == NULL) {
468 		pMsg(ERR, &cleanArgs,
469 		     "%d : Could not allocate memory for new test.\n",
470 		     GETLASTERROR());
471 		FREE(pNewTest->args);
472 		FREE(pNewTest);
473 		return NULL;
474 	}
475 	memcpy(pNewTest->args, &cleanArgs, sizeof(child_args_t));
476 	memcpy(pNewTest->env, &cleanEnv, sizeof(test_env_t));
477 
478 	pNewTest->next = testList;
479 	testList = pNewTest;
480 	return pNewTest;
481 }
482 
run()483 test_ll_t *run()
484 {
485 	test_ll_t *newTest = NULL, *lastTest = NULL;
486 
487 	if (cleanArgs.flags & CLD_FLG_FSLIST) {
488 		char *filespec = cleanArgs.device;
489 		char *aFilespec = NULL;
490 		FILE *file = NULL;
491 
492 		if ((aFilespec = (char *)ALLOC(80)) == NULL) {
493 			pMsg(ERR, &cleanArgs,
494 			     "Could not allocate memory to read file");
495 			return newTest;
496 		}
497 
498 		file = fopen(filespec, "r");
499 		if (file == NULL) {
500 			pMsg(ERR,
501 			     &cleanArgs,
502 			     "%s is not a regular file, could not be opened for reading, or was not found.",
503 			     filespec);
504 			FREE(aFilespec);
505 
506 			return newTest;
507 		}
508 
509 		while (!feof(file)) {
510 			memset(aFilespec, 0, 80);
511 			fscanf(file, "%79s", aFilespec);
512 			if (aFilespec[0] != 0) {	/* if we read something useful */
513 				lastTest = newTest;
514 				newTest = getNewTest(lastTest);
515 				if (newTest != lastTest) {
516 					memset(newTest->args->device, 0,
517 					       DEV_NAME_LEN);
518 					strncpy(newTest->args->device,
519 						aFilespec, strlen(aFilespec));
520 					createChild(threadedMain, newTest);
521 				} else {
522 					newTest = lastTest;
523 					break;
524 				}
525 			}
526 		}
527 
528 		fclose(file);
529 		FREE(aFilespec);
530 	} else {
531 		newTest = getNewTest(newTest);
532 		if (newTest != NULL) {
533 			createChild(threadedMain, newTest);
534 		}
535 	}
536 
537 	return newTest;
538 }
539 
main(int argc,char ** argv)540 int main(int argc, char **argv)
541 {
542 	extern time_t global_start_time;
543 	extern unsigned long glb_flags;	/* global flags GLB_FLG_xxx */
544 	int i;
545 
546 #ifdef WINDOWS
547 	WORD wVersionRequested;
548 	WSADATA wsaData;
549 	int err;
550 
551 	wVersionRequested = MAKEWORD(2, 2);
552 
553 	err = WSAStartup(wVersionRequested, &wsaData);
554 	if (err != 0) {
555 		pMsg(WARN, &cleanArgs,
556 		     "Windows setup of Winsock failed, can't retrieve host name, continuing");
557 	}
558 #endif
559 
560 	setup_sig_mask();
561 
562 	memset(hostname, 0, HOSTNAME_SIZE);
563 	gethostname(hostname, HOSTNAME_SIZE);
564 
565 	setbuf(stdout, NULL);
566 
567 	glb_flags = 0;
568 	global_start_time = time(NULL);
569 
570 	strncpy(cleanArgs.device, "No filespec", strlen("No filespec"));
571 	cleanArgs.stop_lba = -1;
572 	cleanArgs.stop_blk = -1;
573 	cleanArgs.ioTimeout = DEFAULT_IO_TIMEOUT;
574 	cleanArgs.flags |= CLD_FLG_ALLDIE;
575 	cleanArgs.flags |= CLD_FLG_ERR_REREAD;
576 	cleanArgs.flags |= CLD_FLG_LBA_SYNC;
577 
578 	for (i = 1; i < argc - 1; i++) {
579 		strncat(cleanArgs.argstr, argv[i],
580 			(MAX_ARG_LEN - 1) - strlen(cleanArgs.argstr));
581 		strncat(cleanArgs.argstr, " ",
582 			(MAX_ARG_LEN - 1) - strlen(cleanArgs.argstr));
583 	}
584 
585 	if (fill_cld_args(argc, argv, &cleanArgs) < 0)
586 		exit(1);
587 
588 	cleanUp(run());
589 
590 #ifdef WINDOWS
591 	WSACleanup();
592 #endif
593 
594 	return 0;
595 }
596