[Ocfs2-tools-devel] [Ocfs2-test-devel] [PATCH 5/6] New set of inline-data testing tools:Add multiple-node MPI testing binary for directory.

tristan.ye tristan.ye at oracle.com
Sat Aug 30 03:39:14 PDT 2008


like multiple-inline-data.c,It was also created on the basis of existing
inline-data.c by injecting the MPI apis to make it runable among
multiple nodes,Most of the testcases inside were similiar to original
inline-data.c.

Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
---

Index: ocfs2-test/programs/inline-data/multiple-inline-dirs.c
===================================================================
--- ocfs2-test/programs/inline-data/multiple-inline-dirs.c	(revision 0)
+++ ocfs2-test/programs/inline-data/multiple-inline-dirs.c	(revision 0)
@@ -0,0 +1,1312 @@
+/*
+ * XXX: A mpi program to verify inline directory data 
+ * concurently among multiple nodes.
+ *
+ * All tests read back the entire directory to verify correctness.
+ *
+ */
+
+#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>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <signal.h>
+#include <sys/wait.h>
+#include <inttypes.h>
+#include <linux/types.h>
+
+#include <mpi.h>
+
+#define OCFS2_MAX_FILENAME_LEN		255
+#define HOSTNAME_MAX_SZ			255
+
+/*
+ * 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)
+
+#define FILE_BUFFERED_RW_FLAGS  	(O_CREAT|O_RDWR|O_TRUNC)
+#define FILE_MODE               	(S_IRUSR|S_IWUSR|S_IXUSR|S_IROTH|\
+                                	S_IWOTH|S_IXOTH|S_IRGRP|S_IWGRP|
S_IXGRP)
+
+/*
+ * 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 my_dirent {
+	unsigned int	type;
+	unsigned int	name_len;
+	unsigned int	seen;
+	char		name[OCFS2_MAX_FILENAME_LEN];
+};
+
+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 */
+};
+
+#define WORK_PLACE      "multiple-inline-data-test"
+static char *prog;
+static char device[100];
+
+static ocfs2_filesys *fs = NULL;
+static struct ocfs2_super_block *ocfs2_sb = NULL;
+
+static unsigned long page_size;
+static unsigned int blocksize = 4096;
+static unsigned long clustersize;
+
+unsigned int id_count;
+unsigned long i_size;
+
+static char mount_point[255];
+static char work_place[255];
+static char dirent_name[255];
+static char dir_name[255];
+
+static int iteration = 1;
+static unsigned int operated_entries = 20;
+
+#define MAX_DIRENTS	1024
+struct my_dirent *dirents = NULL;
+static unsigned int num_dirents = 0;
+
+static unsigned int max_inline_size;
+unsigned int usable_space;
+
+static char path[PATH_MAX];
+static char path1[PATH_MAX];
+
+static int testno = 1;
+
+static int rank = -1, size;
+static char hostname[HOSTNAME_MAX_SZ];
+
+static unsigned long get_rand(unsigned long min, unsigned long max)
+{
+	if (min == 0 && max == 0)
+		return 0;
+
+	return min + (rand() % (max - min + 1));
+}
+
+static inline char rand_char(void)
+{
+	return 'A' + (char) get_rand(0, 25);
+}
+
+static void usage(void)
+{
+	printf("Usage: inline-dirs [-i <iteration>] [-s operated_entries] "
+               "<-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"
+               "device and mount_point are mandatory.\n");
+
+	MPI_Finalize();
+        exit(1);
+}
+
+static void abort_printf(const char *fmt, ...)
+{
+	va_list ap;
+	
+	printf("%s (rank %d): ", hostname, rank);
+	va_start(ap, fmt);
+	vprintf(fmt, ap);
+
+	MPI_Abort(MPI_COMM_WORLD, 1);
+}
+
+static void root_printf(const char *fmt, ...)
+{
+	va_list ap;
+
+	if (rank == 0) {
+		va_start(ap, fmt);
+		vprintf(fmt, ap);
+	}
+}
+
+static int parse_opts(int argc, char **argv)
+{
+	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 's':
+		case 'S':
+			operated_entries = atol(optarg);
+		default:
+			break;
+		}
+	}
+
+	if (strcmp(device, "") == 0)
+		return EINVAL;
+
+	if (argc - optind != 1)
+		return EINVAL;
+
+	strcpy(mount_point, argv[optind]);
+	if (mount_point[strlen(mount_point) - 1] == '/')
+		mount_point[strlen(mount_point) - 1] = '\0';
+
+	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;
+				abort_printf("unlink failure %d: %s\n", ret,
+					      strerror(ret));
+			}
+		}
+
+		dirent->name_len = 0;
+	}
+
+	ret = rmdir(dir_name);
+	if (ret) {
+		ret = errno;
+		abort_printf("rmdir failure %d: %s\n", ret,
+			     strerror(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;
+
+	memset(dirents, 0, sizeof(struct my_dirent) * MAX_DIRENTS);
+
+	dirent = &dirents[0];
+	dirent->type = S_IFDIR >> S_SHIFT;
+	dirent->name_len = 1;
+	strcpy(dirent->name, ".");
+
+	dirent = &dirents[1];
+	dirent->type = S_IFDIR >> S_SHIFT;
+	dirent->name_len = 2;
+	strcpy(dirent->name, "..");
+
+	num_dirents = 2;
+
+	ret = mkdir(dir_name, FILE_MODE);
+	if (ret) {
+		ret = errno;
+		abort_printf("mkdir failure %d: %s\n", ret, strerror(ret));
+	}
+}
+
+static void create_file(char *filename)
+{
+	int ret, fd;
+	struct my_dirent *dirent;
+
+	dirent = &dirents[num_dirents];
+	num_dirents++;
+
+	dirent->type = S_IFREG >> S_SHIFT;
+	dirent->name_len = strlen(filename);
+	dirent->seen = 0;
+	strcpy(dirent->name, filename);
+
+	sprintf(path, "%s/%s", dir_name, dirent->name);
+
+	fd = open(path, FILE_BUFFERED_RW_FLAGS, FILE_MODE);
+	if (fd == -1) {
+		ret = errno;
+		abort_printf("open failure %d: %s\n", ret,
+			     strerror(ret));
+	}
+
+	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 get_max_inlined_entries(int max_inline_size)
+{
+	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;
+        /*if user-specified operated_entries larger than this,decrease
to a
+          right inlined number
+        */
+	if (operated_entries > almost_full_entries)
+		operated_entries = almost_full_entries - 1;
+
+	return almost_full_entries;
+
+}
+static void get_directory_almost_full(int minus_this_many)
+{
+	int almost_full_entries;
+
+	almost_full_entries = get_max_inlined_entries(max_inline_size);
+
+	almost_full_entries -= minus_this_many;
+
+	/* Need up to 20 characters to get a 32 byte entry */
+	create_files("filename-", almost_full_entries);
+}
+
+static void random_unlink(int iters)
+{
+	int i, ret;
+	struct my_dirent *dirent;
+
+	while (iters > 0) {
+		i = get_rand(0, num_dirents - 1);
+		dirent = &dirents[i];
+
+		if (is_dot_entry(dirent))
+			continue;
+		if (dirent->name_len == 0)
+			continue;
+
+		ret = unlink_dirent(dirent);
+		if (ret) {
+			ret = errno;
+			abort_printf("unlink failure %d: %s\n", ret,
+				     strerror(ret));
+		}
+
+		dirent->name_len = 0;
+		iters--;
+	}
+}
+
+static void random_fill_empty_entries(int iters)
+{
+	int i, ret, fd;
+	struct my_dirent *dirent;
+
+	while (iters > 0) {
+		i = get_rand(0, num_dirents - 1);
+		dirent = &dirents[i];
+
+		if (is_dot_entry(dirent))
+			continue;
+		if (dirent->name_len > 0)
+			continue;
+
+		//sprintf(path1, "%s%011d", "filename-", i);
+		dirent->type = S_IFREG >> S_SHIFT;
+		dirent->name_len = strlen(dirent->name);
+		dirent->seen = 0;
+		//strcpy(dirent->name, path1);
+
+		sprintf(path, "%s/%s", dir_name, dirent->name);
+
+		fd = open(path, FILE_BUFFERED_RW_FLAGS, FILE_MODE);
+		if (fd == -1) {
+			ret = errno;
+			abort_printf("open failure %d: %s\n", ret,
+				     strerror(ret));
+		}
+
+		close(fd);
+		
+		iters--;
+	}
+}
+
+static void random_rename_same_reclen(int iters)
+{
+	int i, ret;
+	struct my_dirent *dirent;
+
+	while (iters > 0) {
+		i = get_rand(0, num_dirents - 1);
+		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;
+			abort_printf("rename failure %d,from %s to %s : %s\n",
+				     ret, path, path1, strerror(ret));
+		}
+		dirent->name[0] = 'R';
+		iters--;
+	}
+}
+
+static void random_deleting_rename(int iters)
+{
+	int i, j, ret;
+	struct my_dirent *dirent1, *dirent2;
+
+	while (iters--) {
+		i = get_rand(0, num_dirents - 1);
+		j = get_rand(0, num_dirents - 1);
+		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;
+			abort_printf("rename failure %d,from %s to %s: %s\n",
+				     ret, path, path1, strerror(ret));
+		}
+		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;
+
+	sync();
+
+	dir = opendir(dir_name);
+	if (dir == NULL) {
+		ret = errno;
+		abort_printf("opendir failure %d: %s\n", ret, strerror(ret));
+	}
+
+	dirent = readdir(dir);
+	while (dirent) {
+		my_dirent = find_my_dirent(dirent->d_name);
+		if (!my_dirent) {
+			abort_printf("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);
+		}
+
+		if (my_dirent->type != dirent->d_type) {
+			abort_printf("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);
+		}
+
+		if (my_dirent->seen) {
+			abort_printf("Verify failure: duplicate dirent: "
+				     "(type: %u, name_len: %u, name: %s)\n",
+				     my_dirent->type, my_dirent->name_len,
+				     my_dirent->name);
+		}
+
+		my_dirent->seen++;
+
+		dirent = readdir(dir);
+	}
+
+	for (i = 0; i < num_dirents; i++) {
+		my_dirent = &dirents[i];
+
+		if (my_dirent->seen != 0 || my_dirent->name_len == 0)
+			continue;
+
+		abort_printf("Verify failure: missing dirent: "
+			     "(type: %u, name_len: %u, name: %s)\n",
+			     my_dirent->type, my_dirent->name_len,
+			     my_dirent->name);
+		
+	}
+	closedir(dir);
+}
+
+static int is_dir_inlined(char *dirent_name, unsigned long *i_size,
+                           unsigned int *id_count)
+{
+        int ret;
+	uint64_t workplace_blk_no = 1;
+	uint64_t testdir_blk_no = 1;
+	char *buf = NULL;
+	struct ocfs2_dinode *di;
+	struct ocfs2_super_block *sb = OCFS2_RAW_SB(fs->fs_super);
+
+	sync();
+
+	ocfs2_malloc_block(fs->fs_io, &buf);
+
+	/*lookup worksplace inode*/
+	ret = ocfs2_lookup(fs, sb->s_root_blkno, WORK_PLACE,
+			   strlen(WORK_PLACE), NULL, &workplace_blk_no);
+	if ( ret < 0 ) {
+		ocfs2_free(&buf);
+		abort_printf("failed to lookup work_place(%s)'s"
+			     " inode blkno\n", work_place);
+	}
+
+	/*lookup file inode,then read*/
+	ret = ocfs2_lookup(fs, workplace_blk_no, dirent_name,
strlen(dirent_name),
+			   NULL, &testdir_blk_no);
+	if ( ret < 0 ) {
+		ocfs2_free(&buf);
+		abort_printf("failed to lookup file(%s/%s)'s"
+			     " inode blkno\n", work_place, dirent_name);
+	}
+
+	ret = ocfs2_read_inode(fs, testdir_blk_no, buf);
+	if ( ret < 0 ) {
+		ocfs2_free(&buf);
+		abort_printf("failed to read file(%s/%s/%s)'s"
+			     " inode.\n", mount_point, WORK_PLACE, dirent_name);
+	}
+
+	di = (struct ocfs2_dinode *)buf;
+	*i_size = di->i_size;
+	*id_count = ((di->id2).i_data).id_count;
+	
+	if (di->i_dyn_features & OCFS2_INLINE_DATA_FL)
+		ret = 1;
+	else
+		ret = 0;
+
+	ocfs2_free(&buf);
+	return ret;
+}
+
+static void should_inlined_or_not(int is_inlined, int should_inlined,
int test_no)
+{
+	/* is_inlined represent if the ret is inlined or not
+	   while should_inlined represnt if we expect it inlined or not.
+	*/
+	if (should_inlined) {
+		if (!is_inlined) {
+			fprintf(stderr, "After Test #%d, dir %s should be "
+				"inlined here!\n", test_no, dir_name);
+			fprintf(stderr, "Dir(%s): i_size = %d,id_count = %d\n",
+				dir_name, i_size, id_count);
+			abort_printf("inline-data check failed!\n");
+		}
+
+	} else {
+		if (is_inlined) {
+			fprintf(stderr, "After Test #%d, dir %s should be "
+				"extented here!\n", test_no, dir_name);
+			fprintf(stderr, "Dir(%s): i_size = %d,id_count = %d\n",
+				dir_name, i_size, id_count);
+			abort_printf("inline-data check failed!\n");
+
+		}
+	}
+
+	return;
+}
+
+static void send_dirents_to_ranks();
+
+static void recv_dirents_from_ranks();
+/*
+ * [I] Basic tests of inline-dir code.
+ *    1) Basic add files
+ *    2) Basic delete files
+ *    3) Basic rename files
+ *    4) Add / Remove / Re-add to fragment dir
+ */
+static void run_basic_tests(void)
+{
+	int ret;
+	int i;
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	root_printf("Test %d: fill directory\n", testno);
+	if (rank == 0) {
+		create_and_prep_dir();
+		get_directory_almost_full(0);
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	if (rank != 0)
+		verify_dirents();
+
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 1, testno);
+	testno++;
+	
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	root_printf("Test %d: expand inlined dir to extent exactly\n",
testno);
+	/*Should be 13 bits len dirent_name*/
+	if (rank == 0) {
+		create_file("Iam13bitshere");
+		sync();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	if (rank != 0) {
+		ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+		should_inlined_or_not(ret, 0, testno);
+	}
+	testno++;
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	root_printf("Test %d: remove directory\n", testno);
+	if (rank == 0) {
+		destroy_dir();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+	testno++;
+	
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	root_printf("Test %d: rename files with same namelen\n", testno);
+	if (rank == 0) {
+		create_and_prep_dir();
+		get_directory_almost_full(1);
+		random_rename_same_reclen(operated_entries);
+		sleep(1);
+		sync();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+	
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	if (rank != 0)
+		verify_dirents();
+	
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 1, testno);
+
+	if (rank == 0) {
+		destroy_dir();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+	testno++;
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	root_printf("Test %d: rename files with same namelen on top of each
other\n", testno);
+	if (rank == 0) {
+		create_and_prep_dir();
+		get_directory_almost_full(1);
+		random_deleting_rename(operated_entries);
+		sleep(1);
+		sync();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+	if (rank != 0)
+		verify_dirents();
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 1, testno);
+	if (rank == 0) {
+		destroy_dir();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+	testno++;
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	root_printf("Test %d: random unlink/fill entries.\n", testno);
+	if (rank == 0) {
+		create_and_prep_dir();
+		get_directory_almost_full(0);
+		random_unlink(operated_entries);
+		random_fill_empty_entries(operated_entries);
+		sleep(1);
+		sync();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	if (rank != 0)
+		verify_dirents();
+
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 1, testno);
+	if (rank == 0) {
+		destroy_dir();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+	testno++;
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	root_printf("Test %d: random rename/unlink files with same namelen\n",
+	       	    testno);
+	if (rank == 0) {
+		create_and_prep_dir();
+		get_directory_almost_full(1);
+		random_unlink(operated_entries / 2);
+		random_rename_same_reclen(operated_entries / 2);
+		sleep(1);
+		sync();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+	
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+	
+	if (rank != 0)
+		verify_dirents();
+
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 1, testno);
+	
+	if (rank == 0) {
+		destroy_dir();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+	testno++;
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	root_printf("Test %d: fragment directory with unlinks/creates/renames
\n",
+		    testno);
+	if (rank == 0) {
+		create_and_prep_dir();
+		get_directory_almost_full(1);
+		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);
+		sleep(2);
+		sync();
+		send_dirents_to_ranks();
+	
+	} else {
+		recv_dirents_from_ranks();
+	}
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+	
+	if (rank != 0) 
+		verify_dirents();
+
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 0, testno);
+
+	if (rank == 0) {
+		destroy_dir();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+	testno++;
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+}
+
+/*
+ * [II] Tests intended to push a dir out to extents
+ *    1) Add enough files to push out one block
+ *    2) Add enough files to push out two blocks
+ *    3) Fragment dir, add enough files to push out to extents
+ */
+static void run_large_dir_tests(void)
+{
+	int ret;
+
+	root_printf("Test %d: Add file name large enough to push out one "
+		    "block\n", testno);
+	if (rank == 0) {
+		create_and_prep_dir();
+		get_directory_almost_full(0);
+		create_files("Pushedfn-", 1);
+		sleep(1);
+		sync();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+	
+	if (rank != 0)
+		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);
+	}
+	
+	if (rank == 0) {
+		destroy_dir();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+	testno++;
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	root_printf("Test %d: Add file name large enough to push out two "
+		    "blocks\n", testno);
+	if (rank == 0) {
+		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);
+		sleep(1);
+		sync();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	if (rank != 0)
+		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);
+	}
+	if (rank == 0) {
+		destroy_dir();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+	testno++;
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	root_printf("Test %d: fragment directory then push out to extents.\n",
+	       testno);
+	if (rank == 0) {
+		create_and_prep_dir();
+		get_directory_almost_full(1);
+		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);
+		sleep(2);
+		sync();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	if (rank != 0)
+		verify_dirents();
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 0, testno);
+	if (rank == 0) {
+		destroy_dir();
+		send_dirents_to_ranks();
+	} else {
+		recv_dirents_from_ranks();
+	}
+	testno++;
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+
+	root_printf("Test %d: Multiple directories.\n", testno);
+
+	snprintf(dirent_name, 255, "multiple-inline-data-dir-test-%d", rank);
+	snprintf(dir_name, 255, "%s/%s", work_place, dirent_name);
+	create_and_prep_dir();
+	get_directory_almost_full(1);
+	random_rename_same_reclen(operated_entries);
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 1, testno);
+	random_unlink(operated_entries / 2);
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 1, testno);
+
+	create_files("Iam13bitshere", operated_entries * 2);
+
+	ret = is_dir_inlined(dirent_name, &i_size, &id_count);
+	should_inlined_or_not(ret, 0, testno);
+
+	destroy_dir();
+
+	snprintf(dirent_name, 255, "multiple-inline-data-dir-test");
+        snprintf(dir_name, 255, "%s/%s", work_place, dirent_name);
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Barrier failed: %d\n", ret);
+}
+
+static int open_ocfs2_volume(char *device_name)
+{
+	int open_flags = OCFS2_FLAG_HEARTBEAT_DEV_OK | OCFS2_FLAG_RO;
+	int ret;
+
+	ret = ocfs2_open(device_name, open_flags, 0, 0, &fs);
+	if (ret < 0)
+		abort_printf("Not a ocfs2 volume!\n");
+
+	ocfs2_sb = OCFS2_RAW_SB(fs->fs_super);
+	if (!(ocfs2_sb->s_feature_incompat &
OCFS2_FEATURE_INCOMPAT_INLINE_DATA))
+		abort_printf("Inline-data not supported on this volume\n");
+
+	blocksize = 1 << ocfs2_sb->s_blocksize_bits;
+	clustersize = 1 << ocfs2_sb->s_clustersize_bits;
+	max_inline_size = ocfs2_max_inline_data(blocksize);
+
+	return 0;
+}
+
+
+static void setup(int argc, char *argv[])
+{
+	int ret;
+	
+	ret = MPI_Init(&argc, &argv);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Init Failed!\n");
+
+	if (gethostname(hostname, HOSTNAME_MAX_SZ) < 0)
+		abort_printf("get hostname!\n");
+
+	ret = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Comm_rank failed: %d\n", ret);
+
+	ret = MPI_Comm_size(MPI_COMM_WORLD,&size);
+	if (ret != MPI_SUCCESS)
+		abort_printf("MPI_Comm_size failed: %d\n", ret);
+
+
+	prog = strrchr(argv[0], '/');
+	if (prog == NULL)
+		prog = argv[0];
+	else
+		prog++;
+
+	if (parse_opts(argc, argv))
+		usage();
+
+	ret = open_ocfs2_volume(device);
+	if (ret < 0) 
+		abort_printf("open ocfs2 volume failed!\n");
+
+	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, 255, "%s/%s",mount_point,WORK_PLACE);
+
+	snprintf(dirent_name, 255, "multiple-inline-data-dir-test");
+	snprintf(dir_name, 255, "%s/%s", work_place, dirent_name);
+
+	
+	if (rank == 0) {
+		mkdir(work_place, FILE_MODE);
+		root_printf("BlockSize:\t\t%d\nMax Inline Data Size:\t%d\n"
+		       "ClusterSize:\t\t%d\nPageSize:\t\t%d\nWorkingPlace:"
+		       "\t\t%s\nNumOfMaxInlinedEntries:\t\t%d\n\n", blocksize,
+		       max_inline_size,clustersize, page_size, work_place,
+		       get_max_inlined_entries(max_inline_size));
+	}
+
+        return ;
+}
+
+static int teardown(void)
+{
+	if (dirents)
+		free(dirents);
+
+	if (rank == 0)
+		rmdir(work_place);
+
+	MPI_Finalize();
+	
+	return 0;
+}
+
+static void send_dirents_to_ranks(void)
+{
+	int i, ret;
+
+	MPI_Request request;
+	MPI_Status status;
+
+	if (rank == 0) {
+		for (i = 1; i < size; i++) {
+			ret = MPI_Isend(dirents, 
+					sizeof(struct my_dirent) * MAX_DIRENTS,
+					MPI_BYTE, i, 1,
+					MPI_COMM_WORLD, &request);
+			if (ret != MPI_SUCCESS)
+				abort_printf("MPI_Isend dirents failed!\n");
+			MPI_Wait(&request, &status);
+
+			ret = MPI_Isend(&num_dirents, sizeof(unsigned int),
+					MPI_BYTE, i, 1,
+					MPI_COMM_WORLD, &request);
+			if (ret != MPI_SUCCESS)
+				abort_printf("MPI_Isend num_dirents failed!\n");
+			MPI_Wait(&request, &status);
+		}
+
+	} else {
+		ret = MPI_Isend(dirents,
+				sizeof(struct my_dirent) * MAX_DIRENTS,
+				MPI_BYTE, 0, 1, MPI_COMM_WORLD, &request);
+		if (ret != MPI_SUCCESS)
+			abort_printf("MPI_Isend dirents failed!\n");
+		MPI_Wait(&request, &status);
+
+		ret = MPI_Isend(&num_dirents, sizeof(unsigned int), MPI_BYTE,
+				i, 1, MPI_COMM_WORLD, &request);
+		if (ret != MPI_SUCCESS)
+			abort_printf("MPI_Isend num_dirents failed!\n");
+		MPI_Wait(&request, &status);
+	}
+}
+
+static void recv_dirents_from_ranks(void)
+{
+	int i, ret;
+
+	MPI_Request request;
+	MPI_Status status;
+
+	if (rank == 0) {
+		for (i = 1; i < size; i++) {
+			ret = MPI_Irecv(dirents,
+					sizeof(struct my_dirent) * MAX_DIRENTS,
+					MPI_BYTE, i, 1,
+					MPI_COMM_WORLD, &request);
+
+			if (ret != MPI_SUCCESS)
+				abort_printf("MPI_Irecv dirents failed!\n");
+			MPI_Wait(&request, &status);
+
+			ret = MPI_Irecv(&num_dirents, sizeof(unsigned int),
+					MPI_BYTE, i, 1,
+					MPI_COMM_WORLD, &request);
+			if (ret != MPI_SUCCESS)
+				abort_printf("MPI_Irecv num_dirents failed!\n");
+			MPI_Wait(&request, &status);
+		}
+
+	} else {
+		ret = MPI_Irecv(dirents,
+				sizeof(struct my_dirent) * MAX_DIRENTS,
+				MPI_BYTE, 0, 1, MPI_COMM_WORLD, &request);
+
+		if (ret != MPI_SUCCESS)
+			abort_printf("MPI_Irecv dirents failed!\n");
+		MPI_Wait(&request, &status);
+
+		ret = MPI_Irecv(&num_dirents, sizeof(unsigned int), MPI_BYTE,
+				0, 1, MPI_COMM_WORLD, &request);
+		if (ret != MPI_SUCCESS)
+			abort_printf("MPI_Irecv num_dirents failed!\n");
+		MPI_Wait(&request, &status);
+	}
+
+}
+
+int main(int argc, char **argv)
+{
+	int i, ret;
+
+	setup(argc,argv);
+
+	for (i = 0; i < iteration; i++){
+
+		root_printf("################Test Round %d################\n", i);
+		testno = 1;
+		run_basic_tests();
+		run_large_dir_tests();
+		root_printf("All File I/O Tests Passed\n");
+		
+		ret = MPI_Barrier(MPI_COMM_WORLD);
+		if (ret != MPI_SUCCESS)
+			abort_printf("MPI_Barrier failed: %d\n", ret);
+		sleep(1);
+
+	}
+
+	teardown();
+
+	return 0;
+}




More information about the Ocfs2-tools-devel mailing list