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