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

Reply via email to