[Ocfs2-test-devel] [PATCH 1/1] Ocfs2-test: Add manipulation codes for file verification, and make it public.

Tristan Ye tristan.ye at oracle.com
Tue Jan 25 01:17:01 PST 2011


The original intention to make it public was driven by the requirement of doing
a thorough verification test for defragmentation after crash.

File verification is very common and critical in many area of filesystem's validation
test, especially to validate the file's data after a crash, which makes it necessary
to keep a series of verification codes into libo2test library to benifit all tests,
such as directio/reflink tests, and our destructive tests for deframentation later
also can take advantage from this.

The essence of verification logic is to format file's data in terms of chunks, with a
certain pattern for each chunk, each chunk consists of following parts:

         * chunkno
	 * timestamp
	 * checksum
	 * random chars
         * checksum
	 * timestamp
	 * chunkno

During the tests, it also requires the writers to write file in chunks, with a give pattern.
writing record can be kept locally, or remotely via socket.

After crash, the verification test can be done, with a remote/local write log being provided.

Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
---
 programs/libocfs2test/Makefile      |    6 +-
 programs/libocfs2test/crc32table.h  |  151 ++++++++
 programs/libocfs2test/file_verify.c |  710 +++++++++++++++++++++++++++++++++++
 programs/libocfs2test/file_verify.h |   63 +++
 4 files changed, 928 insertions(+), 2 deletions(-)
 create mode 100644 programs/libocfs2test/crc32table.h
 create mode 100644 programs/libocfs2test/file_verify.c
 create mode 100644 programs/libocfs2test/file_verify.h

diff --git a/programs/libocfs2test/Makefile b/programs/libocfs2test/Makefile
index aaaa16a..853d1cb 100644
--- a/programs/libocfs2test/Makefile
+++ b/programs/libocfs2test/Makefile
@@ -10,7 +10,8 @@ CFILES =		\
 	dir_ops.c	\
 	xattr_ops.c	\
 	mpi_ops.c	\
-	aio.c
+	aio.c		\
+	file_verify.c
 
 ifdef OCFS2_TEST_REFLINK
 CFILES +=	file_ops.c
@@ -20,7 +21,8 @@ HFILES =		\
 	dir_ops.h	\
 	xattr_ops.h	\
 	mpi_ops.h	\
-	aio.h
+	aio.h		\
+	file_verify.h
 
 ifdef OCFS2_TEST_REFLINK
 HFILES +=	file_ops.h
diff --git a/programs/libocfs2test/crc32table.h b/programs/libocfs2test/crc32table.h
new file mode 100644
index 0000000..ac7e97b
--- /dev/null
+++ b/programs/libocfs2test/crc32table.h
@@ -0,0 +1,151 @@
+/* this file is generated - do not edit */
+
+/*
+ * This file is generated in the kernel sources by lib/gen_crc32table.c.
+ * The following includes and defines are for our usage.
+ */
+#include <inttypes.h>
+#include <byteswap.h>
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define tole(x) ((uint32_t)(x))
+# define tobe(x) ((uint32_t)__bswap_constant_32(x))
+#elif __BYTE_ORDER == __BIG_ENDIAN
+# define tole(x) ((uint32_t)__bswap_constant_32(x))
+# define tobe(x) ((uint32_t)(x))
+#else
+# error Invalid byte order __BYTE_ORDER
+#endif
+
+static const uint32_t crc32table_le[] = {
+tole(0x00000000L), tole(0x77073096L), tole(0xee0e612cL), tole(0x990951baL),
+tole(0x076dc419L), tole(0x706af48fL), tole(0xe963a535L), tole(0x9e6495a3L),
+tole(0x0edb8832L), tole(0x79dcb8a4L), tole(0xe0d5e91eL), tole(0x97d2d988L),
+tole(0x09b64c2bL), tole(0x7eb17cbdL), tole(0xe7b82d07L), tole(0x90bf1d91L),
+tole(0x1db71064L), tole(0x6ab020f2L), tole(0xf3b97148L), tole(0x84be41deL),
+tole(0x1adad47dL), tole(0x6ddde4ebL), tole(0xf4d4b551L), tole(0x83d385c7L),
+tole(0x136c9856L), tole(0x646ba8c0L), tole(0xfd62f97aL), tole(0x8a65c9ecL),
+tole(0x14015c4fL), tole(0x63066cd9L), tole(0xfa0f3d63L), tole(0x8d080df5L),
+tole(0x3b6e20c8L), tole(0x4c69105eL), tole(0xd56041e4L), tole(0xa2677172L),
+tole(0x3c03e4d1L), tole(0x4b04d447L), tole(0xd20d85fdL), tole(0xa50ab56bL),
+tole(0x35b5a8faL), tole(0x42b2986cL), tole(0xdbbbc9d6L), tole(0xacbcf940L),
+tole(0x32d86ce3L), tole(0x45df5c75L), tole(0xdcd60dcfL), tole(0xabd13d59L),
+tole(0x26d930acL), tole(0x51de003aL), tole(0xc8d75180L), tole(0xbfd06116L),
+tole(0x21b4f4b5L), tole(0x56b3c423L), tole(0xcfba9599L), tole(0xb8bda50fL),
+tole(0x2802b89eL), tole(0x5f058808L), tole(0xc60cd9b2L), tole(0xb10be924L),
+tole(0x2f6f7c87L), tole(0x58684c11L), tole(0xc1611dabL), tole(0xb6662d3dL),
+tole(0x76dc4190L), tole(0x01db7106L), tole(0x98d220bcL), tole(0xefd5102aL),
+tole(0x71b18589L), tole(0x06b6b51fL), tole(0x9fbfe4a5L), tole(0xe8b8d433L),
+tole(0x7807c9a2L), tole(0x0f00f934L), tole(0x9609a88eL), tole(0xe10e9818L),
+tole(0x7f6a0dbbL), tole(0x086d3d2dL), tole(0x91646c97L), tole(0xe6635c01L),
+tole(0x6b6b51f4L), tole(0x1c6c6162L), tole(0x856530d8L), tole(0xf262004eL),
+tole(0x6c0695edL), tole(0x1b01a57bL), tole(0x8208f4c1L), tole(0xf50fc457L),
+tole(0x65b0d9c6L), tole(0x12b7e950L), tole(0x8bbeb8eaL), tole(0xfcb9887cL),
+tole(0x62dd1ddfL), tole(0x15da2d49L), tole(0x8cd37cf3L), tole(0xfbd44c65L),
+tole(0x4db26158L), tole(0x3ab551ceL), tole(0xa3bc0074L), tole(0xd4bb30e2L),
+tole(0x4adfa541L), tole(0x3dd895d7L), tole(0xa4d1c46dL), tole(0xd3d6f4fbL),
+tole(0x4369e96aL), tole(0x346ed9fcL), tole(0xad678846L), tole(0xda60b8d0L),
+tole(0x44042d73L), tole(0x33031de5L), tole(0xaa0a4c5fL), tole(0xdd0d7cc9L),
+tole(0x5005713cL), tole(0x270241aaL), tole(0xbe0b1010L), tole(0xc90c2086L),
+tole(0x5768b525L), tole(0x206f85b3L), tole(0xb966d409L), tole(0xce61e49fL),
+tole(0x5edef90eL), tole(0x29d9c998L), tole(0xb0d09822L), tole(0xc7d7a8b4L),
+tole(0x59b33d17L), tole(0x2eb40d81L), tole(0xb7bd5c3bL), tole(0xc0ba6cadL),
+tole(0xedb88320L), tole(0x9abfb3b6L), tole(0x03b6e20cL), tole(0x74b1d29aL),
+tole(0xead54739L), tole(0x9dd277afL), tole(0x04db2615L), tole(0x73dc1683L),
+tole(0xe3630b12L), tole(0x94643b84L), tole(0x0d6d6a3eL), tole(0x7a6a5aa8L),
+tole(0xe40ecf0bL), tole(0x9309ff9dL), tole(0x0a00ae27L), tole(0x7d079eb1L),
+tole(0xf00f9344L), tole(0x8708a3d2L), tole(0x1e01f268L), tole(0x6906c2feL),
+tole(0xf762575dL), tole(0x806567cbL), tole(0x196c3671L), tole(0x6e6b06e7L),
+tole(0xfed41b76L), tole(0x89d32be0L), tole(0x10da7a5aL), tole(0x67dd4accL),
+tole(0xf9b9df6fL), tole(0x8ebeeff9L), tole(0x17b7be43L), tole(0x60b08ed5L),
+tole(0xd6d6a3e8L), tole(0xa1d1937eL), tole(0x38d8c2c4L), tole(0x4fdff252L),
+tole(0xd1bb67f1L), tole(0xa6bc5767L), tole(0x3fb506ddL), tole(0x48b2364bL),
+tole(0xd80d2bdaL), tole(0xaf0a1b4cL), tole(0x36034af6L), tole(0x41047a60L),
+tole(0xdf60efc3L), tole(0xa867df55L), tole(0x316e8eefL), tole(0x4669be79L),
+tole(0xcb61b38cL), tole(0xbc66831aL), tole(0x256fd2a0L), tole(0x5268e236L),
+tole(0xcc0c7795L), tole(0xbb0b4703L), tole(0x220216b9L), tole(0x5505262fL),
+tole(0xc5ba3bbeL), tole(0xb2bd0b28L), tole(0x2bb45a92L), tole(0x5cb36a04L),
+tole(0xc2d7ffa7L), tole(0xb5d0cf31L), tole(0x2cd99e8bL), tole(0x5bdeae1dL),
+tole(0x9b64c2b0L), tole(0xec63f226L), tole(0x756aa39cL), tole(0x026d930aL),
+tole(0x9c0906a9L), tole(0xeb0e363fL), tole(0x72076785L), tole(0x05005713L),
+tole(0x95bf4a82L), tole(0xe2b87a14L), tole(0x7bb12baeL), tole(0x0cb61b38L),
+tole(0x92d28e9bL), tole(0xe5d5be0dL), tole(0x7cdcefb7L), tole(0x0bdbdf21L),
+tole(0x86d3d2d4L), tole(0xf1d4e242L), tole(0x68ddb3f8L), tole(0x1fda836eL),
+tole(0x81be16cdL), tole(0xf6b9265bL), tole(0x6fb077e1L), tole(0x18b74777L),
+tole(0x88085ae6L), tole(0xff0f6a70L), tole(0x66063bcaL), tole(0x11010b5cL),
+tole(0x8f659effL), tole(0xf862ae69L), tole(0x616bffd3L), tole(0x166ccf45L),
+tole(0xa00ae278L), tole(0xd70dd2eeL), tole(0x4e048354L), tole(0x3903b3c2L),
+tole(0xa7672661L), tole(0xd06016f7L), tole(0x4969474dL), tole(0x3e6e77dbL),
+tole(0xaed16a4aL), tole(0xd9d65adcL), tole(0x40df0b66L), tole(0x37d83bf0L),
+tole(0xa9bcae53L), tole(0xdebb9ec5L), tole(0x47b2cf7fL), tole(0x30b5ffe9L),
+tole(0xbdbdf21cL), tole(0xcabac28aL), tole(0x53b39330L), tole(0x24b4a3a6L),
+tole(0xbad03605L), tole(0xcdd70693L), tole(0x54de5729L), tole(0x23d967bfL),
+tole(0xb3667a2eL), tole(0xc4614ab8L), tole(0x5d681b02L), tole(0x2a6f2b94L),
+tole(0xb40bbe37L), tole(0xc30c8ea1L), tole(0x5a05df1bL), tole(0x2d02ef8dL)
+};
+
+static const uint32_t crc32table_be[] = {
+tobe(0x00000000L), tobe(0x04c11db7L), tobe(0x09823b6eL), tobe(0x0d4326d9L),
+tobe(0x130476dcL), tobe(0x17c56b6bL), tobe(0x1a864db2L), tobe(0x1e475005L),
+tobe(0x2608edb8L), tobe(0x22c9f00fL), tobe(0x2f8ad6d6L), tobe(0x2b4bcb61L),
+tobe(0x350c9b64L), tobe(0x31cd86d3L), tobe(0x3c8ea00aL), tobe(0x384fbdbdL),
+tobe(0x4c11db70L), tobe(0x48d0c6c7L), tobe(0x4593e01eL), tobe(0x4152fda9L),
+tobe(0x5f15adacL), tobe(0x5bd4b01bL), tobe(0x569796c2L), tobe(0x52568b75L),
+tobe(0x6a1936c8L), tobe(0x6ed82b7fL), tobe(0x639b0da6L), tobe(0x675a1011L),
+tobe(0x791d4014L), tobe(0x7ddc5da3L), tobe(0x709f7b7aL), tobe(0x745e66cdL),
+tobe(0x9823b6e0L), tobe(0x9ce2ab57L), tobe(0x91a18d8eL), tobe(0x95609039L),
+tobe(0x8b27c03cL), tobe(0x8fe6dd8bL), tobe(0x82a5fb52L), tobe(0x8664e6e5L),
+tobe(0xbe2b5b58L), tobe(0xbaea46efL), tobe(0xb7a96036L), tobe(0xb3687d81L),
+tobe(0xad2f2d84L), tobe(0xa9ee3033L), tobe(0xa4ad16eaL), tobe(0xa06c0b5dL),
+tobe(0xd4326d90L), tobe(0xd0f37027L), tobe(0xddb056feL), tobe(0xd9714b49L),
+tobe(0xc7361b4cL), tobe(0xc3f706fbL), tobe(0xceb42022L), tobe(0xca753d95L),
+tobe(0xf23a8028L), tobe(0xf6fb9d9fL), tobe(0xfbb8bb46L), tobe(0xff79a6f1L),
+tobe(0xe13ef6f4L), tobe(0xe5ffeb43L), tobe(0xe8bccd9aL), tobe(0xec7dd02dL),
+tobe(0x34867077L), tobe(0x30476dc0L), tobe(0x3d044b19L), tobe(0x39c556aeL),
+tobe(0x278206abL), tobe(0x23431b1cL), tobe(0x2e003dc5L), tobe(0x2ac12072L),
+tobe(0x128e9dcfL), tobe(0x164f8078L), tobe(0x1b0ca6a1L), tobe(0x1fcdbb16L),
+tobe(0x018aeb13L), tobe(0x054bf6a4L), tobe(0x0808d07dL), tobe(0x0cc9cdcaL),
+tobe(0x7897ab07L), tobe(0x7c56b6b0L), tobe(0x71159069L), tobe(0x75d48ddeL),
+tobe(0x6b93dddbL), tobe(0x6f52c06cL), tobe(0x6211e6b5L), tobe(0x66d0fb02L),
+tobe(0x5e9f46bfL), tobe(0x5a5e5b08L), tobe(0x571d7dd1L), tobe(0x53dc6066L),
+tobe(0x4d9b3063L), tobe(0x495a2dd4L), tobe(0x44190b0dL), tobe(0x40d816baL),
+tobe(0xaca5c697L), tobe(0xa864db20L), tobe(0xa527fdf9L), tobe(0xa1e6e04eL),
+tobe(0xbfa1b04bL), tobe(0xbb60adfcL), tobe(0xb6238b25L), tobe(0xb2e29692L),
+tobe(0x8aad2b2fL), tobe(0x8e6c3698L), tobe(0x832f1041L), tobe(0x87ee0df6L),
+tobe(0x99a95df3L), tobe(0x9d684044L), tobe(0x902b669dL), tobe(0x94ea7b2aL),
+tobe(0xe0b41de7L), tobe(0xe4750050L), tobe(0xe9362689L), tobe(0xedf73b3eL),
+tobe(0xf3b06b3bL), tobe(0xf771768cL), tobe(0xfa325055L), tobe(0xfef34de2L),
+tobe(0xc6bcf05fL), tobe(0xc27dede8L), tobe(0xcf3ecb31L), tobe(0xcbffd686L),
+tobe(0xd5b88683L), tobe(0xd1799b34L), tobe(0xdc3abdedL), tobe(0xd8fba05aL),
+tobe(0x690ce0eeL), tobe(0x6dcdfd59L), tobe(0x608edb80L), tobe(0x644fc637L),
+tobe(0x7a089632L), tobe(0x7ec98b85L), tobe(0x738aad5cL), tobe(0x774bb0ebL),
+tobe(0x4f040d56L), tobe(0x4bc510e1L), tobe(0x46863638L), tobe(0x42472b8fL),
+tobe(0x5c007b8aL), tobe(0x58c1663dL), tobe(0x558240e4L), tobe(0x51435d53L),
+tobe(0x251d3b9eL), tobe(0x21dc2629L), tobe(0x2c9f00f0L), tobe(0x285e1d47L),
+tobe(0x36194d42L), tobe(0x32d850f5L), tobe(0x3f9b762cL), tobe(0x3b5a6b9bL),
+tobe(0x0315d626L), tobe(0x07d4cb91L), tobe(0x0a97ed48L), tobe(0x0e56f0ffL),
+tobe(0x1011a0faL), tobe(0x14d0bd4dL), tobe(0x19939b94L), tobe(0x1d528623L),
+tobe(0xf12f560eL), tobe(0xf5ee4bb9L), tobe(0xf8ad6d60L), tobe(0xfc6c70d7L),
+tobe(0xe22b20d2L), tobe(0xe6ea3d65L), tobe(0xeba91bbcL), tobe(0xef68060bL),
+tobe(0xd727bbb6L), tobe(0xd3e6a601L), tobe(0xdea580d8L), tobe(0xda649d6fL),
+tobe(0xc423cd6aL), tobe(0xc0e2d0ddL), tobe(0xcda1f604L), tobe(0xc960ebb3L),
+tobe(0xbd3e8d7eL), tobe(0xb9ff90c9L), tobe(0xb4bcb610L), tobe(0xb07daba7L),
+tobe(0xae3afba2L), tobe(0xaafbe615L), tobe(0xa7b8c0ccL), tobe(0xa379dd7bL),
+tobe(0x9b3660c6L), tobe(0x9ff77d71L), tobe(0x92b45ba8L), tobe(0x9675461fL),
+tobe(0x8832161aL), tobe(0x8cf30badL), tobe(0x81b02d74L), tobe(0x857130c3L),
+tobe(0x5d8a9099L), tobe(0x594b8d2eL), tobe(0x5408abf7L), tobe(0x50c9b640L),
+tobe(0x4e8ee645L), tobe(0x4a4ffbf2L), tobe(0x470cdd2bL), tobe(0x43cdc09cL),
+tobe(0x7b827d21L), tobe(0x7f436096L), tobe(0x7200464fL), tobe(0x76c15bf8L),
+tobe(0x68860bfdL), tobe(0x6c47164aL), tobe(0x61043093L), tobe(0x65c52d24L),
+tobe(0x119b4be9L), tobe(0x155a565eL), tobe(0x18197087L), tobe(0x1cd86d30L),
+tobe(0x029f3d35L), tobe(0x065e2082L), tobe(0x0b1d065bL), tobe(0x0fdc1becL),
+tobe(0x3793a651L), tobe(0x3352bbe6L), tobe(0x3e119d3fL), tobe(0x3ad08088L),
+tobe(0x2497d08dL), tobe(0x2056cd3aL), tobe(0x2d15ebe3L), tobe(0x29d4f654L),
+tobe(0xc5a92679L), tobe(0xc1683bceL), tobe(0xcc2b1d17L), tobe(0xc8ea00a0L),
+tobe(0xd6ad50a5L), tobe(0xd26c4d12L), tobe(0xdf2f6bcbL), tobe(0xdbee767cL),
+tobe(0xe3a1cbc1L), tobe(0xe760d676L), tobe(0xea23f0afL), tobe(0xeee2ed18L),
+tobe(0xf0a5bd1dL), tobe(0xf464a0aaL), tobe(0xf9278673L), tobe(0xfde69bc4L),
+tobe(0x89b8fd09L), tobe(0x8d79e0beL), tobe(0x803ac667L), tobe(0x84fbdbd0L),
+tobe(0x9abc8bd5L), tobe(0x9e7d9662L), tobe(0x933eb0bbL), tobe(0x97ffad0cL),
+tobe(0xafb010b1L), tobe(0xab710d06L), tobe(0xa6322bdfL), tobe(0xa2f33668L),
+tobe(0xbcb4666dL), tobe(0xb8757bdaL), tobe(0xb5365d03L), tobe(0xb1f740b4L)
+};
diff --git a/programs/libocfs2test/file_verify.c b/programs/libocfs2test/file_verify.c
new file mode 100644
index 0000000..54aa5f1
--- /dev/null
+++ b/programs/libocfs2test/file_verify.c
@@ -0,0 +1,710 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * file_verify.c
+ *
+ * Provide generic utility fuctions on file verification for ocfs2-tests
+ *
+ * Written by tristan.ye at oracle.com
+ *
+ * Copyright (C) 2010 Oracle.  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 version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will 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.
+ */
+
+#define _GNU_SOURCE
+#define _XOPEN_SOURCE 500
+#define _LARGEFILE64_SOURCE
+
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <linux/types.h>
+#include <sys/time.h>
+#include <sys/sem.h>
+#include <sys/wait.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdarg.h>
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ocfs2/byteorder.h>
+#include "crc32table.h"
+#include "file_verify.h"
+
+#define FILE_MODE               (S_IRUSR|S_IWUSR|S_IXUSR|S_IROTH|\
+				 S_IWOTH|S_IXOTH|S_IRGRP|S_IWGRP|S_IXGRP)
+
+static uint32_t crc32_checksum(uint32_t crc, char *p, size_t len)
+{
+	const uint32_t      *b = (uint32_t *)p;
+	const uint32_t      *tab = crc32table_le;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define DO_CRC(x) crc = tab[(crc ^ (x)) & 255] ^ (crc >> 8)
+#else
+# define DO_CRC(x) crc = tab[((crc >> 24) ^ (x)) & 255] ^ (crc << 8)
+#endif
+
+	crc = cpu_to_le32(crc);
+	/* Align it */
+	if (((long)b)&3 && len) {
+		do {
+			uint8_t *p = (uint8_t *)b;
+			DO_CRC(*p++);
+			b = (void *)p;
+		} while ((--len) && ((long)b)&3);
+	}
+	if (len >= 4) {
+		/* load data 32 bits wide, xor data 32 bits wide. */
+		size_t save_len = len & 3;
+		len = len >> 2;
+		--b; /* use pre increment below(*++b) for speed */
+		do {
+			crc ^= *++b;
+			DO_CRC(0);
+			DO_CRC(0);
+			DO_CRC(0);
+			DO_CRC(0);
+		} while (--len);
+		b++; /* point to next byte(s) */
+		len = save_len;
+	}
+	/* And the last few bytes */
+	if (len) {
+		do {
+			uint8_t *p = (uint8_t *)b;
+			DO_CRC(*p++);
+			b = (void *)p;
+		} while (--len);
+	}
+
+	return le32_to_cpu(crc);
+#undef DO_CRC
+}
+
+static unsigned long get_rand_ul(unsigned long min, unsigned long max)
+{
+	if (min == 0 && max == 0)
+		return 0;
+
+	return min + (rand() % (max - min + 1));
+}
+
+static char rand_char(void)
+{
+	return 'A' + (char) get_rand_ul(0, 25);
+}
+
+static int open_file(const char *filename, int flags)
+{
+	int fd, ret = 0;
+
+	fd = open64(filename, flags, FILE_MODE);
+	if (fd < 0) {
+		ret = errno;
+		fprintf(stderr, "open file %s failed:%d:%s\n", filename, ret,
+			strerror(ret));
+		return -1;
+	}
+
+	return fd;
+}
+
+int get_i_size(char *filename, unsigned long *size, int flags)
+{
+	struct stat stat;
+	int ret = 0, fd;
+
+	fd = open_file(filename, O_RDONLY);
+	if (fd)
+		return fd;
+
+	ret = fstat(fd, &stat);
+	if (ret == -1) {
+		ret = errno;
+		fprintf(stderr, "stat failure %d: %s\n", ret, strerror(ret));
+		return ret;
+	}
+
+	*size = (unsigned long) stat.st_size;
+	return ret;
+}
+
+static int read_at(int fd, void *buf, size_t count, off_t offset)
+{
+	int ret;
+	size_t bytes_read;
+
+	ret = pread(fd, buf, count, offset);
+	if (ret < 0) {
+		ret = errno;
+		fprintf(stderr, "read error %d: \"%s\"\n", ret, strerror(ret));
+		return -1;
+	}
+
+	bytes_read = ret;
+	while (bytes_read < count) {
+
+		ret = pread(fd, buf + bytes_read, count - bytes_read, offset +
+			    bytes_read);
+		if (ret < 0) {
+			ret = errno;
+			fprintf(stderr, "read error %d: \"%s\"\n", ret,
+				strerror(ret));
+			return -1;
+		}
+
+		bytes_read += ret;
+	}
+
+	return count;
+}
+
+static int write_at(int fd, const void *buf, size_t count, off_t offset)
+{
+	int ret;
+	size_t bytes_write;
+
+	ret = pwrite(fd, buf, count, offset);
+
+	if (ret < 0) {
+		ret = errno;
+		fprintf(stderr, "write error %d: \"%s\"\n", ret, strerror(ret));
+		return -1;
+	}
+
+	bytes_write = ret;
+	while (bytes_write < count) {
+
+		ret = pwrite(fd, buf + bytes_write, count - bytes_write,
+			     offset + bytes_write);
+
+		if (ret < 0) {
+			ret = errno;
+			fprintf(stderr, "write error %d: \"%s\"\n", ret,
+				strerror(ret));
+			return -1;
+		}
+
+		bytes_write += ret;
+	}
+
+	return count;
+}
+
+static int fill_chunk_pattern(char *pattern, struct write_unit *wu)
+{
+	unsigned long offset = 0;
+	uint32_t checksum = 0;
+	unsigned int chunksize = wu->wu_chunksize;
+
+	memset(pattern, 0, chunksize);
+	offset = 0;
+
+	memmove(pattern , &wu->wu_chunk_no, sizeof(unsigned long));
+	offset += sizeof(unsigned long);
+	memmove(pattern + offset, &wu->wu_timestamp, sizeof(unsigned long long));
+	offset += sizeof(unsigned long long);
+
+	offset += sizeof(uint32_t);
+
+	memset(pattern + offset, wu->wu_char, chunksize - offset * 2);
+
+	checksum = crc32_checksum(~0, pattern + offset,
+				  (size_t)chunksize - offset * 2);
+
+	offset = chunksize - offset;
+
+	memmove(pattern + offset, &checksum, sizeof(uint32_t));
+	offset += sizeof(uint32_t);
+	memmove(pattern + offset, &wu->wu_timestamp,
+		sizeof(unsigned long long));
+	offset += sizeof(unsigned long long);
+	memmove(pattern + offset, &wu->wu_chunk_no, sizeof(unsigned long));
+
+	offset = sizeof(unsigned long) + sizeof(unsigned long long);
+	memmove(pattern + offset, &checksum, sizeof(uint32_t));
+
+	wu->wu_checksum = checksum;
+
+	return 0;
+}
+
+static int dump_pattern(char *pattern, unsigned int chunksize,
+			struct write_unit *wu)
+{
+	unsigned long offset = 0;
+
+	memset(wu, 0, sizeof(struct write_unit));
+
+	wu->wu_chunksize = chunksize;
+
+	memmove(&wu->wu_chunk_no, pattern, sizeof(unsigned long));
+	offset += sizeof(unsigned long);
+	memmove(&wu->wu_timestamp, pattern + offset, sizeof(unsigned long long));
+	offset += sizeof(unsigned long long);
+	memmove(&wu->wu_checksum, pattern + offset, sizeof(uint32_t));
+	offset += sizeof(uint32_t);
+
+	memmove(&wu->wu_char, pattern + offset, 1);
+	offset = chunksize - offset;
+
+	memmove(&wu->wu_checksum, pattern + offset, sizeof(uint32_t));
+	offset += sizeof(uint32_t);
+	memmove(&wu->wu_timestamp, pattern + offset, sizeof(unsigned long long));
+	offset += sizeof(unsigned long long);
+	memmove(&wu->wu_chunk_no, pattern + offset, sizeof(unsigned long));
+
+	return 0;
+}
+
+static int verify_chunk_pattern(char *pattern, struct write_unit *wu)
+{
+	int match;
+	char *tmp_pattern;
+
+	tmp_pattern = (char *)malloc(wu->wu_chunksize);
+	fill_chunk_pattern(tmp_pattern, wu);
+	match = !memcmp(pattern, tmp_pattern, wu->wu_chunksize);
+
+	if (tmp_pattern)
+		free(tmp_pattern);
+
+	return match;
+}
+
+static 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 write_unit *wu, unsigned long chunk_no,
+			       unsigned int chunksize)
+{
+	char *tmp_pattern;
+
+	tmp_pattern = (char *)malloc(chunksize);
+
+	wu->wu_char = rand_char();
+	wu->wu_chunk_no = chunk_no;
+	wu->wu_chunksize = chunksize;
+	wu->wu_timestamp = get_time_microseconds();
+
+	/*
+	 * the reason to do a redundant filling here is to get a checksum;-)
+	 */
+	fill_chunk_pattern(tmp_pattern, wu);
+
+	if (tmp_pattern)
+		free(tmp_pattern);
+}
+
+int do_write_chunk(int fd, struct write_unit wu)
+{
+	int ret;
+	char *tmp_pattern;
+	size_t count = wu.wu_chunksize;
+	off_t offset = wu.wu_chunksize * wu.wu_chunk_no;
+
+	tmp_pattern = (char *)malloc(wu.wu_chunksize);
+	fill_chunk_pattern(tmp_pattern, &wu);
+
+	ret = write_at(fd, tmp_pattern, count, offset);
+
+	if (tmp_pattern)
+		free(tmp_pattern);
+
+	return ret;
+}
+
+int do_read_chunk(int fd, unsigned long chunk_no, unsigned int chunksize,
+		  struct write_unit *wu)
+{
+	int ret;
+	char *tmp_pattern;
+	size_t count = chunksize;
+	off_t offset = chunksize * chunk_no;
+
+	tmp_pattern = (char *)malloc(chunksize);
+
+	ret = read_at(fd, tmp_pattern, count, offset);
+	if (ret < 0)
+		goto out;
+
+	dump_pattern(tmp_pattern, chunksize, wu);
+
+out:
+	if (tmp_pattern)
+		free(tmp_pattern);
+
+	return ret;
+}
+
+int prep_orig_file_in_chunks(char *file_name, unsigned long filesize,
+			     unsigned int chunksize, int flags)
+{
+
+	int fd, ret;
+	char *tmp_pattern;
+	unsigned long offset = 0, chunk_no = 0;
+	static struct write_unit wu;
+
+	tmp_pattern = (char *)malloc(chunksize);
+
+	fd = open_file(file_name, flags);
+	if (fd < 0)
+		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 < filesize) {
+
+		prep_rand_dest_write_unit(&wu, chunk_no, chunksize);
+
+		fill_chunk_pattern(tmp_pattern, &wu);
+
+		ret = do_write_chunk(fd, wu);
+		if (ret < 0)
+			goto bail;
+
+		chunk_no++;
+		offset += chunksize;
+	}
+
+bail:
+	if (tmp_pattern)
+		free(tmp_pattern);
+
+	close(fd);
+
+	return 0;
+}
+
+int verify_file(int is_remote, FILE *logfile, struct write_unit *remote_wus,
+		char *filename, unsigned long filesize, unsigned int chunksize,
+		int verbose)
+{
+	int fd = 0, ret = 0;
+	struct write_unit *wus, wu, ewu;
+	unsigned long num_chunks = filesize / chunksize;
+	unsigned long i, t_bytes = sizeof(struct write_unit) * num_chunks;
+	char arg1[100], arg2[100], arg3[100], arg4[100], *tmp_pattern;
+
+	tmp_pattern = (char *)malloc(chunksize);
+
+	memset(&wu, 0, sizeof(struct write_unit));
+	memset(&ewu, 0, sizeof(struct write_unit));
+
+	wus = (struct write_unit *)malloc(t_bytes);
+	memset(wus, 0, t_bytes);
+
+	if (is_remote) {
+		memcpy(wus, remote_wus, t_bytes);
+		goto verify_body;
+	}
+
+	for (i = 0; i < num_chunks; i++)
+		wus[i].wu_chunk_no = i;
+
+	while (!feof(logfile)) {
+
+		ret = fscanf(logfile, "%s\t%s\t%s\t%s\n", arg1, arg2,
+			     arg3, arg4);
+		if (ret != 4) {
+			fprintf(stderr, "input failure from write log, ret "
+				"%d, %d %s\n", ret, errno, strerror(errno));
+			ret = -EINVAL;
+			goto bail;
+		}
+
+		wu.wu_chunk_no = atol(arg1);
+		if (wu.wu_chunk_no > num_chunks) {
+			fprintf(stderr, "Chunkno grabed from write log"
+				"exceeds the filesize, you may probably"
+				" specify a too small filesize.\n");
+			return -EINVAL;
+		}
+
+		wu.wu_timestamp = atoll(arg2);
+		wu.wu_checksum = atoi(arg3);
+		wu.wu_char = arg4[0];
+
+		if (wu.wu_timestamp >= wus[wu.wu_chunk_no].wu_timestamp) {
+
+			memmove(&wus[wu.wu_chunk_no], &wu,
+				sizeof(struct write_unit));
+		}
+	}
+
+verify_body:
+	fd = open_file(filename, O_RDONLY);
+	if (fd < 0)
+		return fd;
+
+	for (i = 0; i < num_chunks; i++) {
+		/*
+		 * Verification consists of two following parts:
+		 *
+		 *    - verify write records.
+		 *    - verify pattern of chunks absent from write records.
+		 */
+		
+		ret = do_read_chunk(fd, i, chunksize, &wu);
+		if (ret < 0)
+			return ret;
+		/*
+		 * verify pattern of chunks absent from write records.
+		 */
+		if (!wus[i].wu_timestamp) {
+
+			if (verbose)
+				fprintf(stdout, "  verifying #%lu chunk "
+					"out of write records\n", i);
+			/*
+			 * skip holes
+			 */
+			if (!wu.wu_timestamp)
+				continue;
+
+			if (wu.wu_chunk_no != i) {
+				fprintf(stderr, "Chunk no expected: %lu, Found: %lu\n",
+					i, wu.wu_chunk_no);
+				return -EINVAL;
+			}
+
+			/*
+			 * recalculate checksum
+			 */
+			memcpy(&ewu, &wu, sizeof(wu));
+                	fill_chunk_pattern(tmp_pattern, &ewu);
+                	if (wu.wu_checksum != ewu.wu_checksum) {
+                	        fprintf(stderr, "Checksum expected: %u Found: %u\n",
+                	                ewu.wu_checksum, wu.wu_checksum);
+                	        return -1;
+                	}
+
+			continue;
+		}
+
+		/*
+		 * verify write records in logfile.
+		 */
+		if (verbose)
+			fprintf(stdout, "  verifying #%lu chunk in write "
+				"records\n", i);
+
+		if (ret < chunksize) {
+			fprintf(stderr, "Short read(readed:%d, expected:%d)"
+				"happened, you may probably set too big "
+				"filesize for verfiy_test.\n", ret, chunksize);
+			return -1;
+		}
+
+		fill_chunk_pattern(tmp_pattern, &wu);
+
+		if (!verify_chunk_pattern(tmp_pattern, &wus[i])) {
+
+			dump_pattern(tmp_pattern, chunksize, &wu);
+			fprintf(stderr, "Inconsistent chunk found in file %s!\n"
+				"Expected:\tchunkno(%ld)\ttimestmp(%llu)\t"
+				"chksum(%d)\tchar(%c)\nFound   :\tchunkno"
+				"(%ld)\ttimestmp(%llu)\tchksum(%d)\tchar(%c)\n",
+				filename,
+				wus[i].wu_chunk_no, wus[i].wu_timestamp,
+				wus[i].wu_checksum, wus[i].wu_char,
+				wu.wu_chunk_no, wu.wu_timestamp,
+				wu.wu_checksum, wu.wu_char);
+			ret = -1;
+			goto bail;
+
+		}
+	}
+
+	ret = 0;
+
+bail:
+	if (tmp_pattern)
+		free(tmp_pattern);
+
+	if (wus)
+		free(wus);
+
+	if (fd)
+		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 set_semvalue(int sem_id, int val)
+{
+	union semun sem_union;
+
+	sem_union.val = val;
+	if (semctl(sem_id, 0, SETVAL, sem_union) == -1) {
+		perror("semctl");
+		return -1;
+	}
+
+	return 0;
+}
+
+int semaphore_init(int val)
+{
+	int ret, sem_id;
+	key_t sem_key = IPC_PRIVATE;
+
+	/*get and init semaphore*/
+	sem_id = semget(sem_key, 1, 0766 | IPC_CREAT);
+	if (sem_id < 0) {
+		sem_id = errno;
+		fprintf(stderr, "semget failed, %s.\n", strerror(sem_id));
+		return -1;
+	}
+
+	ret = set_semvalue(sem_id, 1);
+	if (ret < 0) {
+		fprintf(stderr, "Set semaphore value failed!\n");
+		return ret;
+	}
+
+	return sem_id;
+}
+
+int semaphore_close(int sem_id)
+{
+	int ret = 0;
+
+	ret = semctl(sem_id, 0, IPC_RMID);
+	if (ret < 0) {
+		ret = errno;
+		fprintf(stderr, "semctl to close sem failed, %s.\n", strerror(ret));
+		return -1;
+	}
+
+	return ret;
+}
+
+int semaphore_p(int sem_id)
+{
+	struct sembuf sem_b;
+
+	sem_b.sem_num = 0;
+	sem_b.sem_op = -1; /* P() */
+	sem_b.sem_flg = SEM_UNDO;
+	if (semop(sem_id, &sem_b, 1) == -1) {
+		fprintf(stderr, "semaphore_p failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int semaphore_v(int sem_id)
+{
+	struct sembuf sem_b;
+
+	sem_b.sem_num = 0;
+	sem_b.sem_op = 1; /* V() */
+	sem_b.sem_flg = SEM_UNDO;
+	if (semop(sem_id, &sem_b, 1) == -1) {
+		fprintf(stderr, "semaphore_v failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int open_logfile(FILE **logfile, const char *logname, int readonly)
+{
+	if (readonly) {
+		if (!logname)
+			*logfile = stdin;
+		else
+			*logfile = fopen(logname, "r");
+	} else {
+		if (!logname)
+			*logfile = stdout;
+		else *logfile = fopen(logname, "wa");
+		
+	}
+
+	if (!(*logfile)) {
+		fprintf(stderr, "Error %d opening logfile: %s\n", errno,
+			strerror(errno));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int log_write(struct write_unit *wu, union log_handler log, int remote)
+{
+	int fd, ret = 0;
+	char log_rec[1024];
+
+	if (remote) {
+		snprintf(log_rec, sizeof(log_rec), "%lu\t%llu\t%d\t%c\n",
+			 wu->wu_chunk_no, wu->wu_timestamp, wu->wu_checksum,
+			 wu->wu_char);
+		ret = write(log.socket_log, log_rec, strlen(log_rec) + 1);
+		if (ret < 0) {
+			ret = errno;
+			fprintf(stderr, "write socket error:%d, %s\n",
+				ret , strerror(ret));
+			return -EINVAL;
+		}
+	} else {
+		fprintf(log.stream_log, "%lu\t%llu\t%d\t%c\n", wu->wu_chunk_no,
+			wu->wu_timestamp, wu->wu_checksum, wu->wu_char);
+                fflush(log.stream_log);
+		fd = fileno(log.stream_log);
+		fsync(fd);
+	}
+
+	return ret;
+}
diff --git a/programs/libocfs2test/file_verify.h b/programs/libocfs2test/file_verify.h
new file mode 100644
index 0000000..24b7939
--- /dev/null
+++ b/programs/libocfs2test/file_verify.h
@@ -0,0 +1,63 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * file_verify.h
+ *
+ * Copyright (C) 2011 Oracle.  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 version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will 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.
+ */
+
+#ifndef FILE_VERIFY_H
+#define FILE_VERIFY_H
+
+struct write_unit {
+	unsigned long wu_chunk_no;
+	unsigned long long wu_timestamp;
+	unsigned int wu_chunksize;
+	uint32_t wu_checksum;
+	char wu_char;
+};
+
+union log_handler {
+	FILE *stream_log;
+	int socket_log;
+};
+
+union semun {
+	int val;                    /* value for SETVAL */
+	struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
+	unsigned short int *array;  /* array for GETALL, SETALL */
+	struct seminfo *__buf;      /* buffer for IPC_INFO */
+};
+
+int get_i_size(char *filename, unsigned long *size, int flags);
+int prep_orig_file_in_chunks(char *file_name, unsigned long filesize,
+			     unsigned int chunksize, int flags);
+void prep_rand_dest_write_unit(struct write_unit *wu, unsigned long chunk_no,
+			       unsigned int chunksize);
+int do_write_chunk(int fd, struct write_unit wu);
+int do_read_chunk(int fd, unsigned long chunk_no, unsigned int chunksize,
+		  struct write_unit *wu);
+int verify_file(int is_remote, FILE *logfile, struct write_unit *wus,
+		char *filename, unsigned long filesize, unsigned int chunksize,
+		int verbose);
+
+int init_sock(char *serv, int port);
+int set_semvalue(int sem_id, int val);
+int semaphore_init(int val);
+int semaphore_close(int sem_id);
+int semaphore_p(int sem_id);
+int semaphore_v(int sem_id);
+
+int open_logfile(FILE **logfile, const char *logname, int readonly);
+int log_write(struct write_unit *wu, union log_handler log, int remote);
+
+#endif
-- 
1.5.5




More information about the Ocfs2-test-devel mailing list