sfunc.c revision ec6edca7aa42b6affd989ef91b5897f96795e40f
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 */
66long 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 */
84OFF_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*/
101OFF_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) bHex = 1;
115				continue;
116			case ' ':
117			case '\t':
118				continue;
119			case '-':
120				neg = 1;
121				/*FALLTHROUGH*/
122			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*/
153int 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,
227		struct_time.tm_min,
228		struct_time.tm_sec
229	);
230
231	len += strlen(FORMAT);
232	len += strlen(time_str);
233	len += strlen(levelStr);
234	len += sizeof(pid_t)*8 + 1;
235	len += strlen(VER_STR);
236	len += strlen(args->device);
237	len += strlen(Msg);
238
239	if ((cpTheMsg = (char *)ALLOC(len)) == NULL) {
240		printf("Can't print formatted message, printing message raw.\n");
241		rv = vprintf(Msg,l);
242		va_end(l);
243		return rv;
244	}
245
246	memset(cpTheMsg, 0, len);
247	sprintf(cpTheMsg, FORMAT, time_str, levelStr, args->pid, VER_STR, args->device, Msg);
248
249	rv = vprintf(cpTheMsg,l);
250	FREE(cpTheMsg);
251
252	va_end(l);
253	return rv;
254}
255
256OFF_T getByteOrderedData(const OFF_T data)
257{
258	OFF_T off_tpat = 0;
259
260#ifdef WINDOWS
261	unsigned char *ucharpattern;
262	size_t i = 0;
263
264	ucharpattern = (unsigned char *) &data;
265	for (i=0;i<sizeof(OFF_T);i++) {
266		off_tpat |= (((OFF_T)(ucharpattern[i])) << sizeof(OFF_T)*((sizeof(OFF_T)-1)-i));
267	}
268#endif
269
270#ifdef AIX
271	off_tpat = data;
272#endif
273
274#ifdef LINUX
275#if __BYTE_ORDER == __LITTLE_ENDIAN
276	unsigned char *ucharpattern;
277	size_t i = 0;
278
279	ucharpattern = (unsigned char *) &data;
280	for (i=0;i<sizeof(OFF_T);i++) {
281		off_tpat |= (((OFF_T)(ucharpattern[i])) << sizeof(OFF_T)*((sizeof(OFF_T)-1)-i));
282	}
283#else
284	off_tpat = data;
285#endif
286#endif
287
288	return off_tpat;
289}
290
291void mark_buffer(void *buf, const size_t buf_len, void *lba, const child_args_t *args, const test_env_t *env)
292{
293	OFF_T *plocal_lba = lba;
294	OFF_T local_lba = *plocal_lba;
295	OFF_T *off_tbuf = buf;
296	OFF_T off_tpat = 0, off_tpat2 = 0, off_tpat3 = 0, off_tpat4 = 0;
297	OFF_T pass_count = env->pass_count;
298	OFF_T start_time = (OFF_T)env->start_time;
299	unsigned char * ucharBuf = (unsigned char *)buf;
300	size_t i = 0;
301	extern char hostname[];
302
303	off_tpat2 = getByteOrderedData(pass_count);
304	if (args->flags & CLD_FLG_ALT_MARK) {
305		off_tpat3 = getByteOrderedData(args->alt_mark);
306	} else {
307		off_tpat3 = getByteOrderedData(start_time);
308	}
309	off_tpat4 = getByteOrderedData(args->seed);
310
311	for (i=0;i<buf_len;i=i+BLK_SIZE) {
312		if (args->flags & CLD_FLG_MRK_LBA) {
313			/* fill first 8 bytes with lba number */
314			off_tpat = getByteOrderedData(local_lba);
315			*(off_tbuf+(i/sizeof(OFF_T))) = off_tpat;
316		}
317		if (args->flags & CLD_FLG_MRK_PASS) {
318			/* fill second 8 bytes with pass_count */
319			*(off_tbuf+(i/sizeof(OFF_T))+1) = off_tpat2;
320		}
321		if (args->flags & CLD_FLG_MRK_TIME) {
322			/* fill third 8 bytes with start_time */
323			*(off_tbuf+(i/sizeof(OFF_T))+2) = off_tpat3;
324		}
325		if (args->flags & CLD_FLG_MRK_SEED) {
326			/* fill fourth 8 bytes with seed data */
327			*(off_tbuf+(i/sizeof(OFF_T))+3) = off_tpat4;
328		}
329		if (args->flags & CLD_FLG_MRK_HOST) {
330			/* now add the hostname to the mark data */
331			memcpy(ucharBuf+32+i, hostname, HOSTNAME_SIZE);
332		}
333		if (args->flags & CLD_FLG_MRK_TARGET) {
334			/* now add the target to the mark data */
335			memcpy(ucharBuf+32+HOSTNAME_SIZE+i, args->device, strlen(args->device));
336		}
337
338		local_lba++;
339	}
340}
341
342/*
343* function fill_buffer
344* This function fills the passed buffer with data based on the pattern and patten type.
345* for pattern types of counting the pattern does not matter.  For lba pattern type, the
346* pattern will be the address of the lba.
347*/
348
349void fill_buffer(void *buf, size_t len, void *pattern, size_t pattern_len, const unsigned int pattern_type)
350{
351	size_t i, j;
352	unsigned char *ucharbuf = buf;
353	OFF_T *off_tbuf = buf;
354	unsigned char *ucharpattern = pattern;
355	OFF_T *poff_tpattern = pattern;
356	OFF_T off_tpat, off_tpat2;
357
358	switch (pattern_type) { /* the pattern type should only be one of the following */
359		case CLD_FLG_CPTYPE :
360			/* Will fill buffer with counting pattern 0x00 thru 0xff */
361			for (i=0;i<len;i++)
362				ucharbuf[i] = (unsigned char) (i & 0xff);
363			break;
364		case CLD_FLG_FPTYPE :
365			/* arrange data to go on the wire correctly */
366			off_tpat = 0;
367			for (j=0;j<(sizeof(OFF_T)/pattern_len);j++)
368				for (i=0;i<pattern_len;++i)
369#ifdef WINDOWS
370					off_tpat |= (((OFF_T)(ucharpattern[i])) << 8*(7-((j*pattern_len)+i)));
371#endif
372#ifdef AIX
373					off_tpat |= (((OFF_T)(ucharpattern[(8-pattern_len)+i])) << 8*(7-((j*pattern_len)+i)));
374#endif
375#ifdef LINUX
376#if __BYTE_ORDER == __LITTLE_ENDIAN
377					off_tpat |= (((OFF_T)(ucharpattern[i])) << 8*(7-((j*pattern_len)+i)));
378#else
379					off_tpat |= (((OFF_T)(ucharpattern[(8-pattern_len)+i])) << 8*(7-((j*pattern_len)+i)));
380#endif
381#endif
382
383			/* fill buffer with fixed pattern */
384			for (i=0;i<len/8;i++)
385				*(off_tbuf+i) = off_tpat;
386			break;
387		case CLD_FLG_LPTYPE :
388			off_tpat2 = *poff_tpattern;
389			for (j=0;j<len;j++) {
390				/* arrange data to go on the wire correctly */
391				ucharpattern = (unsigned char *) &off_tpat2;
392				off_tpat = 0;
393				for (i=0;i<pattern_len;i++)
394#ifdef WINDOWS
395					off_tpat |= (((OFF_T)(ucharpattern[i])) << 8*(7-i));
396#endif
397#ifdef AIX
398					off_tpat |= (((OFF_T)(ucharpattern[(8-pattern_len)+i])) << 8*(7-i));
399#endif
400#ifdef LINUX
401#if __BYTE_ORDER == __LITTLE_ENDIAN
402					off_tpat |= (((OFF_T)(ucharpattern[i])) << 8*(7-i));
403#else
404					off_tpat |= (((OFF_T)(ucharpattern[(8-pattern_len)+i])) << 8*(7-i));
405#endif
406#endif
407
408				/* fill buffer with lba number */
409				for (i=0;i<BLK_SIZE/8;i++) {
410					*(off_tbuf+i+(j*(BLK_SIZE/8))) = off_tpat;
411				}
412				off_tpat2++;
413			}
414			break;
415		case CLD_FLG_RPTYPE :
416			/* Will fill buffer with a random pattern.
417			 * Unfortunatly, every LBA, 512 bytes of data will be
418			 * the same random data set, this is due to the LBA
419			 * boundary requirement of disktest.  This should be fixed
420			 * at some point...
421			 */
422			for (i=0;i<BLK_SIZE/sizeof(OFF_T);i++)
423				*(off_tbuf+i) = Rand64();
424
425			for (i=BLK_SIZE;i<len;i+=BLK_SIZE)
426				memcpy((ucharbuf+i), ucharbuf, BLK_SIZE);
427			break;
428		default :
429			printf("Unknown fill pattern\n");
430			exit(1);
431	}
432}
433
434void normalize_percs(child_args_t *args)
435{
436	int i, j;
437
438	if ((args->flags & CLD_FLG_R) && !(args->flags & CLD_FLG_W)) {
439		if ((args->flags & CLD_FLG_DUTY) && (args->rperc < 100)) {
440			pMsg(WARN, args, "Read specified w/o write, ignoring -D, forcing read only...\n");
441		}
442		args->rperc = 100;
443		args->wperc = 0;
444	} else if ((args->flags & CLD_FLG_W) && !(args->flags & CLD_FLG_R)) {
445		if ((args->flags & CLD_FLG_DUTY) && (args->wperc < 100)) {
446			pMsg(WARN, args, "Write specified w/o read, ignoring -D, forcing write only...\n");
447		}
448		args->rperc = 0;
449		args->wperc = 100;
450	} else { /* must be reading and writing */
451		if (args->rperc == 0 && args->wperc == 0) {
452			args->rperc = 50;
453			args->wperc = 50;
454		} else if (args->rperc == 0) {
455			args->rperc = 100 - args->wperc;
456		} else if (args->wperc == 0) {
457			args->wperc = 100 - args->rperc;
458		}
459	}
460
461	if (args->rperc + args->wperc != 100) {
462		pMsg(INFO, args, "Balancing percentage between reads and writes\n");
463		if ((args->flags & CLD_FLG_R) && (args->flags & CLD_FLG_W)) {
464			i = 100 - (args->rperc + args->wperc);
465			j = i / 2;
466			args->wperc += j;
467			args->rperc += (i - j);
468		}
469	}
470}
471
472#ifndef WINDOWS
473char *strupr(char *String) {
474	unsigned int i;
475
476	for (i=0;i<strlen(String);i++) {
477		*(String+i) = toupper(*(String+i));
478	}
479	return(String);
480}
481
482char *strlwr(char *String) {
483	unsigned int i;
484
485	for (i=0;i<strlen(String);i++) {
486		*(String+i) = tolower(*(String+i));
487	}
488	return(String);
489}
490#endif
491
492OFF_T get_file_size(char *device) {
493	OFF_T size = 0;
494	fd_t fd;
495
496#ifdef WINDOWS
497	SetLastError(0);
498
499	fd = CreateFile(device,
500		GENERIC_READ,
501		FILE_SHARE_READ,
502		NULL,
503		OPEN_EXISTING,
504		0,
505		NULL);
506#else
507	fd = open(device, 0);
508#endif
509
510	if (INVALID_FD(fd)) {
511		return size;
512	}
513
514	size = SeekEnd(fd);
515	size /= BLK_SIZE;
516
517	CLOSE(fd);
518	return size;
519}
520
521OFF_T get_vsiz(const char *device)
522{
523#ifdef PPC
524	unsigned long size = 0;
525#else
526	OFF_T size = 0;
527#endif
528
529#ifdef WINDOWS
530	HANDLE hFileHandle;
531	BOOL bRV;
532	DWORD dwLength;
533	GET_LENGTH_INFORMATION myLengthInfo;
534	DISK_GEOMETRY DiskGeom;
535
536	hFileHandle = CreateFile(device,
537		GENERIC_READ,
538		FILE_SHARE_READ,
539		NULL,
540		OPEN_EXISTING,
541		0,
542		NULL);
543
544	if (hFileHandle == INVALID_HANDLE_VALUE) {
545		return(GetLastError());
546	}
547
548	SetLastError(0);
549	bRV = DeviceIoControl(hFileHandle,
550		IOCTL_DISK_GET_LENGTH_INFO,
551		NULL,
552		0,
553		&myLengthInfo,
554		sizeof(GET_LENGTH_INFORMATION),
555		&dwLength,
556		NULL);
557
558	if (bRV) {
559		size = myLengthInfo.Length.QuadPart;
560		size /= BLK_SIZE; /* return requires BLOCK */
561	} else {
562		bRV = DeviceIoControl(hFileHandle,
563			IOCTL_DISK_GET_DRIVE_GEOMETRY,
564			NULL,
565			0,
566			&DiskGeom,
567			sizeof(DISK_GEOMETRY),
568			&dwLength,
569			NULL);
570
571		if (bRV) {
572			size =  (OFF_T) DiskGeom.Cylinders.QuadPart;
573			size *= (OFF_T) DiskGeom.TracksPerCylinder;
574			size *= (OFF_T) DiskGeom.SectorsPerTrack;
575		} else {
576			size = 0;
577		}
578	}
579	CloseHandle(hFileHandle);
580#else
581	int fd = 0;
582#if AIX
583	struct devinfo *my_devinfo = NULL;
584	unsigned long ulSizeTmp;
585#endif
586
587	if ((fd = open(device, 0)) < 0) {
588		return 0;
589	}
590
591#if AIX
592	my_devinfo = (struct devinfo*) ALLOC(sizeof(struct devinfo));
593	if (my_devinfo != NULL) {
594		memset(my_devinfo, 0, sizeof(struct devinfo));
595		if (ioctl(fd, IOCINFO, my_devinfo) == -1) size = -1;
596		else {
597			if (my_devinfo->flags & DF_LGDSK) {
598				ulSizeTmp = (unsigned long) my_devinfo->un.scdk64.hi_numblks;
599				size |= ((((OFF_T)ulSizeTmp) << 32) & 0xFFFFFFFF00000000ll);
600				ulSizeTmp = (unsigned long) my_devinfo->un.scdk64.lo_numblks;
601				size |= (((OFF_T) ulSizeTmp) & 0x00000000FFFFFFFFll);
602			} else {
603				ulSizeTmp = (unsigned long) my_devinfo->un.scdk.numblks;
604				size |= (((OFF_T) ulSizeTmp) & 0x00000000FFFFFFFFll);
605			}
606		}
607		FREE(my_devinfo);
608	}
609#else
610	if (ioctl(fd, BLKGETSIZE, &size) == -1) size = -1;
611#endif
612
613	close(fd);
614#endif
615
616#ifdef PPC
617	return((OFF_T)size);
618#else
619	return(size);
620#endif
621}
622
623#ifndef WINDOWS
624void Sleep(unsigned int msecs)
625{
626	usleep(msecs*1000);
627}
628#endif
629
630fmt_time_t format_time(time_t seconds)
631{
632	fmt_time_t time_struct;
633
634	time_struct.days    = seconds/86400;
635	time_struct.hours   = (seconds%86400)/3600;
636	time_struct.minutes = (seconds%3600)/60;
637	time_struct.seconds = seconds%60;
638
639	return time_struct;
640}
641