Raw pattern checker...less well polished...runs on a lot of platforms... Avoids trashing disk labels...
Usage is a little less than obvious... 1. patchk RAWDISK TransferSize c Create/Validate/Test patterns.. creates patterns in TransferSize chunks..validates that they were correctly written, then randoml reads or updates same patterns. 2. patchk RAWDISK TransferSize u Skips the create step.... 3. patchk RAWDISK TransferSize v Skips the create and refresh test- just validates the pattern. Gary Palmer managed to find some pretty serious problems in a disk array by running multiple 'u' instantiations on the same partitition after an initial 'c' test. /* * Copyright (c) 1999 Matthew Jacob * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: patchk.c,v 1.3 1999/08/27 18:14:34 mjacob Exp $ */ #ifdef convex #include <sys/types.h> extern int optind; extern int getopt(int, char **, const char *); #define SEEK_T off64_t #define SEEK lseek64 #define FSTAT fstat64 #define STAT_T stat64_t #else #define SEEK_T off_t #define SEEK lseek #define FSTAT fstat #define STAT_T struct stat #endif #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <fcntl.h> #include <string.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/param.h> #include <sys/ioctl.h> #ifdef sun #define rand lrand48 #define srand srand48 #ifdef __SVR4 #include <sys/dkio.h> #else #include <sun/dkio.h> extern int gettimeofday(struct timeval *, struct timezone *); extern void bzero(char *, int); extern int strtol(const char *, char **, int); #endif extern int optind; #endif #ifdef __linux__ #include <sys/ioctl.h> #include <linux/fs.h> #endif #ifdef convex #include <sys/ioctl.h> #include <interfaces/io_if/scsi/scsi.h> #endif #if defined(__NetBSD__) || defined(__OpenBSD__) #include <sys/disklabel.h> #include <sys/dkio.h> #endif #ifdef __FreeBSD__ #include <sys/disklabel.h> #endif #ifdef __ultrix extern int optind; #endif #ifndef O_LARGEFILE #define O_LARGEFILE 0 #endif static int szarg(char *); int main(int a, char **v) { SEEK_T seekbase, seeklim, *buffer, wloc; int blksize; long long sb, sl; STAT_T st; int fd, i, error, create, nowrite; seekbase = (SEEK_T) 0; nowrite = 0; srand((int)(time((time_t *) 0)/getpid())); if (a != 4) { usage: fprintf(stderr, "Usage: %s raw-disk xfersize {c[reate]|u[se]|v[alidate]}\n", *v); return (1); } blksize = szarg(v[2]); buffer = (SEEK_T *) calloc((size_t) blksize, sizeof (SEEK_T)); if (buffer == NULL) { perror("malloc"); return (1); } if (*v[3] == 'c') { create = 1; } else if (*v[3] == 'u') { create = 0; } else if (*v[3] == 'v') { create = 0; nowrite = 1; } else { goto usage; } fd = open(v[1], nowrite? O_RDONLY : O_RDWR, 0666); if (fd < 0) { perror(v[2]); exit(1); } if (FSTAT(fd, &st) < 0) { perror("fstat"); exit(1); } if (S_ISCHR(st.st_mode)) { #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) int part; struct disklabel x; if (ioctl(fd, DIOCGDINFO, (caddr_t) &x) < 0) { perror("DIOCGDINFO"); exit(1); } seekbase = 8192; part = v[1][strlen(v[1]) - 1] - 'a'; seeklim = ((SEEK_T) x.d_partitions[part].p_size) * (SEEK_T) DEV_BSIZE; #elif defined(sun) struct dk_allmap x; int part; if (blksize < DEV_BSIZE) { fprintf(stderr, "%s: block size must be at least %d bytes on " "raw device\n", *v, DEV_BSIZE); exit(1); } #if defined(__svr4__) part = v[1][strlen(v[1]) - 1] - '0'; #else part = v[1][strlen(v[1]) - 1] - 'a'; #endif if (ioctl(fd, DKIOCGAPART, (caddr_t) &x) < 0) { perror("DKIOCGAPART"); exit(1); } seekbase = 8192; seeklim = ((SEEK_T) x.dka_map[part].dkl_nblk) * (SEEK_T) DEV_BSIZE; #elif defined(convex) struct topology top; seeklim = 0; if (ioctl(fd, SIOC_READ_TOPOLOGY, (caddr_t)&top) >= 0) { seeklim = (SEEK_T) top.partition[st.st_rdev & 0xf].size * (SEEK_T) DEV_BSIZE; } #else seeklim = (SEEK_T) 1; #endif } else { #ifdef linux if (ioctl(fd, BLKGETSIZE, (caddr_t) &seeklim) < 0) { perror("BLKGETSIZE"); exit(1); } seeklim <<= 9; #else fprintf(stderr, "%s: is not a raw device\n", v[1]); return (1); #endif } if (seekbase < blksize) seekbase = blksize; /* * Truncate to lower block boundary. */ seeklim &= ~(blksize-1); /* * An back off one. */ seeklim -= blksize; if (seeklim < (SEEK_T) 0) { printf("%s too big for lseek(2) call\n", v[1]); exit(1); } if (seeklim < (seekbase+blksize)) { fprintf(stderr, "%s: botch, seeklim (%ld) < seekbase + blksize (%ld)\n", *v, seeklim, seekbase + blksize); exit(1); } sb = (long long) seekbase; sl = (long long) seeklim; fprintf(stdout, "%s: Seek base %lx%08lx Seek lim %lx%08lx blocksize %d\n", v[1], (long) (sb >> 32LL), (long) (sb & 0xFFFFFFFF), (long) (sl >> 32LL), (long) (sl & 0xFFFFFFFF), blksize); wloc = SEEK(fd, (SEEK_T) seekbase, 0); if (wloc < (SEEK_T) 0) { perror("seek"); exit (1); } if (create) { fprintf(stdout, "Creating Patterns..."); fflush(stdout); for (wloc = seekbase; wloc < seeklim; wloc += blksize) { sb = (long long) wloc; for (i = 0; i < (blksize/sizeof (SEEK_T)); i++) { buffer[i] = wloc; } if ((i = write(fd, (char *)buffer, (int) blksize)) != blksize) { if (errno) perror("write"); fprintf(stderr, "write returned %d at offset 0x%lx0x%08lx\n", i, (long) (sb >> 32LL), (long) (sb & 0xFFFFFFFF)); exit (1); } } wloc = SEEK(fd, (SEEK_T) seekbase, 0); if (wloc < (SEEK_T) 0) { perror("seek"); exit (1); } } fprintf(stdout, "Checking Patterns..."); fflush(stdout); for (wloc = seekbase; wloc < seeklim; wloc += blksize) { sb = (long long) wloc; if ((i = read(fd, (char *)buffer, blksize)) != blksize) { if (errno) perror("read"); fprintf(stderr, "read returned %d at offset 0x%lx%08lx\n", i, (long) (sb >> 32LL), (long) (sb & 0xFFFFFFFF)); exit (1); } for (error = i = 0; i < (blksize/sizeof (SEEK_T)); i++) { if (buffer[i] != wloc) { sb = wloc; sl = (long long) buffer[i]; error++; fprintf(stderr, "compare error at block loc 0x%lx%08lx offset " "%d got %lx%08lx\n", (long) (sb >> 32LL), (long) (sb & 0xFFFFFFFF), i, (long) (sl >> 32LL), (long) (sl & 0xFFFFFFFF)); } } if (error) exit (1); } fprintf(stdout, "Randomly Checking Patterns\n"); while (1) { SEEK_T sloc; wloc = rand(); wloc &= ~(((SEEK_T)blksize) - 1); if (wloc < seekbase) continue; if (wloc >= (seeklim-(SEEK_T) blksize)) continue; sloc = SEEK(fd, wloc, 0); if (sloc < (SEEK_T) 0) { perror("seek"); exit (1); } if (sloc != wloc) { if (errno) perror("seek2"); fprintf(stderr, "wanted to seek to %lx and got to %lx instead\n", wloc, sloc); continue; } sb = (long long) wloc; if (!nowrite && (rand() & 1)) { for (i = 0; i < (blksize/sizeof (SEEK_T)); i++) { buffer[i] = wloc; } if ((i = write(fd, (char *)buffer, blksize)) != blksize) { fprintf(stderr, "\n"); if (errno) perror("write"); fprintf(stderr, "write returned %d at offset 0x%lx%08lx\n", i, (long) (sb >> 32LL), (long) (sb & 0xFFFFFFFF)); printf("wloc %lx sloc %lx\n", wloc, sloc); exit (1); } } else { if ((i = read(fd, (char *)buffer, blksize)) != blksize) { fprintf(stderr, "\n"); if (errno) perror("read"); fprintf(stderr, "read returned %d at offset 0x%lx%08lx\n", i, (long) (sb >> 32LL), (long) (sb & 0xFFFFFFFF)); printf("wloc %lx sloc %lx\n", wloc, sloc); exit (1); } for (error = i = 0; i < (blksize/sizeof (SEEK_T)); i++) { if (buffer[i] != wloc) { sb = wloc; sl = (long long) buffer[i]; if (error++ == 0) fprintf(stderr, "\n"); fprintf(stderr, "compare error at buffer offset %d should " "be 0x%lx%08lx got 0x%lx%08lx\n", i, (long) (sb >> 32LL), (long) (sb & 0xFFFFFFFF), (long) (sl >> 32LL), (long) (sl & 0xFFFFFFFF)); } } if (error) exit (1); } } } static int szarg(char *n) { register int shift = 0; register char *q = n; while (*q != (char) 0) q++; q--; if (*q == 'b' || *q == 'B') q--; if (*q == 'k' || *q == 'K') { shift = 10; *q = 0; } else if (*q == 'm' || *q == 'M') { shift = 20; *q = 0; } else if (*q == 'g' || *q == 'G') { shift = 30; *q = 0; } return ((SEEK_T) strtol((const char *)n, (char **) NULL, 0) << shift); } /* * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 4 * c-brace-imaginary-offset: 0 * c-brace-offset: -4 * c-argdecl-indent: 4 * c-label-offset: -4 * c-continued-statement-offset: 4 * c-continued-brace-offset: 0 * End: */ To Unsubscribe: send mail to majord...@freebsd.org with "unsubscribe freebsd-hackers" in the body of the message