xref: /freebsd/tools/test/stress2/misc/umountf2.sh (revision d26c565597b88eb5c6000dbba9e348debe7095e3)
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