1
0
Files
irix-657m-src/irix/cmd/stress/IO/rawdisk.c
2022-09-29 17:59:04 +03:00

364 lines
8.6 KiB
C

/*****************************************************************************
* This program tests raw device by:
* 1) Divide the whole disk into randomly sized regions and then fork a child
* for each one. The number of regions is between 5 and 10.
* 2) Each child will start at the beginning of its region and write a random
* number of blocks sequentially until the whole region is filled.
* 3) The child will seek back to the start of its region and read a random
* number of blocks. The child will verify that the blocks contain the
* appropriate contents, and then do another read.
* 4) After the contents of all the blocks have been verified, the child will
* exit.
* 5) When all child processes have completed, the parent will log the time to
* standard output.
*
* Ling Lee 8/1/91
*****************************************************************************
*/
#include <fcntl.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <sys/errno.h>
#include <sys/wait.h>
#define MIN_PROCS 5 /* minimum # conurrent processes */
#define MAX_PROCS 10 /* maximum # conurrent processes */
#define BLOCK_SIZE 512 /* basic block size */
#define MIN_BLOCKS 8 /* min read/write unit (4KB) */
#define MAX_BLOCKS 80 /* max read/write unit (32KB) */
#define BUF_SIZE (MAX_BLOCKS*BLOCK_SIZE)
struct testrec {
int reg_base; /* offset from the beginning of the partition */
int reg_size; /* size of the region in basic blocks */
int pid; /* pid of the child process checking this region */
} region[MAX_PROCS];
int num_regions; /* number of regions partition divided into */
int iterations; /* number of times entire partition read/verified */
int fullcompare; /* if 1 then compare all words in read/write buffers */
void abnormal_exit(child_pid)
int child_pid;
{
int i;
for (i = 0; i < num_regions; i++) {
if (region[i].pid == child_pid) {
fprintf(stderr, "\tRegion %d (PID %d) exited abnormally: blocks %d to %d\n",
i, child_pid, region[i].reg_base,
region[i].reg_size+region[i].reg_base-1);
return;
}
}
fprintf(stderr, "Unexpected exit - pid %d\n", child_pid);
return;
}
waitforchildren()
{
int status, child_pid;
extern int errno;
for(;;) {
child_pid = wait(&status);
if ((child_pid < 0) && (errno == ECHILD))
break;
else if (!WIFEXITED(status))
abnormal_exit(child_pid);
#ifdef DEBUG
else {
int i;
for (i = 0; i < num_regions; i++) {
if (region[i].pid == child_pid) {
printf("Rawtest(%d): exited OK\n", i);
break;
}
}
if (i == num_regions)
fprintf(stderr, "Unexpected exit - pid %d\n",
child_pid);
}
#endif
}
#ifdef DEBUG
sleep(8);
#endif
return 0;
}
/* get a random number of basic blocks to read/write */
get_num_blocks()
{
return((rand() % (MAX_BLOCKS - MIN_BLOCKS + 1)) + MIN_BLOCKS);
}
/*
* set the sizes for each of the regions
*/
int
set_regions(int part_size)
{
int numregs, basicsize;
int base, size, i;
numregs = (rand() % (MAX_PROCS - MIN_PROCS + 1)) + MIN_PROCS;
basicsize = part_size / numregs;
for (base = 0, i = 0; base < part_size; base += size, i++) {
size = rand() % (basicsize / 4); /* 0% to 25% of partition */
size -= (basicsize / 8); /* range of -12% to +12% */
size += basicsize; /* new region size */
if ((base + size) > part_size)
size = part_size - base;
region[i].reg_base = base;
region[i].reg_size = size;
printf("Region %2d: from %8d, to %8d (%8d blocks)\n",
i, base, base+size-1, size);
}
return(i);
}
void
data_check(int id, int num_blocks, int start_block, char *buf)
{
register unsigned *rp, testval;
register int i, j;
if (fullcompare) {
rp = (unsigned *) buf;
for (j = 0; j < num_blocks; j++) {
testval = (id << 24) | (j + start_block);
for (i = 0; i < BLOCK_SIZE/4; rp++, i++) {
if (*rp != testval) {
fprintf(stderr, "%d: bad compare at %x, expected: %x, got: %x\n",
id, start_block + j,
testval, *rp);
}
}
}
} else {
for (rp = (unsigned *) buf, j = 0;
j < num_blocks;
rp += (BLOCK_SIZE/4), j++)
{
testval = (id << 24) | (j + start_block);
if (*rp != testval) {
fprintf(stderr, "%d: bad compare at %x, expected: %x, got: %x\n",
id, start_block + j,
testval, *rp);
}
}
}
}
void
fillbuf(int id, int num_blocks, int start_block, char *buf)
{
register unsigned *rp, setval;
register int i, j;
if (fullcompare) {
rp = (unsigned *) buf;
for (j = 0; j < num_blocks; j++) {
setval = (id << 24) | (j + start_block);
for (i = 0; i < BLOCK_SIZE/4; rp++, i++)
*rp = setval;
}
} else {
for (rp = (unsigned *) buf, j = 0;
j < num_blocks;
rp += (BLOCK_SIZE/4), j++)
{
*rp = (id << 24) | (j + start_block);
}
}
}
char buffer[BUF_SIZE];
int
dorawtest(char *fname, int id, int base, int size)
{
int numblocks, offset, fd;
#ifdef DEBUG
printf("Rawtest(%d): base %d, size %d\n", id, base, size);
#endif
srand((unsigned) getpid()); /* seed the randomizer in this child */
/* open the raw device */
if ((fd = open(fname, O_RDWR)) == -1) {
fprintf(stderr, "Can't open: %s \n", fname);
exit (1);
}
/*
* seek to base of region within device
*/
if (lseek(fd, (long)(base*BLOCK_SIZE), SEEK_SET) < 0) {
fprintf(stderr, "%d: lseek(%d) failed\n",
id, (base*BLOCK_SIZE));
return (-1);
}
#ifdef DEBUG2
printf("process %d lseek to block %d\n", id, base);
#endif
/*
* write data to fill region
*/
for (offset = 0; offset < size; offset += numblocks) {
numblocks = get_num_blocks();
if ((numblocks + offset) > size)
numblocks = size - offset;
fillbuf(id, numblocks, offset, buffer);
#ifdef DEBUG2
printf("process %d writing blocks %ld to %ld\n",
id, offset, offset+numblocks-1);
#endif
if (write(fd, buffer, numblocks*BLOCK_SIZE) !=
(numblocks*BLOCK_SIZE)) {
perror("write");
exit(1);
}
}
/*
* seek back to the base of the region
*/
if (lseek(fd, (long)(base*BLOCK_SIZE), SEEK_SET) < 0) {
fprintf(stderr, "%d: lseek(%d) failed\n",
id, (base*BLOCK_SIZE));
return (-1);
}
#ifdef DEBUG2
printf("process %d lseek to block %d\n", id, base);
#endif
/*
* read and verify data in region
*/
for (offset = 0; offset < size; offset += numblocks) {
numblocks = get_num_blocks();
if ((numblocks + offset) > size)
numblocks = size - offset;
#ifdef DEBUG2
printf("process %d reading blocks %ld to %ld\n",
id, offset, offset+numblocks-1);
#endif
if (read(fd, buffer, numblocks*BLOCK_SIZE) !=
(numblocks*BLOCK_SIZE)) {
perror("read");
exit(1);
}
data_check(id, numblocks, offset, buffer);
}
return 0;
}
void
main(argc, argv)
int argc;
char **argv;
{
char *fname, *tstamp;
int fsize; /* raw disk size */
int i, k, fd;
time_t now;
struct stat sb;
if (argc < 3) {
fprintf(stderr, "Usage:\t%s <file_to_stat> <file_to_test> [[-]iterations]\n");
fprintf(stderr, "\twhere iterations < 0 means compare 128 words/block\n");
fprintf(stderr, "\t iterations >= 0 means compare 1 word/block\n");
exit (1);
}
if (argc < 4)
iterations = 1;
else
iterations = atoi(argv[3]);
fullcompare = 0;
if (iterations < 0) {
iterations = -iterations; /* make it positive again */
fullcompare = 1;
}
#define STAT_WORKING
#ifdef STAT_WORKING
if ((fd = open(argv[1], O_RDWR)) < 0) {
fprintf(stderr, "Can't open %s\n", argv[1]);
exit(1);
}
if (fstat(fd, &sb) < 0) {
fprintf(stderr, "Can't fstat %s\n", argv[1]);
exit(1);
}
fsize = sb.st_size; /* file size in # of blocks */
if (fsize <= 0) {
fprintf(stderr, "Bad device size (%ld) on device %s\n",
fsize, argv[1]);
exit(1);
}
close(fd);
#else /* STAT_WORKING */
fsize = 100000; /* 2023350; file size in # of blocks */
#endif /* STAT_WORKING */
#ifdef DEBUG
printf("fsize = %ld (pid = %d)\n", fsize, getpid());
#endif
/* open the raw device */
if ((fd = open(argv[2], O_RDWR)) == -1) {
fprintf(stderr, "Can't open: %s ", argv[2]);
exit (1);
}
close (fd);
fname = argv[2];
srand((unsigned) getpid()); /* seed the randomizer */
for (k = 0; k < iterations; k++) {
time(&now);
tstamp = ctime(&now);
tstamp[24] = 0;
printf("\nMain Loop Iteration %d (started: %s)\n", k, tstamp);
num_regions = set_regions(fsize);
for (i = 0; i < num_regions; i++) {
int pid;
if ((pid = fork()) < 0) {
perror("fork()");
sleep(10);
} else if (pid == 0) {
int ret; /* child proc */
ret = dorawtest(fname, i, region[i].reg_base,
region[i].reg_size);
exit(ret);
}
/* parent, successful fork */
region[i].pid = pid;
}
waitforchildren();
time(&now);
tstamp = ctime(&now);
tstamp[24] = 0;
printf("Ended: %s\n", tstamp);
}
}