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 (at) 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 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 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 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 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 652 void Sleep(unsigned int msecs) 653 { 654 usleep(msecs * 1000); 655 } 656 #endif 657 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