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