📄 fsx.c
字号:
/* * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ * * File: fsx.c * Author: Avadis Tevanian, Jr. * * File system exerciser. * * Rewrite and enhancements 1998-2001 Conrad Minshall -- conrad@mac.com * * Various features from Joe Sokol, Pat Dirks, and Clark Warner. * * Small changes to work under Linux -- davej@suse.de * * Sundry porting patches from Guy Harris 12/2001 * $FreeBSD: src/tools/regression/fsx/fsx.c,v 1.1 2001/12/20 04:15:57 jkh Exp $ */#include <sys/types.h>#include <sys/stat.h>#if defined(_UWIN) || defined(__linux__)# include <sys/param.h># include <limits.h># include <time.h># include <strings.h># include <sys/time.h>#endif#include <fcntl.h>#include <sys/mman.h>#ifndef MAP_FILE# define MAP_FILE 0#endif#include <limits.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <stdarg.h>#include <errno.h>#define NUMPRINTCOLUMNS 32 /* # columns of data to print on each line *//* * A log entry is an operation and a bunch of arguments. */struct log_entry { int operation; struct timeval tv; int args[3];};#define LOGSIZE 1000struct log_entry oplog[LOGSIZE]; /* the log */int logptr = 0; /* current position in log */int logcount = 0; /* total ops *//* * Define operations */#define OP_READ 1#define OP_WRITE 2#define OP_TRUNCATE 3#define OP_CLOSEOPEN 4#define OP_MAPREAD 5#define OP_MAPWRITE 6#define OP_SKIPPED 7int page_size;int page_mask;char *original_buf; /* a pointer to the original data */char *good_buf; /* a pointer to the correct data */char *temp_buf; /* a pointer to the current data */char *fname; /* name of our test file */char logfile[1024]; /* name of our log file */char goodfile[1024]; /* name of our test file */off_t file_size = 0;off_t biggest = 0;char state[256];unsigned long testcalls = 0; /* calls to function "test" */unsigned long simulatedopcount = 0; /* -b flag */int closeprob = 0; /* -c flag */int debug = 0; /* -d flag */unsigned long debugstart = 0; /* -D flag */unsigned long maxfilelen = 256 * 1024; /* -l flag */int sizechecks = 1; /* -n flag disables them */int maxoplen = 64 * 1024; /* -o flag */int quiet = 0; /* -q flag */unsigned long progressinterval = 0; /* -p flag */int readbdy = 1; /* -r flag */int style = 0; /* -s flag */int truncbdy = 1; /* -t flag */int writebdy = 1; /* -w flag */long monitorstart = -1; /* -m flag */long monitorend = -1; /* -m flag */int lite = 0; /* -L flag */long numops = -1; /* -N flag */int randomoplen = 1; /* -O flag disables it */int seed = 1; /* -S flag */int mapped_writes = 1; /* -W flag disables */int mapped_reads = 1; /* -R flag disables it */int fsxgoodfd = 0;FILE * fsxlogf = NULL;int badoff = -1;voidvwarnc(code, fmt, ap) int code; const char *fmt; va_list ap;{ fprintf(stderr, "fsx: "); if (fmt != NULL) { vfprintf(stderr, fmt, ap); fprintf(stderr, ": "); } fprintf(stderr, "%s\n", strerror(code));}voidwarn(const char * fmt, ...){ va_list ap; va_start(ap, fmt); vwarnc(errno, fmt, ap); va_end(ap);}void__attribute__((format(printf, 1, 2)))prt(char *fmt, ...){ va_list args; va_start(args, fmt); vfprintf(stdout, fmt, args); va_end(args); if (fsxlogf) { va_start(args, fmt); vfprintf(fsxlogf, fmt, args); va_end(args); }}voidprterr(char *prefix){ prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno));}voidlog4(int operation, int arg0, int arg1, int arg2, struct timeval *tv){ struct log_entry *le; le = &oplog[logptr]; le->tv = *tv; le->operation = operation; le->args[0] = arg0; le->args[1] = arg1; le->args[2] = arg2; logptr++; logcount++; if (logptr >= LOGSIZE) logptr = 0;}voidlogdump(void){ int i, count, down; struct log_entry *lp; prt("LOG DUMP (%d total operations):\n", logcount); if (logcount < LOGSIZE) { i = 0; count = logcount; } else { i = logptr; count = LOGSIZE; } for ( ; count > 0; count--) { int opnum; opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE; lp = &oplog[i]; prt("%d: %lu.%06lu ", opnum, lp->tv.tv_sec, lp->tv.tv_usec); switch (lp->operation) { case OP_MAPREAD: prt("MAPREAD 0x%x thru 0x%x (0x%x bytes)", lp->args[0], lp->args[0] + lp->args[1] - 1, lp->args[1]); if (badoff >= lp->args[0] && badoff < lp->args[0] + lp->args[1]) prt("\t***RRRR***"); break; case OP_MAPWRITE: prt("MAPWRITE 0x%x thru 0x%x (0x%x bytes)", lp->args[0], lp->args[0] + lp->args[1] - 1, lp->args[1]); if (badoff >= lp->args[0] && badoff < lp->args[0] + lp->args[1]) prt("\t******WWWW"); break; case OP_READ: prt("READ 0x%x thru 0x%x (0x%x bytes)", lp->args[0], lp->args[0] + lp->args[1] - 1, lp->args[1]); if (badoff >= lp->args[0] && badoff < lp->args[0] + lp->args[1]) prt("\t***RRRR***"); break; case OP_WRITE: prt("WRITE 0x%x thru 0x%x (0x%x bytes)", lp->args[0], lp->args[0] + lp->args[1] - 1, lp->args[1]); if (lp->args[0] > lp->args[2]) prt(" HOLE"); else if (lp->args[0] + lp->args[1] > lp->args[2]) prt(" EXTEND"); if ((badoff >= lp->args[0] || badoff >=lp->args[2]) && badoff < lp->args[0] + lp->args[1]) prt("\t***WWWW"); break; case OP_TRUNCATE: down = lp->args[0] < lp->args[1]; prt("TRUNCATE %s\tfrom 0x%x to 0x%x", down ? "DOWN" : "UP", lp->args[1], lp->args[0]); if (badoff >= lp->args[!down] && badoff < lp->args[!!down]) prt("\t******WWWW"); break; case OP_CLOSEOPEN: prt("CLOSE/OPEN"); break; case OP_SKIPPED: prt("SKIPPED (no operation)"); break; default: prt("BOGUS LOG ENTRY (operation code = %d)!", lp->operation); } prt("\n"); i++; if (i == LOGSIZE) i = 0; }}voidsave_buffer(char *buffer, off_t bufferlength, int fd){ off_t ret; ssize_t byteswritten; if (fd <= 0 || bufferlength == 0) return; if (bufferlength > SSIZE_MAX) { prt("fsx flaw: overflow in save_buffer\n"); exit(67); } if (lite) { off_t size_by_seek = lseek(fd, (off_t)0, SEEK_END); if (size_by_seek == (off_t)-1) prterr("save_buffer: lseek eof"); else if (bufferlength > size_by_seek) { warn("save_buffer: .fsxgood file too short... will" "save 0x%llx bytes instead of 0x%llx\n", (unsigned long long)size_by_seek, (unsigned long long)bufferlength); bufferlength = size_by_seek; } } ret = lseek(fd, (off_t)0, SEEK_SET); if (ret == (off_t)-1) prterr("save_buffer: lseek 0"); byteswritten = write(fd, buffer, (size_t)bufferlength); if (byteswritten != bufferlength) { if (byteswritten == -1) prterr("save_buffer write"); else warn("save_buffer: short write, 0x%x bytes instead" "of 0x%llx\n", (unsigned)byteswritten, (unsigned long long)bufferlength); }}voidreport_failure(int status){ logdump(); if (fsxgoodfd) { if (good_buf) { save_buffer(good_buf, file_size, fsxgoodfd); prt("Correct content saved for comparison\n"); prt("(maybe hexdump \"%s\" vs \"%s\")\n", fname, goodfile); } close(fsxgoodfd); } exit(status);}#define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \ *(((unsigned char *)(cp)) + 1)))voidcheck_buffers(unsigned offset, unsigned size){ unsigned char c, t; unsigned i = 0; unsigned n = 0; unsigned op = 0; unsigned bad = 0; if (memcmp(good_buf + offset, temp_buf, size) != 0) { prt("READ BAD DATA: offset = 0x%x, size = 0x%x\n", offset, size); prt("OFFSET\tGOOD\tBAD\tRANGE\n"); while (size > 0) { c = good_buf[offset]; t = temp_buf[i]; if (c != t) { if (n == 0) { bad = short_at(&temp_buf[i]); prt("%#07x\t%#06x\t%#06x", offset, short_at(&good_buf[offset]), bad); op = temp_buf[offset & 1 ? i+1 : i]; } n++; badoff = offset; } offset++; i++; size--; } if (n) { prt("\t%#7x\n", n); if (bad) prt("operation# (mod 256) for the bad data" "may be %u\n", ((unsigned)op & 0xff)); else prt("operation# (mod 256) for the bad data" "unknown, check HOLE and EXTEND ops\n"); } else prt("????????????????\n"); report_failure(110); }}struct test_file { char *path; int fd;} *test_files = NULL;int num_test_files = 0;enum fd_iteration_policy { FD_SINGLE, FD_ROTATE, FD_RANDOM,};int fd_policy = FD_RANDOM;int fd_last = 0;struct test_file * get_tf(void){ unsigned index = 0; switch (fd_policy) { case FD_ROTATE: index = fd_last++; break; case FD_RANDOM: index = random(); break; case FD_SINGLE: index = 0; break; default: prt("unknown policy"); exit(1); break; } return &test_files[ index % num_test_files ];}voidassign_fd_policy(char *policy){ if (!strcmp(policy, "random")) fd_policy = FD_RANDOM; else if (!strcmp(policy, "rotate")) fd_policy = FD_ROTATE; else { prt("unknown -I policy: '%s'\n", policy); exit(1); }}intget_fd(void){ struct test_file *tf = get_tf(); return tf->fd;}static const char *my_basename(const char *path){ char *c = strrchr(path, '/'); return c ? c++ : path;}voidopen_test_files(char **argv, int argc){ struct test_file *tf; int i; num_test_files = argc; if (num_test_files == 1) fd_policy = FD_SINGLE; test_files = calloc(num_test_files, sizeof(*test_files)); if (test_files == NULL) { prterr("reallocating space for test files");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -