1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* #include <version.h> SKK */ 27 #include <errno.h> 28 #include <sys/types.h> 29 #include <sys/time.h> 30 #include <sys/param.h> 31 #include <sys/inttypes.h> 32 #include <stdio.h> 33 #include <strings.h> 34 #include <fcntl.h> 35 #include <sys/shm.h> 36 #include <sys/wait.h> 37 #include <unistd.h> 38 #include <nsctl.h> 39 40 #include <sys/nsctl/sd_cache.h> 41 #include <sys/nsctl/sd_conf.h> 42 43 #include <stdlib.h> 44 #include <thread.h> 45 #include <synch.h> 46 47 #define MAXPARTS 100 /* Max disks */ 48 #define MAXBUF 65536 /* Max buffer size in long words */ 49 #define DISKLIST "disk_config" /* Default config file */ 50 #define DEF_SIZE 8192 /* Default buffer size */ 51 #define DEF_LOOP 1000 /* Loops for test */ 52 #define RAND_LOOPS DEF_LOOP /* # of random ios to do */ 53 54 /* 55 * >>>>>>>>> USER LEVEL SD CACHE DIAGNOSTICS <<<<<<<<<< 56 * 57 * Write and read data blocks w/multiple processes 58 * Starts one process for each partition specified in 59 * the config file 60 */ 61 62 int buf1[MAXBUF]; 63 int buf2[MAXBUF]; 64 char name[MAXPARTS][80]; 65 int pattern[MAXPARTS]; 66 int bufsize = DEF_SIZE; 67 int fba_num_bufsize; 68 nsc_size_t loops = DEF_LOOP; 69 nsc_size_t r_loops = RAND_LOOPS; 70 int fsize = -1; 71 int readercount = 3; 72 int Rflag = O_EXCL; 73 char config_file[32]; 74 75 int 76 read_parts() 77 { 78 FILE *dfile; 79 int partitions = 0; 80 int i; 81 82 dfile = fopen(config_file, "r"); 83 if (dfile == NULL) { 84 (void) printf("cannot open file: %s\n", config_file); 85 perror("fopen"); 86 exit(errno); 87 } 88 for (i = 0; i < MAXPARTS; i++) { 89 if (fscanf(dfile, "%s %x", name[i], (uint_t *)&pattern[i]) == 90 EOF) { 91 break; 92 } else 93 if (name[i][0] == '#' || strchr(name[i], '/') == NULL) { 94 i--; 95 continue; 96 } 97 partitions++; 98 } 99 (void) fclose(dfile); 100 (void) printf("No. of partitions listed in file '%s' = %d\n\n", 101 config_file, partitions); 102 return (partitions); 103 } 104 105 void 106 print_usage() 107 { 108 (void) printf("Usage:\n"); 109 (void) printf( 110 "sd_diag [-R] [-b <bufsize>] [-d <datasize>] [-l <loops>] [-r <readers>]\n"); 111 (void) printf( 112 " [-f <disk_config_file>] <test#>\n"); 113 (void) printf(" test 1 = random read/write\n"); 114 (void) printf(" 2 = random read/write/verify, read after write\n"); 115 (void) printf(" 3 = random read/write/verify,"); 116 (void) printf(" all reads after all writes\n"); 117 (void) printf(" 4 = sequential read/write\n"); 118 (void) printf(" 5 = sequential write/read/verify,"); 119 (void) printf(" all reads after all writes\n"); 120 (void) printf( 121 " 6 = altenating top/bottom sequential read/write/verify\n"); 122 (void) printf(" 7 = multiple readers/1 random writer\n"); 123 (void) printf(" 8 = random writes\n"); 124 (void) printf(" 9 = sequential write of known data\n"); 125 (void) printf(" 10 = sequential copy of datasize disk/verify\n"); 126 (void) printf(" 11 = sequential read/verify test 9 data -"); 127 (void) printf(" then clear data with timestamp\n"); 128 (void) printf(" 12 = sequential read/verify test 9 data -"); 129 (void) printf(" no clear data\n"); 130 (void) printf("\n"); 131 (void) printf(" <bufsize> in bytes (minimum is 512 bytes)\n"); 132 (void) printf(" <datasize> in Mbytes per disk\n"); 133 (void) printf(" <loops> is count of reads/writes,\n"); 134 (void) printf(" loops = 0 tests entire datasize disk"); 135 (void) printf(" for sequential tests.\n"); 136 (void) printf(" loops = 0 performs %d I/Os for the random " 137 "tests\n", RAND_LOOPS); 138 (void) printf(" <readers> is count of readers for test #7 (default " 139 "is 3).\n"); 140 (void) printf(" [ defaults: bufsize = %d bytes, loops = %d,", 141 DEF_SIZE, DEF_LOOP); 142 (void) printf(" datasize = disksize ]\n"); 143 (void) printf("\n"); 144 (void) printf(" -R : do nsc_reserve(), nsc_release(0 around each " 145 "I/O\n"); 146 } 147 148 void 149 parse_opts(int argc, char *argv[]) 150 { 151 extern char *optarg; 152 int c; 153 154 while ((c = getopt(argc, argv, "b:d:l:r:Rf:")) != -1) { 155 switch (c) { 156 case 'f': 157 /* printf("\n%s", optarg); */ 158 strcpy(config_file, optarg); 159 break; 160 case 'b': 161 /* bufsize between 1*512 and 512*512 */ 162 bufsize = strtol(optarg, 0, 0); 163 if (bufsize > (MAXBUF*4)) 164 bufsize = MAXBUF*4; 165 else if (bufsize < FBA_SIZE(1)) 166 bufsize = FBA_SIZE(1); 167 break; 168 case 'd': 169 /* convert datasize from Mb's to fba */ 170 fsize = strtol(optarg, 0, 0) * FBA_NUM(1 << 20); 171 break; 172 case 'l': 173 loops = (nsc_size_t)strtoll(optarg, 0, 0); 174 break; 175 case 'r': 176 /* count of readers for test 7 */ 177 readercount = strtol(optarg, 0, 0); 178 break; 179 case 'R': 180 /* do reserve, release on a per io basis */ 181 Rflag = 0; 182 break; 183 case '?': 184 print_usage(); 185 exit(0); 186 } 187 } 188 bufsize &= ~FBA_MASK; /* multiple of 512 bytes for SECTMODE I/O */ 189 fba_num_bufsize = FBA_NUM(bufsize); 190 191 /* set #ios for random io tests */ 192 if (loops != 0) 193 r_loops = loops; 194 195 } 196 197 nsc_size_t 198 set_part_size(char *path, nsc_fd_t *sdfd) 199 { 200 nsc_size_t filesize; 201 int rc; 202 203 rc = nsc_partsize(sdfd, &filesize); /* partsize in FBAs (512 bytes) */ 204 if (rc < 0 || filesize == 0) { 205 (void) fprintf(stderr, 206 "set_part_size: cannot access partition size"); 207 (void) fprintf(stderr, " for %s\n", path); 208 (void) nsc_close(sdfd); 209 exit(1); 210 } 211 212 (void) printf("Partition %s, size:%" NSC_SZFMT " blocks\n", path, 213 filesize); 214 215 if (fsize != -1 && fsize < filesize) 216 filesize = fsize; 217 filesize -= fba_num_bufsize; 218 if (filesize < fba_num_bufsize) { 219 (void) printf("ERROR: Max block size %" NSC_SZFMT "\n", 220 filesize); 221 (void) nsc_close(sdfd); 222 exit(0); 223 } 224 225 return (filesize); 226 } 227 228 int 229 do_sdtest1(int fd, nsc_size_t loops, nsc_size_t filesize) 230 { 231 nsc_off_t seekpos; 232 nsc_size_t i; 233 ssize_t r; 234 235 for (i = 0; i < loops; i++) { 236 seekpos = ( 237 #ifdef NSC_MULTI_TERABYTE 238 ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) | 239 #endif 240 (rand() << 16) | rand()) % filesize; 241 r = pwrite(fd, buf1, bufsize, (off_t)(seekpos << SCTRSHFT)); 242 if (r <= 0) { 243 perror("Test1: write"); 244 return (1); 245 } 246 seekpos = ( 247 #ifdef NSC_MULTI_TERABYTE 248 ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) | 249 #endif 250 (rand() << 16) | rand()) % filesize; 251 r = pread(fd, buf2, bufsize, (off_t)(seekpos << SCTRSHFT)); 252 if (r <= 0) { 253 perror("Test1: read"); 254 return (1); 255 } 256 } 257 return (0); 258 } 259 260 void 261 gen_data(int *buffer, int size) 262 { 263 int i; 264 265 size /= 4; 266 for (i = 0; i < size; i++) 267 buffer[i] = rand() << 16 | rand(); 268 } 269 270 int 271 do_sdtest2(int fd, nsc_size_t loops, nsc_size_t filesize, int h) 272 { 273 nsc_off_t seekpos; 274 int err = 0; 275 ssize_t r; 276 nsc_size_t i; 277 278 for (i = 0; i < loops; i++) { 279 seekpos = ( 280 #ifdef NSC_MULTI_TERABYTE 281 ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) | 282 #endif 283 (rand() << 16) | rand()) % filesize; 284 gen_data(buf1, bufsize); 285 r = pwrite(fd, buf1, bufsize, (off_t)(seekpos << SCTRSHFT)); 286 if (r <= 0) { 287 perror("Test2: write"); 288 err++; 289 return (err); 290 } 291 r = pread(fd, buf2, bufsize, (off_t)(seekpos << SCTRSHFT)); 292 if (r <= 0) { 293 perror("Test2: read"); 294 err++; 295 return (err); 296 } 297 if (memcmp(buf1, buf2, bufsize)) { 298 (void) printf("Test2: Data corruption," 299 " fd:%s, fpos:%" PRId64 ", len:%d\n", 300 name[h], (int64_t)(seekpos << SCTRSHFT), 301 bufsize); 302 err++; 303 } 304 } 305 return (err); 306 } 307 308 int 309 do_sdtest3(int fd, nsc_size_t loops, nsc_size_t filesize, int h, nsc_fd_t *sdfd) 310 { 311 nsc_off_t *seekpos; 312 int err = 0; 313 nsc_size_t i; 314 ssize_t r; 315 316 seekpos = malloc(loops*sizeof (nsc_off_t)); 317 if (seekpos == NULL) { 318 perror("Test3: malloc"); 319 (void) nsc_close(sdfd); 320 exit(errno); 321 } 322 gen_data(buf1, bufsize); 323 324 for (i = 0; i < loops; i++) { 325 seekpos[i] = ( 326 #ifdef NSC_MULTI_TERABYTE 327 ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) | 328 #endif 329 (rand() << 16) | rand()) % filesize; 330 seekpos[i] -= seekpos[i] % fba_num_bufsize; 331 r = pwrite(fd, buf1, bufsize, (off_t)(seekpos[i] << SCTRSHFT)); 332 if (r <= 0) { 333 perror("Test3: write"); 334 err++; 335 goto cleanup; 336 } 337 } 338 for (i = 0; i < loops; i++) { 339 buf2[0] = '\0'; /* clear buf to make sure something is read */ 340 r = pread(fd, buf2, bufsize, (off_t)(seekpos[i] << SCTRSHFT)); 341 if (r <= 0) { 342 perror("Test3: read"); 343 err++; 344 goto cleanup; 345 } 346 if (memcmp(buf1, buf2, bufsize)) { 347 (void) printf("Data corruption, fd:%s, fpos:%" PRId64 348 ", len:%d\n", name[h], 349 (int64_t)(seekpos[i] << SCTRSHFT), bufsize); 350 err++; 351 } 352 } 353 354 cleanup: 355 free(seekpos); 356 return (err); 357 } 358 359 int 360 do_sdtest4(int fd, nsc_size_t loops, nsc_size_t filesize) 361 { 362 ssize_t r; 363 nsc_size_t i; 364 365 /* 366 * Do sequential reads/writes for loops number 367 * of bufsize chunks, unless loops == 0, then do 368 * entire disk. 369 * 1. sequential reads from the top down, 370 * 2. sequential writes from the top down, 371 * 3. sequential reads from the bottom up, 372 * 4. sequential writes from the bottom up. 373 */ 374 if ((loops > (filesize / fba_num_bufsize)) || (!loops)) 375 loops = filesize / fba_num_bufsize; /* entire disk */ 376 377 for (i = 0; i < loops; i++) { 378 r = pread(fd, buf2, bufsize, (i*fba_num_bufsize) << SCTRSHFT); 379 if (r <= 0) { 380 perror("Test4: read"); 381 return (1); 382 } 383 } 384 for (i = 0; i < loops; i++) { 385 r = pwrite(fd, buf1, bufsize, (i*fba_num_bufsize) << SCTRSHFT); 386 if (r <= 0) { 387 perror("Test4: write"); 388 return (1); 389 } 390 } 391 for (i = loops - 1; i + 1 > 0; i--) { 392 r = pread(fd, buf2, bufsize, (i*fba_num_bufsize) << SCTRSHFT); 393 if (r <= 0) { 394 perror("Test4: read"); 395 return (1); 396 } 397 } 398 for (i = loops - 1; i + 1 > 0; i--) { 399 r = pwrite(fd, buf1, bufsize, (i*fba_num_bufsize) << SCTRSHFT); 400 if (r <= 0) { 401 perror("Test4: write"); 402 return (1); 403 } 404 } 405 return (0); 406 } 407 408 int 409 do_sdtest5(int fd, nsc_size_t loops, nsc_size_t filesize, int h) 410 { 411 int err = 0; 412 ssize_t r; 413 nsc_size_t i; 414 415 /* 416 * Do sequential writes with verify reads for loops number 417 * of bufsize chunks, unless loops == 0, then do 418 * entire disk. 419 * 1. sequential writes from the top down, 420 * 2. sequential reads from the top down with verify, 421 * 3. sequential writes from the bottom up, 422 * 4. sequential reads from the bottom up with verify. 423 */ 424 if ((loops > (filesize / fba_num_bufsize)) || (!loops)) 425 loops = filesize / fba_num_bufsize; /* entire disk */ 426 427 gen_data(buf1, bufsize); 428 429 for (i = 0; i < loops; i++) { 430 r = pwrite(fd, buf1, bufsize, (i*fba_num_bufsize) << SCTRSHFT); 431 if (r <= 0) { 432 perror("Test5: write"); 433 err++; 434 return (err); 435 } 436 } 437 for (i = 0; i < loops; i++) { 438 buf2[0] = '\0'; /* clear buf to make sure something is read */ 439 r = pread(fd, buf2, bufsize, (i*fba_num_bufsize) << SCTRSHFT); 440 if (r <= 0) { 441 perror("Test5: read"); 442 err++; 443 return (err); 444 } 445 if (memcmp(buf1, buf2, bufsize)) { 446 (void) printf("Test5: Data corruption," 447 " fd:%s, fpos:%" NSC_SZFMT ", len:%d\n", 448 name[h], i, bufsize); 449 err++; 450 } 451 } 452 453 gen_data(buf1, bufsize); 454 455 for (i = loops - 1; i + 1 > 0; i--) { 456 r = pwrite(fd, buf1, bufsize, (i*fba_num_bufsize) << SCTRSHFT); 457 if (r <= 0) { 458 perror("Test5: write"); 459 err++; 460 return (err); 461 } 462 } 463 for (i = loops - 1; i + 1 > 0; i--) { 464 buf2[0] = '\0'; /* clear buf to make sure something is read */ 465 r = pread(fd, buf2, bufsize, (i*fba_num_bufsize) << SCTRSHFT); 466 if (r <= 0) { 467 perror("Test5: read"); 468 err++; 469 return (err); 470 } 471 if (memcmp(buf1, buf2, bufsize)) { 472 (void) printf("Test5: Data corruption," 473 " fd:%s, fpos:%" NSC_SZFMT ", len:%d\n", 474 name[h], i, bufsize); 475 err++; 476 } 477 } 478 return (err); 479 } 480 481 482 int 483 do_sdtest6(int fd, nsc_size_t loops, nsc_size_t filesize, int h) 484 { 485 int err = 0; 486 nsc_size_t i; 487 ssize_t r; 488 nsc_size_t endloop = filesize / fba_num_bufsize; 489 int buf3[MAXBUF]; 490 int buf4[MAXBUF]; 491 nsc_off_t top_pos, bottom_pos; 492 493 /* 494 * Do alternating top down and bottom up sequential writes 495 * (working towards middle) and verify with reads 496 * for loops number of bufsize chunks, unless loops == 0, then do 497 * entire disk. 498 */ 499 if ((loops > (filesize / fba_num_bufsize)) || (!loops)) 500 loops = filesize / fba_num_bufsize; /* entire disk */ 501 502 for (i = 0; i < loops; i++) { 503 gen_data(buf1, bufsize); 504 bottom_pos = i*fba_num_bufsize; 505 r = pwrite(fd, buf1, bufsize, (off_t)(bottom_pos << SCTRSHFT)); 506 if (r <= 0) { 507 perror("Test6: write"); 508 err++; 509 return (err); 510 } 511 gen_data(buf2, bufsize); 512 top_pos = (endloop - i - 1)*fba_num_bufsize; 513 514 /* Make sure we don't collide in the middle */ 515 516 if (abs(top_pos - bottom_pos) < fba_num_bufsize) 517 top_pos = bottom_pos + fba_num_bufsize; 518 519 r = pwrite(fd, buf2, bufsize, (off_t)(top_pos << SCTRSHFT)); 520 if (r <= 0) { 521 perror("Test6: write"); 522 err++; 523 return (err); 524 } 525 r = pread(fd, buf3, bufsize, (off_t)(bottom_pos << SCTRSHFT)); 526 if (r <= 0) { 527 perror("Test6: read"); 528 err++; 529 return (err); 530 } 531 if (memcmp(buf1, buf3, bufsize)) { 532 (void) printf("Data corruption(1), fd:%s, fpos:%" 533 PRId64 ", len:%d\n", name[h], 534 (int64_t)(bottom_pos << SCTRSHFT), bufsize); 535 err++; 536 } 537 r = pread(fd, buf4, bufsize, (off_t)(top_pos << SCTRSHFT)); 538 if (r <= 0) { 539 perror("Test6: read"); 540 return (1); 541 } 542 if (memcmp(buf2, buf4, bufsize)) { 543 (void) printf("Test6: Data corruption(2)," 544 " fd:%s, fpos:%" PRId64 ", len:%d\n", 545 name[h], (int64_t)(top_pos << SCTRSHFT), bufsize); 546 err++; 547 } 548 } 549 return (err); 550 } 551 552 int shmid; 553 554 #define MAXREADERS 32 555 556 struct shm_struct { 557 int writebuf[MAXBUF]; 558 volatile nsc_off_t writepos; 559 int quit; 560 int err; 561 mutex_t err_mutex; 562 int rd_done[MAXREADERS]; 563 int rd_done_mask[MAXREADERS]; 564 } *shm; 565 566 #define WRITEBUF (shm->writebuf) 567 #define WRITEPOS (shm->writepos) 568 569 #define QUIT (shm->quit) 570 #define ERR (shm->err) 571 #define ERRMUTEX (shm->err_mutex) 572 #define RD_DONE (shm->rd_done) 573 #define RD_DONE_MASK (shm->rd_done_mask) 574 575 #define LOCKWRITE 576 #define LOCKREAD(i) 577 578 /* Clear RD_DONE and Set WRITEPOS */ 579 #define FREEWRITE { \ 580 bzero(RD_DONE, sizeof (RD_DONE)); \ 581 WRITEPOS = wr_pos; } 582 583 /* Reader i+1 marks himself as finished */ 584 #define FREEREAD(i) (RD_DONE[(i)] = 1) 585 586 587 int 588 do_sdtest7read(int fd, int h, int which) 589 { 590 int err; 591 ssize_t r_rd; 592 nsc_off_t curr_pos; 593 nsc_size_t loop_cnt; 594 err = 0; curr_pos = 0; loop_cnt = 0; 595 for (;;) { 596 /* Already read this? */ 597 if (curr_pos == WRITEPOS) { 598 if (!QUIT) { 599 continue; 600 } else { 601 /* Time to go! */ 602 /* printf("Quitting [%d]\n", which+1); */ 603 break; 604 } 605 } 606 607 /* get location to read from */ 608 curr_pos = WRITEPOS; 609 610 r_rd = pread(fd, buf1, bufsize, (curr_pos << SCTRSHFT)); 611 loop_cnt += 1; 612 if (r_rd <= 0) { 613 FREEREAD(which); 614 perror("Test7: read"); 615 err += 1; 616 continue; 617 } 618 619 if (memcmp(buf1, WRITEBUF, bufsize)) { 620 FREEREAD(which); 621 (void) printf("\nTest7: Data corruption, reader #%d, " 622 "fd:%s, \ 623 fpos:%" PRId64 ", len:%d\n", which + 1, name[h], 624 (int64_t)(curr_pos << SCTRSHFT), bufsize); 625 err += 1; 626 continue; 627 } 628 629 FREEREAD(which); 630 } 631 632 (void) printf( 633 "Partition %s, Test 7, reader #%d: %d errors %lld loops\n", 634 name[h], which+1, err, loop_cnt); 635 636 if (err > 0) { 637 (void) mutex_lock(&ERRMUTEX); 638 ERR += err; 639 (void) mutex_unlock(&ERRMUTEX); 640 } 641 642 if (err) 643 return (1); 644 else 645 return (0); 646 } 647 648 649 int 650 do_sdtest7write(int fd, nsc_size_t filesize, int h) 651 { 652 int err = 0; 653 ssize_t r; 654 nsc_off_t wr_pos; 655 656 /* Wait for readers to finish */ 657 while (memcmp(RD_DONE, RD_DONE_MASK, readercount*sizeof (int))) 658 ; 659 660 gen_data(WRITEBUF, bufsize); 661 wr_pos = ( 662 #ifdef NSC_MULTI_TERABYTE 663 ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) | 664 #endif 665 (rand() << 16) | rand()) % filesize; 666 r = pwrite(fd, WRITEBUF, bufsize, (off_t)(wr_pos << SCTRSHFT)); 667 if (r <= 0) { 668 FREEWRITE; 669 perror("Test7: write"); 670 return (1); 671 } 672 FREEWRITE; 673 674 /* verify write */ 675 r = pread(fd, buf1, bufsize, (off_t)(wr_pos << SCTRSHFT)); 676 if (r <= 0) { 677 perror("Test7: writer: read"); 678 return (1); 679 } 680 681 682 if (memcmp(buf1, WRITEBUF, bufsize)) { 683 (void) printf("\nTest7: Data corruption in writer," 684 " fd:%s, fpos:%" PRId64 ", len:%d\n", 685 name[h], (int64_t)(wr_pos << SCTRSHFT), bufsize); 686 err++; 687 } 688 689 690 return (err); 691 } 692 693 void 694 init_shm() 695 { 696 int i; 697 698 /* Clear out everything */ 699 bzero(shm, sizeof (struct shm_struct)); 700 701 (void) mutex_init(&ERRMUTEX, USYNC_PROCESS, NULL); 702 703 /* Set up mask (constant) to test reader doneness */ 704 for (i = 0; i < readercount; i++) 705 RD_DONE_MASK[i] = 1; 706 707 /* Mark all readers done - so writer can start */ 708 for (i = 0; i < readercount; i++) 709 RD_DONE[i] = 1; 710 } 711 712 int 713 do_sdtest7(int fd, nsc_size_t loops, nsc_size_t filesize, int h, nsc_fd_t *sdfd) 714 { 715 int r, i, err; 716 nsc_size_t j; 717 718 if ((shmid = shmget(IPC_PRIVATE, sizeof (struct shm_struct), 719 IPC_CREAT | 0666)) < 0) { 720 perror("shmget error: "); 721 (void) nsc_close(sdfd); 722 exit(1); 723 } 724 725 shm = (struct shm_struct *)shmat(shmid, NULL, 0); 726 if (shm == (struct shm_struct *)-1) { 727 perror("shmat error: "); 728 (void) nsc_close(sdfd); 729 exit(1); /* cleanup exits */ 730 } 731 732 init_shm(); 733 734 /* Start Readers */ 735 for (i = 0; i < readercount; i++) { 736 r = fork(); 737 if (r == 0) { /* child */ 738 (void) do_sdtest7read(fd, h, i); 739 (void) nsc_close(sdfd); 740 exit(0); 741 } else 742 continue; 743 } 744 745 /* Start Writer */ 746 srand(getpid()); err = 0; 747 for (j = 0; j < loops; j++) { 748 err += do_sdtest7write(fd, filesize, h); 749 } 750 QUIT = 1; 751 752 (void) printf("\n\nPartition %s, Test 7, writer: %d errors\n", 753 name[h], err); 754 755 for (i = 0; i < readercount; i++) 756 wait(0); 757 758 /* No lock needed here - everybody's finished */ 759 err += ERR; 760 761 (void) mutex_destroy(&ERRMUTEX); 762 shmctl(shmid, IPC_RMID, 0); 763 return (err); 764 } 765 766 int 767 do_sdtest8(int fd, nsc_size_t loops, nsc_size_t filesize) 768 { 769 nsc_off_t seekpos; 770 int err = 0; 771 ssize_t r; 772 nsc_size_t i; 773 774 for (i = 0; i < loops; i++) { 775 seekpos = ( 776 #ifdef NSC_MULTI_TERABYTE 777 ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) | 778 #endif 779 (rand() << 16) | rand()) % filesize; 780 gen_data(buf1, bufsize); 781 r = pwrite(fd, buf1, bufsize, (off_t)(seekpos << SCTRSHFT)); 782 if (r <= 0) { 783 perror("Test8: write"); 784 err++; 785 return (err); 786 } 787 } 788 return (err); 789 } 790 791 void 792 gen_data_known(int *buffer, int size, int data) 793 { 794 int i; 795 796 size /= 4; 797 for (i = 0; i < size; i++) 798 buffer[i] = data; 799 } 800 801 int 802 do_sdtest9(int fd, nsc_size_t loops, nsc_size_t filesize, int h) 803 { 804 int err = 0; 805 ssize_t r; 806 nsc_off_t fba_offset; 807 nsc_size_t i, wrapval; 808 809 /* 810 * Test 9 will write a given pattern over and over Test 11 or 811 * Test 12 will read same pattern. 812 */ 813 /* Large loop value that would cause write overflow will wrap */ 814 815 gen_data_known(buf1, bufsize, pattern[h]); 816 817 wrapval = filesize / fba_num_bufsize; 818 819 if (loops == 0) 820 loops = wrapval; /* entire disk */ 821 822 for (i = 0; i < loops; i++) { 823 fba_offset = i % wrapval; 824 r = pwrite(fd, buf1, bufsize, 825 (off_t)(fba_offset * fba_num_bufsize) << SCTRSHFT); 826 if (r <= 0) { 827 perror("Test9: write"); 828 err++; 829 return (err); 830 } 831 } 832 return (err); 833 } 834 835 int 836 do_sdtest10(int fd1, int fd2, nsc_size_t loops, nsc_size_t filesize1, 837 nsc_size_t filesize2, int h) 838 { 839 nsc_size_t filesize; 840 int err = 0; 841 nsc_size_t i; 842 ssize_t r; 843 844 /* 845 * Do sequential copy of disk1 to disk2 for loops number 846 * of bufsize chunks, unless loops == 0, then copy size of 847 * the smaller disk. 848 * Go back and verify that the two disks are identical. 849 */ 850 851 filesize = (filesize1 < filesize2) ? filesize1 : filesize2; 852 if ((loops > (filesize / fba_num_bufsize)) || (!loops)) 853 loops = filesize / fba_num_bufsize; 854 855 /* copy disk1 to to disk2 */ 856 for (i = 0; i < loops; i++) { 857 r = pread(fd1, buf1, bufsize, 858 (off_t)(i*fba_num_bufsize) << SCTRSHFT); 859 if (r <= 0) { 860 perror("Test10: read"); 861 return (1); 862 } 863 r = pwrite(fd2, buf1, bufsize, 864 (off_t)(i*fba_num_bufsize) << SCTRSHFT); 865 if (r <= 0) { 866 perror("Test10: write"); 867 return (1); 868 } 869 } 870 871 /* verify disks are identical */ 872 for (i = 0; i < loops; i++) { 873 buf1[0] = '\0'; /* clear buf to make sure something is read */ 874 r = pread(fd1, buf1, bufsize, 875 (off_t)(i * fba_num_bufsize) << SCTRSHFT); 876 if (r <= 0) { 877 perror("Test10: read"); 878 return (1); 879 } 880 buf2[0] = 'x'; /* make sure something is read */ 881 r = pread(fd2, buf2, bufsize, 882 (off_t)(i * fba_num_bufsize) << SCTRSHFT); 883 if (r <= 0) { 884 perror("Test10: read"); 885 return (1); 886 } 887 if (memcmp(buf1, buf2, bufsize)) { 888 (void) printf("Test10: Data corruption," 889 " fd1:%s, fd2:%s fpos:%" NSC_SZFMT ", len:%d\n", 890 name[2*h], name[2*h+1], i, bufsize); 891 err++; 892 } 893 } 894 return (err); 895 } 896 897 int 898 buffcmp(int *b1, int *b2, int size) 899 { 900 int i; 901 902 for (i = 0; i < size/4; i++) { 903 if (b1[i] != b2[i]) { 904 (void) printf("Word %d does not match b1=0x%x, " 905 "b2=0x%x\n", i, b1[i], b2[i]); 906 return (1); 907 } 908 } 909 return (0); 910 911 } 912 913 int 914 do_sdtest11(int fd, nsc_size_t loops, nsc_size_t filesize, int h) 915 { 916 int err = 0; 917 nsc_size_t i; 918 ssize_t r; 919 int buf3[MAXBUF]; 920 int buf4[MAXBUF]; 921 int timestamp; 922 time_t clock; 923 struct tm *tm; 924 925 926 /* 927 * Test 9 will write a given pattern over and over Test 11 will read 928 * same pattern and clear with timestamp data (MM:SS). 929 */ 930 931 clock = time(NULL); 932 tm = localtime(&clock); 933 (void) ascftime((char *)×tamp, "%M""%S", tm); 934 935 gen_data_known(buf1, bufsize, pattern[h]); 936 gen_data_known(buf4, bufsize, timestamp); 937 if ((loops > filesize / fba_num_bufsize) || (!loops)) 938 loops = filesize / fba_num_bufsize; /* entire disk */ 939 940 for (i = 0; i < loops; i++) { 941 r = pread(fd, buf3, bufsize, 942 (off_t)(i*fba_num_bufsize) << SCTRSHFT); 943 if (r <= 0) { 944 perror("Test11: read"); 945 err++; 946 return (err); 947 } 948 if (buffcmp(buf1, buf3, bufsize)) { 949 (void) printf("Data corr, fd:%s, fpos:%" NSC_SZFMT 950 ", len:%d\n", name[h], i, bufsize); 951 err++; 952 return (err); 953 } 954 r = pwrite(fd, buf4, bufsize, 955 (off_t)(i*fba_num_bufsize) << SCTRSHFT); 956 if (r <= 0) { 957 perror("Test11: write"); 958 err++; 959 return (err); 960 } 961 } 962 return (err); 963 } 964 965 int 966 do_sdtest12(int fd, nsc_size_t loops, nsc_size_t filesize, int h) 967 { 968 int err = 0; 969 nsc_size_t i; 970 ssize_t r; 971 int buf3[MAXBUF]; 972 973 /* 974 * Test 9 will write a given pattern over and over Test 12 will read 975 * same pattern 976 */ 977 978 gen_data_known(buf1, bufsize, pattern[h]); 979 if ((loops > filesize / fba_num_bufsize) || (!loops)) 980 loops = filesize / fba_num_bufsize; /* entire disk */ 981 982 for (i = 0; i < loops; i++) { 983 r = pread(fd, buf3, bufsize, 984 (off_t)(i*fba_num_bufsize) << SCTRSHFT); 985 if (r <= 0) { 986 perror("Test12: read"); 987 err++; 988 return (err); 989 } 990 if (buffcmp(buf1, buf3, bufsize)) { 991 (void) printf("Data corr, fd:%s, fpos:%" NSC_SZFMT 992 ", len:%d\n", name[h], i, bufsize); 993 err++; 994 return (err); 995 } 996 } 997 return (err); 998 } 999 1000 #ifdef lint 1001 int 1002 sd_diag_lintmain(int argc, char *argv[]) 1003 #else 1004 int 1005 main(int argc, char *argv[]) 1006 #endif 1007 { 1008 int procs; 1009 nsc_size_t filesize, filesize2; 1010 int fd, fd2, r, id, h, i; 1011 nsc_fd_t *sdfd, *sdfd2; 1012 1013 if (argc < 2) { 1014 print_usage(); 1015 exit(0); 1016 } 1017 strcpy(config_file, DISKLIST); 1018 parse_opts(argc, argv); 1019 1020 _nsc_nocheck(); 1021 if ((procs = read_parts()) == 0) 1022 exit(0); 1023 1024 id = strtol(argv[optind], 0, 0); 1025 if (id == 10) { 1026 /* 1027 * each process gets 2 disks and copies disk1 to disk2, 1028 * then goes back and verifies that the two disks are 1029 * identical. 1030 */ 1031 if (procs < 2) { 1032 (void) printf("%s requires having at least 2 disks for test " 1033 "#10.\n", config_file); 1034 exit(0); 1035 } 1036 1037 for (h = 0; h < procs/2; h++) { 1038 r = fork(); 1039 if (r == 0) { 1040 srand(getpid()); 1041 1042 1043 if (!(sdfd = nsc_open(name[2*h], NSC_CACHE, 1044 O_RDWR | Rflag))) { 1045 (void) fprintf(stderr, 1046 "sd_diag: Error opening %s\n", name[2*h]); 1047 exit(1); 1048 } 1049 fd = nsc_fileno(sdfd); 1050 if (fd == -1) { 1051 (void) fprintf(stderr, 1052 "sd_diag: Error opening %s\n", name[2*h]); 1053 (void) nsc_close(sdfd); 1054 exit(1); 1055 } 1056 filesize = set_part_size(name[2*h], sdfd); 1057 if (!(sdfd2 = nsc_open(name[2*h+1], NSC_CACHE, 1058 O_RDWR | Rflag))) { 1059 (void) fprintf(stderr, 1060 "sd_diag: Error opening %s\n", name[2*h+1]); 1061 exit(1); 1062 } 1063 fd2 = nsc_fileno(sdfd2); 1064 if (fd2 == -1) { 1065 (void) fprintf(stderr, 1066 "sd_diag: Error opening %s\n", name[2*h+1]); 1067 (void) nsc_close(sdfd2); 1068 exit(1); 1069 } 1070 filesize2 = set_part_size(name[2*h+1], sdfd2); 1071 (void) sleep(2); 1072 r = do_sdtest10(fd, fd2, loops, filesize, filesize2, h); 1073 1074 (void) printf("Partitions %s and %s, Test %d," 1075 " Completed %d errors\n", 1076 name[2*h], name[2*h+1], id, r); 1077 (void) nsc_close(sdfd); 1078 (void) nsc_close(sdfd2); 1079 exit(0); 1080 } else if (r == -1) { 1081 perror("fork"); 1082 break; 1083 } else 1084 continue; 1085 } /* for */ 1086 for (i = 0; i < h; i++) 1087 wait(0); 1088 } else { 1089 1090 for (h = 0; h < procs; h++) { 1091 r = fork(); 1092 if (r == 0) { 1093 srand(getpid()); 1094 1095 id = strtol(argv[optind], 0, 0); 1096 if (!(sdfd = nsc_open(name[h], NSC_CACHE, 1097 O_RDWR | Rflag))) { 1098 (void) fprintf(stderr, 1099 "sd_diag: Error opening %s\n", name[h]); 1100 exit(1); 1101 } 1102 fd = nsc_fileno(sdfd); 1103 1104 if (fd == -1) { 1105 (void) fprintf(stderr, 1106 "sd_diag: Error opening %s\n", name[h]); 1107 (void) nsc_close(sdfd); 1108 exit(1); 1109 } 1110 filesize = set_part_size(name[h], sdfd); 1111 1112 (void) sleep(2); 1113 1114 1115 switch (id) { 1116 case 1: 1117 r = do_sdtest1(fd, r_loops, filesize); 1118 break; 1119 case 2: 1120 r = do_sdtest2(fd, r_loops, filesize, h); 1121 break; 1122 case 3: 1123 r = do_sdtest3(fd, r_loops, filesize, h, sdfd); 1124 break; 1125 case 4: 1126 r = do_sdtest4(fd, loops, filesize); 1127 break; 1128 case 5: 1129 r = do_sdtest5(fd, loops, filesize, h); 1130 break; 1131 case 6: 1132 r = do_sdtest6(fd, loops, filesize, h); 1133 break; 1134 case 7: 1135 r = do_sdtest7(fd, r_loops, filesize, h, sdfd); 1136 break; 1137 case 8: 1138 r = do_sdtest8(fd, r_loops, filesize); 1139 break; 1140 case 9: 1141 r = do_sdtest9(fd, loops, filesize, h); 1142 break; 1143 case 11: 1144 r = do_sdtest11(fd, loops, filesize, h); 1145 break; 1146 case 12: 1147 r = do_sdtest12(fd, loops, filesize, h); 1148 break; 1149 default: 1150 break; 1151 } 1152 1153 (void) printf("Partition %s, Test %d, Completed %d " 1154 "errors\n", name[h], id, r); 1155 (void) nsc_close(sdfd); 1156 exit(r ? 1 : 0); 1157 } else if (r == -1) { 1158 perror("fork"); 1159 break; 1160 } else 1161 continue; 1162 } 1163 for (i = 0; i < h; i++) 1164 wait(0); 1165 } 1166 1167 return (0); 1168 } 1169