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 [EMAIL PROTECTED]
with "unsubscribe freebsd-hackers" in the body of the message