/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* #include SKK */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAXPARTS 100 /* Max disks */ #define MAXBUF 65536 /* Max buffer size in long words */ #define DISKLIST "disk_config" /* Default config file */ #define DEF_SIZE 8192 /* Default buffer size */ #define DEF_LOOP 1000 /* Loops for test */ #define RAND_LOOPS DEF_LOOP /* # of random ios to do */ /* * >>>>>>>>> USER LEVEL SD CACHE DIAGNOSTICS <<<<<<<<<< * * Write and read data blocks w/multiple processes * Starts one process for each partition specified in * the config file */ int buf1[MAXBUF]; int buf2[MAXBUF]; char name[MAXPARTS][80]; int pattern[MAXPARTS]; int bufsize = DEF_SIZE; int fba_num_bufsize; nsc_size_t loops = DEF_LOOP; nsc_size_t r_loops = RAND_LOOPS; int fsize = -1; int readercount = 3; int Rflag = O_EXCL; char config_file[32]; int read_parts() { FILE *dfile; int partitions = 0; int i; dfile = fopen(config_file, "r"); if (dfile == NULL) { (void) printf("cannot open file: %s\n", config_file); perror("fopen"); exit(errno); } for (i = 0; i < MAXPARTS; i++) { if (fscanf(dfile, "%s %x", name[i], (uint_t *)&pattern[i]) == EOF) { break; } else if (name[i][0] == '#' || strchr(name[i], '/') == NULL) { i--; continue; } partitions++; } (void) fclose(dfile); (void) printf("No. of partitions listed in file '%s' = %d\n\n", config_file, partitions); return (partitions); } void print_usage() { (void) printf("Usage:\n"); (void) printf( "sd_diag [-R] [-b ] [-d ] [-l ] [-r ]\n"); (void) printf( " [-f ] \n"); (void) printf(" test 1 = random read/write\n"); (void) printf(" 2 = random read/write/verify, read after write\n"); (void) printf(" 3 = random read/write/verify,"); (void) printf(" all reads after all writes\n"); (void) printf(" 4 = sequential read/write\n"); (void) printf(" 5 = sequential write/read/verify,"); (void) printf(" all reads after all writes\n"); (void) printf( " 6 = altenating top/bottom sequential read/write/verify\n"); (void) printf(" 7 = multiple readers/1 random writer\n"); (void) printf(" 8 = random writes\n"); (void) printf(" 9 = sequential write of known data\n"); (void) printf(" 10 = sequential copy of datasize disk/verify\n"); (void) printf(" 11 = sequential read/verify test 9 data -"); (void) printf(" then clear data with timestamp\n"); (void) printf(" 12 = sequential read/verify test 9 data -"); (void) printf(" no clear data\n"); (void) printf("\n"); (void) printf(" in bytes (minimum is 512 bytes)\n"); (void) printf(" in Mbytes per disk\n"); (void) printf(" is count of reads/writes,\n"); (void) printf(" loops = 0 tests entire datasize disk"); (void) printf(" for sequential tests.\n"); (void) printf(" loops = 0 performs %d I/Os for the random " "tests\n", RAND_LOOPS); (void) printf(" is count of readers for test #7 (default " "is 3).\n"); (void) printf(" [ defaults: bufsize = %d bytes, loops = %d,", DEF_SIZE, DEF_LOOP); (void) printf(" datasize = disksize ]\n"); (void) printf("\n"); (void) printf(" -R : do nsc_reserve(), nsc_release(0 around each " "I/O\n"); } void parse_opts(int argc, char *argv[]) { extern char *optarg; int c; while ((c = getopt(argc, argv, "b:d:l:r:Rf:")) != -1) { switch (c) { case 'f': /* printf("\n%s", optarg); */ (void) strcpy(config_file, optarg); break; case 'b': /* bufsize between 1*512 and 512*512 */ bufsize = strtol(optarg, 0, 0); if (bufsize > (MAXBUF*4)) bufsize = MAXBUF*4; else if (bufsize < FBA_SIZE(1)) bufsize = FBA_SIZE(1); break; case 'd': /* convert datasize from Mb's to fba */ fsize = strtol(optarg, 0, 0) * FBA_NUM(1 << 20); break; case 'l': loops = (nsc_size_t)strtoll(optarg, 0, 0); break; case 'r': /* count of readers for test 7 */ readercount = strtol(optarg, 0, 0); break; case 'R': /* do reserve, release on a per io basis */ Rflag = 0; break; case '?': print_usage(); exit(0); } } bufsize &= ~FBA_MASK; /* multiple of 512 bytes for SECTMODE I/O */ fba_num_bufsize = FBA_NUM(bufsize); /* set #ios for random io tests */ if (loops != 0) r_loops = loops; } nsc_size_t set_part_size(char *path, nsc_fd_t *sdfd) { nsc_size_t filesize; int rc; rc = nsc_partsize(sdfd, &filesize); /* partsize in FBAs (512 bytes) */ if (rc < 0 || filesize == 0) { (void) fprintf(stderr, "set_part_size: cannot access partition size"); (void) fprintf(stderr, " for %s\n", path); (void) nsc_close(sdfd); exit(1); } (void) printf("Partition %s, size:%" NSC_SZFMT " blocks\n", path, filesize); if (fsize != -1 && fsize < filesize) filesize = fsize; filesize -= fba_num_bufsize; if (filesize < fba_num_bufsize) { (void) printf("ERROR: Max block size %" NSC_SZFMT "\n", filesize); (void) nsc_close(sdfd); exit(0); } return (filesize); } int do_sdtest1(int fd, nsc_size_t loops, nsc_size_t filesize) { nsc_off_t seekpos; nsc_size_t i; ssize_t r; for (i = 0; i < loops; i++) { seekpos = ( #ifdef NSC_MULTI_TERABYTE ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) | #endif (rand() << 16) | rand()) % filesize; r = pwrite(fd, buf1, bufsize, (off_t)(seekpos << SCTRSHFT)); if (r <= 0) { perror("Test1: write"); return (1); } seekpos = ( #ifdef NSC_MULTI_TERABYTE ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) | #endif (rand() << 16) | rand()) % filesize; r = pread(fd, buf2, bufsize, (off_t)(seekpos << SCTRSHFT)); if (r <= 0) { perror("Test1: read"); return (1); } } return (0); } void gen_data(int *buffer, int size) { int i; size /= 4; for (i = 0; i < size; i++) buffer[i] = rand() << 16 | rand(); } int do_sdtest2(int fd, nsc_size_t loops, nsc_size_t filesize, int h) { nsc_off_t seekpos; int err = 0; ssize_t r; nsc_size_t i; for (i = 0; i < loops; i++) { seekpos = ( #ifdef NSC_MULTI_TERABYTE ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) | #endif (rand() << 16) | rand()) % filesize; gen_data(buf1, bufsize); r = pwrite(fd, buf1, bufsize, (off_t)(seekpos << SCTRSHFT)); if (r <= 0) { perror("Test2: write"); err++; return (err); } r = pread(fd, buf2, bufsize, (off_t)(seekpos << SCTRSHFT)); if (r <= 0) { perror("Test2: read"); err++; return (err); } if (memcmp(buf1, buf2, bufsize)) { (void) printf("Test2: Data corruption," " fd:%s, fpos:%" PRId64 ", len:%d\n", name[h], (int64_t)(seekpos << SCTRSHFT), bufsize); err++; } } return (err); } int do_sdtest3(int fd, nsc_size_t loops, nsc_size_t filesize, int h, nsc_fd_t *sdfd) { nsc_off_t *seekpos; int err = 0; nsc_size_t i; ssize_t r; seekpos = malloc(loops*sizeof (nsc_off_t)); if (seekpos == NULL) { perror("Test3: malloc"); (void) nsc_close(sdfd); exit(errno); } gen_data(buf1, bufsize); for (i = 0; i < loops; i++) { seekpos[i] = ( #ifdef NSC_MULTI_TERABYTE ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) | #endif (rand() << 16) | rand()) % filesize; seekpos[i] -= seekpos[i] % fba_num_bufsize; r = pwrite(fd, buf1, bufsize, (off_t)(seekpos[i] << SCTRSHFT)); if (r <= 0) { perror("Test3: write"); err++; goto cleanup; } } for (i = 0; i < loops; i++) { buf2[0] = '\0'; /* clear buf to make sure something is read */ r = pread(fd, buf2, bufsize, (off_t)(seekpos[i] << SCTRSHFT)); if (r <= 0) { perror("Test3: read"); err++; goto cleanup; } if (memcmp(buf1, buf2, bufsize)) { (void) printf("Data corruption, fd:%s, fpos:%" PRId64 ", len:%d\n", name[h], (int64_t)(seekpos[i] << SCTRSHFT), bufsize); err++; } } cleanup: free(seekpos); return (err); } int do_sdtest4(int fd, nsc_size_t loops, nsc_size_t filesize) { ssize_t r; nsc_size_t i; /* * Do sequential reads/writes for loops number * of bufsize chunks, unless loops == 0, then do * entire disk. * 1. sequential reads from the top down, * 2. sequential writes from the top down, * 3. sequential reads from the bottom up, * 4. sequential writes from the bottom up. */ if ((loops > (filesize / fba_num_bufsize)) || (!loops)) loops = filesize / fba_num_bufsize; /* entire disk */ for (i = 0; i < loops; i++) { r = pread(fd, buf2, bufsize, (i*fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test4: read"); return (1); } } for (i = 0; i < loops; i++) { r = pwrite(fd, buf1, bufsize, (i*fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test4: write"); return (1); } } for (i = loops - 1; i + 1 > 0; i--) { r = pread(fd, buf2, bufsize, (i*fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test4: read"); return (1); } } for (i = loops - 1; i + 1 > 0; i--) { r = pwrite(fd, buf1, bufsize, (i*fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test4: write"); return (1); } } return (0); } int do_sdtest5(int fd, nsc_size_t loops, nsc_size_t filesize, int h) { int err = 0; ssize_t r; nsc_size_t i; /* * Do sequential writes with verify reads for loops number * of bufsize chunks, unless loops == 0, then do * entire disk. * 1. sequential writes from the top down, * 2. sequential reads from the top down with verify, * 3. sequential writes from the bottom up, * 4. sequential reads from the bottom up with verify. */ if ((loops > (filesize / fba_num_bufsize)) || (!loops)) loops = filesize / fba_num_bufsize; /* entire disk */ gen_data(buf1, bufsize); for (i = 0; i < loops; i++) { r = pwrite(fd, buf1, bufsize, (i*fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test5: write"); err++; return (err); } } for (i = 0; i < loops; i++) { buf2[0] = '\0'; /* clear buf to make sure something is read */ r = pread(fd, buf2, bufsize, (i*fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test5: read"); err++; return (err); } if (memcmp(buf1, buf2, bufsize)) { (void) printf("Test5: Data corruption," " fd:%s, fpos:%" NSC_SZFMT ", len:%d\n", name[h], i, bufsize); err++; } } gen_data(buf1, bufsize); for (i = loops - 1; i + 1 > 0; i--) { r = pwrite(fd, buf1, bufsize, (i*fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test5: write"); err++; return (err); } } for (i = loops - 1; i + 1 > 0; i--) { buf2[0] = '\0'; /* clear buf to make sure something is read */ r = pread(fd, buf2, bufsize, (i*fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test5: read"); err++; return (err); } if (memcmp(buf1, buf2, bufsize)) { (void) printf("Test5: Data corruption," " fd:%s, fpos:%" NSC_SZFMT ", len:%d\n", name[h], i, bufsize); err++; } } return (err); } int do_sdtest6(int fd, nsc_size_t loops, nsc_size_t filesize, int h) { int err = 0; nsc_size_t i; ssize_t r; nsc_size_t endloop = filesize / fba_num_bufsize; int buf3[MAXBUF]; int buf4[MAXBUF]; nsc_off_t top_pos, bottom_pos; /* * Do alternating top down and bottom up sequential writes * (working towards middle) and verify with reads * for loops number of bufsize chunks, unless loops == 0, then do * entire disk. */ if ((loops > (filesize / fba_num_bufsize)) || (!loops)) loops = filesize / fba_num_bufsize; /* entire disk */ for (i = 0; i < loops; i++) { gen_data(buf1, bufsize); bottom_pos = i*fba_num_bufsize; r = pwrite(fd, buf1, bufsize, (off_t)(bottom_pos << SCTRSHFT)); if (r <= 0) { perror("Test6: write"); err++; return (err); } gen_data(buf2, bufsize); top_pos = (endloop - i - 1)*fba_num_bufsize; /* Make sure we don't collide in the middle */ if (abs(top_pos - bottom_pos) < fba_num_bufsize) top_pos = bottom_pos + fba_num_bufsize; r = pwrite(fd, buf2, bufsize, (off_t)(top_pos << SCTRSHFT)); if (r <= 0) { perror("Test6: write"); err++; return (err); } r = pread(fd, buf3, bufsize, (off_t)(bottom_pos << SCTRSHFT)); if (r <= 0) { perror("Test6: read"); err++; return (err); } if (memcmp(buf1, buf3, bufsize)) { (void) printf("Data corruption(1), fd:%s, fpos:%" PRId64 ", len:%d\n", name[h], (int64_t)(bottom_pos << SCTRSHFT), bufsize); err++; } r = pread(fd, buf4, bufsize, (off_t)(top_pos << SCTRSHFT)); if (r <= 0) { perror("Test6: read"); return (1); } if (memcmp(buf2, buf4, bufsize)) { (void) printf("Test6: Data corruption(2)," " fd:%s, fpos:%" PRId64 ", len:%d\n", name[h], (int64_t)(top_pos << SCTRSHFT), bufsize); err++; } } return (err); } int shmid; #define MAXREADERS 32 struct shm_struct { int writebuf[MAXBUF]; volatile nsc_off_t writepos; int quit; int err; mutex_t err_mutex; int rd_done[MAXREADERS]; int rd_done_mask[MAXREADERS]; } *shm; #define WRITEBUF (shm->writebuf) #define WRITEPOS (shm->writepos) #define QUIT (shm->quit) #define ERR (shm->err) #define ERRMUTEX (shm->err_mutex) #define RD_DONE (shm->rd_done) #define RD_DONE_MASK (shm->rd_done_mask) #define LOCKWRITE #define LOCKREAD(i) /* Clear RD_DONE and Set WRITEPOS */ #define FREEWRITE { \ bzero(RD_DONE, sizeof (RD_DONE)); \ WRITEPOS = wr_pos; } /* Reader i+1 marks himself as finished */ #define FREEREAD(i) (RD_DONE[(i)] = 1) int do_sdtest7read(int fd, int h, int which) { int err; ssize_t r_rd; nsc_off_t curr_pos; nsc_size_t loop_cnt; err = 0; curr_pos = 0; loop_cnt = 0; for (;;) { /* Already read this? */ if (curr_pos == WRITEPOS) { if (!QUIT) { continue; } else { /* Time to go! */ /* printf("Quitting [%d]\n", which+1); */ break; } } /* get location to read from */ curr_pos = WRITEPOS; r_rd = pread(fd, buf1, bufsize, (curr_pos << SCTRSHFT)); loop_cnt += 1; if (r_rd <= 0) { FREEREAD(which); perror("Test7: read"); err += 1; continue; } if (memcmp(buf1, WRITEBUF, bufsize)) { FREEREAD(which); (void) printf("\nTest7: Data corruption, reader #%d, " "fd:%s, \ fpos:%" PRId64 ", len:%d\n", which + 1, name[h], (int64_t)(curr_pos << SCTRSHFT), bufsize); err += 1; continue; } FREEREAD(which); } (void) printf( "Partition %s, Test 7, reader #%d: %d errors %lld loops\n", name[h], which+1, err, loop_cnt); if (err > 0) { (void) mutex_lock(&ERRMUTEX); ERR += err; (void) mutex_unlock(&ERRMUTEX); } if (err) return (1); else return (0); } int do_sdtest7write(int fd, nsc_size_t filesize, int h) { int err = 0; ssize_t r; nsc_off_t wr_pos; /* Wait for readers to finish */ while (memcmp(RD_DONE, RD_DONE_MASK, readercount*sizeof (int))) ; gen_data(WRITEBUF, bufsize); wr_pos = ( #ifdef NSC_MULTI_TERABYTE ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) | #endif (rand() << 16) | rand()) % filesize; r = pwrite(fd, WRITEBUF, bufsize, (off_t)(wr_pos << SCTRSHFT)); if (r <= 0) { FREEWRITE; perror("Test7: write"); return (1); } FREEWRITE; /* verify write */ r = pread(fd, buf1, bufsize, (off_t)(wr_pos << SCTRSHFT)); if (r <= 0) { perror("Test7: writer: read"); return (1); } if (memcmp(buf1, WRITEBUF, bufsize)) { (void) printf("\nTest7: Data corruption in writer," " fd:%s, fpos:%" PRId64 ", len:%d\n", name[h], (int64_t)(wr_pos << SCTRSHFT), bufsize); err++; } return (err); } void init_shm() { int i; /* Clear out everything */ bzero(shm, sizeof (struct shm_struct)); (void) mutex_init(&ERRMUTEX, USYNC_PROCESS, NULL); /* Set up mask (constant) to test reader doneness */ for (i = 0; i < readercount; i++) RD_DONE_MASK[i] = 1; /* Mark all readers done - so writer can start */ for (i = 0; i < readercount; i++) RD_DONE[i] = 1; } int do_sdtest7(int fd, nsc_size_t loops, nsc_size_t filesize, int h, nsc_fd_t *sdfd) { int r, i, err; nsc_size_t j; if ((shmid = shmget(IPC_PRIVATE, sizeof (struct shm_struct), IPC_CREAT | 0666)) < 0) { perror("shmget error: "); (void) nsc_close(sdfd); exit(1); } shm = (struct shm_struct *)shmat(shmid, NULL, 0); if (shm == (struct shm_struct *)-1) { perror("shmat error: "); (void) nsc_close(sdfd); exit(1); /* cleanup exits */ } init_shm(); /* Start Readers */ for (i = 0; i < readercount; i++) { r = fork(); if (r == 0) { /* child */ (void) do_sdtest7read(fd, h, i); (void) nsc_close(sdfd); exit(0); } else continue; } /* Start Writer */ srand(getpid()); err = 0; for (j = 0; j < loops; j++) { err += do_sdtest7write(fd, filesize, h); } QUIT = 1; (void) printf("\n\nPartition %s, Test 7, writer: %d errors\n", name[h], err); for (i = 0; i < readercount; i++) (void) wait(0); /* No lock needed here - everybody's finished */ err += ERR; (void) mutex_destroy(&ERRMUTEX); (void) shmctl(shmid, IPC_RMID, 0); return (err); } int do_sdtest8(int fd, nsc_size_t loops, nsc_size_t filesize) { nsc_off_t seekpos; int err = 0; ssize_t r; nsc_size_t i; for (i = 0; i < loops; i++) { seekpos = ( #ifdef NSC_MULTI_TERABYTE ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) | #endif (rand() << 16) | rand()) % filesize; gen_data(buf1, bufsize); r = pwrite(fd, buf1, bufsize, (off_t)(seekpos << SCTRSHFT)); if (r <= 0) { perror("Test8: write"); err++; return (err); } } return (err); } void gen_data_known(int *buffer, int size, int data) { int i; size /= 4; for (i = 0; i < size; i++) buffer[i] = data; } int do_sdtest9(int fd, nsc_size_t loops, nsc_size_t filesize, int h) { int err = 0; ssize_t r; nsc_off_t fba_offset; nsc_size_t i, wrapval; /* * Test 9 will write a given pattern over and over Test 11 or * Test 12 will read same pattern. */ /* Large loop value that would cause write overflow will wrap */ gen_data_known(buf1, bufsize, pattern[h]); wrapval = filesize / fba_num_bufsize; if (loops == 0) loops = wrapval; /* entire disk */ for (i = 0; i < loops; i++) { fba_offset = i % wrapval; r = pwrite(fd, buf1, bufsize, (off_t)(fba_offset * fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test9: write"); err++; return (err); } } return (err); } int do_sdtest10(int fd1, int fd2, nsc_size_t loops, nsc_size_t filesize1, nsc_size_t filesize2, int h) { nsc_size_t filesize; int err = 0; nsc_size_t i; ssize_t r; /* * Do sequential copy of disk1 to disk2 for loops number * of bufsize chunks, unless loops == 0, then copy size of * the smaller disk. * Go back and verify that the two disks are identical. */ filesize = (filesize1 < filesize2) ? filesize1 : filesize2; if ((loops > (filesize / fba_num_bufsize)) || (!loops)) loops = filesize / fba_num_bufsize; /* copy disk1 to to disk2 */ for (i = 0; i < loops; i++) { r = pread(fd1, buf1, bufsize, (off_t)(i*fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test10: read"); return (1); } r = pwrite(fd2, buf1, bufsize, (off_t)(i*fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test10: write"); return (1); } } /* verify disks are identical */ for (i = 0; i < loops; i++) { buf1[0] = '\0'; /* clear buf to make sure something is read */ r = pread(fd1, buf1, bufsize, (off_t)(i * fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test10: read"); return (1); } buf2[0] = 'x'; /* make sure something is read */ r = pread(fd2, buf2, bufsize, (off_t)(i * fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test10: read"); return (1); } if (memcmp(buf1, buf2, bufsize)) { (void) printf("Test10: Data corruption," " fd1:%s, fd2:%s fpos:%" NSC_SZFMT ", len:%d\n", name[2*h], name[2*h+1], i, bufsize); err++; } } return (err); } int buffcmp(int *b1, int *b2, int size) { int i; for (i = 0; i < size/4; i++) { if (b1[i] != b2[i]) { (void) printf("Word %d does not match b1=0x%x, " "b2=0x%x\n", i, b1[i], b2[i]); return (1); } } return (0); } int do_sdtest11(int fd, nsc_size_t loops, nsc_size_t filesize, int h) { int err = 0; nsc_size_t i; ssize_t r; int buf3[MAXBUF]; int buf4[MAXBUF]; int timestamp; time_t clock; struct tm *tm; /* * Test 9 will write a given pattern over and over Test 11 will read * same pattern and clear with timestamp data (MM:SS). */ clock = time(NULL); tm = localtime(&clock); (void) ascftime((char *)×tamp, "%M""%S", tm); gen_data_known(buf1, bufsize, pattern[h]); gen_data_known(buf4, bufsize, timestamp); if ((loops > filesize / fba_num_bufsize) || (!loops)) loops = filesize / fba_num_bufsize; /* entire disk */ for (i = 0; i < loops; i++) { r = pread(fd, buf3, bufsize, (off_t)(i*fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test11: read"); err++; return (err); } if (buffcmp(buf1, buf3, bufsize)) { (void) printf("Data corr, fd:%s, fpos:%" NSC_SZFMT ", len:%d\n", name[h], i, bufsize); err++; return (err); } r = pwrite(fd, buf4, bufsize, (off_t)(i*fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test11: write"); err++; return (err); } } return (err); } int do_sdtest12(int fd, nsc_size_t loops, nsc_size_t filesize, int h) { int err = 0; nsc_size_t i; ssize_t r; int buf3[MAXBUF]; /* * Test 9 will write a given pattern over and over Test 12 will read * same pattern */ gen_data_known(buf1, bufsize, pattern[h]); if ((loops > filesize / fba_num_bufsize) || (!loops)) loops = filesize / fba_num_bufsize; /* entire disk */ for (i = 0; i < loops; i++) { r = pread(fd, buf3, bufsize, (off_t)(i*fba_num_bufsize) << SCTRSHFT); if (r <= 0) { perror("Test12: read"); err++; return (err); } if (buffcmp(buf1, buf3, bufsize)) { (void) printf("Data corr, fd:%s, fpos:%" NSC_SZFMT ", len:%d\n", name[h], i, bufsize); err++; return (err); } } return (err); } #ifdef lint int sd_diag_lintmain(int argc, char *argv[]) #else int main(int argc, char *argv[]) #endif { int procs; nsc_size_t filesize, filesize2; int fd, fd2, r, id, h, i; nsc_fd_t *sdfd, *sdfd2; if (argc < 2) { print_usage(); exit(0); } (void) strcpy(config_file, DISKLIST); parse_opts(argc, argv); _nsc_nocheck(); if ((procs = read_parts()) == 0) exit(0); id = strtol(argv[optind], 0, 0); if (id == 10) { /* * each process gets 2 disks and copies disk1 to disk2, * then goes back and verifies that the two disks are * identical. */ if (procs < 2) { (void) printf("%s requires having at least 2 disks for test " "#10.\n", config_file); exit(0); } for (h = 0; h < procs/2; h++) { r = fork(); if (r == 0) { srand(getpid()); if (!(sdfd = nsc_open(name[2*h], NSC_CACHE, O_RDWR | Rflag))) { (void) fprintf(stderr, "sd_diag: Error opening %s\n", name[2*h]); exit(1); } fd = nsc_fileno(sdfd); if (fd == -1) { (void) fprintf(stderr, "sd_diag: Error opening %s\n", name[2*h]); (void) nsc_close(sdfd); exit(1); } filesize = set_part_size(name[2*h], sdfd); if (!(sdfd2 = nsc_open(name[2*h+1], NSC_CACHE, O_RDWR | Rflag))) { (void) fprintf(stderr, "sd_diag: Error opening %s\n", name[2*h+1]); exit(1); } fd2 = nsc_fileno(sdfd2); if (fd2 == -1) { (void) fprintf(stderr, "sd_diag: Error opening %s\n", name[2*h+1]); (void) nsc_close(sdfd2); exit(1); } filesize2 = set_part_size(name[2*h+1], sdfd2); (void) sleep(2); r = do_sdtest10(fd, fd2, loops, filesize, filesize2, h); (void) printf("Partitions %s and %s, Test %d," " Completed %d errors\n", name[2*h], name[2*h+1], id, r); (void) nsc_close(sdfd); (void) nsc_close(sdfd2); exit(0); } else if (r == -1) { perror("fork"); break; } else continue; } /* for */ for (i = 0; i < h; i++) (void) wait(0); } else { for (h = 0; h < procs; h++) { r = fork(); if (r == 0) { srand(getpid()); id = strtol(argv[optind], 0, 0); if (!(sdfd = nsc_open(name[h], NSC_CACHE, O_RDWR | Rflag))) { (void) fprintf(stderr, "sd_diag: Error opening %s\n", name[h]); exit(1); } fd = nsc_fileno(sdfd); if (fd == -1) { (void) fprintf(stderr, "sd_diag: Error opening %s\n", name[h]); (void) nsc_close(sdfd); exit(1); } filesize = set_part_size(name[h], sdfd); (void) sleep(2); switch (id) { case 1: r = do_sdtest1(fd, r_loops, filesize); break; case 2: r = do_sdtest2(fd, r_loops, filesize, h); break; case 3: r = do_sdtest3(fd, r_loops, filesize, h, sdfd); break; case 4: r = do_sdtest4(fd, loops, filesize); break; case 5: r = do_sdtest5(fd, loops, filesize, h); break; case 6: r = do_sdtest6(fd, loops, filesize, h); break; case 7: r = do_sdtest7(fd, r_loops, filesize, h, sdfd); break; case 8: r = do_sdtest8(fd, r_loops, filesize); break; case 9: r = do_sdtest9(fd, loops, filesize, h); break; case 11: r = do_sdtest11(fd, loops, filesize, h); break; case 12: r = do_sdtest12(fd, loops, filesize, h); break; default: break; } (void) printf("Partition %s, Test %d, Completed %d " "errors\n", name[h], id, r); (void) nsc_close(sdfd); exit(r ? 1 : 0); } else if (r == -1) { perror("fork"); break; } else continue; } for (i = 0; i < h; i++) (void) wait(0); } return (0); }