[Ocfs2-test-devel] [PATCH 1/1] Ocfs2-test: Add destructive testcase for reflink_test v1.

Tristan Ye tristan.ye at oracle.com
Mon Nov 2 03:15:47 PST 2009


Per sunil's request, we're going to add a destructive testcase for reflink
to expose an expected issue in existing reflink kernel codes: O_DIRECT writes
will not flush the metadata accordingly when being performed on reflinked files
after the completion of write operation, which means a reflinked file may wrongly
points to an old reflinked extent after a unexpectedly crash of machine.

The v1 testcase is really a quick&dirty one, but it did reveal the problem we
mentioned above. after doing reflinks, we fork procs to perform random writes
on a reflinked file, and each write is going to be logged accordingly via wire
to a remote listener server. then crash the machine somehow, afterwards, the
logfile recorded by listener will be used for verification.

I may file a bug on bugzilla to track the issue when tao get ready to change the
reflink kernel codes.

Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
---
 programs/reflink_tests/reflink_test.c       |  198 +++++++++++++++++-
 programs/reflink_tests/reflink_test.h       |   28 +++
 programs/reflink_tests/reflink_test_utils.c |  301 +++++++++++++++++++++++++++
 3 files changed, 522 insertions(+), 5 deletions(-)

diff --git a/programs/reflink_tests/reflink_test.c b/programs/reflink_tests/reflink_test.c
index 9370925..cf16424 100755
--- a/programs/reflink_tests/reflink_test.c
+++ b/programs/reflink_tests/reflink_test.c
@@ -50,8 +50,13 @@ static char ref_path[PATH_MAX];
 static char fh_log_orig[PATH_MAX];
 static char fh_log_dest[PATH_MAX];
 
+static char dest_log_path[PATH_MAX];
+
+static char lsnr_addr[HOSTNAME_LEN];
+
 static int iteration = 1;
 static int testno = 1;
+static unsigned long port = 9999;
 
 static unsigned long ref_counts = 10;
 static unsigned long ref_trees = 10;
@@ -103,7 +108,7 @@ static void usage(void)
 	printf("Usage: reflink_tests [-i iteration] <-n ref_counts> "
 	       "<-p refcount_tree_pairs> <-l file_size> <-d disk> "
 	       "<-w workplace> -f -b [-c conc_procs] -m -s -r [-x xattr_nums]"
-	       " [-h holes_num] [-o holes_filling_log] -O -I\n\n"
+	       " [-h holes_num] [-o holes_filling_log] -O -D -I\n\n"
 	       "-f enable basic feature test.\n"
 	       "-b enable boundary test.\n"
 	       "-c enable concurrent tests with conc_procs processes.\n"
@@ -111,12 +116,16 @@ static void usage(void)
 	       "-r enable random test.\n"
 	       "-s enable stress test.\n"
 	       "-O enable O_DIRECT test.\n"
+	       "-D enable destructive test.\n"
+	       "-v enable verification for destructive test.\n"
 	       "-I enable inline-data test.\n"
 	       "-x enable combination test with xattr.\n"
 	       "-h enable holes punching and filling tests.\n"
 	       "-o specify logfile for holes filling tests,it takes effect"
 	       " when -h enabled.\n"
 	       "-p specify number of refcount trees in fs.\n"
+	       "-a specify listener's ip addr for destructive test.\n"
+	       "-P specify listener's listening port for destructive test.\n"
 	       "iteration specify the running times.\n"
 	       "ref_counts specify the reflinks number for one shared inode.\n"
 	       "refcount_tree_pairs specify the refcount tree numbers in fs.\n"
@@ -132,8 +141,8 @@ static int parse_opts(int argc, char **argv)
 
 	while (1) {
 		c = getopt(argc, argv,
-			   "i:d:w:IOfFbBsSrRmMW:n:N:"
-			   "l:L:c:C:p:P:x:X:h:H:o:");
+			   "i:d:w:IODfFbBsSrRmMW:n:N:"
+			   "l:L:c:C:p:x:X:h:H:o:v:a:P:");
 		if (c == -1)
 			break;
 
@@ -146,7 +155,6 @@ static int parse_opts(int argc, char **argv)
 			ref_counts = atol(optarg);
 			break;
 		case 'p':
-		case 'P':
 			ref_trees = atol(optarg);
 			break;
 		case 'l':
@@ -159,6 +167,9 @@ static int parse_opts(int argc, char **argv)
 		case 'O':
 			test_flags |= ODCT_TEST;
 			break;
+		case 'D':
+			test_flags |= DSCV_TEST;
+			break;
 		case 'I':
 			test_flags |= INLN_TEST;
 			xattr_nums = 100;
@@ -170,6 +181,13 @@ static int parse_opts(int argc, char **argv)
 		case 'o':
 			strcpy(fh_log_orig, optarg);
 			break;
+		case 'v':
+			strcpy(dest_log_path, optarg);
+			test_flags |= VERI_TEST;
+			break;
+		case 'a':
+			strcpy(lsnr_addr, optarg);
+			break;
 		case 'f':
 		case 'F':
 			test_flags |= BASC_TEST;
@@ -204,6 +222,8 @@ static int parse_opts(int argc, char **argv)
 		case 'H':
 			test_flags |= HOLE_TEST;
 			hole_nums = atol(optarg);
+		case 'P':
+			port = atol(optarg);
 		default:
 			break;
 		}
@@ -215,6 +235,10 @@ static int parse_opts(int argc, char **argv)
 	if (strcmp(device, "") == 0)
 		return EINVAL;
 
+	if (test_flags & DSCV_TEST)
+		if (strcmp(lsnr_addr, "") == 0)
+			return EINVAL;
+
 	return 0;
 }
 
@@ -890,7 +914,7 @@ static int concurrent_test()
 
 	signal(SIGCHLD, sigchld_handler);
 
-	 for (i = 0; i < child_nums; i++) {
+	for (i = 0; i < child_nums; i++) {
 
 		pid = fork();
 
@@ -1768,6 +1792,164 @@ static int holes_fill_test(void)
 	return 0;
 }
 
+static int destructive_test(void)
+{
+	int ret, o_flags_rw, o_flags_ro, sockfd, i, j, status, rc;
+	int sub_testno = 1;
+	char log_rec[100], dest[PATH_MAX];
+
+	struct dest_write_unit du;
+
+	unsigned long align_slice = CHUNK_SIZE;
+	unsigned long align_filesz = align_slice;
+	unsigned long chunk_no = 0;
+
+	pid_t pid;
+
+        while (align_filesz < file_size)
+                align_filesz += CHUNK_SIZE;
+
+	chunk_no = file_size / CHUNK_SIZE;
+
+	printf("Test %d: Destructive reflink test.\n", testno);
+
+	o_flags_rw = open_rw_flags;
+	o_flags_ro = open_ro_flags;
+
+	open_rw_flags |= O_DIRECT;
+	open_ro_flags |= O_DIRECT;
+
+	snprintf(orig_path, PATH_MAX, "%s/original_destructive_refile", workplace);
+
+	printf("  *SubTest %d: Prepare original file in %ld chunks.\n",
+	       sub_testno++, chunk_no);
+
+	ret = prep_orig_file_in_chunks(orig_path, chunk_no);
+	should_exit(ret);
+
+	printf("  *SubTest %d: Do reflinks to reflink the extents.\n",
+	       sub_testno++);
+
+	ret = do_reflinks(orig_path, orig_path, ref_counts, 0);
+	should_exit(ret);
+
+	/*flush out the father's i/o buffer*/
+	fflush(stderr);
+	fflush(stdout);
+
+	signal(SIGCHLD, sigchld_handler);
+
+	printf("  *SubTest %d: Init socket for msg sending\n", sub_testno++);
+
+	sockfd = init_sock(lsnr_addr, port);
+
+	printf("  *SubTest %d: Fork children to write in chunks.\n", sub_testno++);
+
+	for (i = 0; i < child_nums; i++) {
+
+		pid = fork();
+
+		if (pid < 0) {
+			fprintf(stderr, "Fork process error!\n");
+			return pid;
+		}
+
+		/* child to do CoW*/
+		if (pid == 0) {
+
+			srand(getpid());
+
+			for (j = 0; j < chunk_no; j++) {
+				prep_rand_dest_write_unit(&du, get_rand(0, chunk_no - 1));
+				ret = do_write_chunk_file(orig_path, &du);
+				if (ret)
+					return -1;
+			
+				memset(log_rec, 0, sizeof(log_rec));
+				snprintf(log_rec, sizeof(log_rec), "%lu\t%llu\t%c\n",
+					 du.d_chunk_no, du.d_timestamp, 
+					 du.d_char);
+				write(sockfd, log_rec, strlen(log_rec) + 1);
+
+				/*
+				if (get_rand(0, 1)) {
+					snprintf(dest, PATH_MAX,
+						 "%s_target_%d_%d",
+						 orig_path, getpid(), j);
+					ret = reflink(orig_path, dest, 1);
+					should_exit(ret);
+					memset(log_rec, 0, 100);
+					snprintf(log_rec, 100, "Reflinking:\t%s->%s\n",orig_path, dest);
+					write(sockfd, log_rec, 100);
+					
+				}
+				*/
+				usleep(100000);
+			}
+
+			exit(0);
+		}
+
+		if (pid > 0)
+			child_pid_list[i] = pid;
+
+	}
+
+	usleep(100000 * 2);
+
+	/*
+	 * Are you ready to crash the box?
+	*/
+	system("echo b>/proc/sysrq-trigger");
+
+	signal(SIGINT, sigint_handler);
+	signal(SIGTERM, sigterm_handler);
+
+	/*father wait all children to leave*/
+	for (i = 0; i < child_nums; i++) {
+		ret = waitpid(child_pid_list[i], &status, 0);
+		rc = WEXITSTATUS(status);
+		if (rc) {
+			fprintf(stderr, "Child %d exits abnormally with "
+				"RC=%d\n", child_pid_list[i], rc);
+		}
+	}
+
+	open_rw_flags = o_flags_rw;
+        open_ro_flags = o_flags_ro;
+
+	//ret = do_unlinks(orig_path, ref_counts);
+	//should_exit(ret);
+
+	//ret = do_unlink(orig_path);
+	//should_exit(ret);
+
+	close(sockfd);
+
+	return 0;
+}
+
+static int verification_dest(void)
+{
+
+	unsigned long align_slice = CHUNK_SIZE;
+	unsigned long align_filesz = align_slice;
+	unsigned long chunk_no = 0;
+
+        while (align_filesz < file_size)
+                align_filesz += CHUNK_SIZE;
+
+	chunk_no = file_size / CHUNK_SIZE;
+
+	printf("Test %d: Verification for destructive test.\n", testno);
+
+	snprintf(orig_path, PATH_MAX, "%s/original_destructive_refile", workplace);
+
+	verify_dest_files(dest_log_path, orig_path, chunk_no);
+
+	return 0;
+}
+
 static int directio_test(void)
 {
 
@@ -2005,6 +2187,12 @@ static void run_test(void)
 		if (test_flags & INLN_TEST)
 			inline_test();
 
+		if (test_flags & DSCV_TEST)
+			destructive_test();
+
+		if (test_flags & VERI_TEST)
+			verification_dest();
+
 	}
 }
 
diff --git a/programs/reflink_tests/reflink_test.h b/programs/reflink_tests/reflink_test.h
index 3f7b263..2179207 100755
--- a/programs/reflink_tests/reflink_test.h
+++ b/programs/reflink_tests/reflink_test.h
@@ -33,6 +33,7 @@
 #include <sys/ioctl.h>
 #include <inttypes.h>
 #include <linux/types.h>
+#include <sys/time.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -40,6 +41,11 @@
 #include <assert.h>
 #include <getopt.h>
 
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
 #include <ocfs2/ocfs2.h>
 
 #define OCFS2_MAX_FILENAME_LEN	255
@@ -66,6 +72,8 @@
 #define HOLE_TEST		0x00000200
 #define ODCT_TEST		0x00000400
 #define INLN_TEST		0x00000800
+#define DSCV_TEST		0x00001000
+#define VERI_TEST		0x00002000
 
 #define MPI_RET_SUCCESS		0
 #define MPI_RET_FAILED		1
@@ -74,12 +82,21 @@
 #define RAND_CHAR_START 'A'
 #define MAGIC_HOLE_CHAR (RAND_CHAR_START - 1)
 
+#define CHUNK_SIZE	(1024*8)
+#define HOSTNAME_LEN	256
+
 struct write_unit {
 	char w_char;
 	unsigned long w_offset;
 	unsigned int  w_len;
 };
 
+struct dest_write_unit{
+	unsigned long d_chunk_no;
+	unsigned long long d_timestamp;
+	char d_char;
+};
+
 char rand_char(void);
 unsigned long get_rand(unsigned long min, unsigned long max);
 int get_rand_buf(char *buf, unsigned long size);
@@ -97,6 +114,7 @@ int mmap_write_at_file(char *pathname, const void *buf, size_t count,
 int fill_pattern(unsigned long size);
 int prep_orig_file(char *file_name, unsigned long size, int once);
 int prep_orig_file_dio(char *file_name, unsigned long size);
+int prep_orig_file_in_chunks(char *file_name, unsigned long chunks);
 int verify_pattern(char *buf, unsigned long offset, unsigned long size);
 int verify_orig_file(char *orig);
 
@@ -124,4 +142,14 @@ void prep_rand_write_unit(struct write_unit *wu);
 int do_write(int fd, struct write_unit *wu);
 int do_write_file(char *fname, struct write_unit *wu);
 
+unsigned long long get_time_microseconds(void);
+void prep_rand_dest_write_unit(struct dest_write_unit *du,
+			       unsigned long chunk_no);
+int fill_chunk_pattern(char *pattern, struct dest_write_unit dwu);
+int dump_pattern(char *pattern, struct dest_write_unit *dwu);
+int verify_chunk_pattern(char *pattern, struct dest_write_unit dwu);
+int do_write_chunk(int fd, struct dest_write_unit *du);
+int do_write_chunk_file(char *fname, struct dest_write_unit *du);
+int init_sock(char *serv, int port);
+int verify_dest_files(char *log, char *orig, unsigned long chunk_no);
 #endif
diff --git a/programs/reflink_tests/reflink_test_utils.c b/programs/reflink_tests/reflink_test_utils.c
index 1401566..dd01030 100755
--- a/programs/reflink_tests/reflink_test_utils.c
+++ b/programs/reflink_tests/reflink_test_utils.c
@@ -41,6 +41,7 @@ extern struct ocfs2_super_block *ocfs2_sb;
 extern char *prog;
 
 static char buf_dio[DIRECTIO_SLICE] __attribute__ ((aligned(DIRECTIO_SLICE)));
+static char chunk_pattern[CHUNK_SIZE] __attribute__ ((aligned(DIRECTIO_SLICE)));
 
 unsigned long get_rand(unsigned long min, unsigned long max)
 {
@@ -464,6 +465,132 @@ int prep_orig_file_dio(char *file_name, unsigned long size)
 	return 0;
 }
 
+int fill_chunk_pattern(char *pattern, struct dest_write_unit dwu)
+{
+	unsigned long mem_offset = 0;
+	unsigned long checksum = 0;
+
+	memset(pattern, 0, CHUNK_SIZE);
+	mem_offset = 0;
+
+	memmove(pattern , &dwu.d_chunk_no, sizeof(unsigned long));
+	mem_offset += sizeof(unsigned long);
+	memmove(pattern + mem_offset, &dwu.d_timestamp,
+		sizeof(unsigned long long ));
+	mem_offset += sizeof(unsigned long long);
+	memmove(pattern + mem_offset, &checksum, sizeof(unsigned long));
+	mem_offset += sizeof(unsigned long);
+
+	memset(pattern + mem_offset, dwu.d_char, CHUNK_SIZE - mem_offset * 2);
+	mem_offset = CHUNK_SIZE - mem_offset;
+
+	memmove(pattern + mem_offset, &checksum, sizeof(unsigned long));
+	mem_offset += sizeof(unsigned long);
+	memmove(pattern + mem_offset, &dwu.d_timestamp,
+		sizeof(unsigned long long ));
+	mem_offset += sizeof(unsigned long long);
+	memmove(pattern + mem_offset, &dwu.d_chunk_no, sizeof(unsigned long));
+
+	return 0;
+}
+
+int dump_pattern(char *pattern, struct dest_write_unit *dwu)
+{
+	unsigned long mem_offset = 0;
+	unsigned long checksum = 0;
+
+	memset(dwu, 0, sizeof(struct dest_write_unit));
+
+	memmove(&dwu->d_chunk_no, pattern, sizeof(unsigned long));
+	mem_offset += sizeof(unsigned long);
+	memmove(&dwu->d_timestamp, pattern + mem_offset,
+		sizeof(unsigned long long));
+	mem_offset += sizeof(unsigned long);
+	memmove(&checksum, pattern + mem_offset, sizeof(unsigned long));
+	mem_offset += sizeof(unsigned long);
+
+	memmove(&dwu->d_char, pattern + mem_offset, 1);
+	mem_offset = CHUNK_SIZE - mem_offset;
+
+	memmove(&checksum, pattern + mem_offset, sizeof(unsigned long));
+	mem_offset += sizeof(unsigned long);
+	memmove(&dwu->d_timestamp, pattern + mem_offset,
+		sizeof(unsigned long long));
+	mem_offset += sizeof(unsigned long long);
+	memmove(&dwu->d_chunk_no, pattern + mem_offset, sizeof(unsigned long));
+
+	return 0;
+}
+
+int verify_chunk_pattern(char *pattern, struct dest_write_unit dwu)
+{
+	char tmp_pattern[CHUNK_SIZE];
+	
+	fill_chunk_pattern(tmp_pattern, dwu);
+
+	return !memcmp(pattern, tmp_pattern, sizeof(struct dest_write_unit));
+}
+
+int prep_orig_file_in_chunks(char *file_name, unsigned long chunks)
+{
+
+	int fd, ret, o_ret, flags;
+	unsigned long offset = 0;
+	unsigned long size = CHUNK_SIZE * chunks, chunk_no = 0;
+	struct dest_write_unit dwu;
+
+	if ((CHUNK_SIZE % DIRECTIO_SLICE) != 0) {
+
+		fprintf(stderr, "File size in destructive tests is expected to "
+			"be %d aligned, your chunk size %d is not allowed.\n",
+			DIRECTIO_SLICE, CHUNK_SIZE);
+		return -1;
+	}
+
+	flags = FILE_RW_FLAGS;
+
+	fd = open64(file_name, flags, FILE_MODE);
+
+	if (fd < 0) {
+		o_ret = fd;
+		fd = errno;
+		fprintf(stderr, "create file %s failed:%d:%s\n", file_name, fd,
+			strerror(fd));
+		fd = o_ret;
+		return fd;
+	}
+
+	/*
+	 * Original file for desctrutive tests, it consists of chunks.
+	 * Each chunks consists of following parts:
+	 * chunkno + timestamp + checksum + random chars 
+	 * + checksum + timestamp + chunkno
+	 *
+	*/
+	
+	while (offset < size) {
+
+		memset(&dwu, 0, sizeof(struct dest_write_unit));
+		dwu.d_chunk_no = chunk_no;
+		fill_chunk_pattern(chunk_pattern, dwu);
+
+		ret = pwrite(fd, chunk_pattern, CHUNK_SIZE, offset);
+		if (ret < 0) {
+			o_ret = ret;
+			ret = errno;
+			fprintf(stderr, "write failed:%d:%s\n", ret,
+				strerror(ret));
+			return ret;
+		}
+
+		chunk_no++;
+		offset += CHUNK_SIZE;
+	}
+
+	close(fd);
+	return 0;
+}
+
 int verify_reflink_pair(const char *src, const char *dest)
 {
 	int fds, fdd, ret, o_ret;
@@ -1279,3 +1406,177 @@ int do_write_file(char *fname, struct write_unit *wu)
 
 	return ret;
 }
+
+unsigned long long get_time_microseconds(void)
+{
+	unsigned long long curtime_ms = 0;
+	struct timeval curtime;
+
+	gettimeofday(&curtime, NULL);
+
+	curtime_ms = (unsigned long long)curtime.tv_sec * 1000000 +
+					 curtime.tv_usec;
+
+	return curtime_ms;
+}
+
+void prep_rand_dest_write_unit(struct dest_write_unit *du,
+			       unsigned long chunk_no)
+{
+	du->d_char = rand_char();
+	du->d_chunk_no = chunk_no;
+	du->d_timestamp = get_time_microseconds();
+}
+
+int do_write_chunk(int fd, struct dest_write_unit *du)
+{
+	int ret;
+
+	fill_chunk_pattern(chunk_pattern, *du);
+
+	ret = pwrite(fd, chunk_pattern, CHUNK_SIZE, CHUNK_SIZE * du->d_chunk_no);
+	if (ret == -1) {
+		fprintf(stderr, "write error %d: \"%s\"\n", errno,
+			strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+int do_write_chunk_file(char *fname, struct dest_write_unit *du)
+{
+	int fd, ret, o_ret, flags = open_rw_flags;
+
+	if (test_flags & DSCV_TEST)
+		flags |= O_DIRECT;
+
+	fd  = open64(fname, flags);
+
+	if (fd < 0) {
+		o_ret = fd;
+		fd = errno;
+		fprintf(stderr, "open file %s failed:%d:%s\n", fname, fd,
+			strerror(fd));
+		fd = o_ret;
+		return fd;
+	}
+
+        ret = do_write_chunk(fd, du);
+
+	close(fd);
+
+	return ret;
+}
+
+
+int init_sock(char *serv, int port)
+{
+	int sockfd;
+	struct sockaddr_in servaddr;
+
+	sockfd = socket(AF_INET, SOCK_STREAM, 0);
+	bzero(&servaddr, sizeof(struct sockaddr_in));
+	servaddr.sin_family = AF_INET;
+	servaddr.sin_port = htons(port);
+	inet_pton(AF_INET, serv, &servaddr.sin_addr);
+
+	connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
+
+	return sockfd;
+}
+
+int verify_dest_files(char *log, char *orig, unsigned long chunk_no)
+{
+	FILE *logfile;
+	struct dest_write_unit *dwus, dwu;
+	unsigned long i, t_bytes = sizeof(struct dest_write_unit) * chunk_no;
+	int fd = 0, ret = 0, o_ret;
+	char dest[PATH_MAX];
+
+	memset(&dwu, 0, sizeof(struct dest_write_unit));
+
+	dwus = (struct dest_write_unit *)malloc(t_bytes);
+	memset(dwus, 0, t_bytes);
+
+	logfile = fopen(log, "r");
+	if (!logfile) {
+		fprintf(stderr, "Error %d opening dest log: %s\n", errno,
+			strerror(errno));
+		ret = -EINVAL;
+		goto bail;
+	}
+
+	while (!feof(logfile)) {
+
+		ret = fscanf(logfile, "%lu\t%llu\t%c\n", &dwu.d_chunk_no,
+                     &dwu.d_timestamp, &dwu.d_char);
+
+		if (ret != 3) {
+			fprintf(stderr, "input failure from dest log, ret "
+				"%d, %d %s\n", ret, errno, strerror(errno));
+			ret = -EINVAL;
+			goto bail;
+		}
+
+		if (dwu.d_timestamp >= dwus[dwu.d_chunk_no].d_timestamp) {
+
+			/*
+			printf("#%lu \tchunk record updated, from [%llu](%c) to [%llu](%c)\n",
+				dwu.d_chunk_no, dwus[dwu.d_chunk_no].d_timestamp, dwus[dwu.d_chunk_no].d_char,
+				dwu.d_timestamp, dwu.d_char);
+			*/
+			memmove(&dwus[dwu.d_chunk_no], &dwu,
+				sizeof(struct dest_write_unit));
+		}
+
+	}
+
+	fd = open64(orig, open_ro_flags, FILE_MODE);
+	if (fd < 0) {
+		ret = fd;
+		fd = errno;
+		fprintf(stderr, "open file %s failed:%d:%s\n",
+			orig, fd, strerror(fd));
+		goto bail;
+	}
+
+	for (i = 0; i < chunk_no; i++) {
+
+		ret = pread(fd, chunk_pattern, CHUNK_SIZE, CHUNK_SIZE * i);
+		if (ret < 0) {
+			o_ret = ret;
+			ret = errno;
+			fprintf(stderr, "read failed:%d:%s\n", ret,
+				strerror(ret));
+			ret = o_ret;
+			goto bail;
+		}
+
+		if (!verify_chunk_pattern(chunk_pattern, dwus[i])) {
+
+			dump_pattern(chunk_pattern, &dwu);	
+			fprintf(stderr, "An inconsistent chunk record found!\n"
+				"Expected:\tchunkno(%ld)\ttimestamp(%llu)\tchar(%c)\n"
+				"Found   :\tchunkno(%ld)\ttimestamp(%llu)\tchar(%c)\n",
+				dwus[i].d_chunk_no, dwus[i].d_timestamp, dwus[i].d_char,
+				dwu.d_chunk_no, dwu.d_timestamp, dwu.d_char);
+			ret = -1;
+			goto bail;
+
+		}
+
+	}
+
+bail:
+	if (dwus)
+		free(dwus);
+
+	if (logfile)
+		fclose(logfile);
+
+	if (fd)
+		close(fd);
+
+	return ret;
+}
-- 
1.5.5




More information about the Ocfs2-test-devel mailing list