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

Tristan Ye tristan.ye at oracle.com
Tue Nov 3 03:14:56 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 v2 testcase was also a somewhat quick&dirty one which incorporate sunil's
suggestions, and add checksum verification for data chunk.

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.

Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
---
 programs/reflink_tests/Makefile             |    2 +-
 programs/reflink_tests/crc32table.h         |  150 +++++++++++
 programs/reflink_tests/reflink_test.c       |  225 ++++++++++++++++-
 programs/reflink_tests/reflink_test.h       |   34 +++
 programs/reflink_tests/reflink_test_utils.c |  359 +++++++++++++++++++++++++++
 5 files changed, 765 insertions(+), 5 deletions(-)
 create mode 100644 programs/reflink_tests/crc32table.h

diff --git a/programs/reflink_tests/Makefile b/programs/reflink_tests/Makefile
index d2f2110..c73b647 100755
--- a/programs/reflink_tests/Makefile
+++ b/programs/reflink_tests/Makefile
@@ -4,7 +4,7 @@ include $(TOPDIR)/Preamble.make
 
 TESTS = reflink_tests
 
-CFLAGS = -O2 -Wall -g $(OCFS2_CFLAGS)
+CFLAGS = -O2 -Wall -g $(OCFS2_CFLAGS) -ggdb
 
 CFLAGS += $(EXTRA_CFLAGS)
 
diff --git a/programs/reflink_tests/crc32table.h b/programs/reflink_tests/crc32table.h
new file mode 100644
index 0000000..67eae31
--- /dev/null
+++ b/programs/reflink_tests/crc32table.h
@@ -0,0 +1,150 @@
+/* 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/reflink_tests/reflink_test.c b/programs/reflink_tests/reflink_test.c
index 9370925..3e6a7e9 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 <child_nums> -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"
@@ -133,7 +142,7 @@ 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:");
+			   "l:L:c:C:p:x:X:h:H:o:v:a:P:D:");
 		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,10 @@ static int parse_opts(int argc, char **argv)
 		case 'O':
 			test_flags |= ODCT_TEST;
 			break;
+		case 'D':
+			test_flags |= DSCV_TEST;
+			child_nums = atol(optarg);
+			break;
 		case 'I':
 			test_flags |= INLN_TEST;
 			xattr_nums = 100;
@@ -170,6 +182,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 +223,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 +236,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 +915,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 +1793,192 @@ static int holes_fill_test(void)
 	return 0;
 }
 
+static int destructive_test(void)
+{
+	int o_flags_rw, o_flags_ro, sockfd, i, j, status;
+	int ret, o_ret, fd, rc, sub_testno = 1;
+	char log_rec[100], dest[PATH_MAX];
+
+	struct dest_write_unit dwu;
+
+	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++);
+
+	fd  = open64(orig_path, open_rw_flags);
+	if (fd < 0) {
+		o_ret = fd;
+		fd = errno;
+		fprintf(stderr, "open file %s failed:%d:%s\n", orig_path, fd,
+			strerror(fd));
+		fd = o_ret;
+		return fd;
+	}
+	
+	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++) {
+
+				memset(log_rec, 0, sizeof(log_rec));
+				prep_rand_dest_write_unit(&dwu, get_rand(0,
+							  chunk_no - 1));
+				snprintf(log_rec, sizeof(log_rec), "%lu\t%llu"
+					 "\t%c\n", dwu.d_chunk_no,
+					 dwu.d_timestamp, dwu.d_char);
+
+				ret = do_write_chunk(fd, &dwu);
+				if (ret)
+					return -1;
+				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);
+
+				}
+				*/
+
+				/*
+				 * Are you ready to crash the machine?
+				*/
+				if ((j > 1) && (j < chunk_no - 1)) {
+					if (get_rand(1, chunk_no) == chunk_no / 2)
+						system("echo b>/proc/sysrq-trigger");
+				} else if (j == chunk_no - 1)
+						system("echo b>/proc/sysrq-trigger");
+
+				usleep(50000);
+			}
+
+			if (!fd)
+				close(fd);
+
+			if (!sockfd)
+				close(sockfd);
+
+			exit(0);
+		}
+
+		if (pid > 0)
+			child_pid_list[i] = pid;
+	}
+
+	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);
+	*/
+
+	if (fd)
+		close(fd);
+
+	if (sockfd)
+		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 +2216,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..de682c5 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,7 +41,14 @@
 #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>
+#include <ocfs2/byteorder.h>
+#include "crc32table.h"
 
 #define OCFS2_MAX_FILENAME_LEN	255
 #define FILE_RW_FLAGS		(O_CREAT|O_RDWR)
@@ -66,6 +74,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 +84,22 @@
 #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;
+	uint32_t d_checksum;
+	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 +117,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 +145,17 @@ 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 *dwu,
+			       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 *dwu);
+/*
+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);
+uint32_t crc32_checksum(uint32_t crc, char *p, size_t len);
 #endif
diff --git a/programs/reflink_tests/reflink_test_utils.c b/programs/reflink_tests/reflink_test_utils.c
index 1401566..2dd67db 100755
--- a/programs/reflink_tests/reflink_test_utils.c
+++ b/programs/reflink_tests/reflink_test_utils.c
@@ -41,6 +41,55 @@ 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)));
+
+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
+}
 
 unsigned long get_rand(unsigned long min, unsigned long max)
 {
@@ -464,6 +513,137 @@ 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;
+	uint32_t 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(uint32_t);
+
+	memset(pattern + mem_offset, dwu->d_char, CHUNK_SIZE - mem_offset * 2);
+
+	checksum = crc32_checksum(~0, pattern + mem_offset,
+				  (size_t)CHUNK_SIZE - mem_offset * 2);
+
+	mem_offset = CHUNK_SIZE - mem_offset;
+
+	memmove(pattern + mem_offset, &checksum, sizeof(uint32_t));
+	mem_offset += sizeof(uint32_t);
+	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));
+
+	mem_offset = sizeof(unsigned long) + sizeof(unsigned long long);
+	memmove(pattern + mem_offset, &checksum, sizeof(uint32_t));
+
+	dwu->d_checksum = checksum;
+
+	return 0;
+}
+
+int dump_pattern(char *pattern, struct dest_write_unit *dwu)
+{
+	unsigned long mem_offset = 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 long);
+	memmove(&dwu->d_checksum, pattern + mem_offset, sizeof(uint32_t));
+	mem_offset += sizeof(uint32_t);
+
+	memmove(&dwu->d_char, pattern + mem_offset, 1);
+	mem_offset = CHUNK_SIZE - mem_offset;
+
+	memmove(&dwu->d_checksum, pattern + mem_offset, sizeof(uint32_t));
+	mem_offset += sizeof(uint32_t);
+	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, CHUNK_SIZE);
+}
+
+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 = write_at(fd, chunk_pattern, CHUNK_SIZE, offset);
+		if (ret < 0)
+			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 +1459,182 @@ 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 *dwu,
+			       unsigned long chunk_no)
+{
+	dwu->d_char = rand_char();
+	dwu->d_chunk_no = chunk_no;
+	dwu->d_timestamp = get_time_microseconds();
+}
+
+int do_write_chunk(int fd, struct dest_write_unit *dwu)
+{
+	int ret;
+	size_t count = CHUNK_SIZE;
+	off_t offset = CHUNK_SIZE * dwu->d_chunk_no;
+
+	fill_chunk_pattern(chunk_pattern, dwu);
+
+	ret = write_at(fd, chunk_pattern ,count, offset);
+	if (ret < 0)
+		return ret;
+
+	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);
+
+	for (i = 0; i < chunk_no; i++)
+		dwus[i].d_chunk_no = i;
+
+	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, "Inconsistent chunk record found!\n"
+				"Expected:\tchunkno(%ld)\ttimestmp(%llu)\t"
+				"chksum(%d)\tchar(%c)\nFound   :\tchunkno"
+				"(%ld)\ttimestmp(%llu)\tchksum(%d)\tchar(%c)\n",
+				dwus[i].d_chunk_no, dwus[i].d_timestamp,
+				dwus[i].d_checksum, dwus[i].d_char,
+				dwu.d_chunk_no, dwu.d_timestamp,
+				dwu.d_checksum, 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