diff --git a/lustre/tests/fsx.c b/lustre/tests/fsx.c
index 71711ab..cd4d41e 100644
--- a/lustre/tests/fsx.c
+++ b/lustre/tests/fsx.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 1991, NeXT Computer, Inc.  All Rights Reserverd.
  * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved.
  *
  * Copyright (c) 2012, Intel Corporation.
@@ -30,11 +31,24 @@
  *
  *	Various features from Joe Sokol, Pat Dirks, and Clark Warner.
  *
- *	Small changes to work under Linux -- davej@suse.de
+ *	Small changes to work under Linux -- davej.
  *
  *	Sundry porting patches from Guy Harris 12/2001
  * $FreeBSD: src/tools/regression/fsx/fsx.c,v 1.1 2001/12/20 04:15:57 jkh Exp $
+ *
+ *	Checks for mmap last-page zero fill.
+ *
+ *	Add multi-file testing feature -- Zach Brown <zab@clusterfs.com>
+ *
+ *	Add random preallocation calls - Eric Sandeen <sandeen@redhat.com>
+ *
+ * $FreeBSD: src/tools/regression/fsx/fsx.c,v 1.2 2003/04/23 23:42:23 jkh Exp $
+ * $DragonFly: src/test/stress/fsx/fsx.c,v 1.2 2005/05/02 19:31:56 dillon Exp $
  */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
 #include <sys/types.h>
 #include <sys/stat.h>
 #if defined(_UWIN) || defined(__linux__)
@@ -42,8 +56,8 @@
 # include <limits.h>
 # include <time.h>
 # include <strings.h>
-# include <sys/time.h>
 #endif
+#include <sys/time.h>
 #include <fcntl.h>
 #include <sys/mman.h>
 #ifndef MAP_FILE
@@ -52,13 +66,13 @@
 #include <limits.h>
 #include <signal.h>
 #include <stdio.h>
+#include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdarg.h>
 #include <errno.h>
-
-#define NUMPRINTCOLUMNS 32	/* # columns of data to print on each line */
+#include <setjmp.h>
 
 /*
  * Each test run will work with one or more separate file descriptors for the
@@ -68,7 +82,8 @@
 struct test_file {
 	char *path;
 	int fd;
-} *test_files = NULL;
+	int o_direct;
+} *test_files = NULL, *tf;
 
 int num_test_files;
 enum fd_iteration_policy {
@@ -95,21 +110,32 @@ struct log_entry {
 struct log_entry	oplog[LOGSIZE];	/* the log */
 int			logptr = 0;	/* current position in log */
 int			logcount = 0;	/* total ops */
+int			jmpbuf_good;
+jmp_buf			jmpbuf;
 
 /*
  *	Define operations
  */
 
+/* common operations */
 #define	OP_READ		1
 #define OP_WRITE	2
-#define OP_TRUNCATE	3
-#define OP_CLOSEOPEN	4
-#define OP_MAPREAD	5
-#define OP_MAPWRITE	6
-#define OP_SKIPPED	7
-
-int page_size;
-int page_mask;
+#define OP_MAPREAD	3
+#define OP_MAPWRITE	4
+#define OP_MAX_LITE	5
+
+/* !lite operations */
+#define OP_TRUNCATE		5
+#define OP_FALLOCATE		6
+#define OP_PUNCH_HOLE		7
+#define OP_ZERO_RANGE		8
+#define OP_CLOSEOPEN		9
+#define OP_MAX_FULL		10
+
+#define OP_SKIPPED 101
+#define OP_DIRECT 0200
+
+
 
 char	*original_buf;			/* a pointer to the original data */
 char	*good_buf;			/* a pointer to the correct data */
@@ -118,6 +144,7 @@ char	*fname;				/* name of our test file */
 char	logfile[PATH_MAX];		/* name of our log file */
 char	goodfile[PATH_MAX];		/* name of our test file */
 
+struct timeval	tv;			/* time current operation started */
 off_t		file_size = 0;
 off_t		biggest = 0;
 char		state[256];
@@ -127,6 +154,8 @@ long	simulatedopcount = 0;		/* -b flag */
 int	closeprob = 0;			/* -c flag */
 int	debug = 0;			/* -d flag */
 long	debugstart = 0;			/* -D flag */
+int	flush = 0;			/* -f flag */
+int	do_fsync = 0;			/* -y flag */
 long	maxfilelen = 256 * 1024;	/* -l flag */
 int	sizechecks = 1;			/* -n flag disables them */
 int	maxoplen = 64 * 1024;		/* -o flag */
@@ -143,9 +172,16 @@ long	numops = -1;			/* -N flag */
 int	randomoplen = 1;		/* -O flag disables it */
 int	seed = 1;			/* -S flag */
 int     mapped_writes = 1;              /* -W flag disables */
-int	mapped_reads = 1;		/* -R flag disables it */
+int     fallocate_calls = 1;            /* -F flag disables */
+int     punch_hole_calls = 1;           /* -H flag disables */
+int     zero_range_calls = 1;           /* -z flag disables */
+int 	mapped_reads = 1;		/* -R flag disables it */
 int	fsxgoodfd = 0;
 int	o_direct;			/* -Z */
+
+int page_size;
+int page_mask;
+
 FILE *	fsxlogf = NULL;
 int badoff = -1;
 
@@ -165,6 +201,7 @@ vwarnc(code, fmt, ap)
 
 
 void
+__attribute__((format(printf, 1, 2)))
 warn(const char * fmt, ...)
 {
 	va_list ap;
@@ -173,7 +210,6 @@ warn(const char * fmt, ...)
 	va_end(ap);
 }
 
-
 void
 __attribute__((format(printf, 1, 2)))
 prt(char *fmt, ...)
@@ -199,8 +235,7 @@ prterr(char *prefix)
 
 
 void
-log4(int operation, int arg0, int arg1, int arg2, struct timeval *tv,
-	const struct test_file *tf)
+log4(int operation, int arg0, int arg1, int arg2)
 {
 	struct log_entry *le;
 
@@ -209,7 +244,8 @@ log4(int operation, int arg0, int arg1, int arg2, struct timeval *tv,
 	le->args[0] = arg0;
 	le->args[1] = arg1;
 	le->args[2] = arg2;
-	le->tv = *tv;
+	gettimeofday(&tv, NULL);
+	le->tv = tv;
 	le->tf = tf;
 	logptr++;
 	logcount++;
@@ -241,6 +277,7 @@ logdump(void)
 {
 	int	i, count, down;
 	struct log_entry	*lp;
+	char *falloc_type[3] = {"PAST_EOF", "EXTENDING", "INTERIOR"};
 
 	prt("LOG DUMP (%d total operations):\n", logcount);
 	if (logcount < LOGSIZE) {
@@ -255,12 +292,12 @@ logdump(void)
 
 		opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE;
 		lp = &oplog[i];
-		prt("%d%s: %lu.%06lu ", opnum, fill_tf_buf(lp->tf),
-		    lp->tv.tv_sec, lp->tv.tv_usec);
+		prt("%d%s: %lu.%06u ", opnum, fill_tf_buf(lp->tf),
+		    lp->tv.tv_sec, (int)lp->tv.tv_usec);
 
 		switch (lp->operation) {
 		case OP_MAPREAD:
-			prt("MAPREAD  0x%x thru 0x%x (0x%x bytes)",
+			prt("MAPREAD  0x%05x thru 0x%05x (0x%05x bytes)",
 			    lp->args[0], lp->args[0] + lp->args[1] - 1,
 			    lp->args[1]);
 			if (badoff >= lp->args[0] && badoff <
@@ -268,7 +305,7 @@ logdump(void)
 				prt("\t***RRRR***");
 			break;
 		case OP_MAPWRITE:
-			prt("MAPWRITE 0x%x thru 0x%x (0x%x bytes)",
+			prt("MAPWRITE 0x%05x thru 0x%05x (0x%05x bytes)",
 			    lp->args[0], lp->args[0] + lp->args[1] - 1,
 			    lp->args[1]);
 			if (badoff >= lp->args[0] && badoff <
@@ -276,7 +313,9 @@ logdump(void)
 				prt("\t******WWWW");
 			break;
 		case OP_READ:
-			prt("READ     0x%x thru 0x%x (0x%x bytes)",
+		case OP_READ + OP_DIRECT:
+			prt("READ%s  0x%05x thru 0x%05x (0x%05x bytes)",
+			    lp->operation & OP_DIRECT ? "_OD" : "   ",
 			    lp->args[0], lp->args[0] + lp->args[1] - 1,
 			    lp->args[1]);
 			if (badoff >= lp->args[0] &&
@@ -284,7 +323,9 @@ logdump(void)
 				prt("\t***RRRR***");
 			break;
 		case OP_WRITE:
-			prt("WRITE    0x%x thru 0x%x (0x%x bytes)",
+		case OP_WRITE + OP_DIRECT:
+			prt("WRITE%s 0x%05x thru 0x%05x (0x%05x bytes)",
+			    lp->operation & OP_DIRECT ? "_OD" : "   ",
 			    lp->args[0], lp->args[0] + lp->args[1] - 1,
 			    lp->args[1]);
 			if (lp->args[0] > lp->args[2])
@@ -297,14 +338,41 @@ logdump(void)
 			break;
 		case OP_TRUNCATE:
 			down = lp->args[0] < lp->args[1];
-			prt("TRUNCATE %s\tfrom 0x%x to 0x%x",
+			prt("TRUNCATE %s\tfrom 0x%05x to 0x%05x",
 			    down ? "DOWN" : "UP", lp->args[1], lp->args[0]);
 			if (badoff >= lp->args[!down] &&
 			    badoff < lp->args[!!down])
 				prt("\t******WWWW");
 			break;
+		case OP_FALLOCATE:
+			/* 0: offset 1: length 2: where alloced */
+			prt("FALLOC  \tfrom 0x%05x to 0x%05x\t(0x%05x bytes)%s",
+			    lp->args[0], lp->args[0] + lp->args[1],
+			    lp->args[1], falloc_type[lp->args[2]]);
+			if (badoff >= lp->args[0] &&
+			    badoff < lp->args[0] + lp->args[1])
+				prt("\t******FFFF");
+			break;
+		case OP_PUNCH_HOLE:
+			prt("PUNCH    0x%05x thru 0x%05x\t(0x%05x bytes)",
+			    lp->args[0], lp->args[0] + lp->args[1] - 1,
+			    lp->args[1]);
+			if (badoff >= lp->args[0] && badoff <
+						     lp->args[0] + lp->args[1])
+				prt("\t******PPPP");
+			break;
+		case OP_ZERO_RANGE:
+			prt("ZERO     0x%05x thru 0x%05x\t(0x%05x bytes)",
+			    lp->args[0], lp->args[0] + lp->args[1] - 1,
+			    lp->args[1]);
+			if (badoff >= lp->args[0] && badoff <
+						     lp->args[0] + lp->args[1])
+				prt("\t******ZZZZ");
+			break;
 		case OP_CLOSEOPEN:
-			prt("CLOSE/OPEN");
+		case OP_CLOSEOPEN + OP_DIRECT:
+			prt("CLOSE/OPEN%s",
+			    lp->operation & OP_DIRECT ? "_OD" : "   ");
 			break;
 		case OP_SKIPPED:
 			prt("SKIPPED (no operation)");
@@ -330,7 +398,7 @@ save_buffer(char *buffer, off_t bufferlength, int fd)
 	if (fd <= 0 || bufferlength == 0)
 		return;
 
-	if (bufferlength > SSIZE_MAX) {
+	if (bufferlength > INT_MAX) {
 		prt("fsx flaw: overflow in save_buffer\n");
 		exit(67);
 	}
@@ -496,10 +564,12 @@ open_test_files(char **argv, int argc)
 	}
 
 	for (i = 0, tf = test_files; i < num_test_files; i++, tf++) {
-
 		tf->path = argv[i];
-		tf->fd = open(tf->path, O_RDWR|(lite ? 0 : O_CREAT|O_TRUNC)|
-				o_direct, 0666);
+#ifdef O_DIRECT
+		tf->o_direct = (random() % (o_direct + 1)) ? O_DIRECT : 0;
+#endif
+		tf->fd = open(tf->path,
+			O_RDWR|(lite ? 0 : O_CREAT|O_TRUNC)|tf->o_direct, 0666);
 		if (tf->fd < 0) {
 			prterr(tf->path);
 			exit(91);
@@ -580,8 +650,7 @@ check_trunc_hack(void)
 }
 
 void
-output_line(struct test_file *tf, int op, unsigned offset,
-		unsigned size, struct timeval *tv)
+output_line(struct test_file *tf, int op, unsigned offset, unsigned size)
 {
 	char *ops[] = {
 		[OP_READ] = "read",
@@ -589,6 +658,9 @@ output_line(struct test_file *tf, int op, unsigned offset,
 		[OP_TRUNCATE] = "trunc from",
 		[OP_MAPREAD] = "mapread",
 		[OP_MAPWRITE] = "mapwrite",
+		[OP_READ + OP_DIRECT] = "read_OD",
+		[OP_WRITE + OP_DIRECT] = "write_OD",
+		[OP_FALLOCATE] = "fallocate",
 	};
 
 	/* W. */
@@ -600,45 +672,87 @@ output_line(struct test_file *tf, int op, unsigned offset,
 			  (monitorend == -1 || offset <= monitorend)))))))
 		return;
 
-	prt("%06lu%s %lu.%06lu %-10s %#08x %s %#08x\t(0x%x bytes)\n",
-		testcalls, fill_tf_buf(tf), tv->tv_sec, tv->tv_usec,
-		ops[op],
-		offset, op == OP_TRUNCATE ? " to " : "thru",
-		offset + size - 1, size);
+	prt("%06lu%s %lu.%06u %-10s %#08x %s %#08x\t(0x05%x bytes)\n",
+		testcalls, fill_tf_buf(tf), tv.tv_sec, (int)tv.tv_usec,
+		ops[op], offset, op == OP_TRUNCATE ? " to " : "thru",
+		offset + size - 1, (int)size < 0 ? -(int)size : size);
+}
+
+void output_debug(unsigned offset, unsigned size, const char *what)
+{
+	struct timeval t;
+
+	if (!quiet && (debug > 1 &&
+		        (monitorstart == -1 ||
+			 (offset + size >= monitorstart &&
+			  (monitorend == -1 || offset <= monitorend))))) {
+		gettimeofday(&t, NULL);
+		prt("       %lu.%06u %s\n", t.tv_sec, (int)t.tv_usec, what);
+	}
+}
+
+void
+doflush(unsigned offset, unsigned size)
+{
+	unsigned pg_offset;
+	unsigned map_size;
+	char    *p;
+	struct test_file *tf = get_tf();
+	int fd = tf->fd;
+
+	if (tf->o_direct)
+		return;
+
+	pg_offset = offset & page_mask;
+	map_size  = pg_offset + size;
+
+	if ((p = (char *)mmap(0, map_size, PROT_READ | PROT_WRITE,
+			      MAP_FILE | MAP_SHARED, fd,
+			      (off_t)(offset - pg_offset))) == (char *)-1) {
+		prterr("doflush: mmap");
+		report_failure(202);
+	}
+	if (msync(p, map_size, MS_INVALIDATE) != 0) {
+		prterr("doflush: msync");
+		report_failure(203);
+	}
+	if (munmap(p, map_size) != 0) {
+		prterr("doflush: munmap");
+		report_failure(204);
+	}
+	output_debug(offset, size, "flush done");
 }
 
 void
 doread(unsigned offset, unsigned size)
 {
-	struct timeval t;
 	off_t ret;
 	unsigned iret;
 	struct test_file *tf = get_tf();
 	int fd = tf->fd;
 
 	offset -= offset % readbdy;
-	if (o_direct)
+	if (tf->o_direct)
 		size -= size % readbdy;
-	gettimeofday(&t, NULL);
 	if (size == 0) {
-		if (!quiet && testcalls > simulatedopcount && !o_direct)
+		if (!quiet && testcalls > simulatedopcount && !tf->o_direct)
 			prt("skipping zero size read\n");
-		log4(OP_SKIPPED, OP_READ, offset, size, &t, tf);
+		log4(OP_SKIPPED, OP_READ, offset, size);
 		return;
 	}
 	if (size + offset > file_size) {
 		if (!quiet && testcalls > simulatedopcount)
 			prt("skipping seek/read past end of file\n");
-		log4(OP_SKIPPED, OP_READ, offset, size, &t, tf);
+		log4(OP_SKIPPED, OP_READ, offset, size);
 		return;
 	}
 
-	log4(OP_READ, offset, size, 0, &t, tf);
+	log4(OP_READ + tf->o_direct, offset, size, 0);
 
 	if (testcalls <= simulatedopcount)
 		return;
 
-	output_line(tf, OP_READ, offset, size, &t);
+	output_line(tf, OP_READ + tf->o_direct, offset, size);
 
 	ret = lseek(fd, (off_t)offset, SEEK_SET);
 	if (ret == (off_t)-1) {
@@ -646,13 +760,7 @@ doread(unsigned offset, unsigned size)
 		report_failure(140);
 	}
 	iret = read(fd, temp_buf, size);
-	if (!quiet && (debug > 1 &&
-		        (monitorstart == -1 ||
-			 (offset + size > monitorstart &&
-			  (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu read done\n", t.tv_sec, t.tv_usec);
-	}
+	output_debug(offset, size, "read done");
 	if (iret != size) {
 		if (iret == -1)
 			prterr("doread: read");
@@ -664,38 +772,63 @@ doread(unsigned offset, unsigned size)
 	check_buffers(offset, size);
 }
 
+void
+check_eofpage(char *s, unsigned offset, char *p, int size)
+{
+	long last_page, should_be_zero;
+
+	if (offset + size <= (file_size & ~page_mask))
+		return;
+	/*
+	 * we landed in the last page of the file
+	 * test to make sure the VM system provided 0's
+	 * beyond the true end of the file mapping
+	 * (as required by mmap def in 1996 posix 1003.1)
+	 */
+	last_page = ((long)p + (offset & page_mask) + size) & ~page_mask;
+
+	for (should_be_zero = last_page + (file_size & page_mask);
+	     should_be_zero < last_page + page_size;
+	     should_be_zero++)
+		if (*(char *)should_be_zero) {
+			prt("Mapped %s: non-zero data past EOF (0x%llx) page offset 0x%lx is 0x%04x\n",
+			    s, (long long)file_size - 1, should_be_zero & page_mask,
+			    short_at(should_be_zero));
+			report_failure(205);
+		}
+}
+
 
 void
 domapread(unsigned offset, unsigned size)
 {
-	struct timeval t;
 	unsigned pg_offset;
 	unsigned map_size;
 	char    *p;
-	struct test_file *tf = get_tf();
-	int fd = tf->fd;
+	int fd;
 
 	offset -= offset % readbdy;
-	gettimeofday(&t, NULL);
+	tf = get_tf();
+	fd = tf->fd;
 	if (size == 0) {
 		if (!quiet && testcalls > simulatedopcount)
 			prt("skipping zero size read\n");
-		log4(OP_SKIPPED, OP_MAPREAD, offset, size, &t, tf);
+		log4(OP_SKIPPED, OP_MAPREAD, offset, size);
 		return;
 	}
 	if (size + offset > file_size) {
 		if (!quiet && testcalls > simulatedopcount)
 			prt("skipping seek/read past end of file\n");
-		log4(OP_SKIPPED, OP_MAPREAD, offset, size, &t, tf);
+		log4(OP_SKIPPED, OP_MAPREAD, offset, size);
 		return;
 	}
 
-	log4(OP_MAPREAD, offset, size, 0, &t, tf);
+	log4(OP_MAPREAD, offset, size, 0);
 
 	if (testcalls <= simulatedopcount)
 		return;
 
-	output_line(tf, OP_MAPREAD, offset, size, &t);
+	output_line(tf, OP_MAPREAD, offset, size);
 
 	pg_offset = offset & page_mask;
 	map_size  = pg_offset + size;
@@ -705,32 +838,22 @@ domapread(unsigned offset, unsigned size)
 	        prterr("domapread: mmap");
 		report_failure(190);
 	}
-	if (!quiet && (debug > 1 &&
-		        (monitorstart == -1 ||
-			 (offset + size > monitorstart &&
-			  (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu mmap done\n", t.tv_sec, t.tv_usec);
-	}
-	memcpy(temp_buf, p + pg_offset, size);
-	if (!quiet && (debug > 1 &&
-		        (monitorstart == -1 ||
-			 (offset + size > monitorstart &&
-			  (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu memcpy done\n", t.tv_sec, t.tv_usec);
+	output_debug(offset, size, "mmap done");
+	if (setjmp(jmpbuf) == 0) {
+		jmpbuf_good = 1;
+		memcpy(temp_buf, p + pg_offset, size);
+
+		check_eofpage("Read", offset, p, size);
+		jmpbuf_good = 0;
+	} else {
+		report_failure(1901);
 	}
+	output_debug(offset, size, "memcpy done");
 	if (munmap(p, map_size) != 0) {
 		prterr("domapread: munmap");
 		report_failure(191);
 	}
-	if (!quiet && (debug > 1 &&
-		        (monitorstart == -1 ||
-			 (offset + size > monitorstart &&
-			  (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu munmap done\n", t.tv_sec, t.tv_usec);
-	}
+	output_debug(offset, size, "munmap done");
 
 	check_buffers(offset, size);
 }
@@ -751,24 +874,23 @@ gendata(char *original_buf, char *good_buf, unsigned offset, unsigned size)
 void
 dowrite(unsigned offset, unsigned size)
 {
-	struct timeval t;
 	off_t ret;
 	unsigned iret;
-	struct test_file *tf = get_tf();
-	int fd = tf->fd;
+	int fd;
 
+	tf = get_tf();
+	fd = tf->fd;
 	offset -= offset % writebdy;
-	if (o_direct)
+	if (tf->o_direct)
 		size -= size % writebdy;
-	gettimeofday(&t, NULL);
 	if (size == 0) {
-		if (!quiet && testcalls > simulatedopcount && !o_direct)
+		if (!quiet && testcalls > simulatedopcount && !tf->o_direct)
 			prt("skipping zero size write\n");
-		log4(OP_SKIPPED, OP_WRITE, offset, size, &t, tf);
+		log4(OP_SKIPPED, OP_WRITE, offset, size);
 		return;
 	}
 
-	log4(OP_WRITE, offset, size, file_size, &t, tf);
+	log4(OP_WRITE + tf->o_direct, offset, size, file_size);
 
 	gendata(original_buf, good_buf, offset, size);
 	if (file_size < offset + size) {
@@ -784,7 +906,7 @@ dowrite(unsigned offset, unsigned size)
 	if (testcalls <= simulatedopcount)
 		return;
 
-	output_line(tf, OP_WRITE, offset, size, &t);
+	output_line(tf, OP_WRITE + tf->o_direct, offset, size);
 
 	ret = lseek(fd, (off_t)offset, SEEK_SET);
 	if (ret == (off_t)-1) {
@@ -792,13 +914,7 @@ dowrite(unsigned offset, unsigned size)
 		report_failure(150);
 	}
 	iret = write(fd, good_buf + offset, size);
-	if (!quiet && (debug > 1 &&
-		        (monitorstart == -1 ||
-			 (offset + size > monitorstart &&
-			  (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu write done\n", t.tv_sec, t.tv_usec);
-	}
+	output_debug(offset, size, "write done");
 	if (iret != size) {
 		if (iret == -1)
 			prterr("dowrite: write");
@@ -807,31 +923,41 @@ dowrite(unsigned offset, unsigned size)
 			    iret, size);
 		report_failure(151);
 	}
+	if (do_fsync) {
+		if (fsync(fd)) {
+			prt("fsync() failed: %s\n", strerror(errno));
+			report_failure(152);
+		}
+		output_debug(offset, size, "fsync done");
+	}
+	if (flush) {
+		doflush(offset, size);
+		output_debug(offset, size, "flush done");
+	}
 }
 
 
 void
 domapwrite(unsigned offset, unsigned size)
 {
-	struct timeval t;
 	unsigned pg_offset;
 	unsigned map_size;
 	off_t    cur_filesize;
 	char    *p;
-	struct test_file *tf = get_tf();
-	int fd = tf->fd;
+	int fd;
 
+	tf = get_tf();
+	fd = tf->fd;
 	offset -= offset % writebdy;
-	gettimeofday(&t, NULL);
 	if (size == 0) {
 		if (!quiet && testcalls > simulatedopcount)
 			prt("skipping zero size write\n");
-		log4(OP_SKIPPED, OP_MAPWRITE, offset, size, &t, tf);
+		log4(OP_SKIPPED, OP_MAPWRITE, offset, size);
 		return;
 	}
 	cur_filesize = file_size;
 
-	log4(OP_MAPWRITE, offset, size, 0, &t, tf);
+	log4(OP_MAPWRITE, offset, size, 0);
 
 	gendata(original_buf, good_buf, offset, size);
 	if (file_size < offset + size) {
@@ -847,86 +973,62 @@ domapwrite(unsigned offset, unsigned size)
 	if (testcalls <= simulatedopcount)
 		return;
 
-	output_line(tf, OP_MAPWRITE, offset, size, &t);
+	output_line(tf, OP_MAPWRITE, offset, size);
 
 	if (file_size > cur_filesize) {
 	        if (ftruncate(fd, file_size) == -1) {
 		        prterr("domapwrite: ftruncate");
 			exit(201);
 		}
-		if (!quiet && (debug > 1 &&
-			       (monitorstart == -1 ||
-				(offset + size > monitorstart &&
-				 (monitorend == -1 || offset <= monitorend))))) {
-			gettimeofday(&t, NULL);
-			prt("       %lu.%06lu truncate done\n", t.tv_sec, t.tv_usec);
-	}
+		output_debug(offset, size, "truncate done");
 	}
 	pg_offset = offset & page_mask;
 	map_size  = pg_offset + size;
 
-	if ((p = mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_FILE|MAP_SHARED,
-		      fd, (off_t)(offset - pg_offset))) == MAP_FAILED) {
+	if ((p = mmap(0, map_size, PROT_READ | PROT_WRITE,
+		      MAP_FILE | MAP_SHARED, fd,
+		      (off_t)(offset - pg_offset))) == MAP_FAILED) {
 	        prterr("domapwrite: mmap");
 		report_failure(202);
 	}
-	if (!quiet && (debug > 1 &&
-		        (monitorstart == -1 ||
-			 (offset + size > monitorstart &&
-			  (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu mmap done\n", t.tv_sec, t.tv_usec);
-	}
-	memcpy(p + pg_offset, good_buf + offset, size);
-	if (!quiet && (debug > 1 &&
-		        (monitorstart == -1 ||
-			 (offset + size > monitorstart &&
-			  (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu memcpy done\n", t.tv_sec, t.tv_usec);
-	}
-	if (msync(p, map_size, 0) != 0) {
-		prterr("domapwrite: msync");
-		report_failure(203);
-	}
-	if (!quiet && (debug > 1 &&
-		        (monitorstart == -1 ||
-			 (offset + size > monitorstart &&
-			  (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu msync done\n", t.tv_sec, t.tv_usec);
-	}
+	output_debug(offset, map_size, "mmap done");
+	if (setjmp(jmpbuf) == 0) {
+		jmpbuf_good = 1;
+		memcpy(p + pg_offset, good_buf + offset, size);
+		if (msync(p, map_size, MS_SYNC) != 0) {
+			prterr("domapwrite: msync");
+			report_failure(203);
+		}
+		check_eofpage("Write", offset, p, size);
+		jmpbuf_good = 0;
+	} else {
+		report_failure(2021);
+	}
+	output_debug(offset, map_size, "msync done");
 	if (munmap(p, map_size) != 0) {
 		prterr("domapwrite: munmap");
 		report_failure(204);
 	}
-	if (!quiet && (debug > 1 &&
-		        (monitorstart == -1 ||
-			 (offset + size > monitorstart &&
-			  (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu munmap done\n", t.tv_sec, t.tv_usec);
-	}
+	output_debug(offset, map_size, "munmap done");
 }
 
 
 void
 dotruncate(unsigned size)
 {
-	struct timeval t;
 	int oldsize = file_size;
-	struct test_file *tf = get_tf();
-	int fd = tf->fd;
+	int fd;
 
+	tf = get_tf();
+	fd = tf->fd;
 	size -= size % truncbdy;
-	gettimeofday(&t, NULL);
 	if (size > biggest) {
 		biggest = size;
 		if (!quiet && testcalls > simulatedopcount)
 			prt("truncating to largest ever: 0x%x\n", size);
 	}
 
-	log4(OP_TRUNCATE, size, (unsigned)file_size, 0, &t, tf);
+	log4(OP_TRUNCATE, size, (unsigned)file_size, 0);
 
 	if (size > file_size)
 		memset(good_buf + file_size, '\0', size - file_size);
@@ -935,19 +1037,194 @@ dotruncate(unsigned size)
 	if (testcalls <= simulatedopcount)
 		return;
 
-	output_line(tf, OP_TRUNCATE, oldsize, size, &t);
+	output_line(tf, OP_TRUNCATE, oldsize, size - oldsize);
 
 	if (ftruncate(fd, (off_t)size) == -1) {
 	        prt("ftruncate1: %x\n", size);
 		prterr("dotruncate: ftruncate");
 		report_failure(160);
 	}
-	if (!quiet && debug > 1) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu trunc done\n", t.tv_sec, t.tv_usec);
+	output_debug(size, 0, "truncate done");
+}
+
+#ifdef FALLOC_FL_PUNCH_HOLE
+void
+do_punch_hole(unsigned offset, unsigned length)
+{
+	unsigned end_offset;
+	int max_offset = 0;
+	int max_len = 0;
+	int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;
+	int fd;
+
+	tf = get_tf();
+	fd = tf->fd;
+	if (length == 0) {
+		if (!quiet && testcalls > simulatedopcount)
+			prt("skipping zero length punch hole\n");
+			log4(OP_SKIPPED, OP_PUNCH_HOLE, offset, length);
+		return;
 	}
+
+	if (file_size <= (loff_t)offset) {
+		if (!quiet && testcalls > simulatedopcount)
+			prt("skipping hole punch off the end of the file\n");
+			log4(OP_SKIPPED, OP_PUNCH_HOLE, offset, length);
+		return;
+	}
+
+	end_offset = offset + length;
+
+	log4(OP_PUNCH_HOLE, offset, length, 0);
+
+	if (testcalls <= simulatedopcount)
+		return;
+
+	output_line(tf, OP_PUNCH_HOLE, offset, length);
+	if (fallocate(fd, mode, (loff_t)offset, (loff_t)length) == -1) {
+		prt("%punch hole: %x to %x\n", offset, length);
+		prterr("do_punch_hole: fallocate");
+		report_failure(161);
+	}
+	output_debug(offset, size, "zero_range done");
+
+	max_offset = offset < file_size ? offset : file_size;
+	max_len = max_offset + length <= file_size ? length :
+			file_size - max_offset;
+	memset(good_buf + max_offset, '\0', max_len);
 }
 
+#else
+void
+do_punch_hole(unsigned offset, unsigned length)
+{
+	return;
+}
+#define FALLOC_FL_PUNCH_HOLE 0
+#define FALLOC_FL_KEEP_SIZE 0
+#endif
+
+#ifdef FALLOC_FL_ZERO_RANGE
+void
+do_zero_range(unsigned offset, unsigned length)
+{
+	unsigned end_offset;
+	int mode = FALLOC_FL_ZERO_RANGE;
+	int keep_size;
+	int fd;
+
+	tf = get_tf();
+	fd = tf->fd;
+	if (length == 0) {
+		if (!quiet && testcalls > simulatedopcount)
+			prt("skipping zero length zero range\n");
+			log4(OP_SKIPPED, OP_ZERO_RANGE, offset, length);
+		return;
+	}
+
+	keep_size = random() % 2;
+
+	end_offset = keep_size ? 0 : offset + length;
+
+	if (end_offset > biggest) {
+		biggest = end_offset;
+		if (!quiet && testcalls > simulatedopcount)
+			prt("zero_range to largest ever: 0x%x\n", end_offset);
+	}
+
+	/*
+	 * last arg matches fallocate string array index in logdump:
+	 * 	0: allocate past EOF
+	 * 	1: extending prealloc
+	 * 	2: interior prealloc
+	 */
+	log4(OP_ZERO_RANGE, offset, length,
+	     (end_offset > file_size) ? (keep_size ? 0 : 1) : 2);
+
+	if (testcalls <= simulatedopcount)
+		return;
+
+	output_line(tf, OP_TRUNCATE, offset, length);
+
+	if (fallocate(fd, mode, (loff_t)offset, (loff_t)length) == -1) {
+		prt("%pzero range: %x to %x\n", offset, length);
+		prterr("do_zero_range: fallocate");
+		report_failure(161);
+	}
+	output_debug(offset, size, "zero_range done");
+
+	memset(good_buf + offset, '\0', length);
+}
+
+#else
+void
+do_zero_range(unsigned offset, unsigned length)
+{
+	return;
+}
+#define FALLOC_FL_ZERO_RANGE 0
+#endif
+
+#ifdef HAVE_LINUX_FALLOC_H
+/* fallocate is basically a no-op unless extending, then a lot like a truncate */
+void
+do_preallocate(unsigned offset, unsigned length)
+{
+	unsigned end_offset;
+	int keep_size;
+	int fd;
+
+	tf = get_tf();
+	fd = tf->fd;
+        if (length == 0) {
+                if (!quiet && testcalls > simulatedopcount)
+                        prt("skipping zero length fallocate\n");
+                log4(OP_SKIPPED, OP_FALLOCATE, offset, length);
+                return;
+        }
+
+	keep_size = random() % 2;
+
+	end_offset = keep_size ? 0 : offset + length;
+
+	if (end_offset > biggest) {
+		biggest = end_offset;
+		if (!quiet && testcalls > simulatedopcount)
+			prt("fallocating to largest ever: 0x%x\n", end_offset);
+	}
+
+	/*
+	 * last arg matches fallocate string array index in logdump:
+	 * 	0: allocate past EOF
+	 * 	1: extending prealloc
+	 * 	2: interior prealloc
+	 */
+	log4(OP_FALLOCATE, offset, length, (end_offset > file_size) ? (keep_size ? 0 : 1) : 2);
+
+	if (end_offset > file_size) {
+		memset(good_buf + file_size, '\0', end_offset - file_size);
+		file_size = end_offset;
+	}
+
+	if (testcalls <= simulatedopcount)
+		return;
+
+	output_line(tf, OP_FALLOCATE, offset, length);
+
+	if (fallocate(fd, keep_size ? FALLOC_FL_KEEP_SIZE : 0, (loff_t)offset, (loff_t)length) == -1) {
+	        prt("fallocate: %x to %x\n", offset, length);
+		prterr("do_preallocate: fallocate");
+		report_failure(161);
+	}
+	output_debug(offset, length, "fallocate done");
+}
+#else
+void
+do_preallocate(unsigned offset, unsigned length)
+{
+	return;
+}
+#endif
 
 void
 writefileimage()
@@ -965,8 +1242,7 @@ writefileimage()
 			prterr("writefileimage: write");
 		else
 			prt("short write: 0x%lx bytes instead of 0x%llx\n",
-			    (unsigned long)iret,
-			    (unsigned long long)file_size);
+			    (unsigned long)iret, (unsigned long long)file_size);
 		report_failure(172);
 	}
 	if (lite ? 0 : ftruncate(fd, file_size) == -1) {
@@ -980,37 +1256,48 @@ writefileimage()
 void
 docloseopen(void)
 {
-	struct timeval t;
-	struct test_file *tf = get_tf();
+	int direct = 0;
+	const char *tf_num = "";
 
 	if (testcalls <= simulatedopcount)
 		return;
 
-	gettimeofday(&t, NULL);
-	log4(OP_CLOSEOPEN, file_size, (unsigned)file_size, 0, &t, tf);
+	tf = get_tf();
+#ifdef O_DIRECT
+	direct = (random() % (o_direct + 1)) ? O_DIRECT : 0;
+#endif
+	log4(OP_CLOSEOPEN + direct, file_size, (unsigned)file_size, 0);
+
+	if (fd_policy != FD_SINGLE)
+		tf_num = fill_tf_buf(tf);
 
 	if (debug)
-		prt("%06lu %lu.%06lu close/open\n", testcalls, t.tv_sec,
-		    t.tv_usec);
-	if (close(tf->fd)) {
-		prterr("docloseopen: close");
+		prt("%06lu %lu.%06u %sclose/open%s\n", testcalls, tv.tv_sec,
+		    (int)tv.tv_usec, tf_num, direct ? "(O_DIRECT)" : "");
+	if (close(tf->fd))
 		report_failure(180);
-	}
-	if (!quiet && debug > 1) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu close done\n", t.tv_sec, t.tv_usec);
-	}
-	tf->fd = open(tf->path, O_RDWR|o_direct, 0);
+
+	output_debug(monitorstart, 0, "close done");
+	tf->o_direct = direct;
+	tf->fd = open(tf->path, O_RDWR|tf->o_direct, 0);
 	if (tf->fd < 0) {
-		prterr("docloseopen: open");
+		prterr(tf->o_direct ?
+		       "docloseopen: open(O_DIRECT)" : "docloseopen: open");
 		report_failure(181);
 	}
-	if (!quiet && debug > 1) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu open done\n", t.tv_sec, t.tv_usec);
-	}
+	output_debug(monitorstart, 0,
+		     tf->o_direct ? "open(O_DIRECT) done" : "open done");
 }
 
+#define TRIM_OFF_LEN(off, len, size)	\
+do {					\
+	if (size)			\
+		(off) %= (size);	\
+	else				\
+		(off) = 0;		\
+	if ((off) + (len) > (size))	\
+		(len) = (size) - (off);	\
+} while (0)
 
 void
 test(void)
@@ -1018,68 +1305,126 @@ test(void)
 	unsigned long	offset;
 	unsigned long	size = maxoplen;
 	unsigned long	rv = random();
-	unsigned long	op = rv % (3 + !lite + mapped_writes);
-
-        /* turn off the map read if necessary */
-
-        if (op == 2 && !mapped_reads)
-            op = 0;
+	unsigned long	op;
+	int closeopen = 0;
 
 	if (simulatedopcount > 0 && testcalls == simulatedopcount)
 		writefileimage();
 
 	testcalls++;
 
+	if (closeprob)
+		closeopen = (rv >> 3) < (1 << 28) / closeprob;
+
 	if (debugstart > 0 && testcalls >= debugstart)
 		debug = 1;
 
 	if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0)
 		prt("%lu...\n", testcalls);
 
-	/*
-	 * READ:	op = 0
-	 * WRITE:	op = 1
-	 * MAPREAD:     op = 2
-	 * TRUNCATE:	op = 3
-	 * MAPWRITE:    op = 3 or 4
-	 */
-	if (lite ? 0 : op == 3 && (style & 1) == 0) /* vanilla truncate? */
-		dotruncate(random() % maxfilelen);
-	else {
-		if (randomoplen)
-			size = random() % (maxoplen+1);
-		if (lite ? 0 : op == 3)
-			dotruncate(size);
-		else {
-			offset = random();
-			if (op == 1 || op == (lite ? 3 : 4)) {
-				offset %= maxfilelen;
-				if (offset + size > maxfilelen)
-					size = maxfilelen - offset;
-				if (op != 1)
-					domapwrite(offset, size);
-				else
-					dowrite(offset, size);
-			} else {
-				if (file_size)
-					offset %= file_size;
-				else
-					offset = 0;
-				if (offset + size > file_size)
-					size = file_size - offset;
-				if (op != 0)
-					domapread(offset, size);
-				else
-					doread(offset, size);
-			}
+	offset = random();
+	if (randomoplen)
+		size = random() % (maxoplen + 1);
+
+	/* calculate appropriate op to run */
+	if (lite)
+		op = rv % OP_MAX_LITE;
+	else
+		op = rv % OP_MAX_FULL;
+
+	switch (op) {
+	case OP_MAPREAD:
+		if (!mapped_reads)
+			op = OP_READ;
+		break;
+	case OP_MAPWRITE:
+		if (!mapped_writes)
+			op = OP_WRITE;
+		break;
+	case OP_FALLOCATE:
+		if (!fallocate_calls) {
+			log4(OP_SKIPPED, OP_FALLOCATE, offset, size);
+			goto out;
 		}
+		break;
+	case OP_PUNCH_HOLE:
+		if (!punch_hole_calls) {
+			log4(OP_SKIPPED, OP_PUNCH_HOLE, offset, size);
+			goto out;
+		}
+		break;
+	case OP_ZERO_RANGE:
+		if (!zero_range_calls) {
+			log4(OP_SKIPPED, OP_ZERO_RANGE, offset, size);
+			goto out;
+		}
+		break;
+	}
+
+	switch (op) {
+	case OP_READ:
+		TRIM_OFF_LEN(offset, size, file_size);
+		doread(offset, size);
+		break;
+
+	case OP_WRITE:
+		TRIM_OFF_LEN(offset, size, maxfilelen);
+		dowrite(offset, size);
+		break;
+
+	case OP_MAPREAD:
+		TRIM_OFF_LEN(offset, size, file_size);
+		domapread(offset, size);
+		break;
+
+	case OP_MAPWRITE:
+		TRIM_OFF_LEN(offset, size, maxfilelen);
+		domapwrite(offset, size);
+		break;
+
+	case OP_TRUNCATE:
+		if (!style)
+			size = random() % maxfilelen;
+		dotruncate(size);
+		break;
+
+	case OP_FALLOCATE:
+		TRIM_OFF_LEN(offset, size, maxfilelen);
+		do_preallocate(offset, size);
+		break;
+
+	case OP_PUNCH_HOLE:
+		TRIM_OFF_LEN(offset, size, file_size);
+		do_punch_hole(offset, size);
+		break;
+	case OP_ZERO_RANGE:
+		TRIM_OFF_LEN(offset, size, file_size);
+		do_zero_range(offset, size);
+		break;
+	case OP_CLOSEOPEN:
+		if (closeopen)
+			docloseopen();
+		break;
+	default:
+		prterr("test: unknown operation");
+		report_failure(42);
+		break;
 	}
+
+out:
 	if (sizechecks && testcalls > simulatedopcount)
 		check_size();
-	if (closeprob && (rv >> 3) < (1 << 28) / closeprob)
-		docloseopen();
 }
 
+void
+segv(int sig)
+{
+	if (jmpbuf_good) {
+		jmpbuf_good = 0;
+		longjmp(jmpbuf, 1);
+	}
+	report_failure(9999);
+}
 
 void
 cleanup(sig)
@@ -1095,38 +1440,63 @@ cleanup(sig)
 void
 usage(void)
 {
-	fprintf(stdout, "usage: %s",
-		"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] "
-"[ -I random|rotate ] fname [additional paths to fname..]\n"
-"	-b opnum: beginning operation number (default 1)\n"
-"	-c P: 1 in P chance of file close+open at each op (default infinity)\n"
-"	-d: debug output for all operations [-d -d = more debugging]\n"
-"	-l flen: the upper bound on file size (default 262144)\n"
-"	-m startop:endop: monitor (print debug output) specified byte rang"
-"(default 0:infinity)\n"
-"	-n: no verifications of file size\n"
-"	-o oplen: the upper bound on operation size (default 65536)\n"
-"	-p progressinterval: debug output at specified operation interval\n"
-"	-q: quieter operation\n"
-"	-r readbdy: 4096 would make reads page aligned (default 1)\n"
-"	-s style: 1 gives smaller truncates (default 0)\n"
-"	-t truncbdy: 4096 would make truncates page aligned (default 1)\n"
-"	-w writebdy: 4096 would make writes page aligned (default 1)\n"
+	fprintf(stdout, "usage: "
+		"fsx [-dfnqFLOW] [-b opnum] [-c Prob] [-l flen] [-m start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t truncbdy] [-w writebdy] [-D startingop] [ -I random|rotate ] [-N numops] [-P dirpath] [-S seed] [-Z [prob]] fname [additional paths to fname..]\n\
+	-b opnum: beginning operation number (default 1)\n\
+	-c P: 1 in P chance of file close+open at each op (default infinity)\n\
+	-d: debug output for all operations [-d -d = more debugging]\n\
+	-f flush and invalidate cache after I/O\n"
+/* OSX: -d duration: number of hours for the tool to run\n\ */
+/* OSX: -e: tests using an extended attribute rather than a file\n\ */
+/* OSX: -f forkname: test the named fork of fname\n\ */
+/* OSX: -g logpath: path for .fsxlog file\n\ */
+/* OSX: -h: write 0s instead of creating holes (i.e. sparse file)\n\ */
+/* OSX: -i: interactive mode, hit return before performing each operation\n\ */
+"	-l flen: the upper bound on file size (default 262144)\n\
+	-m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\
+	-n: no verifications of file size\n\
+	-o oplen: the upper bound on operation size (default 65536)\n\
+	-p progressinterval: debug output at specified operation interval\n\
+	-q: quieter operation\n\
+	-r readbdy: %1$u would make reads page aligned (default 1)\n\
+	-s style: 1 gives smaller truncates (default 0)\n\
+	-t truncbdy: %1$u would make truncates page aligned (default 1)\n\
+	-w writebdy: %1$u would make writes page aligned (default 1)\n"
+/* XFS: -x: preallocate file space before starting, XFS only (default 0)\n\ */
+"	-y synchronize changes to a file\n"
+/* OSX: -v: debug output for all operations\n\ */
+/* XFS: -A: Use the AIO system calls\n" */
+/* OSX: -C mix cached and un-cached read/write ops\n\ */
 "	-D startingop: debug output starting at specified operation\n"
-"	-L: fsxLite - no file creations & no file size changes\n"
-"	-N numops: total # operations to do (default infinity)\n"
-"	-O: use oplen (see -o flag) for every op (default random)\n"
-"	-P: save .fsxlog and .fsxgood files in dirpath (default ./)\n"
-"	-S seed: for random # generator (default 1) 0 gets timestamp\n"
+#ifdef HAVE_LINUX_FALLOC_H
+"	-F: Do not use fallocate (preallocation) calls\n"
+#endif
+/* OSX: -G logsize: #entries in oplog (default 1024)\n\ */
+#ifdef FALLOC_FL_PUNCH_HOLE
+"	-H: Do not use punch hole calls\n"
+#endif
+#ifdef FALLOC_FL_ZERO_RANGE
+"	-z: Do not use zero range calls\n"
+#endif
+/* XFS: -C: Do not use collapse range calls\n\ */
+"	-I [rotate|random]: When multiple paths to the file are given,\n\
+	    each operation uses a different path.  Iterate through them in\n\
+	    order with 'rotate' or chose them at 'random'.  (default random)\n\
+	-L: fsxLite - no file creations & no file size changes\n"
+/* OSX: -I: start interactive mode since operation opnum\n\ */
+/* OSX: -M: slow motion mode, wait 1 second before each op\n\ */
+"	-N numops: total # operations to do (default infinity)\n\
+	-O: use oplen (see -o flag) for every op (default random)\n\
+	-P: save .fsxlog and .fsxgood files in dirpath (default ./)\n\
+	-R: read() system calls only (mapped reads disabled)\n\
+	-S seed: for random # generator (default 1) 0 gets timestamp\n"
+/* OSX: -T datasize: atomic data element write size [1,2,4] (default 4)\n\ */
 "	-W: mapped write operations DISabled\n"
-"	-R: read() system calls only (mapped reads disabled)\n"
-"	-Z: O_DIRECT (use -R, -W, -r and -w too)\n"
-"	-I: When multiple paths to the file are given each operation uses\n"
-"	    a different path.  Iterate through them in order with 'rotate'\n"
-"	    or chose then at 'random'.  (defaults to random)\n"
-"	fname: this filename is REQUIRED (no default)\n");
+#ifdef O_DIRECT
+"	-Z[P]: O_DIRECT file IO [1 in P chance for each open] (default off)\n"
+#endif
+"	fname: this filename is REQUIRED (no default)\n",
+	page_size);
 	exit(90);
 }
 
@@ -1165,6 +1535,27 @@ getnum(char *s, char **e)
 }
 
 int
+test_fallocate(int mode)
+{
+	int ret = 0;
+#ifdef HAVE_LINUX_FALLOC_H
+	int fd = get_fd();
+
+	if (!lite) {
+		if (fallocate(fd, mode, 0, 1) && errno == EOPNOTSUPP) {
+			if(!quiet)
+				warn("main: filesystem does not support "
+				     "fallocate mode 0x%x, disabling!\n", mode);
+		} else {
+			ret = 1;
+			ftruncate(fd, 0);
+		}
+	}
+#endif
+	return ret;
+}
+
+int
 main(int argc, char **argv)
 {
 	int	i, style, ch;
@@ -1180,14 +1571,13 @@ main(int argc, char **argv)
 	setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */
 
 	while ((ch = getopt(argc, argv,
-				"b:c:dl:m:no:p:qr:s:t:w:D:I:LN:OP:RS:WZ"))
+			    "b:c:dfl:m:no:p:qr:s:t:w:xyD:FHI:LN:OP:RS:WZ::"))
 	       != EOF)
 		switch (ch) {
 		case 'b':
 			simulatedopcount = getnum(optarg, &endp);
 			if (!quiet)
-				fprintf(stdout, "Will begin at operation"
-					"%ld\n",
+				fprintf(stdout, "Will begin at operation %ld\n",
 					simulatedopcount);
 			if (simulatedopcount == 0)
 				usage();
@@ -1205,6 +1595,9 @@ main(int argc, char **argv)
 		case 'd':
 			debug++;
 			break;
+		case 'f':
+			flush = 1;
+			break;
 		case 'l':
 			maxfilelen = getnum(optarg, &endp);
 			if (maxfilelen <= 0)
@@ -1232,7 +1625,7 @@ main(int argc, char **argv)
 			break;
 		case 'p':
 			progressinterval = getnum(optarg, &endp);
-			if (progressinterval < 0)
+			if (progressinterval <= 0)
 				usage();
 			break;
 		case 'q':
@@ -1258,11 +1651,23 @@ main(int argc, char **argv)
 			if (writebdy <= 0)
 				usage();
 			break;
+		case 'y':
+			do_fsync = 1;
+			break;
 		case 'D':
 			debugstart = getnum(optarg, &endp);
 			if (debugstart < 1)
 				usage();
 			break;
+		case 'F':
+			fallocate_calls = 0;
+			break;
+		case 'H':
+			punch_hole_calls = 0;
+			break;
+		case 'z':
+			zero_range_calls = 0;
+			break;
 		case 'I':
 			assign_fd_policy(optarg);
 			break;
@@ -1302,9 +1707,12 @@ main(int argc, char **argv)
 				fprintf(stdout, "mapped writes DISABLED\n");
 			break;
 		case 'Z':
-			o_direct = O_DIRECT;
+#ifdef O_DIRECT
+			if (optarg == NULL ||
+			    (o_direct = getnum(optarg, &endp)) == 0)
+				o_direct = 1;
+#endif
 			break;
-
 		default:
 			usage();
 			/* NOTREACHED */
@@ -1325,6 +1733,8 @@ main(int argc, char **argv)
 	signal(SIGVTALRM,	cleanup);
 	signal(SIGUSR1,	cleanup);
 	signal(SIGUSR2,	cleanup);
+	signal(SIGBUS,	segv);
+	signal(SIGSEGV,	segv);
 
 	initstate(seed, state, 256);
 	setstate(state);
@@ -1362,6 +1772,8 @@ main(int argc, char **argv)
 		}
 	}
 	original_buf = (char *) malloc(maxfilelen);
+	if (original_buf == NULL)
+		exit(96);
 	for (i = 0; i < maxfilelen; i++)
 		original_buf[i] = random() % 256;
 	if (o_direct) {
@@ -1405,19 +1817,30 @@ main(int argc, char **argv)
 				warn("main: error on write");
 			} else
 				warn("main: short write, 0x%x bytes instead"
-					"of 0x%x\n",
+					"of 0x%lx\n",
 				     (unsigned)written, maxfilelen);
 			exit(98);
 		}
-	} else
+	} else 
 		check_trunc_hack();
 
+	if (fallocate_calls)
+		fallocate_calls = test_fallocate(0);
+	if (punch_hole_calls)
+		punch_hole_calls = test_fallocate(FALLOC_FL_PUNCH_HOLE |
+						  FALLOC_FL_KEEP_SIZE);
+	if (zero_range_calls)
+		zero_range_calls = test_fallocate(FALLOC_FL_ZERO_RANGE);
+
 	while (numops == -1 || numops--)
 		test();
 
 	close_test_files();
 	prt("All operations completed A-OK!\n");
 
-	exit(0);
+	free(original_buf);
+	free(good_buf);
+	free(temp_buf);
+
 	return 0;
 }
