[Ocfs2-test-devel] [PATCH 3/5] Ocfs2-test: Add generic dir operation funcs for libocfs2test.

Tristan Ye tristan.ye at oracle.com
Fri Apr 3 00:07:41 PDT 2009


Provide generic utility fuctions on dir operations for ocfs2-tests.

Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
---
 programs/libocfs2test/dir_ops.c |  517 +++++++++++++++++++++++++++++++++++++++
 programs/libocfs2test/dir_ops.h |   88 +++++++
 2 files changed, 605 insertions(+), 0 deletions(-)
 create mode 100644 programs/libocfs2test/dir_ops.c
 create mode 100644 programs/libocfs2test/dir_ops.h

diff --git a/programs/libocfs2test/dir_ops.c b/programs/libocfs2test/dir_ops.c
new file mode 100644
index 0000000..23ab492
--- /dev/null
+++ b/programs/libocfs2test/dir_ops.c
@@ -0,0 +1,517 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * dir_ops.c
+ *
+ * Provide generic utility fuctions on dir operations for ocfs2-tests
+ *
+ * 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.
+ */
+
+#include "dir_ops.h"
+
+extern unsigned long num_dirents;
+extern struct my_dirent *dirents;
+
+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;
+}
+
+int unlink_dirent(char *dirname, struct my_dirent *dirent)
+{
+	char path[PATH_MAX];
+
+	sprintf(path, "%s/%s", dirname, dirent->name);
+
+	memcpy((void *)dirent, (void *)&dirents[num_dirents - 1],
+	       sizeof(struct my_dirent));
+	num_dirents--;
+
+	return unlink(path);
+}
+
+int create_and_prep_dir(char *dirname)
+{
+	int ret;
+	struct my_dirent *dirent;
+
+	dirents = (struct my_dirent *)malloc(sizeof(struct my_dirent) *
+					     MAX_DIRENTS);
+	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(dirname, FILE_MODE);
+	if (ret) {
+		ret = errno;
+		fprintf(stderr, "mkdir failure %d: %s\n", ret, strerror(ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+int destroy_dir(char *dirname)
+{
+	unsigned long i, orig_num_dirents = num_dirents;
+	int ret;
+	struct my_dirent *dirent;
+
+	for (i = 1 ; i <= orig_num_dirents; i++) {
+
+		dirent = &dirents[orig_num_dirents - i];
+
+		if (!is_dot_entry(dirent)) {
+
+			ret = unlink_dirent(dirname, dirent);
+			if (ret < 0) {
+				ret = errno;
+				fprintf(stderr, "unlink failure %d: %s\n", ret,
+					strerror(ret));
+				return ret;
+			}
+
+		}
+
+	}
+
+	ret = rmdir(dirname);
+	if (ret) {
+		ret = errno;
+		fprintf(stderr, "rmdir failure %d: %s\n", ret,
+			strerror(ret));
+		return ret;
+	}
+
+	num_dirents = 0;
+
+	if (dirents)
+		free(dirents);
+
+	return 0;
+}
+
+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 == len &&
+		    strcmp(my_dirent->name, name) == 0)
+			return my_dirent;
+	}
+
+	return NULL;
+}
+
+int unlink_dirent_nam(char *dirname, char *name)
+{
+	struct my_dirent *dirent;
+
+	dirent = find_my_dirent(name);
+
+	return unlink_dirent(dirname, dirent);
+}
+
+int create_file(char *filename, char *dirname)
+{
+	int ret, fd;
+	struct my_dirent *dirent;
+	char path[PATH_MAX];
+
+	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", dirname, dirent->name);
+
+	fd = open(path, FILE_BUFFERED_RW_FLAGS, FILE_MODE);
+	if (fd < 0) {
+		ret = errno;
+		fprintf(stderr, "Create file %s failure %d: %s\n", path, ret,
+			strerror(ret));
+		return ret;
+	}
+
+	close(fd);
+
+	return 0;
+}
+
+int create_files(char *prefix, unsigned long num, char *dirname)
+{
+	int i, ret;
+	char dirent_nam[OCFS2_MAX_FILENAME_LEN];
+	char path[PATH_MAX];
+
+	for (i = 0; i < num; i++) {
+		if (!prefix) {
+			get_rand_nam(dirent_nam, 3, OCFS2_MAX_FILENAME_LEN);
+			ret = create_file(dirent_nam, dirname);
+		} else {
+			snprintf(path, PATH_MAX, "%s%011d", prefix, i);
+			ret = create_file(path, dirname);
+		}
+
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+int is_dir_empty(char *name)
+{
+	DIR *dir;
+	int ret, entries = 0;
+	struct dirent *dirent;
+
+	dir = opendir(name);
+	if (dir < 0) {
+		ret = errno;
+		fprintf(stderr, "dir open failure %d: %s\n", ret,
+			strerror(ret));
+	}
+
+	dirent = readdir(dir);
+	while (dirent) {
+		entries++;
+		dirent = readdir(dir);
+		if (entries > 2)
+			break;
+	}
+
+	closedir(dir);
+
+	if (entries == 2)
+		return 1;
+	else
+		return 0;
+}
+
+int verify_dirents(char *dir)
+{
+	DIR *dd;
+	int ret, i;
+	struct dirent *dirent;
+	struct my_dirent *my_dirent;
+
+	dd = opendir(dir);
+	if (!dd) {
+		ret = errno;
+		fprintf(stderr, "dir open failure %d: %s\n", ret,
+			strerror(ret));
+		return ret;
+	}
+
+	dirent = readdir(dd);
+	while (dirent) {
+		my_dirent = find_my_dirent(dirent->d_name);
+		if (!my_dirent) {
+			fprintf(stderr, "Verify failure: got unexpected dirent:"
+				" dirent: (ino %lu, reclen: %u, type: %u, "
+				"name: %s)\n",
+				dirent->d_ino, dirent->d_reclen,
+				dirent->d_type, dirent->d_name);
+			return -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);
+			return -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);
+			return -1;
+		}
+
+		my_dirent->seen++;
+		dirent = readdir(dd);
+	}
+
+	for (i = 0; i < num_dirents; i++) {
+		my_dirent = &dirents[i];
+
+		if (my_dirent->seen != 0 || my_dirent->name_len == 0)
+			continue;
+
+		if (my_dirent->seen == 0 && my_dirent->name_len != 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);
+	}
+
+	for (i = 0; i < num_dirents; i++) {
+		my_dirent = &dirents[i];
+		my_dirent->seen = 0;
+	}
+
+	closedir(dd);
+
+	return 0;
+}
+
+int build_dir_tree(char *dirname, unsigned long entries,
+		    unsigned long depth, int is_random)
+{
+	unsigned long i, dir_dirents, file_dirents;
+	char fullpath[PATH_MAX];
+	char dirent[OCFS2_MAX_FILENAME_LEN];
+	unsigned long layer = depth;
+
+	int fd, ret;
+
+	ret = mkdir(dirname, FILE_MODE);
+	if (ret < 0) {
+		ret = errno;
+		fprintf(stderr, "mkdir failure %d: %s\n", ret,
+			strerror(ret));
+		return ret;
+	}
+
+	if (layer == 0)
+		return 0;
+
+	if (is_random)
+		dir_dirents = get_rand(1, entries - 1);
+	else
+		dir_dirents = entries / 2;
+
+	file_dirents = entries - dir_dirents;
+
+	for (i = 0; i < file_dirents; i++) {
+		if (is_random) {
+			get_rand_nam(dirent, 1, OCFS2_MAX_FILENAME_LEN - 20);
+			snprintf(fullpath, PATH_MAX, "%s/%s%ld%ld",
+				 dirname, dirent, layer, i);
+		} else
+			snprintf(fullpath, PATH_MAX, "%s/%s%ld%ld",
+				 dirname, "F", layer, i);
+		if (strlen(fullpath) > PATH_MAX)
+			return;
+
+		fd = open(fullpath, FILE_BUFFERED_RW_FLAGS, FILE_MODE);
+		if (fd < 0) {
+			ret = errno;
+			fprintf(stderr, "create file failure %d: %s,"
+				"filename = %s\n", ret, strerror(ret),
+				fullpath);
+			return ret;
+		}
+
+		close(fd);
+	}
+
+	for (i = 0; i < dir_dirents; i++) {
+		if (is_random) {
+			get_rand_nam(dirent, 1, OCFS2_MAX_FILENAME_LEN - 20);
+			snprintf(fullpath, PATH_MAX, "%s/%s%ld%ld",
+				 dirname, dirent, layer, i);
+		} else
+			snprintf(fullpath, PATH_MAX, "%s/%s%ld%ld",
+				 dirname, "D", layer, i);
+		if (strlen(fullpath) > PATH_MAX)
+			return;
+
+		build_dir_tree(fullpath, entries, layer - 1, is_random);
+	}
+
+	return 0;
+}
+
+int traverse_and_destroy(char *name)
+{
+	DIR *dir;
+	int ret;
+	struct dirent *dirent;
+	char fullpath[PATH_MAX];
+	struct stat stat_info;
+
+	dir = opendir(name);
+	if (dir < 0) {
+		ret = errno;
+		fprintf(stderr, "dir open failure %d: %s\n", ret,
+			strerror(ret));
+		return ret;
+	}
+
+	dirent = readdir(dir);
+	while (dirent) {
+		if (dirent->d_type == S_IFREG >> S_SHIFT) {
+			snprintf(fullpath, PATH_MAX, "%s/%s", name,
+				 dirent->d_name);
+			ret = stat(fullpath, &stat_info);
+			if (ret) {
+				ret = errno;
+				fprintf(stderr, "stat failure %d: %s\n", ret,
+					strerror(ret));
+				return ret;
+			}
+
+			ret = unlink(fullpath);
+			if (ret) {
+				ret = errno;
+				fprintf(stderr, "unlink failure %d: %s\n", ret,
+					strerror(ret));
+				return ret;
+			}
+
+		} else {
+			if (dirent->d_type == S_IFDIR >> S_SHIFT) {
+				if ((strcmp(dirent->d_name, ".") == 0) ||
+				    (strcmp(dirent->d_name, "..") == 0)) {
+					dirent = readdir(dir);
+					continue;
+				} else {
+					snprintf(fullpath, PATH_MAX, "%s/%s",
+						 name, dirent->d_name);
+
+					ret = stat(fullpath, &stat_info);
+					if (ret) {
+						ret = errno;
+						fprintf(stderr, "stat failure"
+							" %d: %s\n", ret,
+							strerror(ret));
+						return ret;
+					}
+
+					if (!is_dir_empty(fullpath))
+						traverse_and_destroy(fullpath);
+					else {
+						ret = rmdir(fullpath);
+						if (ret) {
+							ret = errno;
+							fprintf(stderr, "rmdir "
+								"fail%d: %s\n",
+								ret,
+								strerror(ret));
+
+							return ret;
+						}
+					}
+				}
+			}
+		}
+
+		dirent = readdir(dir);
+	}
+
+	ret = rmdir(name);
+	if (ret) {
+		ret = errno;
+		fprintf(stderr, "rmdir failure %d: %s\n", ret,
+			strerror(ret));
+		exit(ret);
+	}
+
+	closedir(dir);
+
+	return 0;
+}
+
+int set_semvalue(int sem_id)
+{
+	union semun sem_union;
+
+	sem_union.val = 1;
+	if (semctl(sem_id, 0, SETVAL, sem_union) == -1) {
+		perror("semctl");
+		return -1;
+	}
+
+	return 0;
+}
+
+int semaphore_p(int sem_id)
+{
+	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;
+}
+
+int semaphore_v(int sem_id)
+{
+	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;
+}
+
+int get_max_inlined_entries(int max_inline_size)
+{
+	unsigned int almost_full_entries;
+
+	/*
+		Borrowed from mark's inline-dirs test to measure
+		how to fill up the inlined directory.
+	*/
+	almost_full_entries = max_inline_size / 512;
+	almost_full_entries *= 512;
+	almost_full_entries /= 32;
+
+	almost_full_entries += 8;
+
+	return almost_full_entries;
+}
+
diff --git a/programs/libocfs2test/dir_ops.h b/programs/libocfs2test/dir_ops.h
new file mode 100644
index 0000000..3b3c289
--- /dev/null
+++ b/programs/libocfs2test/dir_ops.h
@@ -0,0 +1,88 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * dir_ops.h
+ *
+ * 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.
+ */
+
+#ifndef DIR_OPS_H
+#define DIR_OPS_H
+
+#define _XOPEN_SOURCE 600
+#define _GNU_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#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>
+
+#define OCFS2_MAX_FILENAME_LEN          255
+#define MAX_DIRENTS                     40000
+
+#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)
+
+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 */
+};
+
+int is_dot_entry(struct my_dirent *dirent);
+int unlink_dirent(char *dirname, struct my_dirent *dirent);
+int unlink_dirent_nam(char *dirname, char *name);
+int create_and_prep_dir(char *dirname);
+int destroy_dir(char *dirname);
+struct my_dirent *find_my_dirent(char *name);
+int create_file(char *filename, char *dirname);
+int create_files(char *prefix, unsigned long num, char *dirname);
+int is_dir_empty(char *name);
+int verify_dirents(char *dir);
+int build_dir_tree(char *dirname, unsigned long entries, unsigned long depth,
+		   int is_random);
+int traverse_and_destroy(char *name);
+int set_semvalue(int sem_id);
+int semaphore_p(int sem_id);
+int semaphore_v(int sem_id);
+int get_max_inlined_entries(int max_inline_size);
+
+#endif
-- 
1.5.5




More information about the Ocfs2-test-devel mailing list