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