188242Sjkh/* 288242Sjkh * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved. 388242Sjkh * 488242Sjkh * @APPLE_LICENSE_HEADER_START@ 588242Sjkh * 688242Sjkh * The contents of this file constitute Original Code as defined in and 7132704Sjkh * are subject to the Apple Public Source License Version 2.0 (the 888242Sjkh * "License"). You may not use this file except in compliance with the 988242Sjkh * License. Please obtain a copy of the License at 10132704Sjkh * http://www.opensource.apple.com/apsl/ and read it before using this file. 1188242Sjkh * 1288242Sjkh * This Original Code and all software distributed under the License are 1388242Sjkh * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 1488242Sjkh * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 1588242Sjkh * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 1688242Sjkh * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 1788242Sjkh * License for the specific language governing rights and limitations 1888242Sjkh * under the License. 1988242Sjkh * 2088242Sjkh * @APPLE_LICENSE_HEADER_END@ 2188242Sjkh * 2288242Sjkh * File: fsx.c 2388242Sjkh * Author: Avadis Tevanian, Jr. 2488242Sjkh * 25113949Sjkh * File system exerciser. 2688242Sjkh * 2788242Sjkh * Rewrite and enhancements 1998-2001 Conrad Minshall -- conrad@mac.com 2888242Sjkh * 2988242Sjkh * Various features from Joe Sokol, Pat Dirks, and Clark Warner. 3088242Sjkh * 3188242Sjkh * Small changes to work under Linux -- davej@suse.de 3288242Sjkh * 3388242Sjkh * Sundry porting patches from Guy Harris 12/2001 34113949Sjkh * 35113949Sjkh * Checks for mmap last-page zero fill. 36113949Sjkh * 37132704Sjkh * Updated license to APSL 2.0, 2004/7/27 - Jordan Hubbard 38132704Sjkh * 3988242Sjkh * $FreeBSD$ 40113949Sjkh * 4188242Sjkh */ 4288242Sjkh 4388242Sjkh#include <sys/types.h> 4488242Sjkh#include <sys/stat.h> 4588242Sjkh#ifdef _UWIN 4688242Sjkh# include <sys/param.h> 4788242Sjkh# include <limits.h> 4888242Sjkh# include <time.h> 4988242Sjkh# include <strings.h> 5088242Sjkh#endif 5188242Sjkh#include <fcntl.h> 5288242Sjkh#include <sys/mman.h> 5388242Sjkh#ifndef MAP_FILE 5488242Sjkh# define MAP_FILE 0 5588242Sjkh#endif 5688242Sjkh#include <limits.h> 5788242Sjkh#include <signal.h> 5888242Sjkh#include <stdio.h> 5988242Sjkh#include <stdlib.h> 6088242Sjkh#include <string.h> 6188242Sjkh#include <unistd.h> 6288242Sjkh#include <stdarg.h> 6388242Sjkh#include <errno.h> 6488242Sjkh 6588242Sjkh#define NUMPRINTCOLUMNS 32 /* # columns of data to print on each line */ 6688242Sjkh 6788242Sjkh/* 6888242Sjkh * A log entry is an operation and a bunch of arguments. 6988242Sjkh */ 7088242Sjkh 7188242Sjkhstruct log_entry { 7288242Sjkh int operation; 7388242Sjkh int args[3]; 7488242Sjkh}; 7588242Sjkh 7688242Sjkh#define LOGSIZE 1000 7788242Sjkh 7888242Sjkhstruct log_entry oplog[LOGSIZE]; /* the log */ 7988242Sjkhint logptr = 0; /* current position in log */ 8088242Sjkhint logcount = 0; /* total ops */ 8188242Sjkh 8288242Sjkh/* 8388242Sjkh * Define operations 8488242Sjkh */ 8588242Sjkh 8688242Sjkh#define OP_READ 1 8788242Sjkh#define OP_WRITE 2 8888242Sjkh#define OP_TRUNCATE 3 8988242Sjkh#define OP_CLOSEOPEN 4 9088242Sjkh#define OP_MAPREAD 5 9188242Sjkh#define OP_MAPWRITE 6 9288242Sjkh#define OP_SKIPPED 7 93260729Savg#define OP_INVALIDATE 8 9488242Sjkh 9588242Sjkhint page_size; 9688242Sjkhint page_mask; 9788242Sjkh 9888242Sjkhchar *original_buf; /* a pointer to the original data */ 9988242Sjkhchar *good_buf; /* a pointer to the correct data */ 10088242Sjkhchar *temp_buf; /* a pointer to the current data */ 10188242Sjkhchar *fname; /* name of our test file */ 10288242Sjkhint fd; /* fd for our test file */ 10388242Sjkh 10488242Sjkhoff_t file_size = 0; 10588242Sjkhoff_t biggest = 0; 10688242Sjkhchar state[256]; 10788242Sjkhunsigned long testcalls = 0; /* calls to function "test" */ 10888242Sjkh 10988242Sjkhunsigned long simulatedopcount = 0; /* -b flag */ 11088242Sjkhint closeprob = 0; /* -c flag */ 111260729Savgint invlprob = 0; /* -i flag */ 11288242Sjkhint debug = 0; /* -d flag */ 11388242Sjkhunsigned long debugstart = 0; /* -D flag */ 11488242Sjkhunsigned long maxfilelen = 256 * 1024; /* -l flag */ 11588242Sjkhint sizechecks = 1; /* -n flag disables them */ 11688242Sjkhint maxoplen = 64 * 1024; /* -o flag */ 11788242Sjkhint quiet = 0; /* -q flag */ 11888242Sjkhunsigned long progressinterval = 0; /* -p flag */ 11988242Sjkhint readbdy = 1; /* -r flag */ 12088242Sjkhint style = 0; /* -s flag */ 12188242Sjkhint truncbdy = 1; /* -t flag */ 12288242Sjkhint writebdy = 1; /* -w flag */ 12388242Sjkhlong monitorstart = -1; /* -m flag */ 12488242Sjkhlong monitorend = -1; /* -m flag */ 12588242Sjkhint lite = 0; /* -L flag */ 12688242Sjkhlong numops = -1; /* -N flag */ 12788242Sjkhint randomoplen = 1; /* -O flag disables it */ 12888242Sjkhint seed = 1; /* -S flag */ 129113949Sjkhint mapped_writes = 1; /* -W flag disables */ 13088242Sjkhint mapped_reads = 1; /* -R flag disables it */ 131260726Savgint mapped_msync = 1; /* -U flag disables */ 13288242Sjkhint fsxgoodfd = 0; 13388242SjkhFILE * fsxlogf = NULL; 13488242Sjkhint badoff = -1; 13588242Sjkhint closeopen = 0; 136260729Savgint invl = 0; 13788242Sjkh 13888242Sjkh 13988242Sjkhvoid 14088242Sjkhvwarnc(code, fmt, ap) 14188242Sjkh int code; 14288242Sjkh const char *fmt; 14388242Sjkh va_list ap; 14488242Sjkh{ 14588242Sjkh fprintf(stderr, "fsx: "); 14688242Sjkh if (fmt != NULL) { 14788242Sjkh vfprintf(stderr, fmt, ap); 14888242Sjkh fprintf(stderr, ": "); 14988242Sjkh } 15088242Sjkh fprintf(stderr, "%s\n", strerror(code)); 15188242Sjkh} 15288242Sjkh 15388242Sjkh 15488242Sjkhvoid 15588242Sjkhwarn(const char * fmt, ...) 15688242Sjkh{ 15788242Sjkh va_list ap; 15888242Sjkh va_start(ap, fmt); 15988242Sjkh vwarnc(errno, fmt, ap); 16088242Sjkh va_end(ap); 16188242Sjkh} 16288242Sjkh 16388242Sjkh 16488242Sjkhvoid 16588242Sjkhprt(char *fmt, ...) 16688242Sjkh{ 16788242Sjkh va_list args; 16888242Sjkh 16988242Sjkh va_start(args, fmt); 17088242Sjkh vfprintf(stdout, fmt, args); 171171046Sdelphij va_end(args); 172171046Sdelphij 173171046Sdelphij if (fsxlogf) { 174171046Sdelphij va_start(args, fmt); 17588242Sjkh vfprintf(fsxlogf, fmt, args); 176171046Sdelphij va_end(args); 177171046Sdelphij } 17888242Sjkh} 17988242Sjkh 18088242Sjkhvoid 18188242Sjkhprterr(char *prefix) 18288242Sjkh{ 18388242Sjkh prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno)); 18488242Sjkh} 18588242Sjkh 18688242Sjkh 18788242Sjkhvoid 188260729Savgdo_log4(int operation, int arg0, int arg1, int arg2) 18988242Sjkh{ 19088242Sjkh struct log_entry *le; 19188242Sjkh 19288242Sjkh le = &oplog[logptr]; 19388242Sjkh le->operation = operation; 19488242Sjkh le->args[0] = arg0; 19588242Sjkh le->args[1] = arg1; 19688242Sjkh le->args[2] = arg2; 19788242Sjkh logptr++; 19888242Sjkh logcount++; 19988242Sjkh if (logptr >= LOGSIZE) 20088242Sjkh logptr = 0; 20188242Sjkh} 20288242Sjkh 20388242Sjkh 20488242Sjkhvoid 205260729Savglog4(int operation, int arg0, int arg1, int arg2) 206260729Savg{ 207260729Savg do_log4(operation, arg0, arg1, arg2); 208260729Savg if (closeopen) 209260729Savg do_log4(OP_CLOSEOPEN, 0, 0, 0); 210260729Savg if (invl) 211260729Savg do_log4(OP_INVALIDATE, 0, 0, 0); 212260729Savg} 213260729Savg 214260729Savg 215260729Savgvoid 21688242Sjkhlogdump(void) 21788242Sjkh{ 21888242Sjkh struct log_entry *lp; 219260729Savg int i, count, down, opnum; 22088242Sjkh 22188242Sjkh prt("LOG DUMP (%d total operations):\n", logcount); 22288242Sjkh if (logcount < LOGSIZE) { 22388242Sjkh i = 0; 22488242Sjkh count = logcount; 22588242Sjkh } else { 22688242Sjkh i = logptr; 22788242Sjkh count = LOGSIZE; 22888242Sjkh } 229260729Savg 230260729Savg opnum = i + 1 + (logcount/LOGSIZE)*LOGSIZE; 23188242Sjkh for ( ; count > 0; count--) { 232260729Savg lp = &oplog[i]; 23388242Sjkh 234260729Savg if (lp->operation == OP_CLOSEOPEN || 235260729Savg lp->operation == OP_INVALIDATE) { 236260729Savg switch (lp->operation) { 237260729Savg case OP_CLOSEOPEN: 238260729Savg prt("\t\tCLOSE/OPEN\n"); 239260729Savg break; 240260729Savg case OP_INVALIDATE: 241260729Savg prt("\t\tMS_INVALIDATE\n"); 242260729Savg break; 243260729Savg } 244260729Savg i++; 245260729Savg if (i == LOGSIZE) 246260729Savg i = 0; 247260729Savg continue; 248260729Savg } 249260729Savg 25088242Sjkh prt("%d(%d mod 256): ", opnum, opnum%256); 25188242Sjkh switch (lp->operation) { 25288242Sjkh case OP_MAPREAD: 25388242Sjkh prt("MAPREAD\t0x%x thru 0x%x\t(0x%x bytes)", 25488242Sjkh lp->args[0], lp->args[0] + lp->args[1] - 1, 25588242Sjkh lp->args[1]); 25688242Sjkh if (badoff >= lp->args[0] && badoff < 25788242Sjkh lp->args[0] + lp->args[1]) 25888242Sjkh prt("\t***RRRR***"); 25988242Sjkh break; 26088242Sjkh case OP_MAPWRITE: 26188242Sjkh prt("MAPWRITE 0x%x thru 0x%x\t(0x%x bytes)", 26288242Sjkh lp->args[0], lp->args[0] + lp->args[1] - 1, 26388242Sjkh lp->args[1]); 26488242Sjkh if (badoff >= lp->args[0] && badoff < 26588242Sjkh lp->args[0] + lp->args[1]) 26688242Sjkh prt("\t******WWWW"); 26788242Sjkh break; 26888242Sjkh case OP_READ: 26988242Sjkh prt("READ\t0x%x thru 0x%x\t(0x%x bytes)", 27088242Sjkh lp->args[0], lp->args[0] + lp->args[1] - 1, 27188242Sjkh lp->args[1]); 27288242Sjkh if (badoff >= lp->args[0] && 27388242Sjkh badoff < lp->args[0] + lp->args[1]) 27488242Sjkh prt("\t***RRRR***"); 27588242Sjkh break; 27688242Sjkh case OP_WRITE: 27788242Sjkh prt("WRITE\t0x%x thru 0x%x\t(0x%x bytes)", 27888242Sjkh lp->args[0], lp->args[0] + lp->args[1] - 1, 27988242Sjkh lp->args[1]); 28088242Sjkh if (lp->args[0] > lp->args[2]) 28188242Sjkh prt(" HOLE"); 28288242Sjkh else if (lp->args[0] + lp->args[1] > lp->args[2]) 28388242Sjkh prt(" EXTEND"); 28488242Sjkh if ((badoff >= lp->args[0] || badoff >=lp->args[2]) && 28588242Sjkh badoff < lp->args[0] + lp->args[1]) 28688242Sjkh prt("\t***WWWW"); 28788242Sjkh break; 28888242Sjkh case OP_TRUNCATE: 28988242Sjkh down = lp->args[0] < lp->args[1]; 29088242Sjkh prt("TRUNCATE %s\tfrom 0x%x to 0x%x", 29188242Sjkh down ? "DOWN" : "UP", lp->args[1], lp->args[0]); 29288242Sjkh if (badoff >= lp->args[!down] && 29388242Sjkh badoff < lp->args[!!down]) 29488242Sjkh prt("\t******WWWW"); 29588242Sjkh break; 29688242Sjkh case OP_SKIPPED: 29788242Sjkh prt("SKIPPED (no operation)"); 29888242Sjkh break; 29988242Sjkh default: 30088242Sjkh prt("BOGUS LOG ENTRY (operation code = %d)!", 30188242Sjkh lp->operation); 30288242Sjkh } 30388242Sjkh prt("\n"); 304260729Savg opnum++; 30588242Sjkh i++; 30688242Sjkh if (i == LOGSIZE) 30788242Sjkh i = 0; 30888242Sjkh } 30988242Sjkh} 31088242Sjkh 31188242Sjkh 31288242Sjkhvoid 31388242Sjkhsave_buffer(char *buffer, off_t bufferlength, int fd) 31488242Sjkh{ 31588242Sjkh off_t ret; 31688242Sjkh ssize_t byteswritten; 31788242Sjkh 31888242Sjkh if (fd <= 0 || bufferlength == 0) 31988242Sjkh return; 32088242Sjkh 32188242Sjkh if (bufferlength > SSIZE_MAX) { 32288242Sjkh prt("fsx flaw: overflow in save_buffer\n"); 32388242Sjkh exit(67); 32488242Sjkh } 32588242Sjkh if (lite) { 32688242Sjkh off_t size_by_seek = lseek(fd, (off_t)0, SEEK_END); 32788242Sjkh if (size_by_seek == (off_t)-1) 32888242Sjkh prterr("save_buffer: lseek eof"); 32988242Sjkh else if (bufferlength > size_by_seek) { 330113949Sjkh warn("save_buffer: .fsxgood file too short... will save 0x%llx bytes instead of 0x%llx\n", (unsigned long long)size_by_seek, 33188242Sjkh (unsigned long long)bufferlength); 33288242Sjkh bufferlength = size_by_seek; 33388242Sjkh } 33488242Sjkh } 33588242Sjkh 33688242Sjkh ret = lseek(fd, (off_t)0, SEEK_SET); 33788242Sjkh if (ret == (off_t)-1) 33888242Sjkh prterr("save_buffer: lseek 0"); 339113949Sjkh 34088242Sjkh byteswritten = write(fd, buffer, (size_t)bufferlength); 34188242Sjkh if (byteswritten != bufferlength) { 34288242Sjkh if (byteswritten == -1) 34388242Sjkh prterr("save_buffer write"); 34488242Sjkh else 345113949Sjkh warn("save_buffer: short write, 0x%x bytes instead of 0x%llx\n", 34688242Sjkh (unsigned)byteswritten, 34788242Sjkh (unsigned long long)bufferlength); 34888242Sjkh } 34988242Sjkh} 35088242Sjkh 35188242Sjkh 35288242Sjkhvoid 35388242Sjkhreport_failure(int status) 35488242Sjkh{ 35588242Sjkh logdump(); 356113949Sjkh 35788242Sjkh if (fsxgoodfd) { 35888242Sjkh if (good_buf) { 35988242Sjkh save_buffer(good_buf, file_size, fsxgoodfd); 36088242Sjkh prt("Correct content saved for comparison\n"); 36188242Sjkh prt("(maybe hexdump \"%s\" vs \"%s.fsxgood\")\n", 36288242Sjkh fname, fname); 36388242Sjkh } 36488242Sjkh close(fsxgoodfd); 36588242Sjkh } 36688242Sjkh exit(status); 36788242Sjkh} 36888242Sjkh 36988242Sjkh 37088242Sjkh#define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \ 371113949Sjkh *(((unsigned char *)(cp)) + 1))) 37288242Sjkh 37388242Sjkhvoid 37488242Sjkhcheck_buffers(unsigned offset, unsigned size) 37588242Sjkh{ 37688242Sjkh unsigned char c, t; 37788242Sjkh unsigned i = 0; 37888242Sjkh unsigned n = 0; 37988242Sjkh unsigned op = 0; 38088242Sjkh unsigned bad = 0; 38188242Sjkh 38288242Sjkh if (memcmp(good_buf + offset, temp_buf, size) != 0) { 38388242Sjkh prt("READ BAD DATA: offset = 0x%x, size = 0x%x\n", 38488242Sjkh offset, size); 38588242Sjkh prt("OFFSET\tGOOD\tBAD\tRANGE\n"); 38688242Sjkh while (size > 0) { 38788242Sjkh c = good_buf[offset]; 38888242Sjkh t = temp_buf[i]; 38988242Sjkh if (c != t) { 390113949Sjkh if (n == 0) { 39188242Sjkh bad = short_at(&temp_buf[i]); 392113949Sjkh prt("0x%5x\t0x%04x\t0x%04x", offset, 393113949Sjkh short_at(&good_buf[offset]), bad); 39488242Sjkh op = temp_buf[offset & 1 ? i+1 : i]; 39588242Sjkh } 39688242Sjkh n++; 39788242Sjkh badoff = offset; 39888242Sjkh } 39988242Sjkh offset++; 40088242Sjkh i++; 40188242Sjkh size--; 40288242Sjkh } 40388242Sjkh if (n) { 404113949Sjkh prt("\t0x%5x\n", n); 40588242Sjkh if (bad) 406113949Sjkh prt("operation# (mod 256) for the bad data may be %u\n", ((unsigned)op & 0xff)); 40788242Sjkh else 408113949Sjkh prt("operation# (mod 256) for the bad data unknown, check HOLE and EXTEND ops\n"); 40988242Sjkh } else 410113949Sjkh prt("????????????????\n"); 41188242Sjkh report_failure(110); 41288242Sjkh } 41388242Sjkh} 41488242Sjkh 41588242Sjkh 41688242Sjkhvoid 41788242Sjkhcheck_size(void) 41888242Sjkh{ 41988242Sjkh struct stat statbuf; 42088242Sjkh off_t size_by_seek; 42188242Sjkh 42288242Sjkh if (fstat(fd, &statbuf)) { 42388242Sjkh prterr("check_size: fstat"); 42488242Sjkh statbuf.st_size = -1; 42588242Sjkh } 42688242Sjkh size_by_seek = lseek(fd, (off_t)0, SEEK_END); 42788242Sjkh if (file_size != statbuf.st_size || file_size != size_by_seek) { 42888242Sjkh prt("Size error: expected 0x%llx stat 0x%llx seek 0x%llx\n", 42988242Sjkh (unsigned long long)file_size, 43088242Sjkh (unsigned long long)statbuf.st_size, 43188242Sjkh (unsigned long long)size_by_seek); 43288242Sjkh report_failure(120); 43388242Sjkh } 43488242Sjkh} 43588242Sjkh 43688242Sjkh 43788242Sjkhvoid 43888242Sjkhcheck_trunc_hack(void) 43988242Sjkh{ 44088242Sjkh struct stat statbuf; 44188242Sjkh 44288242Sjkh ftruncate(fd, (off_t)0); 44388242Sjkh ftruncate(fd, (off_t)100000); 44488242Sjkh fstat(fd, &statbuf); 44588242Sjkh if (statbuf.st_size != (off_t)100000) { 44688242Sjkh prt("no extend on truncate! not posix!\n"); 44788242Sjkh exit(130); 44888242Sjkh } 449113949Sjkh ftruncate(fd, (off_t)0); 45088242Sjkh} 45188242Sjkh 45288242Sjkh 45388242Sjkhvoid 45488242Sjkhdoread(unsigned offset, unsigned size) 45588242Sjkh{ 45688242Sjkh off_t ret; 45788242Sjkh unsigned iret; 45888242Sjkh 45988242Sjkh offset -= offset % readbdy; 46088242Sjkh if (size == 0) { 46188242Sjkh if (!quiet && testcalls > simulatedopcount) 46288242Sjkh prt("skipping zero size read\n"); 46388242Sjkh log4(OP_SKIPPED, OP_READ, offset, size); 46488242Sjkh return; 46588242Sjkh } 46688242Sjkh if (size + offset > file_size) { 46788242Sjkh if (!quiet && testcalls > simulatedopcount) 46888242Sjkh prt("skipping seek/read past end of file\n"); 46988242Sjkh log4(OP_SKIPPED, OP_READ, offset, size); 47088242Sjkh return; 47188242Sjkh } 47288242Sjkh 47388242Sjkh log4(OP_READ, offset, size, 0); 47488242Sjkh 47588242Sjkh if (testcalls <= simulatedopcount) 47688242Sjkh return; 47788242Sjkh 47888242Sjkh if (!quiet && ((progressinterval && 47988242Sjkh testcalls % progressinterval == 0) || 48088242Sjkh (debug && 481113949Sjkh (monitorstart == -1 || 48288242Sjkh (offset + size > monitorstart && 48388242Sjkh (monitorend == -1 || offset <= monitorend)))))) 48488242Sjkh prt("%lu read\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls, 48588242Sjkh offset, offset + size - 1, size); 48688242Sjkh ret = lseek(fd, (off_t)offset, SEEK_SET); 48788242Sjkh if (ret == (off_t)-1) { 48888242Sjkh prterr("doread: lseek"); 48988242Sjkh report_failure(140); 49088242Sjkh } 49188242Sjkh iret = read(fd, temp_buf, size); 49288242Sjkh if (iret != size) { 49388242Sjkh if (iret == -1) 49488242Sjkh prterr("doread: read"); 49588242Sjkh else 49688242Sjkh prt("short read: 0x%x bytes instead of 0x%x\n", 49788242Sjkh iret, size); 49888242Sjkh report_failure(141); 49988242Sjkh } 50088242Sjkh check_buffers(offset, size); 50188242Sjkh} 50288242Sjkh 50388242Sjkh 50488242Sjkhvoid 505113949Sjkhcheck_eofpage(char *s, unsigned offset, char *p, int size) 506113949Sjkh{ 507160985Sjb uintptr_t last_page, should_be_zero; 508113949Sjkh 509113949Sjkh if (offset + size <= (file_size & ~page_mask)) 510113949Sjkh return; 511113949Sjkh /* 512113949Sjkh * we landed in the last page of the file 513113949Sjkh * test to make sure the VM system provided 0's 514113949Sjkh * beyond the true end of the file mapping 515113949Sjkh * (as required by mmap def in 1996 posix 1003.1) 516113949Sjkh */ 517160985Sjb last_page = ((uintptr_t)p + (offset & page_mask) + size) & ~page_mask; 518113949Sjkh 519113949Sjkh for (should_be_zero = last_page + (file_size & page_mask); 520113949Sjkh should_be_zero < last_page + page_size; 521113949Sjkh should_be_zero++) 522113949Sjkh if (*(char *)should_be_zero) { 523113949Sjkh prt("Mapped %s: non-zero data past EOF (0x%llx) page offset 0x%x is 0x%04x\n", 524113949Sjkh s, file_size - 1, should_be_zero & page_mask, 525113949Sjkh short_at(should_be_zero)); 526113949Sjkh report_failure(205); 527113949Sjkh } 528113949Sjkh} 529113949Sjkh 530113949Sjkh 531113949Sjkhvoid 53288242Sjkhdomapread(unsigned offset, unsigned size) 53388242Sjkh{ 53488242Sjkh unsigned pg_offset; 53588242Sjkh unsigned map_size; 53688242Sjkh char *p; 53788242Sjkh 53888242Sjkh offset -= offset % readbdy; 53988242Sjkh if (size == 0) { 54088242Sjkh if (!quiet && testcalls > simulatedopcount) 54188242Sjkh prt("skipping zero size read\n"); 54288242Sjkh log4(OP_SKIPPED, OP_MAPREAD, offset, size); 54388242Sjkh return; 54488242Sjkh } 54588242Sjkh if (size + offset > file_size) { 54688242Sjkh if (!quiet && testcalls > simulatedopcount) 54788242Sjkh prt("skipping seek/read past end of file\n"); 54888242Sjkh log4(OP_SKIPPED, OP_MAPREAD, offset, size); 54988242Sjkh return; 55088242Sjkh } 55188242Sjkh 55288242Sjkh log4(OP_MAPREAD, offset, size, 0); 55388242Sjkh 55488242Sjkh if (testcalls <= simulatedopcount) 55588242Sjkh return; 55688242Sjkh 55788242Sjkh if (!quiet && ((progressinterval && 55888242Sjkh testcalls % progressinterval == 0) || 55988242Sjkh (debug && 560113949Sjkh (monitorstart == -1 || 56188242Sjkh (offset + size > monitorstart && 56288242Sjkh (monitorend == -1 || offset <= monitorend)))))) 56388242Sjkh prt("%lu mapread\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls, 56488242Sjkh offset, offset + size - 1, size); 56588242Sjkh 56688242Sjkh pg_offset = offset & page_mask; 56788242Sjkh map_size = pg_offset + size; 56888242Sjkh 569113949Sjkh if ((p = (char *)mmap(0, map_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, 57088242Sjkh (off_t)(offset - pg_offset))) == (char *)-1) { 571113949Sjkh prterr("domapread: mmap"); 57288242Sjkh report_failure(190); 57388242Sjkh } 57488242Sjkh memcpy(temp_buf, p + pg_offset, size); 575113949Sjkh 576113949Sjkh check_eofpage("Read", offset, p, size); 577113949Sjkh 57888242Sjkh if (munmap(p, map_size) != 0) { 57988242Sjkh prterr("domapread: munmap"); 58088242Sjkh report_failure(191); 58188242Sjkh } 58288242Sjkh 58388242Sjkh check_buffers(offset, size); 58488242Sjkh} 58588242Sjkh 58688242Sjkh 58788242Sjkhvoid 58888242Sjkhgendata(char *original_buf, char *good_buf, unsigned offset, unsigned size) 58988242Sjkh{ 59088242Sjkh while (size--) { 591113949Sjkh good_buf[offset] = testcalls % 256; 59288242Sjkh if (offset % 2) 59388242Sjkh good_buf[offset] += original_buf[offset]; 59488242Sjkh offset++; 59588242Sjkh } 59688242Sjkh} 59788242Sjkh 59888242Sjkh 59988242Sjkhvoid 60088242Sjkhdowrite(unsigned offset, unsigned size) 60188242Sjkh{ 60288242Sjkh off_t ret; 60388242Sjkh unsigned iret; 60488242Sjkh 60588242Sjkh offset -= offset % writebdy; 60688242Sjkh if (size == 0) { 60788242Sjkh if (!quiet && testcalls > simulatedopcount) 60888242Sjkh prt("skipping zero size write\n"); 60988242Sjkh log4(OP_SKIPPED, OP_WRITE, offset, size); 61088242Sjkh return; 61188242Sjkh } 61288242Sjkh 61388242Sjkh log4(OP_WRITE, offset, size, file_size); 61488242Sjkh 61588242Sjkh gendata(original_buf, good_buf, offset, size); 61688242Sjkh if (file_size < offset + size) { 61788242Sjkh if (file_size < offset) 61888242Sjkh memset(good_buf + file_size, '\0', offset - file_size); 61988242Sjkh file_size = offset + size; 62088242Sjkh if (lite) { 62188242Sjkh warn("Lite file size bug in fsx!"); 62288242Sjkh report_failure(149); 62388242Sjkh } 62488242Sjkh } 62588242Sjkh 62688242Sjkh if (testcalls <= simulatedopcount) 62788242Sjkh return; 62888242Sjkh 62988242Sjkh if (!quiet && ((progressinterval && 63088242Sjkh testcalls % progressinterval == 0) || 63188242Sjkh (debug && 632113949Sjkh (monitorstart == -1 || 63388242Sjkh (offset + size > monitorstart && 63488242Sjkh (monitorend == -1 || offset <= monitorend)))))) 63588242Sjkh prt("%lu write\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls, 63688242Sjkh offset, offset + size - 1, size); 63788242Sjkh ret = lseek(fd, (off_t)offset, SEEK_SET); 63888242Sjkh if (ret == (off_t)-1) { 63988242Sjkh prterr("dowrite: lseek"); 64088242Sjkh report_failure(150); 64188242Sjkh } 64288242Sjkh iret = write(fd, good_buf + offset, size); 64388242Sjkh if (iret != size) { 64488242Sjkh if (iret == -1) 64588242Sjkh prterr("dowrite: write"); 64688242Sjkh else 64788242Sjkh prt("short write: 0x%x bytes instead of 0x%x\n", 64888242Sjkh iret, size); 64988242Sjkh report_failure(151); 65088242Sjkh } 65188242Sjkh} 65288242Sjkh 65388242Sjkh 65488242Sjkhvoid 65588242Sjkhdomapwrite(unsigned offset, unsigned size) 65688242Sjkh{ 65788242Sjkh unsigned pg_offset; 65888242Sjkh unsigned map_size; 65988242Sjkh off_t cur_filesize; 66088242Sjkh char *p; 66188242Sjkh 66288242Sjkh offset -= offset % writebdy; 66388242Sjkh if (size == 0) { 66488242Sjkh if (!quiet && testcalls > simulatedopcount) 66588242Sjkh prt("skipping zero size write\n"); 66688242Sjkh log4(OP_SKIPPED, OP_MAPWRITE, offset, size); 66788242Sjkh return; 66888242Sjkh } 66988242Sjkh cur_filesize = file_size; 67088242Sjkh 67188242Sjkh log4(OP_MAPWRITE, offset, size, 0); 67288242Sjkh 67388242Sjkh gendata(original_buf, good_buf, offset, size); 67488242Sjkh if (file_size < offset + size) { 67588242Sjkh if (file_size < offset) 67688242Sjkh memset(good_buf + file_size, '\0', offset - file_size); 67788242Sjkh file_size = offset + size; 67888242Sjkh if (lite) { 67988242Sjkh warn("Lite file size bug in fsx!"); 68088242Sjkh report_failure(200); 68188242Sjkh } 68288242Sjkh } 68388242Sjkh 68488242Sjkh if (testcalls <= simulatedopcount) 68588242Sjkh return; 68688242Sjkh 68788242Sjkh if (!quiet && ((progressinterval && 68888242Sjkh testcalls % progressinterval == 0) || 68988242Sjkh (debug && 690113949Sjkh (monitorstart == -1 || 69188242Sjkh (offset + size > monitorstart && 69288242Sjkh (monitorend == -1 || offset <= monitorend)))))) 69388242Sjkh prt("%lu mapwrite\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls, 69488242Sjkh offset, offset + size - 1, size); 69588242Sjkh 69688242Sjkh if (file_size > cur_filesize) { 697113949Sjkh if (ftruncate(fd, file_size) == -1) { 698113949Sjkh prterr("domapwrite: ftruncate"); 69988242Sjkh exit(201); 70088242Sjkh } 70188242Sjkh } 70288242Sjkh pg_offset = offset & page_mask; 70388242Sjkh map_size = pg_offset + size; 70488242Sjkh 70588242Sjkh if ((p = (char *)mmap(0, map_size, PROT_READ | PROT_WRITE, 70688242Sjkh MAP_FILE | MAP_SHARED, fd, 707260726Savg (off_t)(offset - pg_offset))) == MAP_FAILED) { 708113949Sjkh prterr("domapwrite: mmap"); 70988242Sjkh report_failure(202); 71088242Sjkh } 71188242Sjkh memcpy(p + pg_offset, good_buf + offset, size); 712260726Savg if (mapped_msync && msync(p, map_size, MS_SYNC) != 0) { 71388242Sjkh prterr("domapwrite: msync"); 71488242Sjkh report_failure(203); 71588242Sjkh } 716113949Sjkh 717113949Sjkh check_eofpage("Write", offset, p, size); 718113949Sjkh 71988242Sjkh if (munmap(p, map_size) != 0) { 72088242Sjkh prterr("domapwrite: munmap"); 72188242Sjkh report_failure(204); 72288242Sjkh } 72388242Sjkh} 72488242Sjkh 72588242Sjkh 72688242Sjkhvoid 72788242Sjkhdotruncate(unsigned size) 72888242Sjkh{ 72988242Sjkh int oldsize = file_size; 73088242Sjkh 73188242Sjkh size -= size % truncbdy; 73288242Sjkh if (size > biggest) { 73388242Sjkh biggest = size; 73488242Sjkh if (!quiet && testcalls > simulatedopcount) 73588242Sjkh prt("truncating to largest ever: 0x%x\n", size); 73688242Sjkh } 73788242Sjkh 73888242Sjkh log4(OP_TRUNCATE, size, (unsigned)file_size, 0); 73988242Sjkh 74088242Sjkh if (size > file_size) 74188242Sjkh memset(good_buf + file_size, '\0', size - file_size); 74288242Sjkh file_size = size; 74388242Sjkh 74488242Sjkh if (testcalls <= simulatedopcount) 74588242Sjkh return; 746113949Sjkh 74788242Sjkh if ((progressinterval && testcalls % progressinterval == 0) || 74888242Sjkh (debug && (monitorstart == -1 || monitorend == -1 || 74988242Sjkh size <= monitorend))) 750113949Sjkh prt("%lu trunc\tfrom 0x%x to 0x%x\n", testcalls, oldsize, size); 75188242Sjkh if (ftruncate(fd, (off_t)size) == -1) { 752113949Sjkh prt("ftruncate1: %x\n", size); 75388242Sjkh prterr("dotruncate: ftruncate"); 75488242Sjkh report_failure(160); 75588242Sjkh } 75688242Sjkh} 75788242Sjkh 75888242Sjkh 75988242Sjkhvoid 76088242Sjkhwritefileimage() 76188242Sjkh{ 76288242Sjkh ssize_t iret; 76388242Sjkh 76488242Sjkh if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { 76588242Sjkh prterr("writefileimage: lseek"); 76688242Sjkh report_failure(171); 76788242Sjkh } 76888242Sjkh iret = write(fd, good_buf, file_size); 76988242Sjkh if ((off_t)iret != file_size) { 77088242Sjkh if (iret == -1) 77188242Sjkh prterr("writefileimage: write"); 77288242Sjkh else 77388242Sjkh prt("short write: 0x%x bytes instead of 0x%llx\n", 77488242Sjkh iret, (unsigned long long)file_size); 77588242Sjkh report_failure(172); 77688242Sjkh } 77788242Sjkh if (lite ? 0 : ftruncate(fd, file_size) == -1) { 778113949Sjkh prt("ftruncate2: %llx\n", (unsigned long long)file_size); 77988242Sjkh prterr("writefileimage: ftruncate"); 78088242Sjkh report_failure(173); 78188242Sjkh } 78288242Sjkh} 78388242Sjkh 78488242Sjkh 78588242Sjkhvoid 78688242Sjkhdocloseopen(void) 787113949Sjkh{ 78888242Sjkh if (testcalls <= simulatedopcount) 78988242Sjkh return; 79088242Sjkh 79188242Sjkh if (debug) 79288242Sjkh prt("%lu close/open\n", testcalls); 79388242Sjkh if (close(fd)) { 79488242Sjkh prterr("docloseopen: close"); 79588242Sjkh report_failure(180); 79688242Sjkh } 79788242Sjkh fd = open(fname, O_RDWR, 0); 79888242Sjkh if (fd < 0) { 79988242Sjkh prterr("docloseopen: open"); 80088242Sjkh report_failure(181); 80188242Sjkh } 80288242Sjkh} 80388242Sjkh 80488242Sjkh 80588242Sjkhvoid 806260729Savgdoinvl(void) 807260729Savg{ 808260729Savg char *p; 809260729Savg 810260729Savg if (file_size == 0) 811260729Savg return; 812260729Savg if (testcalls <= simulatedopcount) 813260729Savg return; 814260729Savg if (debug) 815260729Savg prt("%lu msync(MS_INVALIDATE)\n", testcalls); 816260729Savg 817260729Savg if ((p = (char *)mmap(0, file_size, PROT_READ | PROT_WRITE, 818260729Savg MAP_FILE | MAP_SHARED, fd, 0)) == MAP_FAILED) { 819260729Savg prterr("doinvl: mmap"); 820260729Savg report_failure(205); 821260729Savg } 822260729Savg 823260729Savg if (msync(p, 0, MS_SYNC | MS_INVALIDATE) != 0) { 824260729Savg prterr("doinvl: msync"); 825260729Savg report_failure(206); 826260729Savg } 827260729Savg 828260729Savg if (munmap(p, file_size) != 0) { 829260729Savg prterr("doinvl: munmap"); 830260729Savg report_failure(207); 831260729Savg } 832260729Savg} 833260729Savg 834260729Savg 835260729Savgvoid 83688242Sjkhtest(void) 83788242Sjkh{ 83888242Sjkh unsigned long offset; 83988242Sjkh unsigned long size = maxoplen; 84088242Sjkh unsigned long rv = random(); 84188242Sjkh unsigned long op = rv % (3 + !lite + mapped_writes); 84288242Sjkh 843113949Sjkh /* turn off the map read if necessary */ 84488242Sjkh 845113949Sjkh if (op == 2 && !mapped_reads) 846113949Sjkh op = 0; 84788242Sjkh 84888242Sjkh if (simulatedopcount > 0 && testcalls == simulatedopcount) 84988242Sjkh writefileimage(); 85088242Sjkh 85188242Sjkh testcalls++; 85288242Sjkh 85388242Sjkh if (closeprob) 85488242Sjkh closeopen = (rv >> 3) < (1 << 28) / closeprob; 855260729Savg if (invlprob) 856260729Savg invl = (rv >> 3) < (1 << 28) / invlprob; 85788242Sjkh 85888242Sjkh if (debugstart > 0 && testcalls >= debugstart) 85988242Sjkh debug = 1; 86088242Sjkh 86188242Sjkh if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0) 86288242Sjkh prt("%lu...\n", testcalls); 86388242Sjkh 86488242Sjkh /* 86588242Sjkh * READ: op = 0 86688242Sjkh * WRITE: op = 1 86788242Sjkh * MAPREAD: op = 2 86888242Sjkh * TRUNCATE: op = 3 86988242Sjkh * MAPWRITE: op = 3 or 4 87088242Sjkh */ 871113949Sjkh if (lite ? 0 : op == 3 && style == 0) /* vanilla truncate? */ 87288242Sjkh dotruncate(random() % maxfilelen); 87388242Sjkh else { 87488242Sjkh if (randomoplen) 87588242Sjkh size = random() % (maxoplen+1); 87688242Sjkh if (lite ? 0 : op == 3) 87788242Sjkh dotruncate(size); 87888242Sjkh else { 87988242Sjkh offset = random(); 88088242Sjkh if (op == 1 || op == (lite ? 3 : 4)) { 88188242Sjkh offset %= maxfilelen; 88288242Sjkh if (offset + size > maxfilelen) 88388242Sjkh size = maxfilelen - offset; 88488242Sjkh if (op != 1) 88588242Sjkh domapwrite(offset, size); 88688242Sjkh else 88788242Sjkh dowrite(offset, size); 88888242Sjkh } else { 88988242Sjkh if (file_size) 89088242Sjkh offset %= file_size; 89188242Sjkh else 89288242Sjkh offset = 0; 89388242Sjkh if (offset + size > file_size) 89488242Sjkh size = file_size - offset; 89588242Sjkh if (op != 0) 89688242Sjkh domapread(offset, size); 89788242Sjkh else 89888242Sjkh doread(offset, size); 89988242Sjkh } 90088242Sjkh } 90188242Sjkh } 90288242Sjkh if (sizechecks && testcalls > simulatedopcount) 90388242Sjkh check_size(); 904260729Savg if (invl) 905260729Savg doinvl(); 90688242Sjkh if (closeopen) 90788242Sjkh docloseopen(); 90888242Sjkh} 90988242Sjkh 91088242Sjkh 91188242Sjkhvoid 91288242Sjkhcleanup(sig) 91388242Sjkh int sig; 91488242Sjkh{ 91588242Sjkh if (sig) 91688242Sjkh prt("signal %d\n", sig); 91788242Sjkh prt("testcalls = %lu\n", testcalls); 91888242Sjkh exit(sig); 91988242Sjkh} 92088242Sjkh 92188242Sjkh 92288242Sjkhvoid 92388242Sjkhusage(void) 92488242Sjkh{ 92588242Sjkh fprintf(stdout, "usage: %s", 926113949Sjkh "fsx [-dnqLOW] [-b opnum] [-c Prob] [-l flen] [-m start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t truncbdy] [-w writebdy] [-D startingop] [-N numops] [-P dirpath] [-S seed] fname\n\ 92788242Sjkh -b opnum: beginning operation number (default 1)\n\ 92888242Sjkh -c P: 1 in P chance of file close+open at each op (default infinity)\n\ 92988242Sjkh -d: debug output for all operations\n\ 930260729Savg -i P: 1 in P chance of calling msync(MS_INVALIDATE) (default infinity)\n\ 93188242Sjkh -l flen: the upper bound on file size (default 262144)\n\ 932113949Sjkh -m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\ 93388242Sjkh -n: no verifications of file size\n\ 93488242Sjkh -o oplen: the upper bound on operation size (default 65536)\n\ 93588242Sjkh -p progressinterval: debug output at specified operation interval\n\ 93688242Sjkh -q: quieter operation\n\ 93788242Sjkh -r readbdy: 4096 would make reads page aligned (default 1)\n\ 93888242Sjkh -s style: 1 gives smaller truncates (default 0)\n\ 93988242Sjkh -t truncbdy: 4096 would make truncates page aligned (default 1)\n\ 94088242Sjkh -w writebdy: 4096 would make writes page aligned (default 1)\n\ 94188242Sjkh -D startingop: debug output starting at specified operation\n\ 94288242Sjkh -L: fsxLite - no file creations & no file size changes\n\ 94388242Sjkh -N numops: total # operations to do (default infinity)\n\ 94488242Sjkh -O: use oplen (see -o flag) for every op (default random)\n\ 945113949Sjkh -P dirpath: save .fsxlog and .fsxgood files in dirpath (default ./)\n\ 94688242Sjkh -S seed: for random # generator (default 1) 0 gets timestamp\n\ 94788242Sjkh -W: mapped write operations DISabled\n\ 948113949Sjkh -R: mapped read operations DISabled)\n\ 949260726Savg -U: msync after mapped write operations DISabled\n\ 95088242Sjkh fname: this filename is REQUIRED (no default)\n"); 95188242Sjkh exit(90); 95288242Sjkh} 95388242Sjkh 95488242Sjkh 95588242Sjkhint 95688242Sjkhgetnum(char *s, char **e) 95788242Sjkh{ 95888242Sjkh int ret = -1; 95988242Sjkh 96088242Sjkh *e = (char *) 0; 96188242Sjkh ret = strtol(s, e, 0); 96288242Sjkh if (*e) 96388242Sjkh switch (**e) { 96488242Sjkh case 'b': 96588242Sjkh case 'B': 96688242Sjkh ret *= 512; 96788242Sjkh *e = *e + 1; 96888242Sjkh break; 96988242Sjkh case 'k': 97088242Sjkh case 'K': 97188242Sjkh ret *= 1024; 97288242Sjkh *e = *e + 1; 97388242Sjkh break; 97488242Sjkh case 'm': 97588242Sjkh case 'M': 97688242Sjkh ret *= 1024*1024; 97788242Sjkh *e = *e + 1; 97888242Sjkh break; 97988242Sjkh case 'w': 98088242Sjkh case 'W': 98188242Sjkh ret *= 4; 98288242Sjkh *e = *e + 1; 98388242Sjkh break; 98488242Sjkh } 98588242Sjkh return (ret); 98688242Sjkh} 98788242Sjkh 98888242Sjkh 98988242Sjkhint 99088242Sjkhmain(int argc, char **argv) 99188242Sjkh{ 992113949Sjkh int i, ch; 99388242Sjkh char *endp; 99488242Sjkh char goodfile[1024]; 99588242Sjkh char logfile[1024]; 99688242Sjkh 99788242Sjkh goodfile[0] = 0; 99888242Sjkh logfile[0] = 0; 99988242Sjkh 100088242Sjkh page_size = getpagesize(); 100188242Sjkh page_mask = page_size - 1; 100288242Sjkh 100388242Sjkh setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */ 100488242Sjkh 1005260726Savg while ((ch = getopt(argc, argv, 1006260729Savg "b:c:di:l:m:no:p:qr:s:t:w:D:LN:OP:RS:UW")) != -1) 100788242Sjkh switch (ch) { 100888242Sjkh case 'b': 100988242Sjkh simulatedopcount = getnum(optarg, &endp); 101088242Sjkh if (!quiet) 1011113949Sjkh fprintf(stdout, "Will begin at operation %ld\n", 101288242Sjkh simulatedopcount); 101388242Sjkh if (simulatedopcount == 0) 101488242Sjkh usage(); 101588242Sjkh simulatedopcount -= 1; 101688242Sjkh break; 101788242Sjkh case 'c': 101888242Sjkh closeprob = getnum(optarg, &endp); 101988242Sjkh if (!quiet) 102088242Sjkh fprintf(stdout, 102188242Sjkh "Chance of close/open is 1 in %d\n", 102288242Sjkh closeprob); 102388242Sjkh if (closeprob <= 0) 102488242Sjkh usage(); 102588242Sjkh break; 102688242Sjkh case 'd': 102788242Sjkh debug = 1; 102888242Sjkh break; 1029260729Savg case 'i': 1030260729Savg invlprob = getnum(optarg, &endp); 1031260729Savg if (!quiet) 1032260729Savg fprintf(stdout, 1033260729Savg "Chance of MS_INVALIDATE is 1 in %d\n", 1034260729Savg invlprob); 1035260729Savg if (invlprob <= 0) 1036260729Savg usage(); 1037260729Savg break; 103888242Sjkh case 'l': 103988242Sjkh maxfilelen = getnum(optarg, &endp); 104088242Sjkh if (maxfilelen <= 0) 104188242Sjkh usage(); 104288242Sjkh break; 104388242Sjkh case 'm': 104488242Sjkh monitorstart = getnum(optarg, &endp); 104588242Sjkh if (monitorstart < 0) 104688242Sjkh usage(); 104788242Sjkh if (!endp || *endp++ != ':') 104888242Sjkh usage(); 104988242Sjkh monitorend = getnum(endp, &endp); 105088242Sjkh if (monitorend < 0) 105188242Sjkh usage(); 105288242Sjkh if (monitorend == 0) 105388242Sjkh monitorend = -1; /* aka infinity */ 105488242Sjkh debug = 1; 105588242Sjkh case 'n': 105688242Sjkh sizechecks = 0; 105788242Sjkh break; 105888242Sjkh case 'o': 105988242Sjkh maxoplen = getnum(optarg, &endp); 106088242Sjkh if (maxoplen <= 0) 106188242Sjkh usage(); 106288242Sjkh break; 106388242Sjkh case 'p': 106488242Sjkh progressinterval = getnum(optarg, &endp); 106588242Sjkh if (progressinterval < 0) 106688242Sjkh usage(); 106788242Sjkh break; 106888242Sjkh case 'q': 106988242Sjkh quiet = 1; 107088242Sjkh break; 107188242Sjkh case 'r': 107288242Sjkh readbdy = getnum(optarg, &endp); 107388242Sjkh if (readbdy <= 0) 107488242Sjkh usage(); 107588242Sjkh break; 107688242Sjkh case 's': 107788242Sjkh style = getnum(optarg, &endp); 107888242Sjkh if (style < 0 || style > 1) 107988242Sjkh usage(); 108088242Sjkh break; 108188242Sjkh case 't': 108288242Sjkh truncbdy = getnum(optarg, &endp); 108388242Sjkh if (truncbdy <= 0) 108488242Sjkh usage(); 108588242Sjkh break; 108688242Sjkh case 'w': 108788242Sjkh writebdy = getnum(optarg, &endp); 108888242Sjkh if (writebdy <= 0) 108988242Sjkh usage(); 109088242Sjkh break; 109188242Sjkh case 'D': 109288242Sjkh debugstart = getnum(optarg, &endp); 109388242Sjkh if (debugstart < 1) 109488242Sjkh usage(); 109588242Sjkh break; 109688242Sjkh case 'L': 1097113949Sjkh lite = 1; 109888242Sjkh break; 109988242Sjkh case 'N': 110088242Sjkh numops = getnum(optarg, &endp); 110188242Sjkh if (numops < 0) 110288242Sjkh usage(); 110388242Sjkh break; 110488242Sjkh case 'O': 110588242Sjkh randomoplen = 0; 110688242Sjkh break; 110788242Sjkh case 'P': 110888242Sjkh strncpy(goodfile, optarg, sizeof(goodfile)); 110988242Sjkh strcat(goodfile, "/"); 111088242Sjkh strncpy(logfile, optarg, sizeof(logfile)); 111188242Sjkh strcat(logfile, "/"); 111288242Sjkh break; 1113113949Sjkh case 'R': 1114113949Sjkh mapped_reads = 0; 1115113949Sjkh break; 111688242Sjkh case 'S': 1117113949Sjkh seed = getnum(optarg, &endp); 111888242Sjkh if (seed == 0) 111988242Sjkh seed = time(0) % 10000; 112088242Sjkh if (!quiet) 112188242Sjkh fprintf(stdout, "Seed set to %d\n", seed); 112288242Sjkh if (seed < 0) 112388242Sjkh usage(); 112488242Sjkh break; 112588242Sjkh case 'W': 1126113949Sjkh mapped_writes = 0; 112788242Sjkh if (!quiet) 112888242Sjkh fprintf(stdout, "mapped writes DISABLED\n"); 112988242Sjkh break; 1130260726Savg case 'U': 1131260726Savg mapped_msync = 0; 1132260726Savg if (!quiet) 1133260726Savg fprintf(stdout, "mapped msync DISABLED\n"); 1134260726Savg break; 113588242Sjkh 113688242Sjkh default: 113788242Sjkh usage(); 113888242Sjkh /* NOTREACHED */ 113988242Sjkh } 114088242Sjkh argc -= optind; 114188242Sjkh argv += optind; 114288242Sjkh if (argc != 1) 114388242Sjkh usage(); 114488242Sjkh fname = argv[0]; 114588242Sjkh 114688242Sjkh signal(SIGHUP, cleanup); 114788242Sjkh signal(SIGINT, cleanup); 114888242Sjkh signal(SIGPIPE, cleanup); 114988242Sjkh signal(SIGALRM, cleanup); 115088242Sjkh signal(SIGTERM, cleanup); 115188242Sjkh signal(SIGXCPU, cleanup); 115288242Sjkh signal(SIGXFSZ, cleanup); 115388242Sjkh signal(SIGVTALRM, cleanup); 115488242Sjkh signal(SIGUSR1, cleanup); 115588242Sjkh signal(SIGUSR2, cleanup); 115688242Sjkh 115788242Sjkh initstate(seed, state, 256); 115888242Sjkh setstate(state); 115988242Sjkh fd = open(fname, O_RDWR|(lite ? 0 : O_CREAT|O_TRUNC), 0666); 116088242Sjkh if (fd < 0) { 116188242Sjkh prterr(fname); 116288242Sjkh exit(91); 116388242Sjkh } 116488242Sjkh strncat(goodfile, fname, 256); 116588242Sjkh strcat (goodfile, ".fsxgood"); 116688242Sjkh fsxgoodfd = open(goodfile, O_RDWR|O_CREAT|O_TRUNC, 0666); 116788242Sjkh if (fsxgoodfd < 0) { 116888242Sjkh prterr(goodfile); 116988242Sjkh exit(92); 117088242Sjkh } 117188242Sjkh strncat(logfile, fname, 256); 117288242Sjkh strcat (logfile, ".fsxlog"); 117388242Sjkh fsxlogf = fopen(logfile, "w"); 117488242Sjkh if (fsxlogf == NULL) { 117588242Sjkh prterr(logfile); 117688242Sjkh exit(93); 117788242Sjkh } 117888242Sjkh if (lite) { 117988242Sjkh off_t ret; 118088242Sjkh file_size = maxfilelen = lseek(fd, (off_t)0, SEEK_END); 118188242Sjkh if (file_size == (off_t)-1) { 118288242Sjkh prterr(fname); 118388242Sjkh warn("main: lseek eof"); 118488242Sjkh exit(94); 118588242Sjkh } 118688242Sjkh ret = lseek(fd, (off_t)0, SEEK_SET); 118788242Sjkh if (ret == (off_t)-1) { 118888242Sjkh prterr(fname); 118988242Sjkh warn("main: lseek 0"); 119088242Sjkh exit(95); 119188242Sjkh } 119288242Sjkh } 119388242Sjkh original_buf = (char *) malloc(maxfilelen); 119488242Sjkh for (i = 0; i < maxfilelen; i++) 119588242Sjkh original_buf[i] = random() % 256; 119688242Sjkh good_buf = (char *) malloc(maxfilelen); 119788242Sjkh memset(good_buf, '\0', maxfilelen); 119888242Sjkh temp_buf = (char *) malloc(maxoplen); 119988242Sjkh memset(temp_buf, '\0', maxoplen); 120088242Sjkh if (lite) { /* zero entire existing file */ 120188242Sjkh ssize_t written; 120288242Sjkh 120388242Sjkh written = write(fd, good_buf, (size_t)maxfilelen); 120488242Sjkh if (written != maxfilelen) { 120588242Sjkh if (written == -1) { 120688242Sjkh prterr(fname); 120788242Sjkh warn("main: error on write"); 120888242Sjkh } else 1209113949Sjkh warn("main: short write, 0x%x bytes instead of 0x%x\n", 121088242Sjkh (unsigned)written, maxfilelen); 121188242Sjkh exit(98); 121288242Sjkh } 1213113949Sjkh } else 121488242Sjkh check_trunc_hack(); 121588242Sjkh 121688242Sjkh while (numops == -1 || numops--) 121788242Sjkh test(); 121888242Sjkh 121988242Sjkh if (close(fd)) { 122088242Sjkh prterr("close"); 122188242Sjkh report_failure(99); 122288242Sjkh } 122388242Sjkh prt("All operations completed A-OK!\n"); 122488242Sjkh 122588242Sjkh exit(0); 122688242Sjkh return 0; 122788242Sjkh} 1228113949Sjkh 1229