summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/filebench/common/filebench.h20
-rw-r--r--usr/src/cmd/filebench/common/fileset.c435
-rw-r--r--usr/src/cmd/filebench/common/fileset.h23
-rw-r--r--usr/src/cmd/filebench/common/flowop.c16
-rw-r--r--usr/src/cmd/filebench/common/flowop_library.c133
-rw-r--r--usr/src/cmd/filebench/common/ipc.c104
-rw-r--r--usr/src/cmd/filebench/common/ipc.h142
-rw-r--r--usr/src/cmd/filebench/common/procflow.c18
-rw-r--r--usr/src/cmd/filebench/common/threadflow.c5
-rw-r--r--usr/src/cmd/filebench/common/vars.h6
-rw-r--r--usr/src/cmd/filebench/workloads/Makefile2
-rw-r--r--usr/src/cmd/filebench/workloads/filemicro_statfile.f55
-rw-r--r--usr/src/pkgdefs/SUNWfilebench/prototype_com3
13 files changed, 669 insertions, 293 deletions
diff --git a/usr/src/cmd/filebench/common/filebench.h b/usr/src/cmd/filebench/common/filebench.h
index 74d184494e..e0610a0478 100644
--- a/usr/src/cmd/filebench/common/filebench.h
+++ b/usr/src/cmd/filebench/common/filebench.h
@@ -28,8 +28,6 @@
#ifndef _FB_FILEBENCH_H
#define _FB_FILEBENCH_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "config.h"
#include <stdio.h>
@@ -44,6 +42,14 @@ typedef enum { B_FALSE, B_TRUE } boolean_t;
typedef unsigned long long u_longlong_t;
#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
#include "procflow.h"
#include "misc.h"
#include "ipc.h"
@@ -76,14 +82,6 @@ typedef unsigned long long u_longlong_t;
extern "C" {
#endif
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
extern pid_t my_pid; /* this process' process id */
extern procflow_t *my_procflow; /* if slave process, procflow pointer */
extern int errno;
@@ -119,7 +117,7 @@ void filebench_shutdown(int error);
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#endif
-#define FILEBENCH_VERSION "1.3.3"
+#define FILEBENCH_VERSION "1.3.4"
#define FILEBENCHDIR "/usr/benchmarks/filebench"
#define FILEBENCH_PROMPT "filebench> "
#define MAX_LINE_LEN 1024
diff --git a/usr/src/cmd/filebench/common/fileset.c b/usr/src/cmd/filebench/common/fileset.c
index d402c49431..be81898860 100644
--- a/usr/src/cmd/filebench/common/fileset.c
+++ b/usr/src/cmd/filebench/common/fileset.c
@@ -25,9 +25,6 @@
* Portions Copyright 2008 Denis Cheng
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
@@ -48,21 +45,24 @@
* fileset has been created, has a tree of directories and files
* corresponding to the fileset's filesetentry tree.
*
- * This routine is called from fileset_createset(), which is in turn
- * called from parser_gram.y: parser_create_fileset() when a
- * "create fileset" or "run" command is encountered.
- * When the "create fileset" command is used, it is generally paired with
+ * Fileset entities are allocated by fileset_define() which is called from
+ * parser_gram.y: parser_fileset_define(). The filesetentry tree corrseponding
+ * to the eventual directory and file tree to be instantiated on the storage
+ * medium is built by fileset_populate(), which is called from
+ * fileset_createset(). After calling fileset_populate(), fileset_createset()
+ * will call fileset_create() to pre-allocate designated files and directories.
+ *
+ * Fileset_createset() is called from parser_gram.y: parser_create_fileset()
+ * when a "create fileset" or "run" command is encountered. When the
+ * "create fileset" command is used, it is generally paired with
* a "create processes" command, and must appear first, in order to
* instantiate all the files in the fileset before trying to use them.
*/
static int fileset_checkraw(fileset_t *fileset);
-/* parallel allocation control */
+/* maximum parallel allocation control */
#define MAX_PARALLOC_THREADS 32
-static pthread_mutex_t paralloc_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t paralloc_cv = PTHREAD_COND_INITIALIZER;
-static int paralloc_count;
/*
* returns pointer to file or fileset
@@ -129,8 +129,8 @@ fileset_usage(void)
/*
* Frees up memory mapped file region of supplied size. The
* file descriptor "fd" indicates which memory mapped file.
- * If successful, returns 0. Otherwise returns -1 if "size"
- * is zero, or -1 times the number of times msync() failed.
+ * If successful, returns 0. Otherwise returns -1 times the number of
+ * times msync() failed.
*/
static int
fileset_freemem(int fd, off64_t size)
@@ -224,7 +224,7 @@ fileset_mkdir(char *path, int mode)
}
free(p);
- return (0);
+ return (FILEBENCH_OK);
null_str:
/* clean up */
@@ -234,7 +234,7 @@ null_str:
filebench_log(LOG_ERROR,
"Failed to create directory path %s: Out of memory", path);
- return (-1);
+ return (FILEBENCH_ERROR);
}
/*
@@ -256,12 +256,12 @@ fileset_create_subdirs(fileset_t *fileset, char *filesetpath)
free(part_path);
/* now create this portion of the subdirectory tree */
- if (fileset_mkdir(full_path, 0755) == -1)
- return (-1);
+ if (fileset_mkdir(full_path, 0755) == FILEBENCH_ERROR)
+ return (FILEBENCH_ERROR);
direntry = direntry->fse_dirnext;
}
- return (0);
+ return (FILEBENCH_OK);
}
/*
@@ -293,26 +293,26 @@ fileset_alloc_file(filesetentry_t *entry)
filebench_log(LOG_INFO,
"Attempted but failed to Re-use file %s",
path);
- return (-1);
+ return (FILEBENCH_ERROR);
}
if (sb.st_size == (off64_t)entry->fse_size) {
- filebench_log(LOG_INFO,
+ filebench_log(LOG_DEBUG_IMPL,
"Re-using file %s", path);
if (!avd_get_bool(entry->fse_fileset->fs_cached))
(void) fileset_freemem(fd,
entry->fse_size);
- entry->fse_flags |= FSE_EXISTS;
(void) ipc_mutex_lock(
- &entry->fse_fileset->fs_num_files_lock);
+ &entry->fse_fileset->fs_pick_lock);
+ entry->fse_flags |= FSE_EXISTS;
entry->fse_fileset->fs_num_act_files++;
(void) ipc_mutex_unlock(
- &entry->fse_fileset->fs_num_files_lock);
+ &entry->fse_fileset->fs_pick_lock);
(void) close(fd);
- return (0);
+ return (FILEBENCH_OK);
} else if (sb.st_size > (off64_t)entry->fse_size) {
/* reuse, but too large */
@@ -329,16 +329,15 @@ fileset_alloc_file(filesetentry_t *entry)
(void) fileset_freemem(fd,
entry->fse_size);
- entry->fse_flags |= FSE_EXISTS;
-
(void) ipc_mutex_lock(
- &entry->fse_fileset->fs_num_files_lock);
+ &entry->fse_fileset->fs_pick_lock);
+ entry->fse_flags |= FSE_EXISTS;
entry->fse_fileset->fs_num_act_files++;
(void) ipc_mutex_unlock(
- &entry->fse_fileset->fs_num_files_lock);
+ &entry->fse_fileset->fs_pick_lock);
(void) close(fd);
- return (0);
+ return (FILEBENCH_OK);
}
} else {
@@ -348,18 +347,17 @@ fileset_alloc_file(filesetentry_t *entry)
"Failed to pre-allocate file %s: %s",
path, strerror(errno));
- return (-1);
+ return (FILEBENCH_ERROR);
}
}
if ((buf = (char *)malloc(FILE_ALLOC_BLOCK)) == NULL)
- return (-1);
+ return (FILEBENCH_ERROR);
+ (void) ipc_mutex_lock(&entry->fse_fileset->fs_pick_lock);
entry->fse_flags |= FSE_EXISTS;
-
- (void) ipc_mutex_lock(&entry->fse_fileset->fs_num_files_lock);
entry->fse_fileset->fs_num_act_files++;
- (void) ipc_mutex_unlock(&entry->fse_fileset->fs_num_files_lock);
+ (void) ipc_mutex_unlock(&entry->fse_fileset->fs_pick_lock);
for (seek = 0; seek < entry->fse_size; ) {
off64_t wsize;
@@ -378,7 +376,7 @@ fileset_alloc_file(filesetentry_t *entry)
path, strerror(errno));
(void) close(fd);
free(buf);
- return (-1);
+ return (FILEBENCH_ERROR);
}
seek += wsize;
}
@@ -394,26 +392,27 @@ fileset_alloc_file(filesetentry_t *entry)
"Pre-allocated file %s size %llu",
path, (u_longlong_t)entry->fse_size);
- return (0);
+ return (FILEBENCH_OK);
}
/*
* given a fileset entry, determines if the associated file
* needs to be allocated or not, and if so does the allocation.
+ * Sets shm_fsparalloc_count to -1 on error.
*/
static void *
fileset_alloc_thread(filesetentry_t *entry)
{
- if (fileset_alloc_file(entry) == -1) {
- (void) pthread_mutex_lock(&paralloc_lock);
- paralloc_count = -1;
+ if (fileset_alloc_file(entry) == FILEBENCH_ERROR) {
+ (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock);
+ filebench_shm->shm_fsparalloc_count = -1;
} else {
- (void) pthread_mutex_lock(&paralloc_lock);
- paralloc_count--;
+ (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock);
+ filebench_shm->shm_fsparalloc_count--;
}
- (void) pthread_cond_signal(&paralloc_cv);
- (void) pthread_mutex_unlock(&paralloc_lock);
+ (void) pthread_cond_signal(&filebench_shm->shm_fsparalloc_cv);
+ (void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock);
pthread_exit(NULL);
return (NULL);
@@ -451,16 +450,8 @@ fileset_openfile(fileset_t *fileset,
/* If we are going to create a file, create the parent dirs */
if ((flag & O_CREAT) && (stat64(dir, &sb) != 0)) {
- if (fileset_mkdir(dir, 0755) == -1)
- return (-1);
- }
-
- if (flag & O_CREAT) {
- entry->fse_flags |= FSE_EXISTS;
-
- (void) ipc_mutex_lock(&fileset->fs_num_files_lock);
- fileset->fs_num_act_files++;
- (void) ipc_mutex_unlock(&fileset->fs_num_files_lock);
+ if (fileset_mkdir(dir, 0755) == FILEBENCH_ERROR)
+ return (FILEBENCH_ERROR);
}
if (attrs & FLOW_ATTR_DSYNC) {
@@ -475,10 +466,15 @@ fileset_openfile(fileset_t *fileset,
filebench_log(LOG_ERROR,
"Failed to open file %s: %s",
path, strerror(errno));
- (void) ipc_mutex_unlock(&entry->fse_lock);
- return (-1);
+
+ fileset_unbusy(entry, FALSE, FALSE);
+ return (FILEBENCH_ERROR);
}
- (void) ipc_mutex_unlock(&entry->fse_lock);
+
+ if (flag & O_CREAT)
+ fileset_unbusy(entry, TRUE, TRUE);
+ else
+ fileset_unbusy(entry, FALSE, FALSE);
#ifdef sun
if (attrs & FLOW_ATTR_DIRECTIO)
@@ -505,7 +501,7 @@ fileset_openfile(fileset_t *fileset,
* FILESET_PICKNOEXIST insures that only non extant
* (not FSE_EXISTS) state files are selected.
* Note that the selected fileset entry (file) is returned
- * with its fse_lock field locked.
+ * with its FSE_BUSY flag (in fse_flags) set.
*/
filesetentry_t *
fileset_pick(fileset_t *fileset, int flags, int tid)
@@ -513,26 +509,33 @@ fileset_pick(fileset_t *fileset, int flags, int tid)
filesetentry_t *entry = NULL;
filesetentry_t *first = NULL;
- (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock);
+ (void) ipc_mutex_lock(&fileset->fs_pick_lock);
+
+ /* see if we have to wait for available files or directories */
+ if (flags & FILESET_PICKDIR) {
+ while (fileset->fs_idle_dirs == 0) {
+ (void) pthread_cond_wait(&fileset->fs_idle_dirs_cv,
+ &fileset->fs_pick_lock);
+ }
+ } else {
+ while (fileset->fs_idle_files == 0) {
+ (void) pthread_cond_wait(&fileset->fs_idle_files_cv,
+ &fileset->fs_pick_lock);
+ }
+ }
/* see if asking for impossible */
- (void) ipc_mutex_lock(&fileset->fs_num_files_lock);
if (flags & FILESET_PICKEXISTS) {
if (fileset->fs_num_act_files == 0) {
- (void) ipc_mutex_unlock(&fileset->fs_num_files_lock);
- (void) ipc_mutex_unlock(
- &filebench_shm->shm_fileset_lock);
+ (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
return (NULL);
}
} else if (flags & FILESET_PICKNOEXIST) {
if (fileset->fs_num_act_files == fileset->fs_realfiles) {
- (void) ipc_mutex_unlock(&fileset->fs_num_files_lock);
- (void) ipc_mutex_unlock(
- &filebench_shm->shm_fileset_lock);
+ (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
return (NULL);
}
}
- (void) ipc_mutex_unlock(&fileset->fs_num_files_lock);
while (entry == NULL) {
@@ -575,12 +578,23 @@ fileset_pick(fileset_t *fileset, int flags, int tid)
entry = fileset->fs_dirlist;
fileset->fs_dirrotor = entry->fse_dirnext;
} else {
- entry = fileset->fs_filerotor[tid];
- if (entry == NULL)
+ if (flags & FILESET_PICKNOEXIST) {
+ entry = fileset->fs_file_ne_rotor;
+ if (entry == NULL)
+ fileset->fs_file_ne_rotor =
+ entry =
+ fileset->fs_filelist;
+ fileset->fs_file_ne_rotor =
+ entry->fse_filenext;
+ } else {
+ entry = fileset->fs_filerotor[tid];
+ if (entry == NULL)
+ fileset->fs_filerotor[tid] =
+ entry =
+ fileset->fs_filelist;
fileset->fs_filerotor[tid] =
- entry = fileset->fs_filelist;
- fileset->fs_filerotor[tid] =
- entry->fse_filenext;
+ entry->fse_filenext;
+ }
}
}
@@ -590,34 +604,123 @@ fileset_pick(fileset_t *fileset, int flags, int tid)
if (first == NULL)
first = entry;
- /* Return locked entry */
- (void) ipc_mutex_lock(&entry->fse_lock);
+ /* see if entry in use */
+ if (entry->fse_flags & FSE_BUSY) {
+
+ /* it is, so try next */
+ entry = NULL;
+ continue;
+ }
/* If we ask for an existing file, go round again */
if ((flags & FILESET_PICKEXISTS) &&
- !(entry->fse_flags & FSE_EXISTS)) {
- (void) ipc_mutex_unlock(&entry->fse_lock);
+ !(entry->fse_flags & FSE_EXISTS))
entry = NULL;
- }
/* If we ask for not an existing file, go round again */
if ((flags & FILESET_PICKNOEXIST) &&
- (entry->fse_flags & FSE_EXISTS)) {
- (void) ipc_mutex_unlock(&entry->fse_lock);
+ (entry->fse_flags & FSE_EXISTS))
entry = NULL;
- }
}
- (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock);
+ /* update file or directory idle counts */
+ if (flags & FILESET_PICKDIR)
+ fileset->fs_idle_dirs--;
+ else
+ fileset->fs_idle_files--;
+
+ /* Indicate that file or directory is now busy */
+ entry->fse_flags |= FSE_BUSY;
+
+ (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
filebench_log(LOG_DEBUG_SCRIPT, "Picked file %s", entry->fse_path);
return (entry);
empty:
- (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock);
+ (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
return (NULL);
}
/*
+ * Removes a filesetentry from the "FSE_BUSY" state, signaling any threads
+ * that are waiting for a NOT BUSY filesetentry. Also sets whether it is
+ * existant or not, or leaves that designation alone.
+ */
+void
+fileset_unbusy(filesetentry_t *entry, int update_exist, int new_exist_val)
+{
+ fileset_t *fileset = NULL;
+ int fse_is_dir;
+
+ if (entry)
+ fileset = entry->fse_fileset;
+
+ if (fileset == NULL) {
+ filebench_log(LOG_ERROR, "fileset_unbusy: NO FILESET!");
+ return;
+ }
+
+ (void) ipc_mutex_lock(&fileset->fs_pick_lock);
+ fse_is_dir = entry->fse_flags & FSE_DIR;
+
+ /* increment idle count, clear FSE_BUSY and signal IF it was busy */
+ if (entry->fse_flags & FSE_BUSY) {
+
+ /* unbusy it */
+ entry->fse_flags &= (~FSE_BUSY);
+
+ /* release any threads waiting for unbusy */
+ if (entry->fse_flags & FSE_THRD_WAITNG) {
+ entry->fse_flags &= (~FSE_THRD_WAITNG);
+ (void) pthread_cond_broadcast(
+ &fileset->fs_thrd_wait_cv);
+ }
+
+ /* increment idle count and signal waiting threads */
+ if (fse_is_dir) {
+ fileset->fs_idle_dirs++;
+ if (fileset->fs_idle_dirs == 1) {
+ (void) pthread_cond_signal(
+ &fileset->fs_idle_dirs_cv);
+ }
+ } else {
+ fileset->fs_idle_files++;
+ if (fileset->fs_idle_files == 1) {
+ (void) pthread_cond_signal(
+ &fileset->fs_idle_files_cv);
+ }
+ }
+ }
+
+ /* modify FSE_EXIST flag and actual dirs/files count, if requested */
+ if (update_exist) {
+ if (new_exist_val == TRUE) {
+ if (!(entry->fse_flags & FSE_EXISTS)) {
+
+ /* asked to set, and it was clear */
+ entry->fse_flags |= FSE_EXISTS;
+ if (fse_is_dir)
+ fileset->fs_num_act_dirs++;
+ else
+ fileset->fs_num_act_files++;
+ }
+ } else {
+ if (entry->fse_flags & FSE_EXISTS) {
+
+ /* asked to clear, and it was set */
+ entry->fse_flags &= (~FSE_EXISTS);
+ if (fse_is_dir)
+ fileset->fs_num_act_dirs--;
+ else
+ fileset->fs_num_act_files--;
+ }
+ }
+ }
+
+ (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
+}
+
+/*
* Given a fileset "fileset", create the associated files as
* specified in the attributes of the fileset. The fileset is
* rooted in a directory whose pathname is in fileset_path. If the
@@ -629,7 +732,8 @@ empty:
* their containing subdirectory trees in the filesystem and
* creating actual files for fileset_preallocpercent of them. The
* created files are filled with fse_size bytes of unitialized
- * data. The routine returns -1 on errors, 0 on success.
+ * data. The routine returns FILEBENCH_ERROR on errors,
+ * FILEBENCH_OK on success.
*/
static int
fileset_create(fileset_t *fileset)
@@ -648,22 +752,19 @@ fileset_create(fileset_t *fileset)
if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) {
filebench_log(LOG_ERROR, "%s path not set",
fileset_entity_name(fileset));
- return (-1);
+ return (FILEBENCH_ERROR);
}
if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) {
filebench_log(LOG_ERROR, "%s name not set",
fileset_entity_name(fileset));
- return (-1);
+ return (FILEBENCH_ERROR);
}
- /* declare all files currently non existant (single threaded code) */
- fileset->fs_num_act_files = 0;
-
#ifdef HAVE_RAW_SUPPORT
/* treat raw device as special case */
if (fileset->fs_attrs & FILESET_IS_RAW_DEV)
- return (0);
+ return (FILEBENCH_OK);
#endif /* HAVE_RAW_SUPPORT */
/* XXX Add check to see if there is enough space */
@@ -694,8 +795,8 @@ fileset_create(fileset_t *fileset)
(void) mkdir(path, 0755);
/* make the filesets directory tree */
- if (fileset_create_subdirs(fileset, path) == -1)
- return (-1);
+ if (fileset_create_subdirs(fileset, path) == FILEBENCH_ERROR)
+ return (FILEBENCH_ERROR);
start = gethrtime();
@@ -713,10 +814,8 @@ fileset_create(fileset_t *fileset)
pickflags = FILESET_PICKUNIQUE;
- entry->fse_flags &= ~FSE_EXISTS;
-
/* entry doesn't need to be locked during initialization */
- (void) ipc_mutex_unlock(&entry->fse_lock);
+ fileset_unbusy(entry, FALSE, FALSE);
if (rand() < randno)
continue;
@@ -728,34 +827,52 @@ fileset_create(fileset_t *fileset)
else
entry->fse_flags &= (~FSE_REUSING);
+ /* fire off allocation threads for each file if paralloc set */
if (avd_get_bool(fileset->fs_paralloc)) {
- /* fire off a separate allocation thread */
- (void) pthread_mutex_lock(&paralloc_lock);
- while (paralloc_count >= MAX_PARALLOC_THREADS) {
+ /* limit total number of simultaneous allocations */
+ (void) pthread_mutex_lock(
+ &filebench_shm->shm_fsparalloc_lock);
+ while (filebench_shm->shm_fsparalloc_count
+ >= MAX_PARALLOC_THREADS) {
(void) pthread_cond_wait(
- &paralloc_cv, &paralloc_lock);
+ &filebench_shm->shm_fsparalloc_cv,
+ &filebench_shm->shm_fsparalloc_lock);
}
- if (paralloc_count < 0) {
- (void) pthread_mutex_unlock(&paralloc_lock);
- return (-1);
+ /* quit if any allocation thread reports and error */
+ if (filebench_shm->shm_fsparalloc_count < 0) {
+ (void) pthread_mutex_unlock(
+ &filebench_shm->shm_fsparalloc_lock);
+ return (FILEBENCH_ERROR);
}
- paralloc_count++;
- (void) pthread_mutex_unlock(&paralloc_lock);
+ filebench_shm->shm_fsparalloc_count++;
+ (void) pthread_mutex_unlock(
+ &filebench_shm->shm_fsparalloc_lock);
+ /*
+ * Fire off a detached allocation thread per file.
+ * The thread will self destruct when it finishes
+ * writing pre-allocation data to the file.
+ */
if (pthread_create(&tid, NULL,
(void *(*)(void*))fileset_alloc_thread,
- entry) != 0) {
+ entry) == 0) {
+ /*
+ * A thread was created; detach it so it can
+ * fully quit when finished.
+ */
+ (void) pthread_detach(tid);
+ } else {
filebench_log(LOG_ERROR,
"File prealloc thread create failed");
filebench_shutdown(1);
}
} else {
- if (fileset_alloc_file(entry) == -1)
- return (-1);
+ if (fileset_alloc_file(entry) == FILEBENCH_ERROR)
+ return (FILEBENCH_ERROR);
}
}
@@ -767,7 +884,7 @@ exit:
fileset_entity_name(fileset), fileset_name,
(u_longlong_t)(((gethrtime() - start) / 1000000000) + 1));
- return (0);
+ return (FILEBENCH_OK);
}
/*
@@ -811,8 +928,8 @@ fileset_insdirlist(fileset_t *fileset, filesetentry_t *entry)
* list in the specified parent filesetentry entity, which may
* be a directory filesetentry, or the root filesetentry in the
* fileset. It is also placed on the fileset's list of all
- * contained files. Returns 0 if successful or -1 if ipc memory
- * for the path string cannot be allocated.
+ * contained files. Returns FILEBENCH_OK if successful or FILEBENCH_ERROR
+ * if ipc memory for the path string cannot be allocated.
*/
static int
fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial)
@@ -825,20 +942,24 @@ fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial)
== NULL) {
filebench_log(LOG_ERROR,
"fileset_populate_file: Can't malloc filesetentry");
- return (-1);
+ return (FILEBENCH_ERROR);
}
- (void) pthread_mutex_init(&entry->fse_lock, ipc_mutexattr());
+ /* Another currently idle file */
+ (void) ipc_mutex_lock(&fileset->fs_pick_lock);
+ fileset->fs_idle_files++;
+ (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
+
entry->fse_parent = parent;
entry->fse_fileset = fileset;
- entry->fse_flags |= FSE_FREE;
+ entry->fse_flags = FSE_FREE;
fileset_insfilelist(fileset, entry);
(void) snprintf(tmpname, sizeof (tmpname), "%08d", serial);
if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) {
filebench_log(LOG_ERROR,
"fileset_populate_file: Can't alloc path string");
- return (-1);
+ return (FILEBENCH_ERROR);
}
/* see if random variable was supplied for file size */
@@ -860,7 +981,7 @@ fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial)
fileset->fs_bytes += entry->fse_size;
fileset->fs_realfiles++;
- return (0);
+ return (FILEBENCH_OK);
}
/*
@@ -877,9 +998,9 @@ fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial)
* initial call to this routine is a tree of directories of
* random width and varying depth with sufficient leaf
* directories to contain all required files.
- * Returns 0 on success. Returns -1 if ipc path string memory
- * cannot be allocated and returns an error code (currently
- * also -1) from calls to fileset_populate_file or recursive
+ * Returns FILEBENCH_OK on success. Returns FILEBENCH_ERROR if ipc path
+ * string memory cannot be allocated and returns the error code (currently
+ * also FILEBENCH_ERROR) from calls to fileset_populate_file or recursive
* calls to fileset_populate_subdir.
*/
static int
@@ -899,20 +1020,23 @@ fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent,
== NULL) {
filebench_log(LOG_ERROR,
"fileset_populate_subdir: Can't malloc filesetentry");
- return (-1);
+ return (FILEBENCH_ERROR);
}
- (void) pthread_mutex_init(&entry->fse_lock, ipc_mutexattr());
+ /* another idle directory */
+ (void) ipc_mutex_lock(&fileset->fs_pick_lock);
+ fileset->fs_idle_dirs++;
+ (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
(void) snprintf(tmpname, sizeof (tmpname), "%08d", serial);
if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) {
filebench_log(LOG_ERROR,
"fileset_populate_subdir: Can't alloc path string");
- return (-1);
+ return (FILEBENCH_ERROR);
}
entry->fse_parent = parent;
- entry->fse_flags |= FSE_DIR | FSE_FREE;
+ entry->fse_flags = FSE_DIR | FSE_FREE;
fileset_insdirlist(fileset, entry);
if (fileset->fs_dirdepthrv) {
@@ -969,7 +1093,7 @@ fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent,
if (ret != 0)
return (ret);
}
- return (0);
+ return (FILEBENCH_OK);
}
/*
@@ -997,12 +1121,28 @@ fileset_populate(fileset_t *fileset)
#ifdef HAVE_RAW_SUPPORT
/* check for raw device */
if (fileset->fs_attrs & FILESET_IS_RAW_DEV)
- return (0);
+ return (FILEBENCH_OK);
#endif /* HAVE_RAW_SUPPORT */
/* save value of entries obtained for later, in case it was random */
fileset->fs_constentries = entries;
+ /* declare all files currently non existant */
+ fileset->fs_num_act_files = 0;
+
+ /* initialize idle files and directories condition variables */
+ (void) pthread_cond_init(&fileset->fs_idle_dirs_cv, ipc_condattr());
+ (void) pthread_cond_init(&fileset->fs_idle_files_cv, ipc_condattr());
+
+ /* no files or dirs idle (or busy) yet */
+ fileset->fs_idle_files = 0;
+ fileset->fs_idle_dirs = 0;
+
+ /* initialize locks and other condition variables */
+ (void) pthread_mutex_init(&fileset->fs_pick_lock,
+ ipc_mutexattr(IPC_MUTEX_NORMAL));
+ (void) pthread_cond_init(&fileset->fs_thrd_wait_cv, ipc_condattr());
+
/* is dirwidth a random variable? */
if (AVD_IS_RANDOM(fileset->fs_dirwidth)) {
meandirwidth =
@@ -1054,7 +1194,7 @@ exists:
(u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL));
}
- return (0);
+ return (FILEBENCH_OK);
}
/*
@@ -1084,10 +1224,6 @@ fileset_define(avd_t name)
filebench_log(LOG_DEBUG_IMPL,
"Defining file %s", avd_get_str(name));
- /* initialize fs_num_act_files lock */
- (void) pthread_mutex_init(&fileset->fs_num_files_lock,
- ipc_mutexattr());
-
(void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock);
fileset->fs_dirgamma = avd_int_alloc(1500);
@@ -1129,7 +1265,10 @@ fileset_createset(fileset_t *fileset)
int ret = 0;
/* set up for possible parallel allocate */
- paralloc_count = 0;
+ filebench_shm->shm_fsparalloc_count = 0;
+ (void) pthread_cond_init(
+ &filebench_shm->shm_fsparalloc_cv,
+ ipc_condattr());
if (fileset && avd_get_bool(fileset->fs_prealloc)) {
@@ -1139,7 +1278,7 @@ fileset_createset(fileset_t *fileset)
"file %s/%s is a RAW device",
avd_get_str(fileset->fs_path),
avd_get_str(fileset->fs_name));
- return (0);
+ return (FILEBENCH_OK);
}
filebench_log(LOG_INFO,
@@ -1147,10 +1286,10 @@ fileset_createset(fileset_t *fileset)
fileset_entity_name(fileset),
avd_get_str(fileset->fs_name));
- if ((ret = fileset_populate(fileset)) != 0)
+ if ((ret = fileset_populate(fileset)) != FILEBENCH_OK)
return (ret);
- if ((ret = fileset_create(fileset)) != 0)
+ if ((ret = fileset_create(fileset)) != FILEBENCH_OK)
return (ret);
} else {
@@ -1169,10 +1308,12 @@ fileset_createset(fileset_t *fileset)
continue;
}
- if ((ret = fileset_populate(list)) != 0)
+ if ((ret = fileset_populate(list)) != FILEBENCH_OK)
return (ret);
- if ((ret = fileset_create(list)) != 0)
+
+ if ((ret = fileset_create(list)) != FILEBENCH_OK)
return (ret);
+
list = list->fs_next;
}
}
@@ -1181,15 +1322,17 @@ fileset_createset(fileset_t *fileset)
filebench_log(LOG_INFO,
"waiting for fileset pre-allocation to finish");
- (void) pthread_mutex_lock(&paralloc_lock);
- while (paralloc_count > 0)
- (void) pthread_cond_wait(&paralloc_cv, &paralloc_lock);
- (void) pthread_mutex_unlock(&paralloc_lock);
+ (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock);
+ while (filebench_shm->shm_fsparalloc_count > 0)
+ (void) pthread_cond_wait(
+ &filebench_shm->shm_fsparalloc_cv,
+ &filebench_shm->shm_fsparalloc_lock);
+ (void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock);
- if (paralloc_count < 0)
- return (-1);
+ if (filebench_shm->shm_fsparalloc_count < 0)
+ return (FILEBENCH_ERROR);
- return (0);
+ return (FILEBENCH_OK);
}
/*
@@ -1255,13 +1398,13 @@ fileset_print(fileset_t *fileset, int first)
if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) {
filebench_log(LOG_ERROR, "%s path not set",
fileset_entity_name(fileset));
- return (-1);
+ return (FILEBENCH_ERROR);
}
if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) {
filebench_log(LOG_ERROR, "%s name not set",
fileset_entity_name(fileset));
- return (-1);
+ return (FILEBENCH_ERROR);
}
pathlength = strlen(fileset_path) + strlen(fileset_name);
@@ -1295,7 +1438,7 @@ fileset_print(fileset_t *fileset, int first)
(u_longlong_t)avd_get_int(fileset->fs_dirwidth),
(u_longlong_t)fileset->fs_constentries);
}
- return (0);
+ return (FILEBENCH_OK);
}
/*
* checks to see if the path/name pair points to a raw device. If
@@ -1316,10 +1459,10 @@ fileset_checkraw(fileset_t *fileset)
#ifdef HAVE_RAW_SUPPORT
/* check for raw device */
if ((pathname = avd_get_str(fileset->fs_path)) == NULL)
- return (0);
+ return (FILEBENCH_OK);
if ((setname = avd_get_str(fileset->fs_name)) == NULL)
- return (0);
+ return (FILEBENCH_OK);
(void) strcpy(path, pathname);
(void) strcat(path, "/");
@@ -1339,5 +1482,5 @@ fileset_checkraw(fileset_t *fileset)
}
#endif /* HAVE_RAW_SUPPORT */
- return (0);
+ return (FILEBENCH_OK);
}
diff --git a/usr/src/cmd/filebench/common/fileset.h b/usr/src/cmd/filebench/common/fileset.h
index c20bf28bf5..84ca652c3f 100644
--- a/usr/src/cmd/filebench/common/fileset.h
+++ b/usr/src/cmd/filebench/common/fileset.h
@@ -26,8 +26,7 @@
#ifndef _FB_FILESET_H
#define _FB_FILESET_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
+#include "filebench.h"
#include "config.h"
#ifndef HAVE_OFF64_T
@@ -64,7 +63,8 @@ extern "C" {
#define FSE_FREE 0x02
#define FSE_EXISTS 0x04
#define FSE_BUSY 0x08
-#define FSE_REUSING 0x10
+#define FSE_THRD_WAITNG 0x10
+#define FSE_REUSING 0x20
typedef struct filesetentry {
struct filesetentry *fse_next;
@@ -72,11 +72,10 @@ typedef struct filesetentry {
struct filesetentry *fse_filenext; /* List of files */
struct filesetentry *fse_dirnext; /* List of directories */
struct fileset *fse_fileset; /* Parent fileset */
- pthread_mutex_t fse_lock;
char *fse_path;
int fse_depth;
off64_t fse_size;
- int fse_flags;
+ int fse_flags; /* protected by fs_pick_lock */
} filesetentry_t;
#define FILESET_PICKANY 0x1 /* Pick any file from the set */
@@ -121,13 +120,23 @@ typedef struct fileset {
fbint_t fs_num_act_files; /* total number of files */
/* actually existing in the */
/* host or server's file system */
- pthread_mutex_t fs_num_files_lock; /* lock for fs_num_act_files */
+ fbint_t fs_num_act_dirs; /* total number of directories */
+ /* actually existing in the */
+ /* host or server's file system */
+ int64_t fs_idle_files; /* number of files NOT busy */
+ pthread_cond_t fs_idle_files_cv; /* idle files condition variable */
+ int64_t fs_idle_dirs; /* number of dirs NOT busy */
+ pthread_cond_t fs_idle_dirs_cv; /* idle dirs condition variable */
+ pthread_mutex_t fs_pick_lock; /* per fileset "pick" function lock */
+ pthread_cond_t fs_thrd_wait_cv; /* per fileset file busy wait cv */
filesetentry_t *fs_filelist; /* List of files */
filesetentry_t *fs_dirlist; /* List of directories */
filesetentry_t *fs_filefree; /* Ptr to next free file */
filesetentry_t *fs_dirfree; /* Ptr to next free directory */
filesetentry_t *fs_filerotor[FSE_MAXTID]; /* next file to */
/* select */
+ filesetentry_t *fs_file_ne_rotor; /* next non existent file */
+ /* to select for createfile */
filesetentry_t *fs_dirrotor; /* Ptr to next directory to select */
} fileset_t;
@@ -141,6 +150,8 @@ char *fileset_resolvepath(filesetentry_t *entry);
void fileset_usage(void);
void fileset_iter(int (*cmd)(fileset_t *fileset, int first));
int fileset_print(fileset_t *fileset, int first);
+void fileset_unbusy(filesetentry_t *entry, int update_exist,
+ int new_exist_val);
#ifdef __cplusplus
}
diff --git a/usr/src/cmd/filebench/common/flowop.c b/usr/src/cmd/filebench/common/flowop.c
index b75222cb23..6a7773b795 100644
--- a/usr/src/cmd/filebench/common/flowop.c
+++ b/usr/src/cmd/filebench/common/flowop.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "config.h"
#ifdef HAVE_LWPS
@@ -253,7 +251,9 @@ flowop_initflow(flowop_t *flowop)
* save static copies of two items, in case they are supplied
* from random variables
*/
- flowop->fo_constvalue = avd_get_int(flowop->fo_value);
+ if (!AVD_IS_STRING(flowop->fo_value))
+ flowop->fo_constvalue = avd_get_int(flowop->fo_value);
+
flowop->fo_constwss = avd_get_int(flowop->fo_wss);
if ((*flowop->fo_init)(flowop) < 0) {
@@ -587,7 +587,8 @@ flowop_start(threadflow_t *threadflow)
void
flowop_init(void)
{
- (void) pthread_mutex_init(&controlstats_lock, ipc_mutexattr());
+ (void) pthread_mutex_init(&controlstats_lock,
+ ipc_mutexattr(IPC_MUTEX_NORMAL));
flowoplib_init();
}
@@ -744,7 +745,8 @@ flowop_define_common(threadflow_t *threadflow, char *name, flowop_t *inherit,
if (inherit) {
(void) memcpy(flowop, inherit, sizeof (flowop_t));
- (void) pthread_mutex_init(&flowop->fo_lock, ipc_mutexattr());
+ (void) pthread_mutex_init(&flowop->fo_lock,
+ ipc_mutexattr(IPC_MUTEX_PRI_ROB));
(void) ipc_mutex_lock(&flowop->fo_lock);
flowop->fo_next = NULL;
flowop->fo_exec_next = NULL;
@@ -754,7 +756,8 @@ flowop_define_common(threadflow_t *threadflow, char *name, flowop_t *inherit,
(void) memset(flowop, 0, sizeof (flowop_t));
flowop->fo_iters = avd_int_alloc(1);
flowop->fo_type = type;
- (void) pthread_mutex_init(&flowop->fo_lock, ipc_mutexattr());
+ (void) pthread_mutex_init(&flowop->fo_lock,
+ ipc_mutexattr(IPC_MUTEX_PRI_ROB));
(void) ipc_mutex_lock(&flowop->fo_lock);
}
@@ -814,6 +817,7 @@ flowop_define(threadflow_t *threadflow, char *name, flowop_t *inherit,
return (NULL);
(void) ipc_mutex_unlock(&flowop->fo_lock);
+
return (flowop);
}
diff --git a/usr/src/cmd/filebench/common/flowop_library.c b/usr/src/cmd/filebench/common/flowop_library.c
index 0301b4937f..9299ca0a6b 100644
--- a/usr/src/cmd/filebench/common/flowop_library.c
+++ b/usr/src/cmd/filebench/common/flowop_library.c
@@ -25,8 +25,6 @@
* Portions Copyright 2008 Denis Cheng
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "config.h"
#include <sys/types.h>
@@ -105,6 +103,7 @@ static int flowoplib_init_generic(flowop_t *flowop);
static void flowoplib_destruct_generic(flowop_t *flowop);
static void flowoplib_destruct_noop(flowop_t *flowop);
static int flowoplib_fdnum(threadflow_t *threadflow, flowop_t *flowop);
+static int flowoplib_print(threadflow_t *threadflow, flowop_t *flowop);
static int flowoplib_write(threadflow_t *threadflow, flowop_t *flowop);
#ifdef HAVE_AIO
static int flowoplib_aiowrite(threadflow_t *threadflow, flowop_t *flowop);
@@ -209,6 +208,8 @@ static flowoplib_t flowoplib_funcs[] = {
flowoplib_deletefile, flowoplib_destruct_generic,
FLOW_TYPE_IO, FLOW_ATTR_WRITE, "writewholefile", flowoplib_init_generic,
flowoplib_writewholefile, flowoplib_destruct_generic,
+ FLOW_TYPE_OTHER, 0, "print", flowoplib_init_generic,
+ flowoplib_print, flowoplib_destruct_generic,
/* routine to calculate mean and stddev for output from a randvar */
FLOW_TYPE_OTHER, 0, "testrandvar", flowoplib_testrandvar_init,
flowoplib_testrandvar, flowoplib_testrandvar_destruct
@@ -1964,6 +1965,7 @@ flowoplib_deletefile(threadflow_t *threadflow, flowop_t *flowop)
#endif /* HAVE_RAW_SUPPORT */
if (file == NULL) {
+ /* pick arbitrary, existing (allocated) file */
if ((file = fileset_pick(fileset, FILESET_PICKEXISTS, 0))
== NULL) {
filebench_log(LOG_DEBUG_SCRIPT,
@@ -1971,7 +1973,18 @@ flowoplib_deletefile(threadflow_t *threadflow, flowop_t *flowop)
return (FILEBENCH_NORSC);
}
} else {
- (void) ipc_mutex_lock(&file->fse_lock);
+ /* delete specific file. wait for it to be non-busy */
+ (void) ipc_mutex_lock(&fileset->fs_pick_lock);
+ while (file->fse_flags & FSE_BUSY) {
+ file->fse_flags |= FSE_THRD_WAITNG;
+ (void) pthread_cond_wait(&fileset->fs_thrd_wait_cv,
+ &fileset->fs_pick_lock);
+ }
+
+ /* File now available, grab it for deletion */
+ file->fse_flags |= FSE_BUSY;
+ fileset->fs_idle_files--;
+ (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
}
*path = 0;
@@ -1982,14 +1995,13 @@ flowoplib_deletefile(threadflow_t *threadflow, flowop_t *flowop)
(void) strcat(path, pathtmp);
free(pathtmp);
+ /* delete the selected file */
flowop_beginop(threadflow, flowop);
(void) unlink(path);
flowop_endop(threadflow, flowop, 0);
- file->fse_flags &= ~FSE_EXISTS;
- (void) ipc_mutex_lock(&fileset->fs_num_files_lock);
- fileset->fs_num_act_files--;
- (void) ipc_mutex_unlock(&fileset->fs_num_files_lock);
- (void) ipc_mutex_unlock(&file->fse_lock);
+
+ /* indicate that it is no longer busy and no longer exists */
+ fileset_unbusy(file, TRUE, FALSE);
filebench_log(LOG_DEBUG_SCRIPT, "deleted file %s", file->fse_path);
@@ -2117,33 +2129,84 @@ flowoplib_statfile(threadflow_t *threadflow, flowop_t *flowop)
{
filesetentry_t *file;
fileset_t *fileset;
- char path[MAXPATHLEN];
- char *pathtmp;
+ struct stat statbuf;
+ int fd = flowop->fo_fdnumber;
- if ((fileset = flowop->fo_fileset) == NULL) {
- filebench_log(LOG_ERROR, "flowop NULL file");
+ /* if fd specified and the file is open, use it to access file */
+ if ((fd > 0) && ((threadflow->tf_fd[fd]) > 0)) {
+
+ /* check whether file handle still valid */
+ if ((file = threadflow->tf_fse[fd]) == NULL) {
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "flowop %s trying to stat NULL file at fd = %d",
+ flowop->fo_name, fd);
+ return (FILEBENCH_ERROR);
+ }
+
+ /* if here, we still have a valid file pointer */
+ fileset = file->fse_fileset;
+ } else {
+ /* Otherwise, pick arbitrary file */
+ file = NULL;
+ fileset = flowop->fo_fileset;
+ }
+
+
+ if (fileset == NULL) {
+ filebench_log(LOG_ERROR,
+ "statfile with no fileset specified");
return (FILEBENCH_ERROR);
}
- if ((file = fileset_pick(fileset, FILESET_PICKEXISTS, 0)) == NULL) {
- filebench_log(LOG_DEBUG_SCRIPT,
- "flowop %s failed to pick file",
+#ifdef HAVE_RAW_SUPPORT
+ /* can't be used with raw devices */
+ if (fileset->fs_attrs & FILESET_IS_RAW_DEV) {
+ filebench_log(LOG_ERROR,
+ "flowop %s attempted do a statfile on a RAW device",
flowop->fo_name);
- return (FILEBENCH_NORSC);
+ return (FILEBENCH_ERROR);
}
+#endif /* HAVE_RAW_SUPPORT */
- *path = 0;
- (void) strcpy(path, avd_get_str(fileset->fs_path));
- (void) strcat(path, "/");
- (void) strcat(path, avd_get_str(fileset->fs_name));
- pathtmp = fileset_resolvepath(file);
- (void) strcat(path, pathtmp);
- free(pathtmp);
+ if (file == NULL) {
+ char path[MAXPATHLEN];
+ char *pathtmp;
- flowop_beginop(threadflow, flowop);
- flowop_endop(threadflow, flowop, 0);
+ /* pick arbitrary, existing (allocated) file */
+ if ((file = fileset_pick(fileset, FILESET_PICKEXISTS, 0))
+ == NULL) {
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "Statfile flowop %s failed to pick file",
+ flowop->fo_name);
+ return (FILEBENCH_NORSC);
+ }
+
+ /* resolve path and do a stat on file */
+ *path = 0;
+ (void) strcpy(path, avd_get_str(fileset->fs_path));
+ (void) strcat(path, "/");
+ (void) strcat(path, avd_get_str(fileset->fs_name));
+ pathtmp = fileset_resolvepath(file);
+ (void) strcat(path, pathtmp);
+ free(pathtmp);
+
+ /* stat the file */
+ flowop_beginop(threadflow, flowop);
+ if (stat(path, &statbuf) == -1)
+ filebench_log(LOG_ERROR,
+ "statfile flowop %s failed", flowop->fo_name);
+ flowop_endop(threadflow, flowop, 0);
- (void) ipc_mutex_unlock(&file->fse_lock);
+ fileset_unbusy(file, FALSE, FALSE);
+ } else {
+ /* stat specific file */
+ flowop_beginop(threadflow, flowop);
+ if (fstat(threadflow->tf_fd[fd], &statbuf) == -1)
+ filebench_log(LOG_ERROR,
+ "statfile flowop %s failed", flowop->fo_name);
+ flowop_endop(threadflow, flowop, 0);
+
+ }
return (FILEBENCH_OK);
}
@@ -2565,6 +2628,24 @@ flowoplib_testrandvar_destruct(flowop_t *flowop)
}
/*
+ * prints message to the console from within a thread
+ */
+static int
+flowoplib_print(threadflow_t *threadflow, flowop_t *flowop)
+{
+ procflow_t *procflow;
+
+ procflow = threadflow->tf_process;
+ filebench_log(LOG_INFO,
+ "Message from process (%s,%d), thread (%s,%d): %s",
+ procflow->pf_name, procflow->pf_instance,
+ threadflow->tf_name, threadflow->tf_instance,
+ avd_get_str(flowop->fo_value));
+
+ return (FILEBENCH_OK);
+}
+
+/*
* Prints usage information for flowop operations.
*/
void
diff --git a/usr/src/cmd/filebench/common/ipc.c b/usr/src/cmd/filebench/common/ipc.c
index ae52ee9e43..f0bf6fd14e 100644
--- a/usr/src/cmd/filebench/common/ipc.c
+++ b/usr/src/cmd/filebench/common/ipc.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "config.h"
#include <stdio.h>
@@ -42,7 +40,6 @@
static int shmfd;
filebench_shm_t *filebench_shm = NULL;
-static pthread_mutexattr_t *mutexattr = NULL;
/*
* Interprocess Communication mechanisms. If multiple processes
@@ -114,55 +111,76 @@ ipc_mutex_unlock(pthread_mutex_t *mutex)
}
/*
- * On first invocation, allocates a mutex attributes structure
- * and initializes it with appropriate attributes. In all cases,
- * returns a pointer to the structure.
+ * Initialize mutex attributes for the various flavors of mutexes
*/
-pthread_mutexattr_t *
-ipc_mutexattr(void)
+static void
+ipc_mutexattr_init(int mtx_type)
{
+ pthread_mutexattr_t *mtx_attrp;
+
+ mtx_attrp = &(filebench_shm->shm_mutexattr[mtx_type]);
+
+ (void) pthread_mutexattr_init(mtx_attrp);
+
#ifdef USE_PROCESS_MODEL
- if (mutexattr == NULL) {
- if ((mutexattr =
- malloc(sizeof (pthread_mutexattr_t))) == NULL) {
- filebench_log(LOG_ERROR, "cannot alloc mutex attr");
- filebench_shutdown(1);
- }
#ifdef HAVE_PROCSCOPE_PTHREADS
- (void) pthread_mutexattr_init(mutexattr);
- if (pthread_mutexattr_setpshared(mutexattr,
- PTHREAD_PROCESS_SHARED) != 0) {
- filebench_log(LOG_ERROR, "cannot set mutex attr "
- "PROCESS_SHARED on this platform");
- filebench_shutdown(1);
- }
+ if (pthread_mutexattr_setpshared(mtx_attrp,
+ PTHREAD_PROCESS_SHARED) != 0) {
+ filebench_log(LOG_ERROR, "cannot set mutex attr "
+ "PROCESS_SHARED on this platform");
+ filebench_shutdown(1);
+ }
#ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL
- if (pthread_mutexattr_setprotocol(mutexattr,
+ if (mtx_type & IPC_MUTEX_PRIORITY) {
+ if (pthread_mutexattr_setprotocol(mtx_attrp,
PTHREAD_PRIO_INHERIT) != 0) {
- filebench_log(LOG_ERROR, "cannot set mutex attr "
+ filebench_log(LOG_ERROR,
+ "cannot set mutex attr "
"PTHREAD_PRIO_INHERIT on this platform");
filebench_shutdown(1);
}
+ }
#endif /* HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL */
#endif /* HAVE_PROCSCOPE_PTHREADS */
#ifdef HAVE_ROBUST_MUTEX
- if (pthread_mutexattr_setrobust_np(mutexattr,
+ if (mtx_type & IPC_MUTEX_ROBUST) {
+ if (pthread_mutexattr_setrobust_np(mtx_attrp,
PTHREAD_MUTEX_ROBUST_NP) != 0) {
- filebench_log(LOG_ERROR, "cannot set mutex attr "
+ filebench_log(LOG_ERROR,
+ "cannot set mutex attr "
"PTHREAD_MUTEX_ROBUST_NP on this platform");
filebench_shutdown(1);
}
- if (pthread_mutexattr_settype(mutexattr,
+ if (pthread_mutexattr_settype(mtx_attrp,
PTHREAD_MUTEX_ERRORCHECK) != 0) {
- filebench_log(LOG_ERROR, "cannot set mutex attr "
- "PTHREAD_MUTEX_ERRORCHECK on this platform");
+ filebench_log(LOG_ERROR,
+ "cannot set mutex attr "
+ "PTHREAD_MUTEX_ERRORCHECK "
+ "on this platform");
filebench_shutdown(1);
}
+ }
#endif /* HAVE_ROBUST_MUTEX */
+#endif /* USE_PROCESS_MODEL */
+}
+/*
+ * On first invocation, allocates a mutex attributes structure
+ * and initializes it with appropriate attributes. In all cases,
+ * returns a pointer to the structure.
+ */
+pthread_mutexattr_t *
+ipc_mutexattr(int mtx_type)
+{
+ if ((mtx_type >= IPC_NUM_MUTEX_ATTRS) ||
+ (mtx_type < IPC_MUTEX_NORMAL)) {
+ filebench_log(LOG_ERROR,
+ "ipc_mutexattr called with undefined attr selector %d",
+ mtx_type);
+ return (&(filebench_shm->shm_mutexattr[IPC_MUTEX_NORMAL]));
}
-#endif /* USE_PROCESS_MODEL */
- return (mutexattr);
+
+ return (&(filebench_shm->shm_mutexattr[mtx_type]));
}
static pthread_condattr_t *condattr = NULL;
@@ -332,28 +350,36 @@ ipc_init(void)
filebench_shm->shm_path_ptr = &filebench_shm->shm_filesetpaths[0];
/* Setup mutexes for object lists */
+ ipc_mutexattr_init(IPC_MUTEX_NORMAL);
+ ipc_mutexattr_init(IPC_MUTEX_PRIORITY);
+ ipc_mutexattr_init(IPC_MUTEX_ROBUST);
+ ipc_mutexattr_init(IPC_MUTEX_PRI_ROB);
(void) pthread_mutex_init(&filebench_shm->shm_fileset_lock,
- ipc_mutexattr());
+ ipc_mutexattr(IPC_MUTEX_NORMAL));
(void) pthread_mutex_init(&filebench_shm->shm_procflow_lock,
- ipc_mutexattr());
+ ipc_mutexattr(IPC_MUTEX_NORMAL));
(void) pthread_mutex_init(&filebench_shm->shm_procs_running_lock,
- ipc_mutexattr());
+ ipc_mutexattr(IPC_MUTEX_NORMAL));
(void) pthread_mutex_init(&filebench_shm->shm_threadflow_lock,
- ipc_mutexattr());
+ ipc_mutexattr(IPC_MUTEX_NORMAL));
(void) pthread_mutex_init(&filebench_shm->shm_flowop_lock,
- ipc_mutexattr());
+ ipc_mutexattr(IPC_MUTEX_NORMAL));
(void) pthread_mutex_init(&filebench_shm->shm_msg_lock,
- ipc_mutexattr());
+ ipc_mutexattr(IPC_MUTEX_NORMAL));
(void) pthread_mutex_init(&filebench_shm->shm_eventgen_lock,
- ipc_mutexattr());
+ ipc_mutexattr(IPC_MUTEX_PRI_ROB));
(void) pthread_mutex_init(&filebench_shm->shm_malloc_lock,
- ipc_mutexattr());
+ ipc_mutexattr(IPC_MUTEX_NORMAL));
(void) pthread_mutex_init(&filebench_shm->shm_ism_lock,
- ipc_mutexattr());
+ ipc_mutexattr(IPC_MUTEX_NORMAL));
(void) pthread_cond_init(&filebench_shm->shm_eventgen_cv,
ipc_condattr());
(void) pthread_rwlock_init(&filebench_shm->shm_flowop_find_lock,
ipc_rwlockattr());
+#ifdef USE_PROCESS_MODEL
+ (void) pthread_cond_init(&filebench_shm->shm_procflow_procs_cv,
+ ipc_condattr());
+#endif
(void) pthread_rwlock_init(&filebench_shm->shm_run_lock,
ipc_rwlockattr());
(void) pthread_rwlock_rdlock(&filebench_shm->shm_run_lock);
diff --git a/usr/src/cmd/filebench/common/ipc.h b/usr/src/cmd/filebench/common/ipc.h
index 0bb6ca48e4..937171ca10 100644
--- a/usr/src/cmd/filebench/common/ipc.h
+++ b/usr/src/cmd/filebench/common/ipc.h
@@ -26,8 +26,6 @@
#ifndef _FB_IPC_H
#define _FB_IPC_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "config.h"
#include <pthread.h>
@@ -48,6 +46,13 @@ extern "C" {
#define FILEBENCH_MEMSIZE 2048
#endif /* USE_PROCESS_MODEL */
+/* Mutex Priority Inheritance and Robustness flags */
+#define IPC_MUTEX_NORMAL 0x0
+#define IPC_MUTEX_PRIORITY 0x1
+#define IPC_MUTEX_ROBUST 0x2
+#define IPC_MUTEX_PRI_ROB 0x3
+#define IPC_NUM_MUTEX_ATTRS 4
+
#define FILEBENCH_NFILESETS FILEBENCH_MEMSIZE
#define FILEBENCH_NFILESETENTRIES (1024 * 1024)
#define FILEBENCH_NPROCFLOWS FILEBENCH_MEMSIZE
@@ -80,56 +85,113 @@ extern "C" {
#define FILEBENCH_MODE_QALLDONE 0x2
typedef struct filebench_shm {
- pthread_mutex_t shm_fileset_lock;
- pthread_mutex_t shm_procflow_lock;
- pthread_mutex_t shm_threadflow_lock;
- pthread_mutex_t shm_flowop_lock;
- pthread_mutex_t shm_msg_lock;
- pthread_mutex_t shm_malloc_lock;
- pthread_mutex_t shm_ism_lock;
+ /*
+ * All state down to shm_marker are set to zero during filebench
+ * initialization
+ */
+
+ /*
+ * list of defined filesets and related locks.
+ */
+ fileset_t *shm_filesetlist; /* list of defined filesets */
+ pthread_mutex_t shm_fileset_lock; /* protects access to list */
+
+ /*
+ * parallel file allocation control. Restricts number of spawned
+ * allocation threads and allows waiting for allocation to finish.
+ */
+ pthread_cond_t shm_fsparalloc_cv; /* cv to wait for alloc threads */
+ int shm_fsparalloc_count; /* active alloc thread count */
+ pthread_mutex_t shm_fsparalloc_lock; /* lock to protect count */
+
+ /*
+ * Procflow and process state
+ */
+ procflow_t *shm_proclist; /* list of defined procflows */
+ pthread_mutex_t shm_procflow_lock; /* protects shm_proclist */
+ int shm_procs_running; /* count of running processes */
pthread_mutex_t shm_procs_running_lock; /* protects shm_procs_running */
- pthread_rwlock_t shm_run_lock;
- pthread_rwlock_t shm_flowop_find_lock;
+ int shm_f_abort; /* stop the run NOW! */
+ pthread_rwlock_t shm_run_lock; /* used as barrier to sync run */
+#ifdef USE_PROCESS_MODEL
+ pthread_cond_t shm_procflow_procs_cv; /* pauses procflow_init till */
+#endif /* all procflows are created */
+
+ /*
+ * flowop state
+ */
+ flowop_t *shm_flowoplist; /* list of defined flowops */
+ pthread_mutex_t shm_flowop_lock; /* protects flowoplist */
+ pthread_rwlock_t shm_flowop_find_lock; /* prevents flowop_find() */
+ /* during initial flowop creation */
+
+ /*
+ * lists related to variables
+ */
+
+ var_t *shm_var_list; /* normal variables */
+ var_t *shm_var_dyn_list; /* special system variables */
+ var_t *shm_var_loc_list; /* variables local to comp flowops */
+ randdist_t *shm_rand_list; /* random variables */
+
+ /*
+ * log and statistics dumping controls and state
+ */
+ int shm_debug_level;
+ int shm_bequiet; /* pause run while collecting stats */
+ int shm_log_fd; /* log file descriptor */
+ int shm_dump_fd; /* dump file descriptor */
+ char shm_dump_filename[MAXPATHLEN];
+ /*
+ * Event generator state
+ */
+ int shm_eventgen_hz; /* number of events per sec. */
+ uint64_t shm_eventgen_q; /* count of unclaimed events */
+ pthread_mutex_t shm_eventgen_lock; /* lock protecting count */
+ pthread_cond_t shm_eventgen_cv; /* cv to wait on for more events */
+
+ /*
+ * System 5 semaphore state
+ */
+ key_t shm_semkey;
+ int shm_sys_semid;
+ char shm_semids[FILEBENCH_NSEMS];
+
+ /*
+ * Misc. pointers and state
+ */
+ char shm_fscriptname[1024];
+ int shm_id;
+ int shm_rmode;
+ int shm_1st_err;
+ pthread_mutex_t shm_threadflow_lock;
+ pthread_mutex_t shm_msg_lock;
+ pthread_mutexattr_t shm_mutexattr[IPC_NUM_MUTEX_ATTRS];
char *shm_string_ptr;
char *shm_path_ptr;
- fileset_t *shm_filesetlist;
- flowop_t *shm_flowoplist;
- procflow_t *shm_proclist;
- var_t *shm_var_list;
- var_t *shm_var_dyn_list;
- randdist_t *shm_rand_list;
- var_t *shm_var_loc_list;
- int shm_debug_level;
hrtime_t shm_epoch;
hrtime_t shm_starttime;
- int shm_bequiet;
- key_t shm_semkey;
- int shm_sys_semid;
int shm_utid;
- int shm_log_fd;
- int shm_dump_fd;
- char shm_dump_filename[MAXPATHLEN];
- pthread_mutex_t shm_eventgen_lock;
- pthread_cond_t shm_eventgen_cv;
- int shm_eventgen_hz;
- uint64_t shm_eventgen_q;
- char shm_fscriptname[1024];
- int shm_id;
+
+ /*
+ * Shared memory allocation control
+ */
+ pthread_mutex_t shm_malloc_lock;
+ pthread_mutex_t shm_ism_lock;
+ int shm_bitmap[FILEBENCH_TYPES][FILEBENCH_MAXBITMAP];
+ int shm_lastbitmapindex[FILEBENCH_TYPES];
size_t shm_required;
size_t shm_allocated;
caddr_t shm_addr;
char *shm_ptr;
- int shm_procs_running;
- int shm_f_abort;
- int shm_rmode;
- int shm_1st_err;
- int shm_bitmap[FILEBENCH_TYPES][FILEBENCH_MAXBITMAP];
- int shm_lastbitmapindex[FILEBENCH_TYPES];
- char shm_semids[FILEBENCH_NSEMS];
- int shm_marker;
+ int shm_marker; /* end of pre-zeroed data */
+ /*
+ * actual storage for shared entities.
+ * These are not zeroed during initialization
+ */
fileset_t shm_fileset[FILEBENCH_NFILESETS];
filesetentry_t shm_filesetentry[FILEBENCH_NFILESETENTRIES];
char shm_filesetpaths[FILEBENCH_FILESETPATHMEMORY];
@@ -148,7 +210,7 @@ void ipc_init(void);
void *ipc_malloc(int type);
void ipc_free(int type, char *addr);
int ipc_attach(caddr_t shmaddr);
-pthread_mutexattr_t *ipc_mutexattr(void);
+pthread_mutexattr_t *ipc_mutexattr(int);
pthread_condattr_t *ipc_condattr(void);
int ipc_semidalloc(void);
void ipc_semidfree(int semid);
diff --git a/usr/src/cmd/filebench/common/procflow.c b/usr/src/cmd/filebench/common/procflow.c
index 5cfe559802..4fe5495363 100644
--- a/usr/src/cmd/filebench/common/procflow.c
+++ b/usr/src/cmd/filebench/common/procflow.c
@@ -25,8 +25,6 @@
* Portions Copyright 2008 Denis Cheng
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>
@@ -51,8 +49,6 @@ static enum create_n_wait {
CNW_ERROR
} cnw_wait;
-static pthread_cond_t procflow_procs_created;
-
#endif /* USE_PROCESS_MODEL */
@@ -358,7 +354,7 @@ procflow_createnwait(void *nothing)
else
cnw_wait = CNW_ERROR;
- if (pthread_cond_signal(&procflow_procs_created) != 0)
+ if (pthread_cond_signal(&filebench_shm->shm_procflow_procs_cv) != 0)
exit(1);
(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
@@ -429,15 +425,13 @@ procflow_init(void)
(u_longlong_t)avd_get_int(procflow->pf_instances));
#ifdef USE_PROCESS_MODEL
- if ((ret = pthread_cond_init(&procflow_procs_created, NULL)) != 0)
- return (ret);
if ((pthread_create(&tid, NULL, procflow_createnwait, NULL)) != 0)
return (ret);
(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
- if ((ret = pthread_cond_wait(&procflow_procs_created,
+ if ((ret = pthread_cond_wait(&filebench_shm->shm_procflow_procs_cv,
&filebench_shm->shm_procflow_lock)) != 0)
return (ret);
@@ -638,12 +632,11 @@ procflow_shutdown(void)
int wait_cnt;
(void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock);
- if (filebench_shm->shm_procs_running == 0) {
+ if (filebench_shm->shm_procs_running <= 0) {
/* No processes running, so no need to do anything */
(void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock);
return;
}
- filebench_shm->shm_procs_running = 0;
(void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock);
(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
@@ -670,6 +663,11 @@ procflow_shutdown(void)
filebench_shm->shm_f_abort = 0;
(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
+
+ /* indicate all processes are stopped, even if some are "stuck" */
+ (void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock);
+ filebench_shm->shm_procs_running = 0;
+ (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock);
}
diff --git a/usr/src/cmd/filebench/common/threadflow.c b/usr/src/cmd/filebench/common/threadflow.c
index bcbf243272..0d903cb367 100644
--- a/usr/src/cmd/filebench/common/threadflow.c
+++ b/usr/src/cmd/filebench/common/threadflow.c
@@ -25,8 +25,6 @@
* Portions Copyright 2008 Denis Cheng
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "config.h"
#include <pthread.h>
#ifdef HAVE_LWPS
@@ -426,7 +424,8 @@ threadflow_define_common(procflow_t *procflow, char *name,
threadflow->tf_instance = instance;
(void) strcpy(threadflow->tf_name, name);
threadflow->tf_process = procflow;
- (void) pthread_mutex_init(&threadflow->tf_lock, ipc_mutexattr());
+ (void) pthread_mutex_init(&threadflow->tf_lock,
+ ipc_mutexattr(IPC_MUTEX_NORMAL));
filebench_log(LOG_DEBUG_IMPL, "Defining thread %s-%d",
name, instance);
diff --git a/usr/src/cmd/filebench/common/vars.h b/usr/src/cmd/filebench/common/vars.h
index ede8dca983..d3f8185c97 100644
--- a/usr/src/cmd/filebench/common/vars.h
+++ b/usr/src/cmd/filebench/common/vars.h
@@ -26,8 +26,6 @@
#ifndef _FB_VARS_H
#define _FB_VARS_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "config.h"
#include <stdio.h>
@@ -75,7 +73,9 @@ typedef struct avd {
} avd_val;
} *avd_t;
-#define AVD_IS_RANDOM(vp) ((vp)->avd_type == AVD_IND_RANDVAR)
+#define AVD_IS_RANDOM(vp) ((vp) && ((vp)->avd_type == AVD_IND_RANDVAR))
+#define AVD_IS_STRING(vp) ((vp) && (((vp)->avd_type == AVD_VAL_STR) || \
+ ((vp)->avd_type == AVD_VARVAL_STR)))
typedef struct var {
char *var_name;
diff --git a/usr/src/cmd/filebench/workloads/Makefile b/usr/src/cmd/filebench/workloads/Makefile
index a056d540aa..f7025f58e1 100644
--- a/usr/src/cmd/filebench/workloads/Makefile
+++ b/usr/src/cmd/filebench/workloads/Makefile
@@ -22,7 +22,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
.KEEP_STATE:
@@ -47,6 +46,7 @@ WORKLOADS = \
filemicro_seqread.f \
filemicro_seqwrite.f \
filemicro_seqwriterand.f \
+ filemicro_statfile.f \
filemicro_writefsync.f \
fileserver.f \
mongo.f \
diff --git a/usr/src/cmd/filebench/workloads/filemicro_statfile.f b/usr/src/cmd/filebench/workloads/filemicro_statfile.f
new file mode 100644
index 0000000000..2098d8ce4a
--- /dev/null
+++ b/usr/src/cmd/filebench/workloads/filemicro_statfile.f
@@ -0,0 +1,55 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Creates a fileset of $nfiles number of files, then loops through them
+# using $nthreads number of threads, doing "stat" calls on each file.
+#
+
+set $dir=/tmp
+set $nfiles=10000
+set $meandirwidth=20
+set $filesize=128k
+set $nthreads=20
+
+define fileset name=bigfileset,path=$dir,size=$filesize,entries=$nfiles,dirwidth=$meandirwidth,prealloc=100
+
+define process name=examinefiles,instances=1
+{
+ thread name=examinefilethread, memsize=10m,instances=$nthreads
+ {
+ flowop statfile name=statfile1,filesetname=bigfileset
+ }
+}
+
+echo "Stat File Version 1.0 personality successfully loaded"
+usage "Usage: set \$dir=<dir> defaults to $dir"
+usage " set \$filesize=<size> defaults to $filesize"
+usage " set \$nfiles=<value> defaults to $nfiles"
+usage " set \$nthreads=<value> defaults to $nthreads"
+usage " set \$meandirwidth=<size> defaults to $meandirwidth"
+usage "(sets mean dir width and dir depth is calculated as log (width, nfiles)"
+usage " "
+usage " run runtime (e.g. run 60)"
diff --git a/usr/src/pkgdefs/SUNWfilebench/prototype_com b/usr/src/pkgdefs/SUNWfilebench/prototype_com
index d6d4d67ee6..44a37e9849 100644
--- a/usr/src/pkgdefs/SUNWfilebench/prototype_com
+++ b/usr/src/pkgdefs/SUNWfilebench/prototype_com
@@ -23,8 +23,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# packaging files
i copyright
@@ -69,6 +67,7 @@ f none usr/benchmarks/filebench/workloads/filemicro_seqwrite.f 444 root bin
f none usr/benchmarks/filebench/workloads/filemicro_seqwriterand.f 444 root bin
f none usr/benchmarks/filebench/workloads/filemicro_seqwriterandvargam.f 444 root bin
f none usr/benchmarks/filebench/workloads/filemicro_seqwriterandvartab.f 444 root bin
+f none usr/benchmarks/filebench/workloads/filemicro_statfile.f 444 root bin
f none usr/benchmarks/filebench/workloads/filemicro_writefsync.f 444 root bin
f none usr/benchmarks/filebench/workloads/fileserver.f 444 root bin
f none usr/benchmarks/filebench/workloads/mongo.f 444 root bin