add fstest.c and mmapcat.c - keep a copy of these here so they don't get

lost and so that I can write some QA tests which make use of em.  authors
are listed at the head of each file, minor mods made to fix warnings, etc.
This commit is contained in:
Nathan Scott
2002-06-18 04:37:18 +00:00
parent 9173c16a73
commit eafc89f616
3 changed files with 368 additions and 1 deletions
+2 -1
View File
@@ -35,7 +35,8 @@ include $(TOPDIR)/include/builddefs
TARGETS = alloc acl_get bstat devzero dirstress fault feature \
fsstress fill fill2 getpagesize holes ioctl loggen lstat64 \
nametest permname randholes runas truncfile usemem
nametest permname randholes runas truncfile usemem \
fstest mmapcat
ifeq ($(HAVE_DB), true)
TARGETS += dbtest
endif
+340
View File
@@ -0,0 +1,340 @@
/* Verification tool, designed to detect data corruption on a filesystem
tridge@samba.org, March 2002
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
/* variables settable on the command line */
static int loop_count = 100;
static int num_files = 1;
static int file_size = 1024*1024;
static int block_size = 1024;
static char *base_dir = ".";
static int use_mmap;
static int use_sync;
static int do_frags = 1;
typedef unsigned char uchar;
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
static void *x_malloc(int size)
{
void *ret = malloc(size);
if (!ret) {
fprintf(stderr,"Out of memory for size %d!\n", size);
exit(1);
}
return ret;
}
/* generate a buffer for a particular child, fnum etc. Just use a simple buffer
to make debugging easy
*/
static void gen_buffer(uchar *buf, int loop, int child, int fnum, int ofs)
{
uchar v = (loop+child+fnum+(ofs/block_size)) % 256;
memset(buf, v, block_size);
}
/*
check if a buffer from disk is correct
*/
static void check_buffer(uchar *buf, int loop, int child, int fnum, int ofs)
{
uchar *buf2;
buf2 = x_malloc(block_size);
gen_buffer(buf2, loop, child, fnum, ofs);
if (memcmp(buf, buf2, block_size) != 0) {
int i, j;
for (i=0;buf[i] == buf2[i] && i<block_size;i++) ;
fprintf(stderr,"Corruption in child %d fnum %d at offset %d\n",
child, fnum, ofs+i);
printf("Correct: ");
for (j=0;j<MIN(20, block_size-i);j++) {
printf("%02x ", buf2[j+i]);
}
printf("\n");
printf("Incorrect: ");
for (j=0;j<MIN(20, block_size-i);j++) {
printf("%02x ", buf[j+i]);
}
printf("\n");
exit(1);
}
free(buf2);
}
/*
create a file with a known data set for a child
*/
static void create_file(const char *dir, int loop, int child, int fnum)
{
uchar *buf;
int size, fd;
char fname[1024];
buf = x_malloc(block_size);
sprintf(fname, "%s/file%d", dir, fnum);
fd = open(fname, O_RDWR|O_CREAT|O_TRUNC | (use_sync?O_SYNC:0), 0644);
if (fd == -1) {
perror(fname);
exit(1);
}
if (!use_mmap) {
for (size=0; size<file_size; size += block_size * do_frags) {
gen_buffer(buf, loop, child, fnum, size);
if (pwrite(fd, buf, block_size, size) != block_size) {
fprintf(stderr,"Write failed at offset %d\n", size);
exit(1);
}
}
} else {
char *p;
if (ftruncate(fd, file_size) != 0) {
perror("ftruncate");
exit(1);
}
p = mmap(NULL, file_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (p == (char *)-1) {
perror("mmap");
exit(1);
}
for (size=0; size<file_size; size += block_size * do_frags) {
gen_buffer(p+size, loop, child, fnum, size);
}
munmap(p, file_size);
}
free(buf);
close(fd);
}
/*
check that a file has the right data
*/
static void check_file(const char *dir, int loop, int child, int fnum)
{
uchar *buf;
int size, fd;
char fname[1024];
buf = x_malloc(block_size);
sprintf(fname, "%s/file%d", dir, fnum);
fd = open(fname, O_RDONLY);
if (fd == -1) {
perror(fname);
exit(1);
}
for (size=0; size<file_size; size += block_size * do_frags) {
if (pread(fd, buf, block_size, size) != block_size) {
fprintf(stderr,"read failed at offset %d\n", size);
exit(1);
}
check_buffer(buf, loop, child, fnum, size);
}
free(buf);
close(fd);
}
/*
recursive directory traversal - used for cleanup
fn() is called on all files/dirs in the tree
*/
void traverse(const char *dir, int (*fn)(const char *))
{
DIR *d;
struct dirent *de;
d = opendir(dir);
if (!d) return;
while ((de = readdir(d))) {
char fname[1024];
struct stat st;
if (strcmp(de->d_name,".") == 0) continue;
if (strcmp(de->d_name,"..") == 0) continue;
sprintf(fname, "%s/%s", dir, de->d_name);
if (lstat(fname, &st)) {
perror(fname);
continue;
}
if (S_ISDIR(st.st_mode)) {
traverse(fname, fn);
}
fn(fname);
}
closedir(d);
}
/* the main child function - this creates/checks the file for one child */
static void run_child(int child)
{
int i, loop;
char dir[1024];
sprintf(dir, "%s/child%d", base_dir, child);
/* cleanup any old files */
if (remove(dir) != 0 && errno != ENOENT) {
printf("Child %d cleaning %s\n", child, dir);
traverse(dir, remove);
remove(dir);
}
if (mkdir(dir, 0755) != 0) {
perror(dir);
exit(1);
}
for (loop = 0; loop < loop_count; loop++) {
printf("Child %d loop %d\n", child, loop);
for (i=0;i<num_files;i++) {
create_file(dir, loop, child, i);
}
for (i=0;i<num_files;i++) {
check_file(dir, loop, child, i);
}
}
/* cleanup afterwards */
printf("Child %d cleaning up %s\n", child, dir);
traverse(dir, remove);
remove(dir);
exit(0);
}
static void usage(void)
{
printf("\n"
"Usage: fstest [options]\n"
"\n"
" -F generate files with holes\n"
" -n num_children set number of child processes\n"
" -f num_files set number of files\n"
" -s file_size set file sizes\n"
" -b block_size set block (IO) size\n"
" -p path set base path\n"
" -l loops set loop count\n"
" -m use mmap\n"
" -S use synchronous IO\n"
" -h show this help message\n");
}
/* main program */
int main(int argc, char *argv[])
{
int c;
extern char *optarg;
extern int optind;
int num_children = 1;
int i, status, ret;
while ((c = getopt(argc, argv, "Fn:s:f:p:l:b:Shm")) != -1) {
switch (c) {
case 'F':
do_frags = 2;
break;
case 'n':
num_children = strtol(optarg, NULL, 0);
break;
case 'b':
block_size = strtol(optarg, NULL, 0);
break;
case 'f':
num_files = strtol(optarg, NULL, 0);
break;
case 's':
file_size = strtol(optarg, NULL, 0);
break;
case 'p':
base_dir = optarg;
break;
case 'm':
use_mmap = 1;
break;
case 'S':
use_sync = 1;
break;
case 'l':
loop_count = strtol(optarg, NULL, 0);
break;
case 'h':
usage();
exit(0);
default:
usage();
exit(1);
}
}
argc -= optind;
argv += optind;
/* round up the file size */
if (file_size % block_size != 0) {
file_size = (file_size + (block_size-1)) / block_size;
file_size *= block_size;
printf("Rounded file size to %d\n", file_size);
}
printf("num_children=%d file_size=%d num_files=%d loop_count=%d block_size=%d\nmmap=%d sync=%d\n",
num_children, file_size, num_files, loop_count, block_size, use_mmap, use_sync);
printf("Total data size %.1f Mbyte\n",
num_files * num_children * 1.0e-6 * file_size);
/* fork and run run_child() for each child */
for (i=0;i<num_children;i++) {
if (fork() == 0) {
run_child(i);
exit(0);
}
}
ret = 0;
/* wait for children to exit */
while (waitpid(0, &status, 0) == 0 || errno != ECHILD) {
if (WEXITSTATUS(status) != 0) {
ret = WEXITSTATUS(status);
printf("Child exited with status %d\n", ret);
}
}
if (ret != 0) {
printf("fstest failed with status %d\n", ret);
}
return ret;
}
+26
View File
@@ -0,0 +1,26 @@
/* mmapcat.c - derived from source by misiek@pld.ORG.PL */
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int fd;
char *ptr;
struct stat64 st;
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
perror(argv[1]);
exit(1);
}
fstat64(fd, &st);
ptr = mmap64(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
while (*ptr != 0)
write(1, ptr++, 1);
exit(0);
}