[Ocfs2-tools-devel] [PATCH 3/9] Ocfs2-test: Enhance inline-dirs test for inline-data directory test.

Tristan Ye tristan.ye at oracle.com
Thu Sep 4 03:01:29 PDT 2008


Like the enhancement for inline-data ,herej ust enhance the orignal inline-dirs.c become work-load tunable,to
perform a variety of test,such as stress test. also add concurrent r/w
and multiple directories cases.

Also extract most of its basic funcs to inline-dirs-utils.c for public use.

Specially,to maintain the synchronization of entries list among multiple processes during directory test,we introduce the shared memory and semaphore,let me know if there is a more graceful solution.

Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
---
 programs/inline-data/inline-dirs.c | 1036 +++++++++++++++++++-----------------
 1 files changed, 547 insertions(+), 489 deletions(-)

diff --git a/programs/inline-data/inline-dirs.c b/programs/inline-data/inline-dirs.c
index df9c1b6..d7a4510 100644
--- a/programs/inline-data/inline-dirs.c
+++ b/programs/inline-data/inline-dirs.c
@@ -1,23 +1,42 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * single-inline-dirs.c
+ *
  * Verify inline directory data.
  *
  * All tests read back the entire directory to verify correctness.
  *
  * XXX: This could easily be turned into an mpi program, where a
  * second node does the verification step.
+ *
+ * Copyright (C) 2008 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 _XOPEN_SOURCE 600
+#define _GNU_SOURCE
 
-#include <asm/types.h>
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/vfs.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <limits.h>
 
+#include <ocfs2/ocfs2.h>
+
 #include <dirent.h>
 
 #include <stddef.h>
@@ -26,74 +45,18 @@
 #include <errno.h>
 #include <string.h>
 
-#define OCFS2_MAX_FILENAME_LEN		255
+#include <signal.h>
+#include <sys/wait.h>
+#include <inttypes.h>
+#include <linux/types.h>
 
-/*
- * OCFS2_DIR_PAD defines the directory entries boundaries
- *
- * NOTE: It must be a multiple of 4
- */
-#define OCFS2_DIR_PAD			4
-#define OCFS2_DIR_ROUND			(OCFS2_DIR_PAD - 1)
-#define OCFS2_DIR_MEMBER_LEN 		offsetof(struct ocfs2_dir_entry, name)
-#define OCFS2_DIR_REC_LEN(name_len)	(((name_len) + OCFS2_DIR_MEMBER_LEN + \
-                                          OCFS2_DIR_ROUND) & \
-					 ~OCFS2_DIR_ROUND)
-
-/*
- * Quick reference table of namelen boundaries and their respective reclens.
- *
- * (name: 1  rec: 16)      (name: 5  rec: 20)      (name: 9  rec: 24)
- * (name: 13  rec: 28)     (name: 17  rec: 32)     (name: 21  rec: 36)
- * (name: 25  rec: 40)     (name: 29  rec: 44)     (name: 33  rec: 48)
- * (name: 37  rec: 52)     (name: 41  rec: 56)     (name: 45  rec: 60)
- * (name: 49  rec: 64)     (name: 53  rec: 68)     (name: 57  rec: 72)
- * (name: 61  rec: 76)     (name: 65  rec: 80)     (name: 69  rec: 84)
- * (name: 73  rec: 88)     (name: 77  rec: 92)     (name: 81  rec: 96)
- * (name: 85  rec: 100)    (name: 89  rec: 104)    (name: 93  rec: 108)
- * (name: 97  rec: 112)    (name: 101  rec: 116)   (name: 105  rec: 120)
- * (name: 109  rec: 124)   (name: 113  rec: 128)   (name: 117  rec: 132)
- * (name: 121  rec: 136)   (name: 125  rec: 140)   (name: 129  rec: 144)
- * (name: 133  rec: 148)   (name: 137  rec: 152)   (name: 141  rec: 156)
- * (name: 145  rec: 160)   (name: 149  rec: 164)   (name: 153  rec: 168)
- * (name: 157  rec: 172)   (name: 161  rec: 176)   (name: 165  rec: 180)
- * (name: 169  rec: 184)   (name: 173  rec: 188)   (name: 177  rec: 192)
- * (name: 181  rec: 196)   (name: 185  rec: 200)   (name: 189  rec: 204)
- * (name: 193  rec: 208)   (name: 197  rec: 212)   (name: 201  rec: 216)
- * (name: 205  rec: 220)   (name: 209  rec: 224)   (name: 213  rec: 228)
- * (name: 217  rec: 232)   (name: 221  rec: 236)   (name: 225  rec: 240)
- * (name: 229  rec: 244)   (name: 233  rec: 248)   (name: 237  rec: 252)
- * (name: 241  rec: 256)   (name: 245  rec: 260)   (name: 249  rec: 264)
- * (name: 253  rec: 268)
- */
 
-/*
- * OCFS2 directory file types.  Only the low 3 bits are used.  The
- * other bits are reserved for now.
- */
-#define OCFS2_FT_UNKNOWN	0
-#define OCFS2_FT_REG_FILE	1
-#define OCFS2_FT_DIR		2
-#define OCFS2_FT_CHRDEV		3
-#define OCFS2_FT_BLKDEV		4
-#define OCFS2_FT_FIFO		5
-#define OCFS2_FT_SOCK		6
-#define OCFS2_FT_SYMLINK	7
-
-#define OCFS2_FT_MAX		8
-
-
-#define S_SHIFT			12
-
-struct ocfs2_dir_entry {
-/*00*/	__u64   inode;                  /* Inode number */
-	__u16   rec_len;                /* Directory entry length */
-	__u8    name_len;               /* Name length */
-	__u8    file_type;
-/*0C*/	char    name[OCFS2_MAX_FILENAME_LEN];   /* File name */
-/* Actual on-disk length specified by rec_len */
-} __attribute__ ((packed));
+#define OCFS2_MAX_FILENAME_LEN		255
+#define WORK_PLACE      		"inline-data-test"
+#define MAX_DIRENTS			1024
 
+#define FILE_MODE		(S_IRUSR|S_IWUSR|S_IXUSR|S_IROTH|\
+				 S_IWOTH|S_IXOTH|S_IRGRP|S_IWGRP|S_IXGRP)
 
 struct my_dirent {
 	unsigned int	type;
@@ -102,422 +65,137 @@ struct my_dirent {
 	char		name[OCFS2_MAX_FILENAME_LEN];
 };
 
-#define MAX_DIRENTS	1024
-struct my_dirent dirents[MAX_DIRENTS];
-static unsigned int num_dirents = 0;
-
-static unsigned int max_inline_size;
-unsigned int usable_space;
-
-static unsigned int blocksize;
-static char *dir_name;
-static char path[PATH_MAX];
-static char path1[PATH_MAX];
-
-static int testno = 1;
-
-static unsigned long get_rand(unsigned long min, unsigned long max)
-{
-	if (min == 0 && max == 0)
-		return 0;
-
-	return min + ((rand() % max) - min);
-}
-
-static inline char rand_char(void)
-{
-	return 'A' + (char) get_rand(0, 52);
-}
-
-static void usage(void)
-{
-	printf("Usage: inline-dirs [blocksize] [DIRECTORY]\n"
-	       "Run a series of tests intended to verify I/O to and from\n"
-	       "files with inline data.\n\n"
-	       "blocksize is the blocksize of the underlying file system and\n"
-	       "must be specified.\n"
-	       "DIRECTORY is the name of a directory which will created and\n"
-	       "be used for testing.\n");
-}
-
-static int parse_opts(int argc, char **argv)
-{
-	if (argc < 3)
-		return 1;
-
-	blocksize = atoi(argv[1]);
-	dir_name = argv[2];
-
-	switch (blocksize) {
-	case 4096:
-		max_inline_size = 3896;
-		break;
-	case 2048:
-		max_inline_size = 1848;
-		break;
-	case 1024:
-		max_inline_size = 824;
-		break;
-	case 512:
-		max_inline_size = 312;
-		break;
-	default:
-		fprintf(stderr, "Invalid blocksize, %u\n", blocksize);
-		return 1;
-	}
-
-	usable_space = max_inline_size;
-	usable_space -= OCFS2_DIR_REC_LEN(1) + OCFS2_DIR_REC_LEN(2);
-
-	printf("Blocksize:\t\t%d\nMax Inline Data Size:\t%d\nDir Name:\t\t%s\n"
-	       "Usable Dir Space:\t%d\n",
-	       blocksize, max_inline_size, dir_name, usable_space);
-
-	return 0;
-}
-
-static int is_dot_entry(struct my_dirent *dirent)
-{
-	if (dirent->name_len == 1 && dirent->name[0] == '.')
-		return 1;
-	if (dirent->name_len == 2 && dirent->name[0] == '.'
-	    && dirent->name[1] == '.')
-		return 1;
-	return 0;
-}
-
-static int unlink_dirent(struct my_dirent *dirent)
-{
-	sprintf(path1, "%s/%s", dir_name, dirent->name);
-
-	return unlink(path1);
-}
-
-static void destroy_dir(void)
-{
-	int ret, i;
-	struct my_dirent *dirent;
-
-	for(i = 0; i < num_dirents; i++) {
-		dirent = &dirents[i];
-
-		if (dirent->name_len == 0)
-			continue;
-
-		if (!is_dot_entry(dirent)) {
-			ret = unlink_dirent(dirent);
-			if (ret) {
-				ret = errno;
-				fprintf(stderr, "unlink failure %d: %s\n", ret,
-					strerror(ret));
-				exit(ret);
-			}
-		}
-
-		dirent->name_len = 0;
-	}
-
-	ret = rmdir(dir_name);
-	if (ret) {
-		ret = errno;
-		fprintf(stderr, "rmdir failure %d: %s\n", ret,
-			strerror(ret));
-		exit(ret);
-	}
-}
-
-static struct my_dirent *find_my_dirent(char *name)
-{
-	int i, len;
-	struct my_dirent *my_dirent;
-
-	len = strlen(name);
-
-	for(i = 0; i < num_dirents; i++) {
-		my_dirent = &dirents[i];
-
-		if (my_dirent->name_len == 0)
-			continue;
-
-		if (my_dirent->name_len == len &&
-		    strcmp(my_dirent->name, name) == 0)
-			return my_dirent;
-	}
-
-	return NULL;
-}
-
-static void create_and_prep_dir(void)
-{
-	int ret;
-	struct my_dirent *dirent;
+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 */
+};
 
-	memset(dirents, 0, sizeof(dirents));
+static char *prog;
+static char device[100];
 
-	dirent = &dirents[0];
-	dirent->type = S_IFDIR >> S_SHIFT;
-	dirent->name_len = 1;
-	strcpy(dirent->name, ".");
+ocfs2_filesys *fs;
+struct ocfs2_super_block *ocfs2_sb;
 
-	dirent = &dirents[1];
-	dirent->type = S_IFDIR >> S_SHIFT;
-	dirent->name_len = 2;
-	strcpy(dirent->name, "..");
+static unsigned long page_size;
+unsigned int blocksize = 4096;
+unsigned long clustersize;
+unsigned int max_inline_size;
 
-	num_dirents = 2;
+unsigned int id_count;
+unsigned long i_size;
 
-	ret = mkdir(dir_name, 0755);
-	if (ret) {
-		ret = errno;
-		fprintf(stderr, "mkdir failure %d: %s\n", ret, strerror(ret));
-		exit(ret);
-	}
-}
+char mount_point[OCFS2_MAX_FILENAME_LEN];
+char work_place[OCFS2_MAX_FILENAME_LEN];
+char dirent_name[OCFS2_MAX_FILENAME_LEN];
+char dir_name[OCFS2_MAX_FILENAME_LEN];
 
-static void create_file(char *filename)
-{
-	int ret, fd;
-	struct my_dirent *dirent;
+static int iteration = 1;
+static int do_multi_process_test;
+static int do_multi_file_test;
+static unsigned long child_nums = 2;
+static unsigned long file_nums = 2;
+unsigned int operated_entries = 20;
 
-	dirent = &dirents[num_dirents];
-	num_dirents++;
+pid_t *child_pid_list;
 
-	dirent->type = S_IFREG >> S_SHIFT;
-	dirent->name_len = strlen(filename);
-	dirent->seen = 0;
-	strcpy(dirent->name, filename);
+int shm_id;
+int sem_id;
 
-	sprintf(path, "%s/%s", dir_name, dirent->name);
+struct my_dirent *dirents;
+unsigned int num_dirents;
 
-	fd = open(path, O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
-	if (fd == -1) {
-		ret = errno;
-		fprintf(stderr, "open failure %d: %s\n", ret, strerror(ret));
-		exit(ret);
-	}
+char path[PATH_MAX];
+char path1[PATH_MAX];
 
-	close(fd);
-}
-
-static void create_files(char *prefix, int num)
-{
-	int i;
-
-	for (i = 0; i < num; i++) {
-		sprintf(path1, "%s%011d", prefix, i);
-		create_file(path1);
-	}
-}
+static int testno = 1;
 
-static void get_directory_almost_full(int minus_this_many)
-{
-	unsigned int almost_full_entries;
-
-	/*
-	 * This will create enough entries to leave only 280 free
-	 * bytes in the directory.
-	 *
-	 * max_inline_size % 512 = 312    [always]
-	 * rec overhead for '.' and '..' = 32
-	 * So, 312 - 32 = 280.
-	 *
-	 */
-	almost_full_entries = max_inline_size / 512;
-	almost_full_entries *= 512;
-	almost_full_entries /= 32;
-
-	/*
-	 * Now we add enough 32 byte entries to fill that remaining 280 bytes:
-	 *
-	 * 280 / 32 = 8
-	 *
-	 * And we'll be left over with 24 bytes:
-	 *
-	 * 280 % 32 = 24
-	 *
-	 * Which can easily be overflowed by adding one more 32 byte entry.
-	 */
-	almost_full_entries += 8;
-	almost_full_entries -= minus_this_many;
-
-	/* Need up to 20 characters to get a 32 byte entry */
-	create_files("filename-", almost_full_entries);
-}
+extern unsigned long get_rand(unsigned long min, unsigned long max);
+extern inline char rand_char(void);
+extern int is_dot_entry(struct my_dirent *dirent);
+extern int unlink_dirent(struct my_dirent *dirent);
+extern void destroy_dir(void);
+extern struct my_dirent *find_my_dirent(char *name);
+extern void create_and_prep_dir(void);
+extern void create_file(char *filename);
+extern void create_files(char *prefix, int num);
+extern int get_max_inlined_entries(int max_inline_size);
+extern void get_directory_almost_full(int minus_this_many);
+extern void random_unlink(int iters);
+extern void random_fill_empty_entries(int iters);
+extern void random_rename_same_reclen(int iters);
+extern void random_deleting_rename(int iters);
+extern void verify_dirents(void);
+extern int is_dir_inlined(char *dirent_name, unsigned long *i_size,
+			  unsigned int *id_count);
+extern void should_inlined_or_not(int is_inlined, int should_inlined,
+				  int test_no);
+extern int open_ocfs2_volume(char *device_name);
 
-static void random_unlink(int iters)
+static void usage(void)
 {
-	int i, ret;
-	struct my_dirent *dirent;
-
-	while (iters--) {
-		i = get_rand(0, num_dirents);
-		if (i >= num_dirents)
-			abort();
-		dirent = &dirents[i];
-
-		if (is_dot_entry(dirent))
-			continue;
-		if (dirent->name_len == 0)
-			continue;
-
-		ret = unlink_dirent(dirent);
-		if (ret) {
-			ret = errno;
-			fprintf(stderr, "unlink failure %d: %s\n", ret,
-				strerror(ret));
-			exit(ret);
-		}
-
-		dirent->name_len = 0;
-	}
-}
+	printf("Usage: inline-dirs [-i <iteration>] [-s operated_entries] "
+	       "[-c <concurrent_process_num>] [-m <multi_file_num>] "
+	       "<-d <device>> <mount_point>\n"
+	       "Run a series of tests intended to verify I/O to and from\n"
+	       "dirs with inline data.\n\n"
+	       "iteration specify the running times.\n"
+	       "operated_dir_entries specify the entires number to be "
+	       "operated,such as random create/unlink/rename.\n"
+	       "concurrent_process_num specify the number of concurrent "
+	       "multi_file_num specify the number of multiple dirs"
+	       "processes to perform inline-data read/rename.\n"
+	       "device and mount_point are mandatory.\n");
+	exit(1);
 
-static void random_rename_same_reclen(int iters)
-{
-	int i, ret;
-	struct my_dirent *dirent;
-
-	while (iters--) {
-		i = get_rand(0, num_dirents);
-		if (i >= num_dirents)
-			abort();
-		dirent = &dirents[i];
-
-		if (is_dot_entry(dirent))
-			continue;
-		if (dirent->name_len == 0)
-			continue;
-
-		/*
-		 * We already renamed this one
-		 */
-		if (dirent->name[0] == 'R')
-			continue;
-
-		strcpy(path, dirent->name);
-		path[0] = 'R';
-		sprintf(path1, "%s/%s", dir_name, path);
-		sprintf(path, "%s/%s", dir_name, dirent->name);
-
-		ret = rename(path, path1);
-		if (ret) {
-			ret = errno;
-			fprintf(stderr, "rename failure %d: %s\n", ret,
-				strerror(ret));
-
-			fprintf(stderr, "Failed rename from %s to %s\n",
-				path, path1);
-
-			exit(ret);
-		}
-		dirent->name[0] = 'R';
-	}
 }
 
-static void random_deleting_rename(int iters)
+static int parse_opts(int argc, char **argv)
 {
-	int i, j, ret;
-	struct my_dirent *dirent1, *dirent2;
-
-	while (iters--) {
-		i = get_rand(0, num_dirents);
-		if (i >= num_dirents)
-			abort();
-		j = get_rand(0, num_dirents);
-		if (j >= num_dirents)
-			abort();
-		dirent1 = &dirents[i];
-		dirent2 = &dirents[j];
-
-		if (dirent1 == dirent2)
-			continue;
-		if (is_dot_entry(dirent1) || is_dot_entry(dirent2))
-			continue;
-		if (dirent1->name_len == 0 || dirent2->name_len == 0)
-			continue;
-
-		sprintf(path, "%s/%s", dir_name, dirent1->name);
-		sprintf(path1, "%s/%s", dir_name, dirent2->name);
-
-		ret = rename(path, path1);
-		if (ret) {
-			ret = errno;
-			fprintf(stderr, "rename failure %d: %s\n", ret,
-				strerror(ret));
-
-			fprintf(stderr, "Failed rename from %s to %s\n",
-				path, path1);
-
-			exit(ret);
+	int c;
+	while (1) {
+		c = getopt(argc, argv, "D:d:I:i:C:c:M:m:S:s:");
+		if (c == -1)
+			break;
+		switch (c) {
+		case 'i':
+		case 'I':
+			iteration = atol(optarg);
+			break;
+		case 'd':
+		case 'D':
+			strcpy(device, optarg);
+			break;
+		case 'c':
+		case 'C':
+			do_multi_process_test = 1;
+			child_nums = atol(optarg);
+			break;
+		case 'm':
+		case 'M':
+			do_multi_file_test = 1;
+			file_nums = atol(optarg);
+			break;
+		case 's':
+		case 'S':
+			operated_entries = atol(optarg);
+		default:
+			break;
 		}
-		dirent2->type = dirent1->type;
-		dirent1->name_len = 0;
-	}
-}
-
-static void verify_dirents(void)
-{
-	int i, ret;
-	DIR *dir;
-	struct dirent *dirent;
-	struct my_dirent *my_dirent;
-
-	dir = opendir(dir_name);
-	if (dir == NULL) {
-		ret = errno;
-		fprintf(stderr, "opendir failure %d: %s\n", ret, strerror(ret));
-		exit(ret);
 	}
 
-	dirent = readdir(dir);
-	while (dirent) {
-		my_dirent = find_my_dirent(dirent->d_name);
-		if (!my_dirent) {
-			fprintf(stderr, "Verify failure: got nonexistent "
-				"dirent: (ino %lu, reclen: %u, type: %u, "
-				"name: %s)\n",
-				dirent->d_ino, dirent->d_reclen,
-				dirent->d_type, dirent->d_name);
-			exit(1);
-		}
-
-		if (my_dirent->type != dirent->d_type) {
-			fprintf(stderr, "Verify failure: bad dirent type: "
-				"memory: (type: %u, name_len: %u, name: %s), "
-				"kernel: (ino %lu, reclen: %u, type: %u, "
-				"name: %s)\n",
-				my_dirent->type, my_dirent->name_len,
-				my_dirent->name, dirent->d_ino,
-				dirent->d_reclen, dirent->d_type,
-				dirent->d_name);
-			exit(1);
-		}
-
-		if (my_dirent->seen) {
-			fprintf(stderr, "Verify failure: duplicate dirent: "
-				"(type: %u, name_len: %u, name: %s)\n",
-				my_dirent->type, my_dirent->name_len,
-				my_dirent->name);
-			exit(1);
-		}
-
-		my_dirent->seen++;
-
-		dirent = readdir(dir);
-	}
+	if (strcmp(device, "") == 0)
+		return EINVAL;
 
-	for (i = 0; i < num_dirents; i++) {
-		my_dirent = &dirents[i];
+	if (argc - optind != 1)
+		return EINVAL;
 
-		if (my_dirent->seen != 0 || my_dirent->name_len == 0)
-			continue;
+	strcpy(mount_point, argv[optind]);
+	if (mount_point[strlen(mount_point) - 1] == '/')
+		mount_point[strlen(mount_point) - 1] = '\0';
 
-		fprintf(stderr, "Verify failure: missing dirent: "
-			"(type: %u, name_len: %u, name: %s)\n", my_dirent->type,
-			my_dirent->name_len, my_dirent->name);
-		exit(1);
-	}
-	closedir(dir);
+	return 0;
 }
 
 /*
@@ -529,10 +207,21 @@ static void verify_dirents(void)
  */
 static void run_basic_tests(void)
 {
+	int ret;
+
 	printf("Test %d: fill directory\n", testno);
 	create_and_prep_dir();
 	get_directory_almost_full(0);
 	verify_dirents();
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 1, testno);
+	testno++;
+
+	printf("Test %d: expand inlined dir to extent exactly\n", testno);
+	/*Should be 13 bits len dirent_name*/
+	create_file("Iam13bitshere");
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 0, testno);
 	testno++;
 
 	printf("Test %d: remove directory\n", testno);
@@ -542,16 +231,32 @@ static void run_basic_tests(void)
 	printf("Test %d: rename files with same namelen\n", testno);
 	create_and_prep_dir();
 	get_directory_almost_full(1);
-	random_rename_same_reclen(20);
+	random_rename_same_reclen(operated_entries);
 	verify_dirents();
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 1, testno);
 	destroy_dir();
 	testno++;
 
-	printf("Test %d: rename files with same namelen on top of each other\n", testno);
+	printf("Test %d: rename files with same namelen on top of each other\n",
+	       testno);
 	create_and_prep_dir();
 	get_directory_almost_full(1);
-	random_deleting_rename(20);
+	random_deleting_rename(operated_entries);
+	verify_dirents();
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 1, testno);
+	destroy_dir();
+	testno++;
+
+	printf("Test %d: random unlink/fill entries.\n", testno);
+	create_and_prep_dir();
+	get_directory_almost_full(0);
+	random_unlink(operated_entries);
+	random_fill_empty_entries(operated_entries);
 	verify_dirents();
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 1, testno);
 	destroy_dir();
 	testno++;
 
@@ -559,9 +264,11 @@ static void run_basic_tests(void)
 	       testno);
 	create_and_prep_dir();
 	get_directory_almost_full(1);
-	random_unlink(20);
-	random_rename_same_reclen(20);
+	random_unlink(operated_entries / 2);
+	random_rename_same_reclen(operated_entries / 2);
 	verify_dirents();
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 1, testno);
 	destroy_dir();
 	testno++;
 
@@ -569,14 +276,14 @@ static void run_basic_tests(void)
 	       testno);
 	create_and_prep_dir();
 	get_directory_almost_full(1);
-	random_unlink(20);
-	random_rename_same_reclen(20);
-	create_files("frag1a", 20);
-	random_unlink(20);
-	create_files("frag1b", 20);
-	random_deleting_rename(20);
-	random_rename_same_reclen(20);
-	create_files("frag1c", 20);
+	random_unlink(operated_entries / 2);
+	random_rename_same_reclen(operated_entries / 2);
+	create_files("frag1a", operated_entries / 2);
+	random_unlink(operated_entries / 2);
+	create_files("frag1b", operated_entries / 2);
+	random_deleting_rename(operated_entries / 2);
+	random_rename_same_reclen(operated_entries / 2);
+	create_files("frag1c", operated_entries / 2);
 	verify_dirents();
 	destroy_dir();
 	testno++;
@@ -590,19 +297,40 @@ static void run_basic_tests(void)
  */
 static void run_large_dir_tests(void)
 {
-	printf("Test %d: Add file name large enough to push out one block\n", testno);
+	int ret;
+
+	printf("Test %d: Add file name large enough to push out one block\n",
+	       testno);
 	create_and_prep_dir();
 	get_directory_almost_full(0);
 	create_files("Pushedfn-", 1);
 	verify_dirents();
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 0, testno);
+	/*verify i_size should be one block size here*/
+	if (i_size != blocksize) {
+		fprintf(stderr, "i_size should be %d,while it's % here!\n",
+			blocksize, i_size);
+	}
 	destroy_dir();
 	testno++;
 
-	printf("Test %d: Add file name large enough to push out two blocks\n", testno);
+	printf("Test %d: Add file name large enough to push out two blocks\n",
+	       testno);
 	create_and_prep_dir();
 	get_directory_almost_full(0);
-	create_files("this_is_an_intentionally_long_filename_prefix_to_stress_the_dir_code-this_is_an_intentionally_long_filename_prefix_to_stress_the_dir_code-this_is_an_intentionally_long_filename_prefix_to_stress_the_dir_code", 1);
+	create_files("this_is_an_intentionally_long_filename_prefix_to_stress"
+		     "_the_dir_code-this_is_an_intentionally_long_filename_pr"
+		     "efix_to_stress_the_dir_code-this_is_an_intentionally_lo"
+		     "ng_filename_prefix_to_stress_the_dir_code", 1);
 	verify_dirents();
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 0, testno);
+	/*verify i_size should be one block size here*/
+	if (i_size != blocksize * 2) {
+		fprintf(stderr, "i_size should be %d,while it's % here!\n",
+			blocksize * 2, i_size);
+	}
 	destroy_dir();
 	testno++;
 
@@ -610,33 +338,363 @@ static void run_large_dir_tests(void)
 	       testno);
 	create_and_prep_dir();
 	get_directory_almost_full(1);
-	random_unlink(20);
-	random_rename_same_reclen(20);
-	create_files("frag2a", 20);
-	random_unlink(20);
-	create_files("frag2b", 20);
-	random_deleting_rename(20);
-	random_rename_same_reclen(20);
-	create_files("frag2c", 30);
+	random_unlink(operated_entries / 2);
+	random_rename_same_reclen(operated_entries / 2);
+	create_files("frag2a", operated_entries / 2);
+	random_unlink(operated_entries / 2);
+	create_files("frag2b", operated_entries / 2);
+	random_deleting_rename(operated_entries / 2);
+	random_rename_same_reclen(operated_entries / 2);
+	create_files("frag2c", operated_entries / 2 + 1);
+	create_files("frag2d", operated_entries / 2 + 1);
 	verify_dirents();
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 0, testno);
 	destroy_dir();
 	testno++;
 }
 
-int main(int argc, char **argv)
+static void sigchld_handler()
+{
+	pid_t pid;
+	union wait status;
+
+	while (1) {
+		pid = wait3(&status, WNOHANG, NULL);
+		if (pid <= 0)
+			break;
+	}
+}
+
+static void kill_all_children()
+{
+	int i;
+	int process_nums;
+
+	if (do_multi_process_test)
+		process_nums = child_nums;
+	else
+		process_nums = file_nums;
+
+	for (i = 0; i < process_nums; i++)
+		kill(child_pid_list[i], SIGTERM);
+
+	free(child_pid_list);
+}
+
+static void sigint_handler()
+{
+	kill_all_children();
+
+	signal(SIGINT, SIG_DFL);
+	kill(getpid(), SIGINT);
+
+}
+
+static void sigterm_handler()
+{
+	kill_all_children();
+
+	signal(SIGTERM, SIG_DFL);
+	kill(getpid(), SIGTERM);
+
+}
+
+static int set_semvalue(void)
+{
+	union semun sem_union;
+
+	sem_union.val = 1;
+	if (semctl(sem_id, 0, SETVAL, sem_union) == -1) {
+		perror("semctl");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int semaphore_p(void)
+{
+	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;
+}
+
+static int semaphore_v(void)
+{
+	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;
+}
+
+static void del_semvalue(void)
+{
+	union semun sem_union;
+
+	if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
+		fprintf(stderr, "Failed to delete semaphore\n");
+}
+
+static void run_concurrent_test(void)
+{
+	int ret, rc;
+	int i, j, status;
+	struct my_dirent *old_dirents;
+	key_t sem_key = IPC_PRIVATE, shm_key = IPC_PRIVATE;
+
+	pid_t pid;
+
+	if (!do_multi_process_test)
+		return;
+
+	printf("Test %d: concurrent dir RW with multiple processes!\n", testno);
+	create_and_prep_dir();
+	get_directory_almost_full(1);
+
+	/*get and init semaphore*/
+	sem_id = semget(sem_key, 1, 0766 | IPC_CREAT);
+	if (set_semvalue() < 0) {
+		fprintf(stderr, "Set semaphore value failed!\n");
+		exit(1);
+	}
+
+	/*should use shared memory here */
+	old_dirents = dirents;
+	dirents = NULL;
+
+	shm_id = shmget(shm_key, sizeof(struct my_dirent) * MAX_DIRENTS,
+			IPC_CREAT | 0766);
+	if (shm_id < 0) {
+		perror("shmget");
+		exit(1);
+	}
+
+	dirents = (struct my_dirent *)shmat(shm_id, 0, 0);
+	if (dirents < 0) {
+		perror("shmat");
+		exit(1);
+	}
+
+	shmctl(shm_id, IPC_RMID, 0);
+	memmove(dirents, old_dirents, sizeof(struct my_dirent) * MAX_DIRENTS);
+
+	/*flush out the father's i/o buffer*/
+	fflush(stderr);
+	fflush(stdout);
+
+	signal(SIGCHLD, sigchld_handler);
+
+	for (i = 0; i < child_nums; i++) {
+		pid = fork();
+		if (pid < 0) {
+			fprintf(stderr, "Fork process error!\n");
+			exit(pid);
+		}
+		if (pid == 0) {
+			if (semaphore_p() < 0)
+				exit(-1);
+			/*Concurrent rename for dirents*/
+			random_rename_same_reclen(operated_entries);
+			if (semaphore_v() < 0)
+				exit(-1);
+			/*child exits normally*/
+			sleep(1);
+			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);
+			exit(rc);
+		}
+	}
+	/*father help to verfiy dirents' consistency*/
+	sleep(2);
+	verify_dirents();
+
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 1, testno);
+	destroy_dir();
+
+	/*detach shared memory*/
+	if (shmdt(dirents) == -1) {
+		perror("shmdt");
+		 exit(1);
+	}
+
+	dirents = old_dirents;
+	testno++;
+
+	return;
+}
+
+static void run_multiple_test(void)
+{
+	int i, j, status;
+
+	pid_t pid;
+	int ret, rc;
+
+	if (!do_multi_file_test)
+		return;
+
+	printf("Test %d: multiple dirs RW with multiple processes!\n", testno);
+
+	fflush(stderr);
+	fflush(stdout);
+
+	signal(SIGCHLD, sigchld_handler);
+
+	for (i = 0; i < file_nums; i++) {
+		pid = fork();
+		if (pid < 0) {
+			fprintf(stderr, "Fork process error!\n");
+			exit(pid);
+		}
+		if (pid == 0) {
+			snprintf(dirent_name, OCFS2_MAX_FILENAME_LEN,
+				 "inline-data-dir-test-%d", getpid());
+			snprintf(dir_name, OCFS2_MAX_FILENAME_LEN, "%s/%s",
+				 work_place, dirent_name);
+			create_and_prep_dir();
+			get_directory_almost_full(1);
+			random_rename_same_reclen(operated_entries);
+			random_unlink(operated_entries);
+			random_fill_empty_entries(operated_entries);
+			verify_dirents();
+			sync();
+			sleep(1);
+			ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+			should_inlined_or_not(ret, 1, testno);
+			destroy_dir();
+			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 < file_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);
+			exit(rc);
+		}
+	}
+
+	testno++;
+	return;
+}
+
+static void setup(int argc, char *argv[])
 {
-	if (parse_opts(argc, argv)) {
+	int ret;
+
+	prog = strrchr(argv[0], '/');
+	if (prog == NULL)
+		prog = argv[0];
+	else
+		prog++;
+
+	if (parse_opts(argc, argv))
 		usage();
-		return EINVAL;
+
+	ret = open_ocfs2_volume(device);
+	if (ret < 0) {
+		fprintf(stderr, "Open_ocfs2_volume failed!\n");
+		exit(ret);
 	}
 
+	if (do_multi_process_test)
+		child_pid_list = (pid_t *)malloc(sizeof(pid_t) * child_nums);
+	if (do_multi_file_test)
+		child_pid_list = (pid_t *)malloc(sizeof(pid_t) * file_nums);
+
+	dirents = (struct my_dirent *)malloc(sizeof(struct my_dirent) *
+					     MAX_DIRENTS);
+	memset(dirents, 0, sizeof(struct my_dirent) * MAX_DIRENTS);
+
 	srand(getpid());
+	page_size = sysconf(_SC_PAGESIZE);
+
+	snprintf(work_place, OCFS2_MAX_FILENAME_LEN, "%s/%s", mount_point,
+		 WORK_PLACE);
+	mkdir(work_place, FILE_MODE);
 
-	run_basic_tests();
+	snprintf(dirent_name, 255, "inline-data-dir-test");
+	snprintf(dir_name, 255, "%s/%s", work_place, dirent_name);
 
-	run_large_dir_tests();
+	printf("BlockSize:\t\t%d\nMax Inline Data Size:\t%d\n"
+	       "ClusterSize:\t\t%d\nPageSize:\t\t%d\nWorkingPlace:\t\t%s\n"
+	       "NumOfMaxInlinedEntries:\t\t%d\n\n", blocksize, max_inline_size,
+	       clustersize, page_size, work_place,
+	       get_max_inlined_entries(max_inline_size));
+
+	return;
+
+}
+
+static void teardown(void)
+{
+	if (dirents)
+		free(dirents);
+
+	if (child_pid_list)
+		free(child_pid_list);
+}
+
+int main(int argc, char **argv)
+{
+	int i;
+
+	setup(argc, argv);
+
+	for (i = 0; i < iteration; i++) {
+
+		printf("################Test Round %d################\n", i);
+		testno = 1;
+		run_basic_tests();
+		run_large_dir_tests();
+		run_multiple_test();
+		run_concurrent_test();
+		printf("All File I/O Tests Passed\n");
+
+	}
 
-	printf("All File I/O Tests Passed\n");
+	teardown();
 
 	return 0;
 }
-- 
1.5.5




More information about the Ocfs2-tools-devel mailing list