18a272653SPeter Holm#!/bin/sh 28a272653SPeter Holm 38a272653SPeter Holm# 48a272653SPeter Holm# Copyright (c) 2008 Peter Holm <pho@FreeBSD.org> 58a272653SPeter Holm# All rights reserved. 68a272653SPeter Holm# 78a272653SPeter Holm# Redistribution and use in source and binary forms, with or without 88a272653SPeter Holm# modification, are permitted provided that the following conditions 98a272653SPeter Holm# are met: 108a272653SPeter Holm# 1. Redistributions of source code must retain the above copyright 118a272653SPeter Holm# notice, this list of conditions and the following disclaimer. 128a272653SPeter Holm# 2. Redistributions in binary form must reproduce the above copyright 138a272653SPeter Holm# notice, this list of conditions and the following disclaimer in the 148a272653SPeter Holm# documentation and/or other materials provided with the distribution. 158a272653SPeter Holm# 168a272653SPeter Holm# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 178a272653SPeter Holm# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 188a272653SPeter Holm# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 198a272653SPeter Holm# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 208a272653SPeter Holm# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 218a272653SPeter Holm# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 228a272653SPeter Holm# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 238a272653SPeter Holm# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 248a272653SPeter Holm# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 258a272653SPeter Holm# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 268a272653SPeter Holm# SUCH DAMAGE. 278a272653SPeter Holm# 288a272653SPeter Holm 298a272653SPeter Holm# Test scenario by kris@freebsd.org 308a272653SPeter Holm 318a272653SPeter Holm# Test problems with "umount -f and fsx. Results in a "KDB: enter: watchdog timeout" 328a272653SPeter Holm 338a272653SPeter Holm# http://people.freebsd.org/~pho/stress/log/kostik745.txt 348a272653SPeter Holm# Fixed by r275743 358a272653SPeter Holm 368a272653SPeter Holm[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 378a272653SPeter Holm 388a272653SPeter Holm. ../default.cfg 398a272653SPeter Holm 408a272653SPeter Holmsed '1,/^EOF/d' < $0 > /tmp/fsx.c 418a272653SPeter Holmmycc -o /tmp/fsx -O2 /tmp/fsx.c || exit 1 428a272653SPeter Holmrm -f /tmp/fsx.c 438a272653SPeter Holm 448a272653SPeter HolmD=$diskimage 458a272653SPeter Holmdd if=/dev/zero of=$D bs=1m count=1k status=none || exit 1 468a272653SPeter Holm 47608c97bfSPeter Holmmount | grep "$mntpoint" | grep md$mdstart > /dev/null && umount $mntpoint 488a272653SPeter Holmmdconfig -l | grep md$mdstart > /dev/null && mdconfig -d -u $mdstart 498a272653SPeter Holm 508a272653SPeter Holmmdconfig -a -t vnode -f $D -u $mdstart 51608c97bfSPeter Holmnewfs md$mdstart > /dev/null 2>&1 52608c97bfSPeter Holmmount /dev/md$mdstart $mntpoint 538a272653SPeter Holmsleep 5 548a272653SPeter Holmfor i in `jot 100`; do 558a272653SPeter Holm /tmp/fsx -S $i -q $mntpoint/xxx$i > /dev/null & 568a272653SPeter Holmdone 578a272653SPeter Holmsleep 30 588a272653SPeter Holmumount -f $mntpoint & 598a272653SPeter Holmfor i in `jot 30`; do 608a272653SPeter Holm sleep 30 618a272653SPeter Holm pgrep -q fsx || break 628a272653SPeter Holmdone 638a272653SPeter Holmif pgrep -q fsx; then 648a272653SPeter Holm echo FAIL 658a272653SPeter Holm ps -l $! 668a272653SPeter Holm pkill fsx 678a272653SPeter Holmfi 688a272653SPeter Holmsleep 5 698a272653SPeter Holmwait 708a272653SPeter Holmmdconfig -d -u $mdstart 718a272653SPeter Holmrm -f $D /tmp/fsx 728a272653SPeter Holmexit 0 738a272653SPeter HolmEOF 748a272653SPeter Holm/* 758a272653SPeter Holm * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved. 768a272653SPeter Holm * 778a272653SPeter Holm * @APPLE_LICENSE_HEADER_START@ 788a272653SPeter Holm * 798a272653SPeter Holm * The contents of this file constitute Original Code as defined in and 808a272653SPeter Holm * are subject to the Apple Public Source License Version 2.0 (the 818a272653SPeter Holm * "License"). You may not use this file except in compliance with the 828a272653SPeter Holm * License. Please obtain a copy of the License at 838a272653SPeter Holm * http://www.opensource.apple.com/apsl/ and read it before using this file. 848a272653SPeter Holm * 858a272653SPeter Holm * This Original Code and all software distributed under the License are 868a272653SPeter Holm * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 878a272653SPeter Holm * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 888a272653SPeter Holm * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 898a272653SPeter Holm * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 908a272653SPeter Holm * License for the specific language governing rights and limitations 918a272653SPeter Holm * under the License. 928a272653SPeter Holm * 938a272653SPeter Holm * @APPLE_LICENSE_HEADER_END@ 948a272653SPeter Holm * 958a272653SPeter Holm * File: fsx.c 968a272653SPeter Holm * Author: Avadis Tevanian, Jr. 978a272653SPeter Holm * 988a272653SPeter Holm * File system exerciser. 998a272653SPeter Holm * 1008a272653SPeter Holm * Rewrite and enhancements 1998-2001 Conrad Minshall -- conrad@mac.com 1018a272653SPeter Holm * 1028a272653SPeter Holm * Various features from Joe Sokol, Pat Dirks, and Clark Warner. 1038a272653SPeter Holm * 1048a272653SPeter Holm * Small changes to work under Linux -- davej@suse.de 1058a272653SPeter Holm * 1068a272653SPeter Holm * Sundry porting patches from Guy Harris 12/2001 1078a272653SPeter Holm * 1088a272653SPeter Holm * Checks for mmap last-page zero fill. 1098a272653SPeter Holm * 1108a272653SPeter Holm * Updated license to APSL 2.0, 2004/7/27 - Jordan Hubbard 1118a272653SPeter Holm * 1128a272653SPeter Holm */ 1138a272653SPeter Holm 1148a272653SPeter Holm#include <sys/types.h> 1158a272653SPeter Holm#include <sys/stat.h> 1168a272653SPeter Holm#ifdef _UWIN 1178a272653SPeter Holm# include <sys/param.h> 1188a272653SPeter Holm# include <limits.h> 1198a272653SPeter Holm# include <time.h> 1208a272653SPeter Holm# include <strings.h> 1218a272653SPeter Holm#endif 1228a272653SPeter Holm#include <fcntl.h> 1238a272653SPeter Holm#include <sys/mman.h> 1248a272653SPeter Holm#ifndef MAP_FILE 1258a272653SPeter Holm# define MAP_FILE 0 1268a272653SPeter Holm#endif 1278a272653SPeter Holm#include <limits.h> 1288a272653SPeter Holm#include <signal.h> 1298a272653SPeter Holm#include <stdio.h> 1308a272653SPeter Holm#include <stdlib.h> 1318a272653SPeter Holm#include <string.h> 1328a272653SPeter Holm#include <unistd.h> 1338a272653SPeter Holm#include <stdarg.h> 1348a272653SPeter Holm#include <errno.h> 1358a272653SPeter Holm 1368a272653SPeter Holm#define NUMPRINTCOLUMNS 32 /* # columns of data to print on each line */ 1378a272653SPeter Holm 1388a272653SPeter Holm/* 1398a272653SPeter Holm * A log entry is an operation and a bunch of arguments. 1408a272653SPeter Holm */ 1418a272653SPeter Holm 1428a272653SPeter Holmstruct log_entry { 1438a272653SPeter Holm int operation; 1448a272653SPeter Holm int args[3]; 1458a272653SPeter Holm}; 1468a272653SPeter Holm 1478a272653SPeter Holm#define LOGSIZE 1000 1488a272653SPeter Holm 1498a272653SPeter Holmstruct log_entry oplog[LOGSIZE]; /* the log */ 1508a272653SPeter Holmint logptr = 0; /* current position in log */ 1518a272653SPeter Holmint logcount = 0; /* total ops */ 1528a272653SPeter Holm 1538a272653SPeter Holm/* 1548a272653SPeter Holm * Define operations 1558a272653SPeter Holm */ 1568a272653SPeter Holm 1578a272653SPeter Holm#define OP_READ 1 1588a272653SPeter Holm#define OP_WRITE 2 1598a272653SPeter Holm#define OP_TRUNCATE 3 1608a272653SPeter Holm#define OP_CLOSEOPEN 4 1618a272653SPeter Holm#define OP_MAPREAD 5 1628a272653SPeter Holm#define OP_MAPWRITE 6 1638a272653SPeter Holm#define OP_SKIPPED 7 1648a272653SPeter Holm#define OP_INVALIDATE 8 1658a272653SPeter Holm 1668a272653SPeter Holmint page_size; 1678a272653SPeter Holmint page_mask; 1688a272653SPeter Holm 1698a272653SPeter Holmchar *original_buf; /* a pointer to the original data */ 1708a272653SPeter Holmchar *good_buf; /* a pointer to the correct data */ 1718a272653SPeter Holmchar *temp_buf; /* a pointer to the current data */ 1728a272653SPeter Holmchar *fname; /* name of our test file */ 1738a272653SPeter Holmint fd; /* fd for our test file */ 1748a272653SPeter Holm 1758a272653SPeter Holmoff_t file_size = 0; 1768a272653SPeter Holmoff_t biggest = 0; 1778a272653SPeter Holmchar state[256]; 1788a272653SPeter Holmunsigned long testcalls = 0; /* calls to function "test" */ 1798a272653SPeter Holm 1808a272653SPeter Holmunsigned long simulatedopcount = 0; /* -b flag */ 1818a272653SPeter Holmint closeprob = 0; /* -c flag */ 1828a272653SPeter Holmint invlprob = 0; /* -i flag */ 1838a272653SPeter Holmint debug = 0; /* -d flag */ 1848a272653SPeter Holmunsigned long debugstart = 0; /* -D flag */ 1858a272653SPeter Holmunsigned long maxfilelen = 256 * 1024; /* -l flag */ 1868a272653SPeter Holmint sizechecks = 1; /* -n flag disables them */ 1878a272653SPeter Holmint maxoplen = 64 * 1024; /* -o flag */ 1888a272653SPeter Holmint quiet = 0; /* -q flag */ 1898a272653SPeter Holmunsigned long progressinterval = 0; /* -p flag */ 1908a272653SPeter Holmint readbdy = 1; /* -r flag */ 1918a272653SPeter Holmint style = 0; /* -s flag */ 1928a272653SPeter Holmint truncbdy = 1; /* -t flag */ 1938a272653SPeter Holmint writebdy = 1; /* -w flag */ 1948a272653SPeter Holmlong monitorstart = -1; /* -m flag */ 1958a272653SPeter Holmlong monitorend = -1; /* -m flag */ 1968a272653SPeter Holmint lite = 0; /* -L flag */ 1978a272653SPeter Holmlong numops = -1; /* -N flag */ 1988a272653SPeter Holmint randomoplen = 1; /* -O flag disables it */ 1998a272653SPeter Holmint seed = 1; /* -S flag */ 2008a272653SPeter Holmint mapped_writes = 1; /* -W flag disables */ 2018a272653SPeter Holmint mapped_reads = 1; /* -R flag disables it */ 2028a272653SPeter Holmint mapped_msync = 1; /* -U flag disables */ 2038a272653SPeter Holmint fsxgoodfd = 0; 2048a272653SPeter HolmFILE * fsxlogf = NULL; 2058a272653SPeter Holmint badoff = -1; 2068a272653SPeter Holmint closeopen = 0; 2078a272653SPeter Holmint invl = 0; 2088a272653SPeter Holm 2098a272653SPeter Holmvoid 2108a272653SPeter Holmvwarnc(code, fmt, ap) 2118a272653SPeter Holm int code; 2128a272653SPeter Holm const char *fmt; 2138a272653SPeter Holm va_list ap; 2148a272653SPeter Holm{ 2158a272653SPeter Holm fprintf(stderr, "fsx: "); 2168a272653SPeter Holm if (fmt != NULL) { 2178a272653SPeter Holm vfprintf(stderr, fmt, ap); 2188a272653SPeter Holm fprintf(stderr, ": "); 2198a272653SPeter Holm } 2208a272653SPeter Holm fprintf(stderr, "%s\n", strerror(code)); 2218a272653SPeter Holm} 2228a272653SPeter Holm 2238a272653SPeter Holmvoid 2248a272653SPeter Holmwarn(const char * fmt, ...) 2258a272653SPeter Holm{ 2268a272653SPeter Holm va_list ap; 2278a272653SPeter Holm va_start(ap, fmt); 2288a272653SPeter Holm vwarnc(errno, fmt, ap); 2298a272653SPeter Holm va_end(ap); 2308a272653SPeter Holm} 2318a272653SPeter Holm 2328a272653SPeter Holmvoid 2338a272653SPeter Holmprt(char *fmt, ...) 2348a272653SPeter Holm{ 2358a272653SPeter Holm va_list args; 2368a272653SPeter Holm 2378a272653SPeter Holm va_start(args, fmt); 2388a272653SPeter Holm vfprintf(stdout, fmt, args); 2398a272653SPeter Holm va_end(args); 2408a272653SPeter Holm 2418a272653SPeter Holm if (fsxlogf) { 2428a272653SPeter Holm va_start(args, fmt); 2438a272653SPeter Holm vfprintf(fsxlogf, fmt, args); 2448a272653SPeter Holm va_end(args); 2458a272653SPeter Holm } 2468a272653SPeter Holm} 2478a272653SPeter Holm 2488a272653SPeter Holmvoid 2498a272653SPeter Holmprterr(char *prefix) 2508a272653SPeter Holm{ 2518a272653SPeter Holm prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno)); 2528a272653SPeter Holm} 2538a272653SPeter Holm 2548a272653SPeter Holmvoid 2558a272653SPeter Holmdo_log4(int operation, int arg0, int arg1, int arg2) 2568a272653SPeter Holm{ 2578a272653SPeter Holm struct log_entry *le; 2588a272653SPeter Holm 2598a272653SPeter Holm le = &oplog[logptr]; 2608a272653SPeter Holm le->operation = operation; 2618a272653SPeter Holm le->args[0] = arg0; 2628a272653SPeter Holm le->args[1] = arg1; 2638a272653SPeter Holm le->args[2] = arg2; 2648a272653SPeter Holm logptr++; 2658a272653SPeter Holm logcount++; 2668a272653SPeter Holm if (logptr >= LOGSIZE) 2678a272653SPeter Holm logptr = 0; 2688a272653SPeter Holm} 2698a272653SPeter Holm 2708a272653SPeter Holmvoid 2718a272653SPeter Holmlog4(int operation, int arg0, int arg1, int arg2) 2728a272653SPeter Holm{ 2738a272653SPeter Holm do_log4(operation, arg0, arg1, arg2); 2748a272653SPeter Holm if (closeopen) 2758a272653SPeter Holm do_log4(OP_CLOSEOPEN, 0, 0, 0); 2768a272653SPeter Holm if (invl) 2778a272653SPeter Holm do_log4(OP_INVALIDATE, 0, 0, 0); 2788a272653SPeter Holm} 2798a272653SPeter Holm 2808a272653SPeter Holmvoid 2818a272653SPeter Holmlogdump(void) 2828a272653SPeter Holm{ 2838a272653SPeter Holm struct log_entry *lp; 2848a272653SPeter Holm int i, count, down, opnum; 2858a272653SPeter Holm 2868a272653SPeter Holm prt("LOG DUMP (%d total operations):\n", logcount); 2878a272653SPeter Holm if (logcount < LOGSIZE) { 2888a272653SPeter Holm i = 0; 2898a272653SPeter Holm count = logcount; 2908a272653SPeter Holm } else { 2918a272653SPeter Holm i = logptr; 2928a272653SPeter Holm count = LOGSIZE; 2938a272653SPeter Holm } 2948a272653SPeter Holm 2958a272653SPeter Holm opnum = i + 1 + (logcount/LOGSIZE)*LOGSIZE; 2968a272653SPeter Holm for ( ; count > 0; count--) { 2978a272653SPeter Holm lp = &oplog[i]; 2988a272653SPeter Holm 2998a272653SPeter Holm if (lp->operation == OP_CLOSEOPEN || 3008a272653SPeter Holm lp->operation == OP_INVALIDATE) { 3018a272653SPeter Holm switch (lp->operation) { 3028a272653SPeter Holm case OP_CLOSEOPEN: 3038a272653SPeter Holm prt("\t\tCLOSE/OPEN\n"); 3048a272653SPeter Holm break; 3058a272653SPeter Holm case OP_INVALIDATE: 3068a272653SPeter Holm prt("\t\tMS_INVALIDATE\n"); 3078a272653SPeter Holm break; 3088a272653SPeter Holm } 3098a272653SPeter Holm i++; 3108a272653SPeter Holm if (i == LOGSIZE) 3118a272653SPeter Holm i = 0; 3128a272653SPeter Holm continue; 3138a272653SPeter Holm } 3148a272653SPeter Holm 3158a272653SPeter Holm prt("%d(%d mod 256): ", opnum, opnum%256); 3168a272653SPeter Holm switch (lp->operation) { 3178a272653SPeter Holm case OP_MAPREAD: 3188a272653SPeter Holm prt("MAPREAD\t0x%x thru 0x%x\t(0x%x bytes)", 3198a272653SPeter Holm lp->args[0], lp->args[0] + lp->args[1] - 1, 3208a272653SPeter Holm lp->args[1]); 3218a272653SPeter Holm if (badoff >= lp->args[0] && badoff < 3228a272653SPeter Holm lp->args[0] + lp->args[1]) 3238a272653SPeter Holm prt("\t***RRRR***"); 3248a272653SPeter Holm break; 3258a272653SPeter Holm case OP_MAPWRITE: 3268a272653SPeter Holm prt("MAPWRITE 0x%x thru 0x%x\t(0x%x bytes)", 3278a272653SPeter Holm lp->args[0], lp->args[0] + lp->args[1] - 1, 3288a272653SPeter Holm lp->args[1]); 3298a272653SPeter Holm if (badoff >= lp->args[0] && badoff < 3308a272653SPeter Holm lp->args[0] + lp->args[1]) 3318a272653SPeter Holm prt("\t******WWWW"); 3328a272653SPeter Holm break; 3338a272653SPeter Holm case OP_READ: 3348a272653SPeter Holm prt("READ\t0x%x thru 0x%x\t(0x%x bytes)", 3358a272653SPeter Holm lp->args[0], lp->args[0] + lp->args[1] - 1, 3368a272653SPeter Holm lp->args[1]); 3378a272653SPeter Holm if (badoff >= lp->args[0] && 3388a272653SPeter Holm badoff < lp->args[0] + lp->args[1]) 3398a272653SPeter Holm prt("\t***RRRR***"); 3408a272653SPeter Holm break; 3418a272653SPeter Holm case OP_WRITE: 3428a272653SPeter Holm prt("WRITE\t0x%x thru 0x%x\t(0x%x bytes)", 3438a272653SPeter Holm lp->args[0], lp->args[0] + lp->args[1] - 1, 3448a272653SPeter Holm lp->args[1]); 3458a272653SPeter Holm if (lp->args[0] > lp->args[2]) 3468a272653SPeter Holm prt(" HOLE"); 3478a272653SPeter Holm else if (lp->args[0] + lp->args[1] > lp->args[2]) 3488a272653SPeter Holm prt(" EXTEND"); 3498a272653SPeter Holm if ((badoff >= lp->args[0] || badoff >=lp->args[2]) && 3508a272653SPeter Holm badoff < lp->args[0] + lp->args[1]) 3518a272653SPeter Holm prt("\t***WWWW"); 3528a272653SPeter Holm break; 3538a272653SPeter Holm case OP_TRUNCATE: 3548a272653SPeter Holm down = lp->args[0] < lp->args[1]; 3558a272653SPeter Holm prt("TRUNCATE %s\tfrom 0x%x to 0x%x", 3568a272653SPeter Holm down ? "DOWN" : "UP", lp->args[1], lp->args[0]); 3578a272653SPeter Holm if (badoff >= lp->args[!down] && 3588a272653SPeter Holm badoff < lp->args[!!down]) 3598a272653SPeter Holm prt("\t******WWWW"); 3608a272653SPeter Holm break; 3618a272653SPeter Holm case OP_SKIPPED: 3628a272653SPeter Holm prt("SKIPPED (no operation)"); 3638a272653SPeter Holm break; 3648a272653SPeter Holm default: 3658a272653SPeter Holm prt("BOGUS LOG ENTRY (operation code = %d)!", 3668a272653SPeter Holm lp->operation); 3678a272653SPeter Holm } 3688a272653SPeter Holm prt("\n"); 3698a272653SPeter Holm opnum++; 3708a272653SPeter Holm i++; 3718a272653SPeter Holm if (i == LOGSIZE) 3728a272653SPeter Holm i = 0; 3738a272653SPeter Holm } 3748a272653SPeter Holm} 3758a272653SPeter Holm 3768a272653SPeter Holmvoid 3778a272653SPeter Holmsave_buffer(char *buffer, off_t bufferlength, int fd) 3788a272653SPeter Holm{ 3798a272653SPeter Holm off_t ret; 3808a272653SPeter Holm ssize_t byteswritten; 3818a272653SPeter Holm 3828a272653SPeter Holm if (fd <= 0 || bufferlength == 0) 3838a272653SPeter Holm return; 3848a272653SPeter Holm 3858a272653SPeter Holm if (bufferlength > SSIZE_MAX) { 3868a272653SPeter Holm prt("fsx flaw: overflow in save_buffer\n"); 3878a272653SPeter Holm exit(67); 3888a272653SPeter Holm } 3898a272653SPeter Holm if (lite) { 3908a272653SPeter Holm off_t size_by_seek = lseek(fd, (off_t)0, SEEK_END); 3918a272653SPeter Holm if (size_by_seek == (off_t)-1) 3928a272653SPeter Holm prterr("save_buffer: lseek eof"); 3938a272653SPeter Holm else if (bufferlength > size_by_seek) { 3948a272653SPeter Holm warn("save_buffer: .fsxgood file too short... will save 0x%llx bytes instead of 0x%llx\n", (unsigned long long)size_by_seek, 3958a272653SPeter Holm (unsigned long long)bufferlength); 3968a272653SPeter Holm bufferlength = size_by_seek; 3978a272653SPeter Holm } 3988a272653SPeter Holm } 3998a272653SPeter Holm 4008a272653SPeter Holm ret = lseek(fd, (off_t)0, SEEK_SET); 4018a272653SPeter Holm if (ret == (off_t)-1) 4028a272653SPeter Holm prterr("save_buffer: lseek 0"); 4038a272653SPeter Holm 4048a272653SPeter Holm byteswritten = write(fd, buffer, (size_t)bufferlength); 4058a272653SPeter Holm if (byteswritten != bufferlength) { 4068a272653SPeter Holm if (byteswritten == -1) 4078a272653SPeter Holm prterr("save_buffer write"); 4088a272653SPeter Holm else 4098a272653SPeter Holm warn("save_buffer: short write, 0x%x bytes instead of 0x%llx\n", 4108a272653SPeter Holm (unsigned)byteswritten, 4118a272653SPeter Holm (unsigned long long)bufferlength); 4128a272653SPeter Holm } 4138a272653SPeter Holm} 4148a272653SPeter Holm 4158a272653SPeter Holmvoid 4168a272653SPeter Holmreport_failure(int status) 4178a272653SPeter Holm{ 4188a272653SPeter Holm logdump(); 4198a272653SPeter Holm 4208a272653SPeter Holm if (fsxgoodfd) { 4218a272653SPeter Holm if (good_buf) { 4228a272653SPeter Holm save_buffer(good_buf, file_size, fsxgoodfd); 4238a272653SPeter Holm prt("Correct content saved for comparison\n"); 4248a272653SPeter Holm prt("(maybe hexdump \"%s\" vs \"%s.fsxgood\")\n", 4258a272653SPeter Holm fname, fname); 4268a272653SPeter Holm } 4278a272653SPeter Holm close(fsxgoodfd); 4288a272653SPeter Holm } 4298a272653SPeter Holm exit(status); 4308a272653SPeter Holm} 4318a272653SPeter Holm 4328a272653SPeter Holm#define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \ 4338a272653SPeter Holm *(((unsigned char *)(cp)) + 1))) 4348a272653SPeter Holm 4358a272653SPeter Holmvoid 4368a272653SPeter Holmcheck_buffers(unsigned offset, unsigned size) 4378a272653SPeter Holm{ 4388a272653SPeter Holm unsigned char c, t; 4398a272653SPeter Holm unsigned i = 0; 4408a272653SPeter Holm unsigned n = 0; 4418a272653SPeter Holm unsigned op = 0; 4428a272653SPeter Holm unsigned bad = 0; 4438a272653SPeter Holm 4448a272653SPeter Holm if (memcmp(good_buf + offset, temp_buf, size) != 0) { 4458a272653SPeter Holm prt("READ BAD DATA: offset = 0x%x, size = 0x%x\n", 4468a272653SPeter Holm offset, size); 4478a272653SPeter Holm prt("OFFSET\tGOOD\tBAD\tRANGE\n"); 4488a272653SPeter Holm while (size > 0) { 4498a272653SPeter Holm c = good_buf[offset]; 4508a272653SPeter Holm t = temp_buf[i]; 4518a272653SPeter Holm if (c != t) { 4528a272653SPeter Holm if (n == 0) { 4538a272653SPeter Holm bad = short_at(&temp_buf[i]); 4548a272653SPeter Holm prt("0x%5x\t0x%04x\t0x%04x", offset, 4558a272653SPeter Holm short_at(&good_buf[offset]), bad); 4568a272653SPeter Holm op = temp_buf[offset & 1 ? i+1 : i]; 4578a272653SPeter Holm } 4588a272653SPeter Holm n++; 4598a272653SPeter Holm badoff = offset; 4608a272653SPeter Holm } 4618a272653SPeter Holm offset++; 4628a272653SPeter Holm i++; 4638a272653SPeter Holm size--; 4648a272653SPeter Holm } 4658a272653SPeter Holm if (n) { 4668a272653SPeter Holm prt("\t0x%5x\n", n); 4678a272653SPeter Holm if (bad) 4688a272653SPeter Holm prt("operation# (mod 256) for the bad data may be %u\n", ((unsigned)op & 0xff)); 4698a272653SPeter Holm else 4708a272653SPeter Holm prt("operation# (mod 256) for the bad data unknown, check HOLE and EXTEND ops\n"); 4718a272653SPeter Holm } else 4728a272653SPeter Holm prt("????????????????\n"); 4738a272653SPeter Holm report_failure(110); 4748a272653SPeter Holm } 4758a272653SPeter Holm} 4768a272653SPeter Holm 4778a272653SPeter Holmvoid 4788a272653SPeter Holmcheck_size(void) 4798a272653SPeter Holm{ 4808a272653SPeter Holm struct stat statbuf; 4818a272653SPeter Holm off_t size_by_seek; 4828a272653SPeter Holm 4838a272653SPeter Holm if (fstat(fd, &statbuf)) { 4848a272653SPeter Holm prterr("check_size: fstat"); 4858a272653SPeter Holm statbuf.st_size = -1; 4868a272653SPeter Holm } 4878a272653SPeter Holm size_by_seek = lseek(fd, (off_t)0, SEEK_END); 4888a272653SPeter Holm if (file_size != statbuf.st_size || file_size != size_by_seek) { 4898a272653SPeter Holm prt("Size error: expected 0x%llx stat 0x%llx seek 0x%llx\n", 4908a272653SPeter Holm (unsigned long long)file_size, 4918a272653SPeter Holm (unsigned long long)statbuf.st_size, 4928a272653SPeter Holm (unsigned long long)size_by_seek); 4938a272653SPeter Holm report_failure(120); 4948a272653SPeter Holm } 4958a272653SPeter Holm} 4968a272653SPeter Holm 4978a272653SPeter Holmvoid 4988a272653SPeter Holmcheck_trunc_hack(void) 4998a272653SPeter Holm{ 5008a272653SPeter Holm struct stat statbuf; 5018a272653SPeter Holm 5028a272653SPeter Holm ftruncate(fd, (off_t)0); 5038a272653SPeter Holm ftruncate(fd, (off_t)100000); 5048a272653SPeter Holm fstat(fd, &statbuf); 5058a272653SPeter Holm if (statbuf.st_size != (off_t)100000) { 5068a272653SPeter Holm prt("no extend on truncate! not posix!\n"); 5078a272653SPeter Holm exit(130); 5088a272653SPeter Holm } 5098a272653SPeter Holm ftruncate(fd, (off_t)0); 5108a272653SPeter Holm} 5118a272653SPeter Holm 5128a272653SPeter Holmvoid 5138a272653SPeter Holmdoread(unsigned offset, unsigned size) 5148a272653SPeter Holm{ 5158a272653SPeter Holm off_t ret; 5168a272653SPeter Holm unsigned iret; 5178a272653SPeter Holm 5188a272653SPeter Holm offset -= offset % readbdy; 5198a272653SPeter Holm if (size == 0) { 5208a272653SPeter Holm if (!quiet && testcalls > simulatedopcount) 5218a272653SPeter Holm prt("skipping zero size read\n"); 5228a272653SPeter Holm log4(OP_SKIPPED, OP_READ, offset, size); 5238a272653SPeter Holm return; 5248a272653SPeter Holm } 5258a272653SPeter Holm if (size + offset > file_size) { 5268a272653SPeter Holm if (!quiet && testcalls > simulatedopcount) 5278a272653SPeter Holm prt("skipping seek/read past end of file\n"); 5288a272653SPeter Holm log4(OP_SKIPPED, OP_READ, offset, size); 5298a272653SPeter Holm return; 5308a272653SPeter Holm } 5318a272653SPeter Holm 5328a272653SPeter Holm log4(OP_READ, offset, size, 0); 5338a272653SPeter Holm 5348a272653SPeter Holm if (testcalls <= simulatedopcount) 5358a272653SPeter Holm return; 5368a272653SPeter Holm 5378a272653SPeter Holm if (!quiet && ((progressinterval && 5388a272653SPeter Holm testcalls % progressinterval == 0) || 5398a272653SPeter Holm (debug && 5408a272653SPeter Holm (monitorstart == -1 || 5418a272653SPeter Holm (offset + size > monitorstart && 5428a272653SPeter Holm (monitorend == -1 || offset <= monitorend)))))) 5438a272653SPeter Holm prt("%lu read\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls, 5448a272653SPeter Holm offset, offset + size - 1, size); 5458a272653SPeter Holm ret = lseek(fd, (off_t)offset, SEEK_SET); 5468a272653SPeter Holm if (ret == (off_t)-1) { 5478a272653SPeter Holm prterr("doread: lseek"); 5488a272653SPeter Holm report_failure(140); 5498a272653SPeter Holm } 5508a272653SPeter Holm iret = read(fd, temp_buf, size); 5518a272653SPeter Holm if (iret != size) { 5528a272653SPeter Holm if (iret == -1) 5538a272653SPeter Holm prterr("doread: read"); 5548a272653SPeter Holm else 5558a272653SPeter Holm prt("short read: 0x%x bytes instead of 0x%x\n", 5568a272653SPeter Holm iret, size); 5578a272653SPeter Holm report_failure(141); 5588a272653SPeter Holm } 5598a272653SPeter Holm check_buffers(offset, size); 5608a272653SPeter Holm} 5618a272653SPeter Holm 5628a272653SPeter Holmvoid 5638a272653SPeter Holmcheck_eofpage(char *s, unsigned offset, char *p, int size) 5648a272653SPeter Holm{ 5658a272653SPeter Holm uintptr_t last_page, should_be_zero; 5668a272653SPeter Holm 5678a272653SPeter Holm if (offset + size <= (file_size & ~page_mask)) 5688a272653SPeter Holm return; 5698a272653SPeter Holm /* 5708a272653SPeter Holm * we landed in the last page of the file 5718a272653SPeter Holm * test to make sure the VM system provided 0's 5728a272653SPeter Holm * beyond the true end of the file mapping 5738a272653SPeter Holm * (as required by mmap def in 1996 posix 1003.1) 5748a272653SPeter Holm */ 5758a272653SPeter Holm last_page = ((uintptr_t)p + (offset & page_mask) + size) & ~page_mask; 5768a272653SPeter Holm 5778a272653SPeter Holm for (should_be_zero = last_page + (file_size & page_mask); 5788a272653SPeter Holm should_be_zero < last_page + page_size; 5798a272653SPeter Holm should_be_zero++) 5808a272653SPeter Holm if (*(char *)should_be_zero) { 5818a272653SPeter Holm prt("Mapped %s: non-zero data past EOF (0x%llx) page offset 0x%x is 0x%04x\n", 5828a272653SPeter Holm s, file_size - 1, should_be_zero & page_mask, 5838a272653SPeter Holm short_at(should_be_zero)); 5848a272653SPeter Holm report_failure(205); 5858a272653SPeter Holm } 5868a272653SPeter Holm} 5878a272653SPeter Holm 5888a272653SPeter Holmvoid 5898a272653SPeter Holmdomapread(unsigned offset, unsigned size) 5908a272653SPeter Holm{ 5918a272653SPeter Holm unsigned pg_offset; 5928a272653SPeter Holm unsigned map_size; 5938a272653SPeter Holm char *p; 5948a272653SPeter Holm 5958a272653SPeter Holm offset -= offset % readbdy; 5968a272653SPeter Holm if (size == 0) { 5978a272653SPeter Holm if (!quiet && testcalls > simulatedopcount) 5988a272653SPeter Holm prt("skipping zero size read\n"); 5998a272653SPeter Holm log4(OP_SKIPPED, OP_MAPREAD, offset, size); 6008a272653SPeter Holm return; 6018a272653SPeter Holm } 6028a272653SPeter Holm if (size + offset > file_size) { 6038a272653SPeter Holm if (!quiet && testcalls > simulatedopcount) 6048a272653SPeter Holm prt("skipping seek/read past end of file\n"); 6058a272653SPeter Holm log4(OP_SKIPPED, OP_MAPREAD, offset, size); 6068a272653SPeter Holm return; 6078a272653SPeter Holm } 6088a272653SPeter Holm 6098a272653SPeter Holm log4(OP_MAPREAD, offset, size, 0); 6108a272653SPeter Holm 6118a272653SPeter Holm if (testcalls <= simulatedopcount) 6128a272653SPeter Holm return; 6138a272653SPeter Holm 6148a272653SPeter Holm if (!quiet && ((progressinterval && 6158a272653SPeter Holm testcalls % progressinterval == 0) || 6168a272653SPeter Holm (debug && 6178a272653SPeter Holm (monitorstart == -1 || 6188a272653SPeter Holm (offset + size > monitorstart && 6198a272653SPeter Holm (monitorend == -1 || offset <= monitorend)))))) 6208a272653SPeter Holm prt("%lu mapread\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls, 6218a272653SPeter Holm offset, offset + size - 1, size); 6228a272653SPeter Holm 6238a272653SPeter Holm pg_offset = offset & page_mask; 6248a272653SPeter Holm map_size = pg_offset + size; 6258a272653SPeter Holm 6268a272653SPeter Holm if ((p = (char *)mmap(0, map_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, 6278a272653SPeter Holm (off_t)(offset - pg_offset))) == (char *)-1) { 6288a272653SPeter Holm prterr("domapread: mmap"); 6298a272653SPeter Holm report_failure(190); 6308a272653SPeter Holm } 6318a272653SPeter Holm memcpy(temp_buf, p + pg_offset, size); 6328a272653SPeter Holm 6338a272653SPeter Holm check_eofpage("Read", offset, p, size); 6348a272653SPeter Holm 6358a272653SPeter Holm if (munmap(p, map_size) != 0) { 6368a272653SPeter Holm prterr("domapread: munmap"); 6378a272653SPeter Holm report_failure(191); 6388a272653SPeter Holm } 6398a272653SPeter Holm 6408a272653SPeter Holm check_buffers(offset, size); 6418a272653SPeter Holm} 6428a272653SPeter Holm 6438a272653SPeter Holmvoid 6448a272653SPeter Holmgendata(char *original_buf, char *good_buf, unsigned offset, unsigned size) 6458a272653SPeter Holm{ 6468a272653SPeter Holm while (size--) { 6478a272653SPeter Holm good_buf[offset] = testcalls % 256; 6488a272653SPeter Holm if (offset % 2) 6498a272653SPeter Holm good_buf[offset] += original_buf[offset]; 6508a272653SPeter Holm offset++; 6518a272653SPeter Holm } 6528a272653SPeter Holm} 6538a272653SPeter Holm 6548a272653SPeter Holmvoid 6558a272653SPeter Holmdowrite(unsigned offset, unsigned size) 6568a272653SPeter Holm{ 6578a272653SPeter Holm off_t ret; 6588a272653SPeter Holm unsigned iret; 6598a272653SPeter Holm 6608a272653SPeter Holm offset -= offset % writebdy; 6618a272653SPeter Holm if (size == 0) { 6628a272653SPeter Holm if (!quiet && testcalls > simulatedopcount) 6638a272653SPeter Holm prt("skipping zero size write\n"); 6648a272653SPeter Holm log4(OP_SKIPPED, OP_WRITE, offset, size); 6658a272653SPeter Holm return; 6668a272653SPeter Holm } 6678a272653SPeter Holm 6688a272653SPeter Holm log4(OP_WRITE, offset, size, file_size); 6698a272653SPeter Holm 6708a272653SPeter Holm gendata(original_buf, good_buf, offset, size); 6718a272653SPeter Holm if (file_size < offset + size) { 6728a272653SPeter Holm if (file_size < offset) 6738a272653SPeter Holm memset(good_buf + file_size, '\0', offset - file_size); 6748a272653SPeter Holm file_size = offset + size; 6758a272653SPeter Holm if (lite) { 6768a272653SPeter Holm warn("Lite file size bug in fsx!"); 6778a272653SPeter Holm report_failure(149); 6788a272653SPeter Holm } 6798a272653SPeter Holm } 6808a272653SPeter Holm 6818a272653SPeter Holm if (testcalls <= simulatedopcount) 6828a272653SPeter Holm return; 6838a272653SPeter Holm 6848a272653SPeter Holm if (!quiet && ((progressinterval && 6858a272653SPeter Holm testcalls % progressinterval == 0) || 6868a272653SPeter Holm (debug && 6878a272653SPeter Holm (monitorstart == -1 || 6888a272653SPeter Holm (offset + size > monitorstart && 6898a272653SPeter Holm (monitorend == -1 || offset <= monitorend)))))) 6908a272653SPeter Holm prt("%lu write\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls, 6918a272653SPeter Holm offset, offset + size - 1, size); 6928a272653SPeter Holm ret = lseek(fd, (off_t)offset, SEEK_SET); 6938a272653SPeter Holm if (ret == (off_t)-1) { 6948a272653SPeter Holm prterr("dowrite: lseek"); 6958a272653SPeter Holm report_failure(150); 6968a272653SPeter Holm } 6978a272653SPeter Holm iret = write(fd, good_buf + offset, size); 6988a272653SPeter Holm if (iret != size) { 6998a272653SPeter Holm if (iret == -1) 7008a272653SPeter Holm prterr("dowrite: write"); 7018a272653SPeter Holm else 7028a272653SPeter Holm prt("short write: 0x%x bytes instead of 0x%x\n", 7038a272653SPeter Holm iret, size); 7048a272653SPeter Holm report_failure(151); 7058a272653SPeter Holm } 7068a272653SPeter Holm} 7078a272653SPeter Holm 7088a272653SPeter Holmvoid 7098a272653SPeter Holmdomapwrite(unsigned offset, unsigned size) 7108a272653SPeter Holm{ 7118a272653SPeter Holm unsigned pg_offset; 7128a272653SPeter Holm unsigned map_size; 7138a272653SPeter Holm off_t cur_filesize; 7148a272653SPeter Holm char *p; 7158a272653SPeter Holm 7168a272653SPeter Holm offset -= offset % writebdy; 7178a272653SPeter Holm if (size == 0) { 7188a272653SPeter Holm if (!quiet && testcalls > simulatedopcount) 7198a272653SPeter Holm prt("skipping zero size write\n"); 7208a272653SPeter Holm log4(OP_SKIPPED, OP_MAPWRITE, offset, size); 7218a272653SPeter Holm return; 7228a272653SPeter Holm } 7238a272653SPeter Holm cur_filesize = file_size; 7248a272653SPeter Holm 7258a272653SPeter Holm log4(OP_MAPWRITE, offset, size, 0); 7268a272653SPeter Holm 7278a272653SPeter Holm gendata(original_buf, good_buf, offset, size); 7288a272653SPeter Holm if (file_size < offset + size) { 7298a272653SPeter Holm if (file_size < offset) 7308a272653SPeter Holm memset(good_buf + file_size, '\0', offset - file_size); 7318a272653SPeter Holm file_size = offset + size; 7328a272653SPeter Holm if (lite) { 7338a272653SPeter Holm warn("Lite file size bug in fsx!"); 7348a272653SPeter Holm report_failure(200); 7358a272653SPeter Holm } 7368a272653SPeter Holm } 7378a272653SPeter Holm 7388a272653SPeter Holm if (testcalls <= simulatedopcount) 7398a272653SPeter Holm return; 7408a272653SPeter Holm 7418a272653SPeter Holm if (!quiet && ((progressinterval && 7428a272653SPeter Holm testcalls % progressinterval == 0) || 7438a272653SPeter Holm (debug && 7448a272653SPeter Holm (monitorstart == -1 || 7458a272653SPeter Holm (offset + size > monitorstart && 7468a272653SPeter Holm (monitorend == -1 || offset <= monitorend)))))) 7478a272653SPeter Holm prt("%lu mapwrite\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls, 7488a272653SPeter Holm offset, offset + size - 1, size); 7498a272653SPeter Holm 7508a272653SPeter Holm if (file_size > cur_filesize) { 7518a272653SPeter Holm if (ftruncate(fd, file_size) == -1) { 7528a272653SPeter Holm prterr("domapwrite: ftruncate"); 7538a272653SPeter Holm exit(201); 7548a272653SPeter Holm } 7558a272653SPeter Holm } 7568a272653SPeter Holm pg_offset = offset & page_mask; 7578a272653SPeter Holm map_size = pg_offset + size; 7588a272653SPeter Holm 7598a272653SPeter Holm if ((p = (char *)mmap(0, map_size, PROT_READ | PROT_WRITE, 7608a272653SPeter Holm MAP_FILE | MAP_SHARED, fd, 7618a272653SPeter Holm (off_t)(offset - pg_offset))) == MAP_FAILED) { 7628a272653SPeter Holm prterr("domapwrite: mmap"); 7638a272653SPeter Holm report_failure(202); 7648a272653SPeter Holm } 7658a272653SPeter Holm memcpy(p + pg_offset, good_buf + offset, size); 7668a272653SPeter Holm if (mapped_msync && msync(p, map_size, MS_SYNC) != 0) { 7678a272653SPeter Holm prterr("domapwrite: msync"); 7688a272653SPeter Holm report_failure(203); 7698a272653SPeter Holm } 7708a272653SPeter Holm 7718a272653SPeter Holm check_eofpage("Write", offset, p, size); 7728a272653SPeter Holm 7738a272653SPeter Holm if (munmap(p, map_size) != 0) { 7748a272653SPeter Holm prterr("domapwrite: munmap"); 7758a272653SPeter Holm report_failure(204); 7768a272653SPeter Holm } 7778a272653SPeter Holm} 7788a272653SPeter Holm 7798a272653SPeter Holmvoid 7808a272653SPeter Holmdotruncate(unsigned size) 7818a272653SPeter Holm{ 7828a272653SPeter Holm int oldsize = file_size; 7838a272653SPeter Holm 7848a272653SPeter Holm size -= size % truncbdy; 7858a272653SPeter Holm if (size > biggest) { 7868a272653SPeter Holm biggest = size; 7878a272653SPeter Holm if (!quiet && testcalls > simulatedopcount) 7888a272653SPeter Holm prt("truncating to largest ever: 0x%x\n", size); 7898a272653SPeter Holm } 7908a272653SPeter Holm 7918a272653SPeter Holm log4(OP_TRUNCATE, size, (unsigned)file_size, 0); 7928a272653SPeter Holm 7938a272653SPeter Holm if (size > file_size) 7948a272653SPeter Holm memset(good_buf + file_size, '\0', size - file_size); 7958a272653SPeter Holm file_size = size; 7968a272653SPeter Holm 7978a272653SPeter Holm if (testcalls <= simulatedopcount) 7988a272653SPeter Holm return; 7998a272653SPeter Holm 8008a272653SPeter Holm if ((progressinterval && testcalls % progressinterval == 0) || 8018a272653SPeter Holm (debug && (monitorstart == -1 || monitorend == -1 || 8028a272653SPeter Holm size <= monitorend))) 8038a272653SPeter Holm prt("%lu trunc\tfrom 0x%x to 0x%x\n", testcalls, oldsize, size); 8048a272653SPeter Holm if (ftruncate(fd, (off_t)size) == -1) { 8058a272653SPeter Holm prt("ftruncate1: %x\n", size); 8068a272653SPeter Holm prterr("dotruncate: ftruncate"); 8078a272653SPeter Holm report_failure(160); 8088a272653SPeter Holm } 8098a272653SPeter Holm} 8108a272653SPeter Holm 8118a272653SPeter Holmvoid 8128a272653SPeter Holmwritefileimage() 8138a272653SPeter Holm{ 8148a272653SPeter Holm ssize_t iret; 8158a272653SPeter Holm 8168a272653SPeter Holm if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { 8178a272653SPeter Holm prterr("writefileimage: lseek"); 8188a272653SPeter Holm report_failure(171); 8198a272653SPeter Holm } 8208a272653SPeter Holm iret = write(fd, good_buf, file_size); 8218a272653SPeter Holm if ((off_t)iret != file_size) { 8228a272653SPeter Holm if (iret == -1) 8238a272653SPeter Holm prterr("writefileimage: write"); 8248a272653SPeter Holm else 8258a272653SPeter Holm prt("short write: 0x%x bytes instead of 0x%llx\n", 8268a272653SPeter Holm iret, (unsigned long long)file_size); 8278a272653SPeter Holm report_failure(172); 8288a272653SPeter Holm } 8298a272653SPeter Holm if (lite ? 0 : ftruncate(fd, file_size) == -1) { 8308a272653SPeter Holm prt("ftruncate2: %llx\n", (unsigned long long)file_size); 8318a272653SPeter Holm prterr("writefileimage: ftruncate"); 8328a272653SPeter Holm report_failure(173); 8338a272653SPeter Holm } 8348a272653SPeter Holm} 8358a272653SPeter Holm 8368a272653SPeter Holmvoid 8378a272653SPeter Holmdocloseopen(void) 8388a272653SPeter Holm{ 8398a272653SPeter Holm if (testcalls <= simulatedopcount) 8408a272653SPeter Holm return; 8418a272653SPeter Holm 8428a272653SPeter Holm if (debug) 8438a272653SPeter Holm prt("%lu close/open\n", testcalls); 8448a272653SPeter Holm if (close(fd)) { 8458a272653SPeter Holm prterr("docloseopen: close"); 8468a272653SPeter Holm report_failure(180); 8478a272653SPeter Holm } 8488a272653SPeter Holm fd = open(fname, O_RDWR, 0); 8498a272653SPeter Holm if (fd < 0) { 8508a272653SPeter Holm prterr("docloseopen: open"); 8518a272653SPeter Holm report_failure(181); 8528a272653SPeter Holm } 8538a272653SPeter Holm} 8548a272653SPeter Holm 8558a272653SPeter Holmvoid 8568a272653SPeter Holmdoinvl(void) 8578a272653SPeter Holm{ 8588a272653SPeter Holm char *p; 8598a272653SPeter Holm 8608a272653SPeter Holm if (file_size == 0) 8618a272653SPeter Holm return; 8628a272653SPeter Holm if (testcalls <= simulatedopcount) 8638a272653SPeter Holm return; 8648a272653SPeter Holm if (debug) 8658a272653SPeter Holm prt("%lu msync(MS_INVALIDATE)\n", testcalls); 8668a272653SPeter Holm 8678a272653SPeter Holm if ((p = (char *)mmap(0, file_size, PROT_READ | PROT_WRITE, 8688a272653SPeter Holm MAP_FILE | MAP_SHARED, fd, 0)) == MAP_FAILED) { 8698a272653SPeter Holm prterr("doinvl: mmap"); 8708a272653SPeter Holm report_failure(205); 8718a272653SPeter Holm } 8728a272653SPeter Holm 8738a272653SPeter Holm if (msync(p, 0, MS_SYNC | MS_INVALIDATE) != 0) { 8748a272653SPeter Holm prterr("doinvl: msync"); 8758a272653SPeter Holm report_failure(206); 8768a272653SPeter Holm } 8778a272653SPeter Holm 8788a272653SPeter Holm if (munmap(p, file_size) != 0) { 8798a272653SPeter Holm prterr("doinvl: munmap"); 8808a272653SPeter Holm report_failure(207); 8818a272653SPeter Holm } 8828a272653SPeter Holm} 8838a272653SPeter Holm 8848a272653SPeter Holmvoid 8858a272653SPeter Holmtest(void) 8868a272653SPeter Holm{ 8878a272653SPeter Holm unsigned long offset; 8888a272653SPeter Holm unsigned long size = maxoplen; 889*d26c5655SPeter Holm unsigned long rv = random(); 8908a272653SPeter Holm unsigned long op = rv % (3 + !lite + mapped_writes); 8918a272653SPeter Holm 8928a272653SPeter Holm /* turn off the map read if necessary */ 8938a272653SPeter Holm 8948a272653SPeter Holm if (op == 2 && !mapped_reads) 8958a272653SPeter Holm op = 0; 8968a272653SPeter Holm 8978a272653SPeter Holm if (simulatedopcount > 0 && testcalls == simulatedopcount) 8988a272653SPeter Holm writefileimage(); 8998a272653SPeter Holm 9008a272653SPeter Holm testcalls++; 9018a272653SPeter Holm 9028a272653SPeter Holm if (closeprob) 9038a272653SPeter Holm closeopen = (rv >> 3) < (1 << 28) / closeprob; 9048a272653SPeter Holm if (invlprob) 9058a272653SPeter Holm invl = (rv >> 3) < (1 << 28) / invlprob; 9068a272653SPeter Holm 9078a272653SPeter Holm if (debugstart > 0 && testcalls >= debugstart) 9088a272653SPeter Holm debug = 1; 9098a272653SPeter Holm 9108a272653SPeter Holm if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0) 9118a272653SPeter Holm prt("%lu...\n", testcalls); 9128a272653SPeter Holm 9138a272653SPeter Holm /* 9148a272653SPeter Holm * READ: op = 0 9158a272653SPeter Holm * WRITE: op = 1 9168a272653SPeter Holm * MAPREAD: op = 2 9178a272653SPeter Holm * TRUNCATE: op = 3 9188a272653SPeter Holm * MAPWRITE: op = 3 or 4 9198a272653SPeter Holm */ 9208a272653SPeter Holm if (lite ? 0 : op == 3 && style == 0) /* vanilla truncate? */ 9218a272653SPeter Holm dotruncate(random() % maxfilelen); 9228a272653SPeter Holm else { 9238a272653SPeter Holm if (randomoplen) 9248a272653SPeter Holm size = random() % (maxoplen+1); 9258a272653SPeter Holm if (lite ? 0 : op == 3) 9268a272653SPeter Holm dotruncate(size); 9278a272653SPeter Holm else { 9288a272653SPeter Holm offset = random(); 9298a272653SPeter Holm if (op == 1 || op == (lite ? 3 : 4)) { 9308a272653SPeter Holm offset %= maxfilelen; 9318a272653SPeter Holm if (offset + size > maxfilelen) 9328a272653SPeter Holm size = maxfilelen - offset; 9338a272653SPeter Holm if (op != 1) 9348a272653SPeter Holm domapwrite(offset, size); 9358a272653SPeter Holm else 9368a272653SPeter Holm dowrite(offset, size); 9378a272653SPeter Holm } else { 9388a272653SPeter Holm if (file_size) 9398a272653SPeter Holm offset %= file_size; 9408a272653SPeter Holm else 9418a272653SPeter Holm offset = 0; 9428a272653SPeter Holm if (offset + size > file_size) 9438a272653SPeter Holm size = file_size - offset; 9448a272653SPeter Holm if (op != 0) 9458a272653SPeter Holm domapread(offset, size); 9468a272653SPeter Holm else 9478a272653SPeter Holm doread(offset, size); 9488a272653SPeter Holm } 9498a272653SPeter Holm } 9508a272653SPeter Holm } 9518a272653SPeter Holm if (sizechecks && testcalls > simulatedopcount) 9528a272653SPeter Holm check_size(); 9538a272653SPeter Holm if (invl) 9548a272653SPeter Holm doinvl(); 9558a272653SPeter Holm if (closeopen) 9568a272653SPeter Holm docloseopen(); 9578a272653SPeter Holm} 9588a272653SPeter Holm 9598a272653SPeter Holmvoid 9608a272653SPeter Holmcleanup(sig) 9618a272653SPeter Holm int sig; 9628a272653SPeter Holm{ 9638a272653SPeter Holm if (sig) 9648a272653SPeter Holm prt("signal %d\n", sig); 9658a272653SPeter Holm prt("testcalls = %lu\n", testcalls); 9668a272653SPeter Holm exit(sig); 9678a272653SPeter Holm} 9688a272653SPeter Holm 9698a272653SPeter Holmvoid 9708a272653SPeter Holmusage(void) 9718a272653SPeter Holm{ 9728a272653SPeter Holm fprintf(stdout, "usage: %s", 9738a272653SPeter Holm "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\ 9748a272653SPeter Holm -b opnum: beginning operation number (default 1)\n\ 9758a272653SPeter Holm -c P: 1 in P chance of file close+open at each op (default infinity)\n\ 9768a272653SPeter Holm -d: debug output for all operations\n\ 9778a272653SPeter Holm -i P: 1 in P chance of calling msync(MS_INVALIDATE) (default infinity)\n\ 9788a272653SPeter Holm -l flen: the upper bound on file size (default 262144)\n\ 9798a272653SPeter Holm -m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\ 9808a272653SPeter Holm -n: no verifications of file size\n\ 9818a272653SPeter Holm -o oplen: the upper bound on operation size (default 65536)\n\ 9828a272653SPeter Holm -p progressinterval: debug output at specified operation interval\n\ 9838a272653SPeter Holm -q: quieter operation\n\ 9848a272653SPeter Holm -r readbdy: 4096 would make reads page aligned (default 1)\n\ 9858a272653SPeter Holm -s style: 1 gives smaller truncates (default 0)\n\ 9868a272653SPeter Holm -t truncbdy: 4096 would make truncates page aligned (default 1)\n\ 9878a272653SPeter Holm -w writebdy: 4096 would make writes page aligned (default 1)\n\ 9888a272653SPeter Holm -D startingop: debug output starting at specified operation\n\ 9898a272653SPeter Holm -L: fsxLite - no file creations & no file size changes\n\ 9908a272653SPeter Holm -N numops: total # operations to do (default infinity)\n\ 9918a272653SPeter Holm -O: use oplen (see -o flag) for every op (default random)\n\ 9928a272653SPeter Holm -P dirpath: save .fsxlog and .fsxgood files in dirpath (default ./)\n\ 9938a272653SPeter Holm -S seed: for random # generator (default 1) 0 gets timestamp\n\ 9948a272653SPeter Holm -W: mapped write operations DISabled\n\ 9958a272653SPeter Holm -R: mapped read operations DISabled)\n\ 9968a272653SPeter Holm -U: msync after mapped write operations DISabled\n\ 9978a272653SPeter Holm fname: this filename is REQUIRED (no default)\n"); 9988a272653SPeter Holm exit(90); 9998a272653SPeter Holm} 10008a272653SPeter Holm 10018a272653SPeter Holmint 10028a272653SPeter Holmgetnum(char *s, char **e) 10038a272653SPeter Holm{ 10048a272653SPeter Holm int ret = -1; 10058a272653SPeter Holm 10068a272653SPeter Holm *e = (char *) 0; 10078a272653SPeter Holm ret = strtol(s, e, 0); 10088a272653SPeter Holm if (*e) 10098a272653SPeter Holm switch (**e) { 10108a272653SPeter Holm case 'b': 10118a272653SPeter Holm case 'B': 10128a272653SPeter Holm ret *= 512; 10138a272653SPeter Holm *e = *e + 1; 10148a272653SPeter Holm break; 10158a272653SPeter Holm case 'k': 10168a272653SPeter Holm case 'K': 10178a272653SPeter Holm ret *= 1024; 10188a272653SPeter Holm *e = *e + 1; 10198a272653SPeter Holm break; 10208a272653SPeter Holm case 'm': 10218a272653SPeter Holm case 'M': 10228a272653SPeter Holm ret *= 1024*1024; 10238a272653SPeter Holm *e = *e + 1; 10248a272653SPeter Holm break; 10258a272653SPeter Holm case 'w': 10268a272653SPeter Holm case 'W': 10278a272653SPeter Holm ret *= 4; 10288a272653SPeter Holm *e = *e + 1; 10298a272653SPeter Holm break; 10308a272653SPeter Holm } 10318a272653SPeter Holm return (ret); 10328a272653SPeter Holm} 10338a272653SPeter Holm 10348a272653SPeter Holmint 10358a272653SPeter Holmmain(int argc, char **argv) 10368a272653SPeter Holm{ 10378a272653SPeter Holm int i, ch; 10388a272653SPeter Holm char *endp; 10398a272653SPeter Holm char goodfile[1024]; 10408a272653SPeter Holm char logfile[1024]; 10418a272653SPeter Holm 10428a272653SPeter Holm goodfile[0] = 0; 10438a272653SPeter Holm logfile[0] = 0; 10448a272653SPeter Holm 10458a272653SPeter Holm page_size = getpagesize(); 10468a272653SPeter Holm page_mask = page_size - 1; 10478a272653SPeter Holm 10488a272653SPeter Holm setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */ 10498a272653SPeter Holm 10508a272653SPeter Holm while ((ch = getopt(argc, argv, 10518a272653SPeter Holm "b:c:di:l:m:no:p:qr:s:t:w:D:LN:OP:RS:UW")) != -1) 10528a272653SPeter Holm switch (ch) { 10538a272653SPeter Holm case 'b': 10548a272653SPeter Holm simulatedopcount = getnum(optarg, &endp); 10558a272653SPeter Holm if (!quiet) 10568a272653SPeter Holm fprintf(stdout, "Will begin at operation %ld\n", 10578a272653SPeter Holm simulatedopcount); 10588a272653SPeter Holm if (simulatedopcount == 0) 10598a272653SPeter Holm usage(); 10608a272653SPeter Holm simulatedopcount -= 1; 10618a272653SPeter Holm break; 10628a272653SPeter Holm case 'c': 10638a272653SPeter Holm closeprob = getnum(optarg, &endp); 10648a272653SPeter Holm if (!quiet) 10658a272653SPeter Holm fprintf(stdout, 10668a272653SPeter Holm "Chance of close/open is 1 in %d\n", 10678a272653SPeter Holm closeprob); 10688a272653SPeter Holm if (closeprob <= 0) 10698a272653SPeter Holm usage(); 10708a272653SPeter Holm break; 10718a272653SPeter Holm case 'd': 10728a272653SPeter Holm debug = 1; 10738a272653SPeter Holm break; 10748a272653SPeter Holm case 'i': 10758a272653SPeter Holm invlprob = getnum(optarg, &endp); 10768a272653SPeter Holm if (!quiet) 10778a272653SPeter Holm fprintf(stdout, 10788a272653SPeter Holm "Chance of MS_INVALIDATE is 1 in %d\n", 10798a272653SPeter Holm invlprob); 10808a272653SPeter Holm if (invlprob <= 0) 10818a272653SPeter Holm usage(); 10828a272653SPeter Holm break; 10838a272653SPeter Holm case 'l': 10848a272653SPeter Holm maxfilelen = getnum(optarg, &endp); 10858a272653SPeter Holm if (maxfilelen <= 0) 10868a272653SPeter Holm usage(); 10878a272653SPeter Holm break; 10888a272653SPeter Holm case 'm': 10898a272653SPeter Holm monitorstart = getnum(optarg, &endp); 10908a272653SPeter Holm if (monitorstart < 0) 10918a272653SPeter Holm usage(); 10928a272653SPeter Holm if (!endp || *endp++ != ':') 10938a272653SPeter Holm usage(); 10948a272653SPeter Holm monitorend = getnum(endp, &endp); 10958a272653SPeter Holm if (monitorend < 0) 10968a272653SPeter Holm usage(); 10978a272653SPeter Holm if (monitorend == 0) 10988a272653SPeter Holm monitorend = -1; /* aka infinity */ 10998a272653SPeter Holm debug = 1; 11008a272653SPeter Holm case 'n': 11018a272653SPeter Holm sizechecks = 0; 11028a272653SPeter Holm break; 11038a272653SPeter Holm case 'o': 11048a272653SPeter Holm maxoplen = getnum(optarg, &endp); 11058a272653SPeter Holm if (maxoplen <= 0) 11068a272653SPeter Holm usage(); 11078a272653SPeter Holm break; 11088a272653SPeter Holm case 'p': 11098a272653SPeter Holm progressinterval = getnum(optarg, &endp); 11108a272653SPeter Holm// if (progressinterval < 0) 11118a272653SPeter Holm// usage(); 11128a272653SPeter Holm break; 11138a272653SPeter Holm case 'q': 11148a272653SPeter Holm quiet = 1; 11158a272653SPeter Holm break; 11168a272653SPeter Holm case 'r': 11178a272653SPeter Holm readbdy = getnum(optarg, &endp); 11188a272653SPeter Holm if (readbdy <= 0) 11198a272653SPeter Holm usage(); 11208a272653SPeter Holm break; 11218a272653SPeter Holm case 's': 11228a272653SPeter Holm style = getnum(optarg, &endp); 11238a272653SPeter Holm if (style < 0 || style > 1) 11248a272653SPeter Holm usage(); 11258a272653SPeter Holm break; 11268a272653SPeter Holm case 't': 11278a272653SPeter Holm truncbdy = getnum(optarg, &endp); 11288a272653SPeter Holm if (truncbdy <= 0) 11298a272653SPeter Holm usage(); 11308a272653SPeter Holm break; 11318a272653SPeter Holm case 'w': 11328a272653SPeter Holm writebdy = getnum(optarg, &endp); 11338a272653SPeter Holm if (writebdy <= 0) 11348a272653SPeter Holm usage(); 11358a272653SPeter Holm break; 11368a272653SPeter Holm case 'D': 11378a272653SPeter Holm debugstart = getnum(optarg, &endp); 11388a272653SPeter Holm if (debugstart < 1) 11398a272653SPeter Holm usage(); 11408a272653SPeter Holm break; 11418a272653SPeter Holm case 'L': 11428a272653SPeter Holm lite = 1; 11438a272653SPeter Holm break; 11448a272653SPeter Holm case 'N': 11458a272653SPeter Holm numops = getnum(optarg, &endp); 11468a272653SPeter Holm if (numops < 0) 11478a272653SPeter Holm usage(); 11488a272653SPeter Holm break; 11498a272653SPeter Holm case 'O': 11508a272653SPeter Holm randomoplen = 0; 11518a272653SPeter Holm break; 11528a272653SPeter Holm case 'P': 11538a272653SPeter Holm strncpy(goodfile, optarg, sizeof(goodfile)); 11548a272653SPeter Holm strcat(goodfile, "/"); 11558a272653SPeter Holm strncpy(logfile, optarg, sizeof(logfile)); 11568a272653SPeter Holm strcat(logfile, "/"); 11578a272653SPeter Holm break; 11588a272653SPeter Holm case 'R': 11598a272653SPeter Holm mapped_reads = 0; 11608a272653SPeter Holm break; 11618a272653SPeter Holm case 'S': 11628a272653SPeter Holm seed = getnum(optarg, &endp); 11638a272653SPeter Holm if (seed == 0) 11648a272653SPeter Holm seed = time(0) % 10000; 11658a272653SPeter Holm if (!quiet) 11668a272653SPeter Holm fprintf(stdout, "Seed set to %d\n", seed); 11678a272653SPeter Holm if (seed < 0) 11688a272653SPeter Holm usage(); 11698a272653SPeter Holm break; 11708a272653SPeter Holm case 'W': 11718a272653SPeter Holm mapped_writes = 0; 11728a272653SPeter Holm if (!quiet) 11738a272653SPeter Holm fprintf(stdout, "mapped writes DISABLED\n"); 11748a272653SPeter Holm break; 11758a272653SPeter Holm case 'U': 11768a272653SPeter Holm mapped_msync = 0; 11778a272653SPeter Holm if (!quiet) 11788a272653SPeter Holm fprintf(stdout, "mapped msync DISABLED\n"); 11798a272653SPeter Holm break; 11808a272653SPeter Holm 11818a272653SPeter Holm default: 11828a272653SPeter Holm usage(); 11838a272653SPeter Holm /* NOTREACHED */ 11848a272653SPeter Holm } 11858a272653SPeter Holm argc -= optind; 11868a272653SPeter Holm argv += optind; 11878a272653SPeter Holm if (argc != 1) 11888a272653SPeter Holm usage(); 11898a272653SPeter Holm fname = argv[0]; 11908a272653SPeter Holm 11918a272653SPeter Holm signal(SIGHUP, cleanup); 11928a272653SPeter Holm signal(SIGINT, cleanup); 11938a272653SPeter Holm signal(SIGPIPE, cleanup); 11948a272653SPeter Holm signal(SIGALRM, cleanup); 11958a272653SPeter Holm signal(SIGTERM, cleanup); 11968a272653SPeter Holm signal(SIGXCPU, cleanup); 11978a272653SPeter Holm signal(SIGXFSZ, cleanup); 11988a272653SPeter Holm signal(SIGVTALRM, cleanup); 11998a272653SPeter Holm signal(SIGUSR1, cleanup); 12008a272653SPeter Holm signal(SIGUSR2, cleanup); 12018a272653SPeter Holm 12028a272653SPeter Holm initstate(seed, state, 256); 12038a272653SPeter Holm setstate(state); 12048a272653SPeter Holm fd = open(fname, O_RDWR|(lite ? 0 : O_CREAT|O_TRUNC), 0666); 12058a272653SPeter Holm if (fd < 0) { 12068a272653SPeter Holm prterr(fname); 12078a272653SPeter Holm exit(91); 12088a272653SPeter Holm } 12098a272653SPeter Holm strncat(goodfile, fname, 256); 12108a272653SPeter Holm strcat (goodfile, ".fsxgood"); 12118a272653SPeter Holm fsxgoodfd = open(goodfile, O_RDWR|O_CREAT|O_TRUNC, 0666); 12128a272653SPeter Holm if (fsxgoodfd < 0) { 12138a272653SPeter Holm prterr(goodfile); 12148a272653SPeter Holm exit(92); 12158a272653SPeter Holm } 12168a272653SPeter Holm strncat(logfile, fname, 256); 12178a272653SPeter Holm strcat (logfile, ".fsxlog"); 12188a272653SPeter Holm fsxlogf = fopen(logfile, "w"); 12198a272653SPeter Holm if (fsxlogf == NULL) { 12208a272653SPeter Holm prterr(logfile); 12218a272653SPeter Holm exit(93); 12228a272653SPeter Holm } 12238a272653SPeter Holm if (lite) { 12248a272653SPeter Holm off_t ret; 12258a272653SPeter Holm file_size = maxfilelen = lseek(fd, (off_t)0, SEEK_END); 12268a272653SPeter Holm if (file_size == (off_t)-1) { 12278a272653SPeter Holm prterr(fname); 12288a272653SPeter Holm warn("main: lseek eof"); 12298a272653SPeter Holm exit(94); 12308a272653SPeter Holm } 12318a272653SPeter Holm ret = lseek(fd, (off_t)0, SEEK_SET); 12328a272653SPeter Holm if (ret == (off_t)-1) { 12338a272653SPeter Holm prterr(fname); 12348a272653SPeter Holm warn("main: lseek 0"); 12358a272653SPeter Holm exit(95); 12368a272653SPeter Holm } 12378a272653SPeter Holm } 12388a272653SPeter Holm original_buf = (char *) malloc(maxfilelen); 12398a272653SPeter Holm for (i = 0; i < maxfilelen; i++) 12408a272653SPeter Holm original_buf[i] = random() % 256; 12418a272653SPeter Holm good_buf = (char *) malloc(maxfilelen); 12428a272653SPeter Holm memset(good_buf, '\0', maxfilelen); 12438a272653SPeter Holm temp_buf = (char *) malloc(maxoplen); 12448a272653SPeter Holm memset(temp_buf, '\0', maxoplen); 12458a272653SPeter Holm if (lite) { /* zero entire existing file */ 12468a272653SPeter Holm ssize_t written; 12478a272653SPeter Holm 12488a272653SPeter Holm written = write(fd, good_buf, (size_t)maxfilelen); 12498a272653SPeter Holm if (written != maxfilelen) { 12508a272653SPeter Holm if (written == -1) { 12518a272653SPeter Holm prterr(fname); 12528a272653SPeter Holm warn("main: error on write"); 12538a272653SPeter Holm } else 12548a272653SPeter Holm warn("main: short write, 0x%x bytes instead of 0x%x\n", 12558a272653SPeter Holm (unsigned)written, maxfilelen); 12568a272653SPeter Holm exit(98); 12578a272653SPeter Holm } 12588a272653SPeter Holm } else 12598a272653SPeter Holm check_trunc_hack(); 12608a272653SPeter Holm 12618a272653SPeter Holm while (numops == -1 || numops--) 12628a272653SPeter Holm test(); 12638a272653SPeter Holm 12648a272653SPeter Holm if (close(fd)) { 12658a272653SPeter Holm prterr("close"); 12668a272653SPeter Holm report_failure(99); 12678a272653SPeter Holm } 12688a272653SPeter Holm prt("All operations completed A-OK!\n"); 12698a272653SPeter Holm 12708a272653SPeter Holm exit(0); 12718a272653SPeter Holm return 0; 12728a272653SPeter Holm} 1273