[PATCH 3/3] xfsqa: Add fiemap exerciser

Dave Chinner david at fromorbit.com
Wed Mar 3 00:19:22 CST 2010


From: Eric Sandeen <sandeen at redhat.com>

Preliminary fiemap testing support based on a test util written by
Josef Bacik.

For now it's only run with preallocation disabled, because xfs has a
tendency to fill in holes with data blocks (EOF prealloc stuff I
think) and similar for explicit preallocation, so this is breaking
the preallocation tests for now, when it finds a "data" block where
it expects a preallocated block.

Signed-off-by: Eric Sandeen <sandeen at redhat.com>
Reviewed-by: Dave Chinner <dchinner at redhat.com>
---
 225                  |   62 +++++
 225.out              |    2 +
 aclocal.m4           |   19 ++
 configure.in         |    2 +
 group                |    1 +
 include/builddefs.in |    2 +
 src/Makefile         |    8 +
 src/fiemap-tester.c  |  638 ++++++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 734 insertions(+), 0 deletions(-)
 create mode 100644 225
 create mode 100644 225.out
 create mode 100644 src/fiemap-tester.c

diff --git a/225 b/225
new file mode 100644
index 0000000..673e93e
--- /dev/null
+++ b/225
@@ -0,0 +1,62 @@
+#! /bin/sh
+# FS QA Test No. 225
+#
+# Run the fiemap (file extent mapping) tester
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2009 Eric Sandeen.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#-----------------------------------------------------------------------
+#
+# creator
+owner=sandeen at sandeen.net
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=tmp/$$
+status=1  # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+	_cleanup_testdir
+}
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+# real QA test starts here
+_supported_fs generic
+_supported_os Linux
+
+_setup_testdir
+
+fiemapfile=$TEST_DIR/fiemap.$$
+
+[ -x $here/src/fiemap-tester ] || _notrun "fiemap-tester not built"
+
+echo "fiemap run without preallocation"
+$here/src/fiemap-tester -q -p 0 -r 200 /mnt/test/fiemapfile
+
+rm -f $fiemapfile
+rm -f $seq.full
+
+status=0
+exit
diff --git a/225.out b/225.out
new file mode 100644
index 0000000..7bc9312
--- /dev/null
+++ b/225.out
@@ -0,0 +1,2 @@
+QA output created by 225
+fiemap run without preallocation
diff --git a/aclocal.m4 b/aclocal.m4
index 02f56f2..6457d39 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -11,6 +11,25 @@
 # even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 # PARTICULAR PURPOSE.
 
+AC_DEFUN([AC_PACKAGE_WANT_LINUX_FIEMAP_H],
+  [ AC_CHECK_HEADERS([linux/fiemap.h], [ have_fiemap=true ], [ have_fiemap=false ])
+    AC_SUBST(have_fiemap)
+  ])
+
+AC_DEFUN([AC_PACKAGE_WANT_FALLOCATE],
+  [ AC_MSG_CHECKING([for fallocate])
+    AC_TRY_LINK([
+#define _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+#include <fcntl.h>
+#include <linux/falloc.h>
+    ], [
+         fallocate(0, 0, 0, 0);
+    ], have_fallocate=yes
+       AC_MSG_RESULT(yes),
+       AC_MSG_RESULT(no))
+    AC_SUBST(have_fallocate)
+  ])
 m4_include([m4/multilib.m4])
 m4_include([m4/package_acldev.m4])
 m4_include([m4/package_aiodev.m4])
diff --git a/configure.in b/configure.in
index 0d6f153..45b7fd1 100644
--- a/configure.in
+++ b/configure.in
@@ -64,6 +64,8 @@ in
 		AC_PACKAGE_WANT_GDBM
 		AC_PACKAGE_WANT_AIO
 		AC_PACKAGE_WANT_DMAPI
+		AC_PACKAGE_WANT_LINUX_FIEMAP_H
+		AC_PACKAGE_WANT_FALLOCATE
 		;;
 esac
 
diff --git a/group b/group
index 5d675f0..8d4a83a 100644
--- a/group
+++ b/group
@@ -338,3 +338,4 @@ deprecated
 222 auto fsr ioctl quick
 223 auto quick
 224 auto
+225 auto quick
diff --git a/include/builddefs.in b/include/builddefs.in
index 23a4991..3bea050 100644
--- a/include/builddefs.in
+++ b/include/builddefs.in
@@ -60,6 +60,8 @@ HAVE_DB = @have_db@
 HAVE_AIO = @have_aio@
 HAVE_DMAPI = @have_dmapi@
 HAVE_ATTR_LIST = @have_attr_list@
+HAVE_FIEMAP = @have_fiemap@
+HAVE_FALLOCATE = @have_fallocate@
 
 GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
 
diff --git a/src/Makefile b/src/Makefile
index d86d50a..2f95fe2 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -25,6 +25,14 @@ ifeq ($(HAVE_XLOG_ASSIGN_LSN), true)
 LINUX_TARGETS += loggen
 endif
 
+ifeq ($(HAVE_FIEMAP), true)
+LINUX_TARGETS += fiemap-tester
+endif
+
+ifeq ($(HAVE_FALLOCATE),yes)
+LCFLAGS += -DHAVE_FALLOCATE
+endif
+
 IRIX_TARGETS = open_unlink
 
 ifeq ($(PKG_PLATFORM),linux)
diff --git a/src/fiemap-tester.c b/src/fiemap-tester.c
new file mode 100644
index 0000000..69016a9
--- /dev/null
+++ b/src/fiemap-tester.c
@@ -0,0 +1,638 @@
+/*
+ * Copyright (c) 2009 Josef Bacik
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/fiemap.h>
+
+/* Global for non-critical message suppression */
+int quiet;
+
+static void
+usage(void)
+{
+	printf("Usage: fiemap-tester [-m map] [-r number of runs] [-s seed] [-q]");
+#ifdef HAVE_FALLOCATE
+	printf("[-p preallocate (1/0)] ");
+#endif
+	printf("filename\n");
+	printf("  -m map    : generate a file with the map given and test\n");
+#ifdef HAVE_FALLOCATE
+	printf("  -p 0/1    : turn block preallocation on or off\n");
+#endif
+	printf("  -r count  : number of runs to execute (default infinity)\n");
+	printf("  -s seed   : seed for random map generator (default 1)\n");
+	printf("  -q        : be quiet about non-errors\n");
+	printf("-m and -r cannot be used together\n");
+	exit(EXIT_FAILURE);
+}
+
+static char *
+generate_file_mapping(int blocks, int prealloc)
+{
+	char *map;
+	int num_types = 2, cur_block = 0;
+	int i = 0;
+
+	map = malloc(sizeof(char) * blocks);
+	if (!map)
+		return NULL;
+
+	if (prealloc)
+		num_types++;
+
+
+	for (i = 0; i < blocks; i++) {
+		long num = random() % num_types;
+		switch (num) {
+		case 0:
+			map[cur_block] = 'D';
+			break;
+		case 1:
+			map[cur_block] = 'H';
+			break;
+		case 2:
+			map[cur_block] = 'P';
+			break;
+		}
+		cur_block++;
+	}
+
+	return map;
+}
+
+static int
+create_file_from_mapping(int fd, char *map, int blocks, int blocksize)
+{
+	int cur_offset = 0, ret = 0, bufsize;
+	char *buf;
+	int i = 0;
+
+	bufsize = sizeof(char) * blocksize;
+	buf = malloc(bufsize);
+	if (!buf)
+		return -1;
+
+	memset(buf, 'a', bufsize);
+
+	for (i = 0; i < blocks; i++) {
+		switch (map[i]) {
+		case 'D':
+			ret = write(fd, buf, bufsize);
+			if (ret < bufsize) {
+				printf("Short write\n");
+				ret = -1;
+				goto out;
+			}
+			break;
+#ifdef HAVE_FALLOCATE
+		case 'P':
+			ret = fallocate(fd, 0, cur_offset, blocksize);
+			if (ret < 0) {
+				printf("Error fallocating\n");
+				goto out;
+			}
+			/* fallthrough; seek to end of prealloc space */
+#endif
+		case 'H':
+			ret = lseek(fd, blocksize, SEEK_CUR);
+			if (ret == (off_t)-1) {
+				printf("Error lseeking\n");
+				ret = -1;
+				goto out;
+			}
+			break;
+		default:
+			printf("Hrm, unrecognized flag in map\n");
+			ret = -1;
+			goto out;
+		}
+		cur_offset += blocksize;
+	}
+
+	ret = 0;
+out:
+	return ret;
+}
+
+static void
+show_extent_block(struct fiemap_extent *extent, int blocksize)
+{
+	__u64	logical = extent->fe_logical;
+	__u64	phys = extent->fe_physical;
+	__u64	length = extent->fe_length;
+	int	flags = extent->fe_flags;
+
+	printf("logical: [%8llu..%8llu] phys: %8llu..%8llu "
+	       "flags: 0x%03X tot: %llu\n",
+		logical / blocksize, (logical + length - 1) / blocksize,
+		phys / blocksize, (phys + length - 1) / blocksize,
+		flags,
+		(length / blocksize));
+}
+
+static void
+show_extents(struct fiemap *fiemap, int blocksize)
+{
+	unsigned int i;
+
+	for (i = 0; i < fiemap->fm_mapped_extents; i++)
+		show_extent_block(&fiemap->fm_extents[i], blocksize);
+}
+
+static int
+check_flags(struct fiemap *fiemap, int blocksize)
+{
+	struct fiemap_extent *extent;
+	__u64 aligned_offset, aligned_length;
+	int c;
+
+	for (c = 0; c < fiemap->fm_mapped_extents; c++) {
+		extent = &fiemap->fm_extents[c];
+
+		aligned_offset = extent->fe_physical & ~((__u64)blocksize - 1);
+		aligned_length = extent->fe_length & ~((__u64)blocksize - 1);
+
+		if ((aligned_offset != extent->fe_physical ||
+		     aligned_length != extent->fe_length) &&
+		    !(extent->fe_flags & FIEMAP_EXTENT_NOT_ALIGNED)) {
+			printf("ERROR: FIEMAP_EXTENT_NOT_ALIGNED is not set "
+			       "but the extent is unaligned: %llu\n",
+			       (unsigned long long)
+			       (extent->fe_logical / blocksize));
+			return -1;
+		}
+
+		if (extent->fe_flags & FIEMAP_EXTENT_DATA_ENCRYPTED &&
+		    !(extent->fe_flags & FIEMAP_EXTENT_ENCODED)) {
+			printf("ERROR: FIEMAP_EXTENT_DATA_ENCRYPTED is set, "
+			       "but FIEMAP_EXTENT_ENCODED is not set: %llu\n",
+			       (unsigned long long)
+			       (extent->fe_logical / blocksize));
+			return -1;
+		}
+
+		if (extent->fe_flags & FIEMAP_EXTENT_NOT_ALIGNED &&
+		    aligned_offset == extent->fe_physical &&
+		    aligned_length == extent->fe_length) {
+			printf("ERROR: FIEMAP_EXTENT_NOT_ALIGNED is set but "
+			       "offset and length is blocksize aligned: "
+			       "%llu\n",
+			       (unsigned long long)
+			       (extent->fe_logical / blocksize));
+			return -1;
+		}
+
+		if (extent->fe_flags & FIEMAP_EXTENT_LAST &&
+		    c + 1 < fiemap->fm_mapped_extents) {
+			printf("ERROR: FIEMAP_EXTENT_LAST is set but there are"
+			       " more extents left: %llu\n",
+			       (unsigned long long)
+			       (extent->fe_logical / blocksize));
+			return -1;
+		}
+
+		if (extent->fe_flags & FIEMAP_EXTENT_DELALLOC &&
+		    !(extent->fe_flags & FIEMAP_EXTENT_UNKNOWN)) {
+			printf("ERROR: FIEMAP_EXTENT_DELALLOC is set but "
+			       "FIEMAP_EXTENT_UNKNOWN is not set: %llu\n",
+			       (unsigned long long)
+			       (extent->fe_logical / blocksize));
+			return -1;
+		}
+
+		if (extent->fe_flags & FIEMAP_EXTENT_DATA_INLINE &&
+		    !(extent->fe_flags & FIEMAP_EXTENT_NOT_ALIGNED)) {
+			printf("ERROR: FIEMAP_EXTENT_DATA_INLINE is set but "
+			       "FIEMAP_EXTENT_NOT_ALIGNED is not set: %llu\n",
+			       (unsigned long long)
+			       (extent->fe_logical / blocksize));
+			return -1;
+		}
+
+		if (extent->fe_flags & FIEMAP_EXTENT_DATA_TAIL &&
+		    !(extent->fe_flags & FIEMAP_EXTENT_NOT_ALIGNED)) {
+			printf("ERROR: FIEMAP_EXTENT_DATA_TAIL is set but "
+			       "FIEMAP_EXTENT_NOT_ALIGNED is not set: %llu\n",
+			       (unsigned long long)
+			       (extent->fe_logical / blocksize));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int
+check_data(struct fiemap *fiemap, __u64 logical_offset, int blocksize,
+	   int last, int prealloc)
+{
+	struct fiemap_extent *extent;
+	__u64 orig_offset = logical_offset;
+	int c, found = 0;
+
+	for (c = 0; c < fiemap->fm_mapped_extents; c++) {
+		__u64 start, end;
+		extent = &fiemap->fm_extents[c];
+
+		start = extent->fe_logical;
+		end = extent->fe_logical + extent->fe_length;
+
+		if (logical_offset > end)
+			continue;
+
+		if (logical_offset + blocksize < start)
+			break;
+
+		if (logical_offset >= start &&
+		    logical_offset < end) {
+			if (prealloc &&
+			    !(extent->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {
+				printf("ERROR: preallocated extent is not "
+				       "marked with FIEMAP_EXTENT_UNWRITTEN: "
+				       "%llu\n",
+				       (unsigned long long)
+				       (start / blocksize));
+				return -1;
+			}
+
+			if (logical_offset + blocksize > end) {
+				logical_offset = end+1;
+				continue;
+			} else {
+				found = 1;
+				break;
+			}
+		}
+	}
+
+	if (!found) {
+		printf("ERROR: couldn't find extent at %llu\n",
+		       (unsigned long long)(orig_offset / blocksize));
+	} else if (last &&
+		   !(fiemap->fm_extents[c].fe_flags & FIEMAP_EXTENT_LAST)) {
+		printf("ERROR: last extent not marked as last: %llu\n",
+		       (unsigned long long)(orig_offset / blocksize));
+		found = 0;
+	}
+
+	return (!found) ? -1 : 0;
+}
+
+static int
+check_weird_fs_hole(int fd, __u64 logical_offset, int blocksize)
+{
+	static int warning_printed = 0;
+	int block, i;
+	size_t buf_len = sizeof(char) * blocksize;
+	char *buf;
+
+	block = (int)(logical_offset / blocksize);
+	if (ioctl(fd, FIBMAP, &block) < 0) {
+		perror("Can't fibmap file");
+		return -1;
+	}
+
+	if (!block) {
+		printf("ERROR: FIEMAP claimed there was data at a block "
+		       "which should be a hole, and FIBMAP confirmend that "
+		       "it is in fact a hole, so FIEMAP is wrong: %llu\n",
+		       (unsigned long long)(logical_offset / blocksize));
+		return -1;
+	}
+
+	buf = malloc(buf_len);
+	if (!buf) {
+		perror("Could not allocate temporary buffer");
+		return -1;
+	}
+
+	if (pread(fd, buf, buf_len, (off_t)logical_offset) < 0) {
+		perror("Error reading from file");
+		free(buf);
+		return -1;
+	}
+
+	for (i = 0; i < buf_len; i++) {
+		if (buf[i] != 0) {
+			printf("ERROR: FIEMAP claimed there was data (%c) at "
+			       "block %llu that should have been a hole, and "
+			       "FIBMAP confirmed that it was allocated, but "
+			       "it should be filled with 0's, but it was not "
+			       "so you have a big problem!\n",
+			       buf[i],
+			       (unsigned long long)(logical_offset / blocksize));
+			free(buf);
+			return -1;
+		}
+	}
+
+	if (warning_printed || quiet) {
+		free(buf);
+		return 0;
+	}
+
+	printf("HEY FS PERSON: your fs is weird.  I specifically wanted a\n"
+	       "hole and you allocated a block anyway.  FIBMAP confirms that\n"
+	       "you allocated a block, and the block is filled with 0's so\n"
+	       "everything is kosher, but you still allocated a block when\n"
+	       "didn't need to.  This may or may not be what you wanted,\n"
+	       "which is why I'm only printing this message once, in case\n"
+	       "you didn't do it on purpose. This was at block %llu.\n",
+	       (unsigned long long)(logical_offset / blocksize));
+	warning_printed = 1;
+	free(buf);
+
+	return 0;
+}
+
+static int
+check_hole(struct fiemap *fiemap, int fd, __u64 logical_offset, int blocksize)
+{
+	struct fiemap_extent *extent;
+	int c;
+
+	for (c = 0; c < fiemap->fm_mapped_extents; c++) {
+		__u64 start, end;
+		extent = &fiemap->fm_extents[c];
+
+		start = extent->fe_logical;
+		end = extent->fe_logical + extent->fe_length;
+
+		if (logical_offset > end)
+			continue;
+		if (logical_offset + blocksize < start)
+			break;
+
+		if (logical_offset >= start &&
+		    logical_offset < end) {
+
+			if (check_weird_fs_hole(fd, logical_offset,
+						blocksize) == 0)
+				break;
+
+			printf("ERROR: found an allocated extent where a hole "
+			       "should be: %llu\n",
+			       (unsigned long long)(start / blocksize));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int
+compare_fiemap_and_map(int fd, char *map, int blocks, int blocksize)
+{
+	struct fiemap *fiemap;
+	char *fiebuf;
+	int blocks_to_map, ret, cur_extent = 0, last_data;
+	__u64 map_start, map_length;
+	int i, c;
+
+	blocks_to_map = (random() % blocks) + 1;
+	fiebuf = malloc(sizeof(struct fiemap) +
+			(blocks_to_map * sizeof(struct fiemap_extent)));
+	if (!fiebuf) {
+		perror("Could not allocate fiemap buffers");
+		return -1;
+	}
+
+	fiemap = (struct fiemap *)fiebuf;
+	map_start = 0;
+	map_length = blocks_to_map * blocksize;
+
+	for (i = 0; i < blocks; i++) {
+		if (map[i] != 'H')
+			last_data = i;
+	}
+
+	fiemap->fm_flags = FIEMAP_FLAG_SYNC;
+	fiemap->fm_extent_count = blocks_to_map;
+	fiemap->fm_mapped_extents = 0;
+
+	do {
+		fiemap->fm_start = map_start;
+		fiemap->fm_length = map_length;
+
+		ret = ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
+		if (ret < 0) {
+			perror("FIEMAP ioctl failed");
+			free(fiemap);
+			return -1;
+		}
+
+		if (check_flags(fiemap, blocksize))
+			goto error;
+
+		for (i = cur_extent, c = 1; i < blocks; i++, c++) {
+			__u64 logical_offset = i * blocksize;
+
+			if (c > blocks_to_map)
+				break;
+
+			switch (map[i]) {
+			case 'D':
+				if (check_data(fiemap, logical_offset,
+					       blocksize, last_data == i, 0))
+					goto error;
+				break;
+			case 'H':
+				if (check_hole(fiemap, fd, logical_offset,
+					       blocksize))
+					goto error;
+				break;
+			case 'P':
+				if (check_data(fiemap, logical_offset,
+					       blocksize, last_data == i, 1))
+					goto error;
+				break;
+			default:
+				printf("ERROR: weird value in map: %c\n",
+				       map[i]);
+				goto error;
+			}
+		}
+		cur_extent = i;
+		map_start = i * blocksize;
+	} while (cur_extent < blocks);
+
+	ret = 0;
+	return ret;
+error:
+	printf("map is '%s'\n", map);
+	show_extents(fiemap, blocksize);
+	return -1;
+}
+
+int
+main(int argc, char **argv)
+{
+	int	blocksize = 0;	/* filesystem blocksize */
+	int	fd;		/* file descriptor */
+	int	opt;
+	int	rc;
+	char	*fname;		/* filename to map */
+	char	*map = NULL;	/* file map to generate */
+	int	runs = -1;	/* the number of runs to have */
+	int	blocks = 0;	/* the number of blocks to generate */
+	int	maxblocks = 0;	/* max # of blocks to create */
+	int	prealloc = 1;	/* whether or not to do preallocation */
+	int	seed = 1;
+
+	while ((opt = getopt(argc, argv, "m:r:s:p:q")) != -1) {
+		switch(opt) {
+		case 'm':
+			map = strdup(optarg);
+			break;
+		case 'p':
+			prealloc = atoi(optarg);;
+#ifndef HAVE_FALLOCATE
+			if (prealloc)
+				printf("Not built with preallocation support\n");
+			usage();
+#endif
+			break;
+		case 'q':
+			quiet = 1;
+			break;
+		/* sync file before mapping */
+		case 'r':
+			runs = atoi(optarg);
+			break;
+		case 's':
+			seed = atoi(optarg);
+			break;
+		default:
+			usage();
+		}
+	}
+
+	if (runs != -1 && map)
+		usage();
+
+	fname = argv[optind++];
+	if (!fname)
+		usage();
+
+	fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0644);
+	if (fd < 0) {
+		perror("Can't open file");
+		exit(1);
+	}
+
+	if (ioctl(fd, FIGETBSZ, &blocksize) < 0) {
+		perror("Can't get filesystem block size");
+		close(fd);
+		exit(1);
+	}
+
+#ifdef HAVE_FALLOCATE
+	/* if fallocate passes, then we can do preallocation, else not */
+	if (prealloc) {
+		prealloc = !((int)fallocate(fd, 0, 0, blocksize));
+		if (!prealloc)
+			printf("preallocation not supported, disabling\n");
+	}
+#else
+	prealloc = 0;
+#endif
+
+	if (ftruncate(fd, 0)) {
+		perror("Can't truncate file");
+		close(fd);
+		exit(1);
+	}
+
+	if (map) {
+		blocks = strlen(map);
+		runs = 0;
+	}
+
+	srandom(seed);
+
+	/* max file size 2mb / block size */
+	maxblocks = (2 * 1024 * 1024) / blocksize;
+
+	if (runs == -1)
+		printf("Starting infinite run, if you don't see any output "
+		       "then its working properly.\n");
+	do {
+		if (!map) {
+			blocks = random() % maxblocks;
+			if (blocks == 0) {
+				if (!quiet)
+					printf("Skipping 0 length file\n");
+				continue;
+			}
+
+			map = generate_file_mapping(blocks, prealloc);
+			if (!map) {
+				printf("Could not create map\n");
+				exit(1);
+			}
+		}
+
+		rc = create_file_from_mapping(fd, map, blocks, blocksize);
+		if (rc) {
+			perror("Could not create file\n");
+			free(map);
+			close(fd);
+			exit(1);
+		}
+
+		rc = compare_fiemap_and_map(fd, map, blocks, blocksize);
+		if (rc) {
+			printf("Problem comparing fiemap and map\n");
+			free(map);
+			close(fd);
+			exit(1);
+		}
+
+		free(map);
+		map = NULL;
+
+		if (ftruncate(fd, 0)) {
+			perror("Could not truncate file\n");
+			close(fd);
+			exit(1);
+		}
+
+		if (lseek(fd, 0, SEEK_SET)) {
+			perror("Could not seek set\n");
+			close(fd);
+			exit(1);
+		}
+
+		if (runs) runs--;
+	} while (runs != 0);
+
+	close(fd);
+
+	return 0;
+}
-- 
1.6.5




More information about the xfs mailing list