[Ocfs2-test-devel] [PATCH 1/7] Discontig_bg_test: Add inodes spawn utility for discontig_bg_test.

Tristan Ye tristan.ye at oracle.com
Mon Jun 28 00:37:20 PDT 2010


We start with spawn_inodes.c, a simple utility of spawning inodes
from mutliple processes, which will be used later as a stress tool
to populate inodes to fill up volume in a quite short time.

Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
---
 programs/Makefile                         |    3 +-
 programs/discontig_bg_test/Makefile       |   20 ++
 programs/discontig_bg_test/spawn_inodes.c |  291 +++++++++++++++++++++++++++++
 3 files changed, 313 insertions(+), 1 deletions(-)
 create mode 100644 programs/discontig_bg_test/Makefile
 create mode 100755 programs/discontig_bg_test/spawn_inodes.c

diff --git a/programs/Makefile b/programs/Makefile
index b5f9858..14bfb69 100644
--- a/programs/Makefile
+++ b/programs/Makefile
@@ -56,7 +56,8 @@ SUBDIRS =			\
 	acl_tests		\
 	quota_tests		\
 	inode_alloc_perf_tests	\
-	reflink_tests
+	reflink_tests		\
+	discontig_bg_test
 
 ifdef OCFS2_TEST_DX_DIRS
 	SUBDIRS += dx_dirs_tests
diff --git a/programs/discontig_bg_test/Makefile b/programs/discontig_bg_test/Makefile
new file mode 100644
index 0000000..1467f39
--- /dev/null
+++ b/programs/discontig_bg_test/Makefile
@@ -0,0 +1,20 @@
+TOPDIR = ../..
+
+include $(TOPDIR)/Preamble.make
+
+TESTS = discontig_bg_test
+
+CFLAGS = -O2 -Wall -g $(OCFS2_CFLAGS)
+
+MPI_LINK = $(MPICC) $(CFLAGS) $(LDFLAGS) -o $@ $^
+
+SOURCES = spawn_inodes.c
+
+DIST_FILES = $(SOURCES)
+
+BIN_PROGRAMS = spawn_inodes
+
+spawn_inode: spawn_inodes.c
+	$(LINK) $(OCFS2_LIBS)
+
+include $(TOPDIR)/Postamble.make
diff --git a/programs/discontig_bg_test/spawn_inodes.c b/programs/discontig_bg_test/spawn_inodes.c
new file mode 100755
index 0000000..6bb7a93
--- /dev/null
+++ b/programs/discontig_bg_test/spawn_inodes.c
@@ -0,0 +1,291 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * spawn_inodes.c
+ *
+ * A simple utility to spawn inodes with multiple processes
+ *
+ * Copyright (C) 2010 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <linux/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <time.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#define FILE_FLAGS		(O_CREAT|O_RDWR|O_APPEND|O_TRUNC)
+
+#define FILE_MODE               (S_IRUSR|S_IWUSR|S_IXUSR|S_IROTH|\
+				 S_IWOTH|S_IXOTH|S_IRGRP|S_IWGRP|S_IXGRP)
+
+char *workplace;
+char hostname[256];
+unsigned long long num_inodes = 1000;
+unsigned long long num_processes = 10;
+int is_random;
+
+pid_t *child_pid_list;
+
+static int usage(void)
+{
+	fprintf(stdout, "spawn_inodes <-n num_inodes> <-m num_processes> "
+		"<-w work_place> [-r]\n");
+	exit(1);
+}
+
+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()
+{
+	unsigned long long i;
+
+	for (i = 0; i < num_processes; i++)
+		if (child_pid_list[i])
+			kill(child_pid_list[i], SIGTERM);
+}
+
+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 void atexit_hook(void)
+{
+	unsigned long long i;
+
+	for (i = 0; i < num_processes; i++)
+		if (child_pid_list[i])
+			kill(child_pid_list[i], SIGKILL);
+
+	if (child_pid_list)
+		free(child_pid_list);
+}
+
+int parse_opts(int argc, char **argv)
+{
+	char c;
+
+	while (1) {
+		c = getopt(argc, argv, "n:m:w:rh:");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'w':
+			workplace = optarg;
+			break;
+		case 'n':
+			num_inodes = atoll(optarg);
+			break;
+		case 'm':
+			num_processes = atoll(optarg);
+			break;
+		case 'r':
+			is_random = 1;
+			break;
+		case 'h':
+			usage();
+			break;
+		default:
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+void setup(int argc, char *argv[])
+{
+	workplace = NULL;
+	is_random = 0;
+
+	if (parse_opts(argc, argv))
+		usage();
+
+	if (!workplace) {
+		fprintf(stderr, "workplace is a mandatory option.\n");
+		usage();
+	}
+
+	if (gethostname(hostname, 256) < 0) {
+		fprintf(stderr, "gethostname failed.\n");
+		exit(1);
+	}
+
+	child_pid_list = (pid_t *)malloc(sizeof(pid_t) * num_processes);
+
+	memset(child_pid_list, 0, sizeof(pid_t) * num_processes);
+
+	/*
+	 * Setup SIGCHLD correctly to avoid zombie processes.
+	 */
+	signal(SIGCHLD, sigchld_handler);
+}
+
+void teardown()
+{
+	if (child_pid_list)
+		free(child_pid_list);
+}
+
+int spawn_inodes(unsigned long long inodes,
+		 unsigned long long processes,
+		 const char *dir)
+{
+	int status = 0, ret = 0, fd;
+	pid_t pid;
+	unsigned long long i, j;
+	unsigned int seed;
+	char path[PATH_MAX];
+
+	for (i = 0; i < processes; i++) {
+
+		pid = fork();
+		if (pid < 0) {
+			fprintf(stderr, "fork error:%s\n", strerror(pid));
+			teardown();
+			exit(pid);
+		}
+
+		if (pid == 0) {
+			snprintf(path, PATH_MAX, "%s/%s-%d", dir, hostname,
+				 getpid());
+
+			ret = mkdir(path, FILE_MODE);
+			if (ret < 0) {
+				fprintf(stderr, "%d failed to mkdir %s: %s\n",
+					getpid(), path, strerror(errno));
+				teardown();
+				exit(ret);
+			}
+
+			for (j = 0; j < inodes; j++) {
+				snprintf(path, PATH_MAX, "%s/%s-%d/inodes-%d-%llu",
+					 dir, hostname, getpid(), getpid(), j);
+
+				fd = open(path, FILE_FLAGS, FILE_MODE);
+				if (fd < 0) {
+					fprintf(stderr, "%d failed to create "
+						"file %s: %s\n", getpid(), path,
+						strerror(errno));
+					teardown();
+					exit(fd);
+				}
+
+				if (!is_random) {
+					close(fd);
+					continue;
+				}
+
+				seed = time(NULL) ^ getpid();
+				srandom(seed);
+
+				if (rand() % 2) {
+					ret = unlink(path);
+					if (ret < 0) {
+						fprintf(stderr, "%d failed to"
+							" unlink %s: %s.\n",
+							getpid(), path,
+							strerror(errno));
+						teardown();
+						exit(ret);
+					}
+				}
+
+				if (!(rand() % 2)) {
+					ret = write(fd, "be-inlined", 100);
+					if (ret < 0) {
+						fprintf(stderr, "%d failed to"
+							" write %s: %s.\n",
+							getpid(), path,
+							strerror(errno));
+						teardown();
+						exit(ret);
+					}
+				}
+
+				close(fd);
+			}
+
+			teardown();
+			exit(0);
+		}
+
+		if (pid > 0)
+			child_pid_list[i] = pid;
+	}
+
+	/*
+	 * We're only going to setup following signals
+	 * for father to avoid zombies and cleaup children
+	 */
+	signal(SIGINT, sigint_handler);
+	signal(SIGTERM, sigterm_handler);
+
+	atexit(atexit_hook);
+
+	for (i = 0; i < num_processes; i++)
+		ret = waitpid(child_pid_list[i], &status, 0);
+
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = 0;
+
+	setup(argc, argv);
+
+	ret = spawn_inodes(num_inodes, num_processes, workplace);
+
+	return ret;
+}
-- 
1.5.5




More information about the Ocfs2-test-devel mailing list