• 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: sfunc.c,v 1.8 2009/02/26 12:02:23 subrata_modak Exp $
26 *
27 */
28 #include <sys/types.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <signal.h>
33 #ifdef WINDOWS
34 #include <winsock2.h>
35 #include <process.h>
36 #include <windows.h>
37 #include <winbase.h>
38 #include <winioctl.h>
39 #else
40 #ifdef AIX
41 #include <sys/ioctl.h>
42 #include <sys/devinfo.h>
43 #endif
44 #include <unistd.h>
45 #include <ctype.h>
46 #endif
47 
48 #include <time.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <string.h>
52 #ifdef LINUX
53 #include <endian.h>
54 #endif
55 
56 #include "main.h"
57 #include "sfunc.h"
58 #include "defs.h"
59 #include "globals.h"
60 #include "io.h"
61 #include "threading.h"
62 
63 /*
64  * Generates a random 32bit number.
65  */
Rand32(void)66 long Rand32(void)
67 {
68 	/*
69 	 * based on the fact that rand returns
70 	 * 0 - 0x7FFF
71 	 */
72 	long myRandomNumber = 0;
73 
74 	myRandomNumber = ((long)(rand() & 0x7FFF)) << 16;
75 	myRandomNumber |= ((long)(rand() & 0x7FFF)) << 1;
76 	myRandomNumber |= ((long)(rand() & 0x1));
77 
78 	return (myRandomNumber);
79 }
80 
81 /*
82  * Generates a random 64bit number.
83  */
Rand64(void)84 OFF_T Rand64(void)
85 {
86 	OFF_T myRandomNumber = 0;
87 
88 	myRandomNumber = ((OFF_T) (rand() & 0x7FFF)) << 48;
89 	myRandomNumber |= ((OFF_T) (rand() & 0x7FFF)) << 33;
90 	myRandomNumber |= ((OFF_T) (rand() & 0x7FFF)) << 18;
91 	myRandomNumber |= ((OFF_T) (rand() & 0x7FFF)) << 3;
92 	myRandomNumber |= ((OFF_T) (rand() & 0x7));
93 
94 	return (myRandomNumber);
95 }
96 
97 /*
98 * could not find a function that represented a conversion
99 * between a long long and a string.
100 */
my_strtofft(const char * pStr)101 OFF_T my_strtofft(const char *pStr)
102 {
103 	OFF_T value = 0;
104 	int bOct = 0, bHex = 0;
105 
106 	int neg = 0;
107 
108 	for (;; pStr++) {
109 		switch (*pStr) {
110 		case '0':
111 			bOct = 1;
112 			continue;
113 		case 'x':
114 			if (bOct)
115 				bHex = 1;
116 			continue;
117 		case ' ':
118 		case '\t':
119 			continue;
120 		case '-':
121 			neg = 1;
122 		 /*FALLTHROUGH*/ case '+':
123 			pStr++;
124 		}
125 		break;
126 	}
127 	if ((!bOct) && (!bHex)) {
128 		while (*pStr >= '0' && *pStr <= '9') {
129 			value = (value * 10) + (*pStr++ - '0');
130 		}
131 	} else if (bHex) {
132 		while ((*pStr >= '0' && *pStr <= '9') ||
133 		       (*pStr >= 'A' && *pStr <= 'F') ||
134 		       (*pStr >= 'a' && *pStr <= 'f')) {
135 			if (*pStr >= '0' && *pStr <= '9')
136 				value = (value << 4) + (*pStr++ - '0');
137 			else if (*pStr >= 'A' && *pStr <= 'F')
138 				value = (value << 4) + 10 + (*pStr++ - 'A');
139 			else if (*pStr >= 'a' && *pStr <= 'f')
140 				value = (value << 4) + 10 + (*pStr++ - 'a');
141 		}
142 	} else if (bOct) {
143 		while (*pStr >= '0' && *pStr <= '7') {
144 			value = (value * 8) + (*pStr++ - '0');
145 		}
146 	}
147 	return (neg ? -value : value);
148 }
149 
150 /*
151 * prints messages to stdout. with added formating
152 */
pMsg(lvl_t level,const child_args_t * args,char * Msg,...)153 int pMsg(lvl_t level, const child_args_t * args, char *Msg, ...)
154 {
155 #define FORMAT "| %s | %s | %d | %s | %s | %s"
156 #define TIME_FORMAT "%04d/%02d/%02d-%02d:%02d:%02d"
157 #define TIME_FMT_LEN 20
158 	va_list l;
159 	int rv = 0;
160 	size_t len = 0;
161 	char *cpTheMsg;
162 	char levelStr[10];
163 	struct tm struct_time;
164 	struct tm *pstruct_time;
165 	char time_str[TIME_FMT_LEN];
166 	time_t my_time;
167 
168 	extern unsigned long glb_flags;
169 
170 #ifndef WINDOWS
171 	static pthread_mutex_t mTime = PTHREAD_MUTEX_INITIALIZER;
172 #endif
173 
174 #ifndef WINDOWS
175 	LOCK(mTime);
176 #endif
177 
178 	time(&my_time);
179 	pstruct_time = localtime(&my_time);
180 	if (pstruct_time != NULL)
181 		memcpy(&struct_time, pstruct_time, sizeof(struct tm));
182 	else
183 		memset(&struct_time, 0, sizeof(struct tm));
184 #ifndef WINDOWS
185 	UNLOCK(mTime);
186 #endif
187 
188 	if ((glb_flags & GLB_FLG_QUIET) && (level == INFO))
189 		return 0;
190 
191 	va_start(l, Msg);
192 
193 	if (glb_flags & GLB_FLG_SUPRESS) {
194 		rv = vprintf(Msg, l);
195 		va_end(l);
196 		return rv;
197 	}
198 
199 	switch (level) {
200 	case START:
201 		strcpy(levelStr, "START");
202 		break;
203 	case END:
204 		strcpy(levelStr, "END  ");
205 		break;
206 	case STAT:
207 		strcpy(levelStr, "STAT ");
208 		break;
209 	case INFO:
210 		strcpy(levelStr, "INFO ");
211 		break;
212 	case DBUG:
213 		strcpy(levelStr, "DEBUG");
214 		break;
215 	case WARN:
216 		strcpy(levelStr, "WARN ");
217 		break;
218 	case ERR:
219 		strcpy(levelStr, "ERROR");
220 		break;
221 	}
222 
223 	sprintf(time_str, TIME_FORMAT, struct_time.tm_year + 1900,
224 		struct_time.tm_mon + 1,
225 		struct_time.tm_mday,
226 		struct_time.tm_hour, struct_time.tm_min, struct_time.tm_sec);
227 
228 	len += strlen(FORMAT);
229 	len += strlen(time_str);
230 	len += strlen(levelStr);
231 	len += sizeof(pid_t) * 8 + 1;
232 	len += strlen(VER_STR);
233 	len += strlen(args->device);
234 	len += strlen(Msg);
235 
236 	if ((cpTheMsg = (char *)ALLOC(len)) == NULL) {
237 		printf
238 		    ("Can't print formatted message, printing message raw.\n");
239 		rv = vprintf(Msg, l);
240 		va_end(l);
241 		return rv;
242 	}
243 
244 	memset(cpTheMsg, 0, len);
245 	sprintf(cpTheMsg, FORMAT, time_str, levelStr, args->pid, VER_STR,
246 		args->device, Msg);
247 
248 	rv = vprintf(cpTheMsg, l);
249 	FREE(cpTheMsg);
250 
251 	va_end(l);
252 	return rv;
253 }
254 
getByteOrderedData(const OFF_T data)255 OFF_T getByteOrderedData(const OFF_T data)
256 {
257 	OFF_T off_tpat = 0;
258 
259 #ifdef WINDOWS
260 	unsigned char *ucharpattern;
261 	size_t i = 0;
262 
263 	ucharpattern = (unsigned char *)&data;
264 	for (i = 0; i < sizeof(OFF_T); i++) {
265 		off_tpat |=
266 		    (((OFF_T) (ucharpattern[i])) << sizeof(OFF_T) *
267 		     ((sizeof(OFF_T) - 1) - i));
268 	}
269 #endif
270 
271 #ifdef AIX
272 	off_tpat = data;
273 #endif
274 
275 #ifdef LINUX
276 #if __BYTE_ORDER == __LITTLE_ENDIAN
277 	unsigned char *ucharpattern;
278 	size_t i = 0;
279 
280 	ucharpattern = (unsigned char *)&data;
281 	for (i = 0; i < sizeof(OFF_T); i++) {
282 		off_tpat |=
283 		    (((OFF_T) (ucharpattern[i])) << sizeof(OFF_T) *
284 		     ((sizeof(OFF_T) - 1) - i));
285 	}
286 #else
287 	off_tpat = data;
288 #endif
289 #endif
290 
291 	return off_tpat;
292 }
293 
mark_buffer(void * buf,const size_t buf_len,void * lba,const child_args_t * args,const test_env_t * env)294 void mark_buffer(void *buf, const size_t buf_len, void *lba,
295 		 const child_args_t * args, const test_env_t * env)
296 {
297 	OFF_T *plocal_lba = lba;
298 	OFF_T local_lba = *plocal_lba;
299 	OFF_T *off_tbuf = buf;
300 	OFF_T off_tpat = 0, off_tpat2 = 0, off_tpat3 = 0, off_tpat4 = 0;
301 	OFF_T pass_count = env->pass_count;
302 	OFF_T start_time = (OFF_T) env->start_time;
303 	unsigned char *ucharBuf = (unsigned char *)buf;
304 	size_t i = 0;
305 	extern char hostname[];
306 
307 	off_tpat2 = getByteOrderedData(pass_count);
308 	if (args->flags & CLD_FLG_ALT_MARK) {
309 		off_tpat3 = getByteOrderedData(args->alt_mark);
310 	} else {
311 		off_tpat3 = getByteOrderedData(start_time);
312 	}
313 	off_tpat4 = getByteOrderedData(args->seed);
314 
315 	for (i = 0; i < buf_len; i = i + BLK_SIZE) {
316 		if (args->flags & CLD_FLG_MRK_LBA) {
317 			/* fill first 8 bytes with lba number */
318 			off_tpat = getByteOrderedData(local_lba);
319 			*(off_tbuf + (i / sizeof(OFF_T))) = off_tpat;
320 		}
321 		if (args->flags & CLD_FLG_MRK_PASS) {
322 			/* fill second 8 bytes with pass_count */
323 			*(off_tbuf + (i / sizeof(OFF_T)) + 1) = off_tpat2;
324 		}
325 		if (args->flags & CLD_FLG_MRK_TIME) {
326 			/* fill third 8 bytes with start_time */
327 			*(off_tbuf + (i / sizeof(OFF_T)) + 2) = off_tpat3;
328 		}
329 		if (args->flags & CLD_FLG_MRK_SEED) {
330 			/* fill fourth 8 bytes with seed data */
331 			*(off_tbuf + (i / sizeof(OFF_T)) + 3) = off_tpat4;
332 		}
333 		if (args->flags & CLD_FLG_MRK_HOST) {
334 			/* now add the hostname to the mark data */
335 			memcpy(ucharBuf + 32 + i, hostname, HOSTNAME_SIZE);
336 		}
337 		if (args->flags & CLD_FLG_MRK_TARGET) {
338 			/* now add the target to the mark data */
339 			memcpy(ucharBuf + 32 + HOSTNAME_SIZE + i, args->device,
340 			       strlen(args->device));
341 		}
342 
343 		local_lba++;
344 	}
345 }
346 
347 /*
348 * function fill_buffer
349 * This function fills the passed buffer with data based on the pattern and patten type.
350 * for pattern types of counting the pattern does not matter.  For lba pattern type, the
351 * pattern will be the address of the lba.
352 */
353 
fill_buffer(void * buf,size_t len,void * pattern,size_t pattern_len,const unsigned int pattern_type)354 void fill_buffer(void *buf, size_t len, void *pattern, size_t pattern_len,
355 		 const unsigned int pattern_type)
356 {
357 	size_t i, j;
358 	unsigned char *ucharbuf = buf;
359 	OFF_T *off_tbuf = buf;
360 	unsigned char *ucharpattern = pattern;
361 	OFF_T *poff_tpattern = pattern;
362 	OFF_T off_tpat, off_tpat2;
363 
364 	switch (pattern_type) {	/* the pattern type should only be one of the following */
365 	case CLD_FLG_CPTYPE:
366 		/* Will fill buffer with counting pattern 0x00 thru 0xff */
367 		for (i = 0; i < len; i++)
368 			ucharbuf[i] = (unsigned char)(i & 0xff);
369 		break;
370 	case CLD_FLG_FPTYPE:
371 		/* arrange data to go on the wire correctly */
372 		off_tpat = 0;
373 		for (j = 0; j < (sizeof(OFF_T) / pattern_len); j++)
374 			for (i = 0; i < pattern_len; ++i)
375 #ifdef WINDOWS
376 				off_tpat |=
377 				    (((OFF_T) (ucharpattern[i])) << 8 *
378 				     (7 - ((j * pattern_len) + i)));
379 #endif
380 #ifdef AIX
381 		off_tpat |=
382 		    (((OFF_T) (ucharpattern[(8 - pattern_len) + i])) << 8 *
383 		     (7 - ((j * pattern_len) + i)));
384 #endif
385 #ifdef LINUX
386 #if __BYTE_ORDER == __LITTLE_ENDIAN
387 		off_tpat |=
388 		    (((OFF_T) (ucharpattern[i])) << 8 *
389 		     (7 - ((j * pattern_len) + i)));
390 #else
391 		off_tpat |=
392 		    (((OFF_T) (ucharpattern[(8 - pattern_len) + i])) << 8 *
393 		     (7 - ((j * pattern_len) + i)));
394 #endif
395 #endif
396 
397 		/* fill buffer with fixed pattern */
398 		for (i = 0; i < len / 8; i++)
399 			*(off_tbuf + i) = off_tpat;
400 		break;
401 	case CLD_FLG_LPTYPE:
402 		off_tpat2 = *poff_tpattern;
403 		for (j = 0; j < len; j++) {
404 			/* arrange data to go on the wire correctly */
405 			ucharpattern = (unsigned char *)&off_tpat2;
406 			off_tpat = 0;
407 			for (i = 0; i < pattern_len; i++)
408 #ifdef WINDOWS
409 				off_tpat |=
410 				    (((OFF_T) (ucharpattern[i])) << 8 *
411 				     (7 - i));
412 #endif
413 #ifdef AIX
414 			off_tpat |=
415 			    (((OFF_T) (ucharpattern[(8 - pattern_len) + i])) <<
416 			     8 * (7 - i));
417 #endif
418 #ifdef LINUX
419 #if __BYTE_ORDER == __LITTLE_ENDIAN
420 			off_tpat |=
421 			    (((OFF_T) (ucharpattern[i])) << 8 * (7 - i));
422 #else
423 			off_tpat |=
424 			    (((OFF_T) (ucharpattern[(8 - pattern_len) + i])) <<
425 			     8 * (7 - i));
426 #endif
427 #endif
428 
429 			/* fill buffer with lba number */
430 			for (i = 0; i < BLK_SIZE / 8; i++) {
431 				*(off_tbuf + i + (j * (BLK_SIZE / 8))) =
432 				    off_tpat;
433 			}
434 			off_tpat2++;
435 		}
436 		break;
437 	case CLD_FLG_RPTYPE:
438 		/* Will fill buffer with a random pattern.
439 		 * Unfortunatly, every LBA, 512 bytes of data will be
440 		 * the same random data set, this is due to the LBA
441 		 * boundary requirement of disktest.  This should be fixed
442 		 * at some point...
443 		 */
444 		for (i = 0; i < BLK_SIZE / sizeof(OFF_T); i++)
445 			*(off_tbuf + i) = Rand64();
446 
447 		for (i = BLK_SIZE; i < len; i += BLK_SIZE)
448 			memcpy((ucharbuf + i), ucharbuf, BLK_SIZE);
449 		break;
450 	default:
451 		printf("Unknown fill pattern\n");
452 		exit(1);
453 	}
454 }
455 
normalize_percs(child_args_t * args)456 void normalize_percs(child_args_t * args)
457 {
458 	int i, j;
459 
460 	if ((args->flags & CLD_FLG_R) && !(args->flags & CLD_FLG_W)) {
461 		if ((args->flags & CLD_FLG_DUTY) && (args->rperc < 100)) {
462 			pMsg(WARN, args,
463 			     "Read specified w/o write, ignoring -D, forcing read only...\n");
464 		}
465 		args->rperc = 100;
466 		args->wperc = 0;
467 	} else if ((args->flags & CLD_FLG_W) && !(args->flags & CLD_FLG_R)) {
468 		if ((args->flags & CLD_FLG_DUTY) && (args->wperc < 100)) {
469 			pMsg(WARN, args,
470 			     "Write specified w/o read, ignoring -D, forcing write only...\n");
471 		}
472 		args->rperc = 0;
473 		args->wperc = 100;
474 	} else {		/* must be reading and writing */
475 		if (args->rperc == 0 && args->wperc == 0) {
476 			args->rperc = 50;
477 			args->wperc = 50;
478 		} else if (args->rperc == 0) {
479 			args->rperc = 100 - args->wperc;
480 		} else if (args->wperc == 0) {
481 			args->wperc = 100 - args->rperc;
482 		}
483 	}
484 
485 	if (args->rperc + args->wperc != 100) {
486 		pMsg(INFO, args,
487 		     "Balancing percentage between reads and writes\n");
488 		if ((args->flags & CLD_FLG_R) && (args->flags & CLD_FLG_W)) {
489 			i = 100 - (args->rperc + args->wperc);
490 			j = i / 2;
491 			args->wperc += j;
492 			args->rperc += (i - j);
493 		}
494 	}
495 }
496 
497 #ifndef WINDOWS
strupr(char * String)498 char *strupr(char *String)
499 {
500 	unsigned int i;
501 
502 	for (i = 0; i < strlen(String); i++) {
503 		*(String + i) = toupper(*(String + i));
504 	}
505 	return (String);
506 }
507 
strlwr(char * String)508 char *strlwr(char *String)
509 {
510 	unsigned int i;
511 
512 	for (i = 0; i < strlen(String); i++) {
513 		*(String + i) = tolower(*(String + i));
514 	}
515 	return (String);
516 }
517 #endif
518 
get_file_size(char * device)519 OFF_T get_file_size(char *device)
520 {
521 	OFF_T size = 0;
522 	fd_t fd;
523 
524 #ifdef WINDOWS
525 	SetLastError(0);
526 
527 	fd = CreateFile(device,
528 			GENERIC_READ,
529 			FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
530 #else
531 	fd = open(device, 0);
532 #endif
533 
534 	if (INVALID_FD(fd)) {
535 		return size;
536 	}
537 
538 	size = SeekEnd(fd);
539 	size /= BLK_SIZE;
540 
541 	CLOSE(fd);
542 	return size;
543 }
544 
get_vsiz(const char * device)545 OFF_T get_vsiz(const char *device)
546 {
547 #ifdef PPC
548 	unsigned long size = 0;
549 #else
550 	OFF_T size = 0;
551 #endif
552 
553 #ifdef WINDOWS
554 	HANDLE hFileHandle;
555 	BOOL bRV;
556 	DWORD dwLength;
557 	GET_LENGTH_INFORMATION myLengthInfo;
558 	DISK_GEOMETRY DiskGeom;
559 
560 	hFileHandle = CreateFile(device,
561 				 GENERIC_READ,
562 				 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
563 
564 	if (hFileHandle == INVALID_HANDLE_VALUE) {
565 		return (GetLastError());
566 	}
567 
568 	SetLastError(0);
569 	bRV = DeviceIoControl(hFileHandle,
570 			      IOCTL_DISK_GET_LENGTH_INFO,
571 			      NULL,
572 			      0,
573 			      &myLengthInfo,
574 			      sizeof(GET_LENGTH_INFORMATION), &dwLength, NULL);
575 
576 	if (bRV) {
577 		size = myLengthInfo.Length.QuadPart;
578 		size /= BLK_SIZE;	/* return requires BLOCK */
579 	} else {
580 		bRV = DeviceIoControl(hFileHandle,
581 				      IOCTL_DISK_GET_DRIVE_GEOMETRY,
582 				      NULL,
583 				      0,
584 				      &DiskGeom,
585 				      sizeof(DISK_GEOMETRY), &dwLength, NULL);
586 
587 		if (bRV) {
588 			size = (OFF_T) DiskGeom.Cylinders.QuadPart;
589 			size *= (OFF_T) DiskGeom.TracksPerCylinder;
590 			size *= (OFF_T) DiskGeom.SectorsPerTrack;
591 		} else {
592 			size = 0;
593 		}
594 	}
595 	CloseHandle(hFileHandle);
596 #else
597 	int fd = 0;
598 #if AIX
599 	struct devinfo *my_devinfo = NULL;
600 	unsigned long ulSizeTmp;
601 #endif
602 
603 	if ((fd = open(device, 0)) < 0) {
604 		return 0;
605 	}
606 #if AIX
607 	my_devinfo = (struct devinfo *)ALLOC(sizeof(struct devinfo));
608 	if (my_devinfo != NULL) {
609 		memset(my_devinfo, 0, sizeof(struct devinfo));
610 		if (ioctl(fd, IOCINFO, my_devinfo) == -1)
611 			size = -1;
612 		else {
613 			if (my_devinfo->flags & DF_LGDSK) {
614 				ulSizeTmp =
615 				    (unsigned long)my_devinfo->un.scdk64.
616 				    hi_numblks;
617 				size |=
618 				    ((((OFF_T) ulSizeTmp) << 32) &
619 				     0xFFFFFFFF00000000ll);
620 				ulSizeTmp =
621 				    (unsigned long)my_devinfo->un.scdk64.
622 				    lo_numblks;
623 				size |=
624 				    (((OFF_T) ulSizeTmp) &
625 				     0x00000000FFFFFFFFll);
626 			} else {
627 				ulSizeTmp =
628 				    (unsigned long)my_devinfo->un.scdk.numblks;
629 				size |=
630 				    (((OFF_T) ulSizeTmp) &
631 				     0x00000000FFFFFFFFll);
632 			}
633 		}
634 		FREE(my_devinfo);
635 	}
636 #else
637 	if (ioctl(fd, BLKGETSIZE, &size) == -1)
638 		size = -1;
639 #endif
640 
641 	close(fd);
642 #endif
643 
644 #ifdef PPC
645 	return ((OFF_T) size);
646 #else
647 	return (size);
648 #endif
649 }
650 
651 #ifndef WINDOWS
Sleep(unsigned int msecs)652 void Sleep(unsigned int msecs)
653 {
654 	usleep(msecs * 1000);
655 }
656 #endif
657 
format_time(time_t seconds)658 fmt_time_t format_time(time_t seconds)
659 {
660 	fmt_time_t time_struct;
661 
662 	time_struct.days = seconds / 86400;
663 	time_struct.hours = (seconds % 86400) / 3600;
664 	time_struct.minutes = (seconds % 3600) / 60;
665 	time_struct.seconds = seconds % 60;
666 
667 	return time_struct;
668 }
669