[Ocfs2-test-devel] [PATCH 3/3] Ocfs2-test: Implement testing body.

Tristan Ye tristan.ye at oracle.com
Mon Aug 23 03:09:01 PDT 2010


It filles the testing bodies for all testing modes.

The test uses the number of concurrent processes and file size
to tune the workload for writes intensity.

The testing file is expected to consist of CHUNKs, a CHUNK is
treated as a basic unit to perform write/read/verification with
a unique pattern being filled, while the CHUNK_SIZE here also
needs to be 512-bytes aligned.

Like the 'fill_verify_holes', directio test also recoreds all
writes as tuples in a logfile for following verification, more
specifically, destructive test uses a remote listener for log
writing.

Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
---
 programs/directio_test/directio_test.c |  354 +++++++++++++++++++++++++++++++-
 1 files changed, 352 insertions(+), 2 deletions(-)

diff --git a/programs/directio_test/directio_test.c b/programs/directio_test/directio_test.c
index 1e1d923..499dc83 100755
--- a/programs/directio_test/directio_test.c
+++ b/programs/directio_test/directio_test.c
@@ -29,9 +29,26 @@
 int open_rw_flags = FILE_RW_FLAGS;
 int open_ro_flags = FILE_RO_FLAGS;
 
+unsigned long file_size = 1024 * 1024;
+
+static char *test_mode;
+
+static char workfile[PATH_MAX];
+static char log_path[PATH_MAX];
+static char lsnr_addr[HOSTNAME_LEN];
+
+static union log_handler log;
+
+static unsigned long port = 9999;
+static unsigned long num_children = 10;
+
+static pid_t *child_pid_list;
+
 int test_flags = 0x00000000;
 int verbose = 0;
 
+int num_tests = 0;
+
 static void usage(void)
 {
 	printf("Usage: directio_test [-p concurrent_process] "
@@ -54,11 +71,61 @@ static int parse_opts(int argc, char **argv)
 
 	while (1) {
 		c = getopt(argc, argv,
-			   "h");
+			   "p:l:o:bafdVvw:h:A:P:");
 		if (c == -1)
 			break;
 
 		switch (c) {
+		case 'p':
+			num_children = atol(optarg);
+			break;
+		case 'l':
+			file_size = atol(optarg);
+			break;
+		case 'o':
+			strcpy(log_path, optarg);
+			break;
+		case 'w':
+			strcpy(workfile, optarg);
+			break;
+		case 'b':
+			test_flags |= BASC_TEST;
+			test_mode = "BASIC";
+			num_tests++;
+			break;
+		case 'a':
+			test_flags |= APPD_TEST;
+			test_mode = "APPEND";
+			num_tests++;
+			break;
+		case 'f':
+			test_flags |= FIHL_TEST;
+			test_mode = "HOLE_FILLING";
+			num_tests++;
+			break;
+		case 'd':
+			test_flags |= DSCV_TEST;
+			test_mode = "DESTRUCTIVE";
+			/*
+			 * Destructive test needs append writing mode.
+			 */
+			test_flags |= APPD_TEST;
+			num_tests++;
+			break;
+		case 'V':
+			test_flags |= VERI_TEST;
+			test_mode = "VERIFY";
+			num_tests++;
+			break;
+		case 'v':
+			verbose = 1;
+			break;
+		case 'A':
+			strcpy(lsnr_addr, optarg);
+			break;
+		case 'P':
+			port = atol(optarg);
+			break;
 		case 'h':
 			usage();
 			break;
@@ -67,16 +134,62 @@ static int parse_opts(int argc, char **argv)
 		}
 	}
 
+	if (strcmp(workfile, "") == 0)
+		return -EINVAL;
+
+	if (test_flags & DSCV_TEST) {
+		if (!strcmp(lsnr_addr, ""))
+			return -EINVAL;
+	}
+
+	if ((file_size % DIRECTIO_SLICE) != 0) {
+		fprintf(stderr, "file size in destructive tests is expected to "
+			"be %d aligned, your file size %lu is not allowed.\n",
+			CHUNK_SIZE, file_size);
+		return -EINVAL;
+	}
+
+	if (!num_tests) {
+		fprintf(stdout, "You'd better specify at least one test.\n");
+		return 0;
+	}
+
+	if (num_tests > 1) {
+		fprintf(stdout, "You have to specify ONLY ONE test a time.\n");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
 static int setup(int argc, char *argv[])
 {
-	int ret = 0;
+	int ret = 0, sockfd;
+	FILE *logfile = NULL;
 
 	if (parse_opts(argc, argv))
 		usage();
 
+	if (test_flags & DSCV_TEST) {
+
+		sockfd = init_sock(lsnr_addr, port);
+		if (sockfd < 0) {
+			fprintf(stderr, "init socket failed.\n");
+			return sockfd;
+		}
+
+		log.socket_log = sockfd;	
+
+	} else {
+		ret = open_logfile(&logfile, log_path);
+		if (ret)
+			return ret;
+
+		log.stream_log = logfile;
+	}
+
+	child_pid_list = (pid_t *)malloc(sizeof(pid_t) * num_children);
+
 	return ret;
 }
 
@@ -84,6 +197,227 @@ static int teardown(void)
 {
 	int ret = 0;
 
+	if (test_flags & DSCV_TEST) {
+		if (log.socket_log)
+			close(log.socket_log);
+	} else {
+		if (log.stream_log)
+			fclose(log.stream_log);
+	}
+
+	if (child_pid_list)
+		free(child_pid_list);
+
+	return ret;
+}
+
+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;
+
+	for (i = 0; i < num_children; 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 basic_test(void)
+{
+	pid_t pid;
+	int fd, sem_id, status, ret = 0;
+	unsigned long i, j, chunk_no = 0, num_chunks = 0;
+	struct write_unit wu;
+
+	sem_id = semaphore_init(1);
+	if (sem_id < 0)
+		return sem_id;
+
+	num_chunks = file_size / CHUNK_SIZE;
+
+	open_rw_flags |= O_DIRECT;
+	open_ro_flags |= O_DIRECT;
+
+	if (test_flags & BASC_TEST) {
+		fprintf(stdout, "# Prepare file in %lu length.\n", file_size);
+		ret = prep_orig_file_in_chunks(workfile, file_size);
+		if (ret)
+			return ret;
+	}
+
+	fflush(stderr);
+	fflush(stdout);
+
+	signal(SIGCHLD, sigchld_handler);
+
+	fd = open_file(workfile, open_rw_flags);
+	if (fd < 0)
+		return fd;
+
+	if (test_flags & FIHL_TEST) {
+		fprintf(stdout, "# Reserve a hole by truncating file to %lu.\n",
+			file_size);
+		ret = ftruncate(fd, file_size);
+		if (ret) {
+			ret = errno;
+			fprintf(stderr, "ftruncate faile:%d,%s\n",
+				ret, strerror(ret));
+			return ret;
+		}
+	}
+
+	fprintf(stdout, "# Fork %lu processes performing writes.\n",
+		num_children);
+	for (i = 0; i < num_children; i++) {
+
+		pid = fork();
+
+		if (pid < 0) {
+			fprintf(stderr, "Fork process error!\n");
+			return pid;
+		}
+
+		if (pid == 0) {
+
+			srand(getpid());
+
+			for (j = 0; j < num_chunks; j++) {
+				if (verbose) 
+					fprintf(stdout, "  #%d process writes "
+						"#%lu chunk\n", getpid(),
+						chunk_no);
+
+				if (semaphore_p(sem_id) < 0) {
+					ret = -1;
+					goto child_bail;
+				}
+
+				if (test_flags & APPD_TEST)
+					chunk_no = j;
+				else
+					chunk_no = get_rand_ul(0, num_chunks - 1);
+
+				prep_rand_dest_write_unit(&wu, chunk_no);
+
+				ret = do_write_chunk(fd, wu);
+				if (ret < 0)
+					goto child_bail;
+
+				ret = log_write(&wu, log);
+				if (ret < 0)
+					goto child_bail;
+
+				if (semaphore_v(sem_id) < 0) {
+					ret = -1;
+					goto child_bail;
+				}
+
+				usleep(10000);
+
+				if (!(test_flags & DSCV_TEST))
+					continue;
+
+				/*
+				 * Are you ready to crash the machine?
+				 */
+
+				if ((j > 1) && (j < num_chunks - 1)) {
+					if (get_rand_ul(1, num_chunks) == num_chunks / 2) {
+
+						if (semaphore_p(sem_id) < 0) {
+							ret = -1;
+							goto child_bail;
+						}
+
+						fprintf(stdout, "#%d process "
+							"tries to crash the "
+							"box.\n", getpid());
+						system("echo b>/proc/sysrq-trigger");
+					}
+				} else if (j == num_chunks - 1) {
+
+						if (semaphore_p(sem_id) < 0) {
+							ret = -1;
+							goto child_bail;
+						}
+
+						fprintf(stdout, "#%d process "
+							"tries to crash the "
+							"box.\n", getpid());
+						system("echo b>/proc/sysrq-trigger");
+				}
+			}
+child_bail:
+			if (fd)
+				close(fd);
+
+			if (ret > 0)
+				ret = 0;
+
+			exit(ret);
+		}
+
+		if (pid > 0)
+			child_pid_list[i] = pid;
+	}
+
+	signal(SIGINT, sigint_handler);
+	signal(SIGTERM, sigterm_handler);
+
+	for (i = 0; i < num_children; i++) {
+		waitpid(child_pid_list[i], &status, 0);
+		ret = WEXITSTATUS(status);
+		if (ret) {
+			fprintf(stderr, "Child %d exits abnormally with "
+				"RC=%d\n", child_pid_list[i], ret);
+		}
+	}
+
+	if (fd)
+		close(fd);
+
+	if (sem_id)
+		semaphore_close(sem_id);
+
+	return ret;
+}
+
+static int verify_test(void)
+{
+	int ret = 0;
+
+	ret = 
+
+	fprintf(stdout, "# Verify file %s in chunks\n", workfile);
+	ret = verify_file(log.stream_log, workfile, file_size);
+
 	return ret;
 }
 
@@ -91,6 +425,22 @@ static int run_test(void)
 {
 	int ret = 0;
 
+		
+	if (!test_flags)
+		return 0;
+
+	fprintf(stdout, "########## %s test running ##########\n", test_mode);
+
+	if (test_flags & VERI_TEST) {
+		ret = verify_test();
+		if (ret < 0)
+			return ret;
+	} else {
+		ret = basic_test();
+		if (ret)
+			return ret;
+	}
+
 	return ret;
 }
 
-- 
1.5.5




More information about the Ocfs2-test-devel mailing list