[PVFS2-CVS] commit by slang in pvfs2/src/common/misc: realpath.c realpath.h module.mk.in msgpairarray.sm pint-cached-config.c pint-cached-config.h pint-event.c pint-event.h pint-textlog.c pint-util.c pint-util.h pvfs2-debug.c pvfs2-util.c server-config-mgr.c server-config.c server-config.h state-machine-fns.h str-utils.c str-utils.h

CVS commit program cvs at parl.clemson.edu
Thu Aug 25 17:38:18 EDT 2005


Update of /projects/cvsroot/pvfs2/src/common/misc
In directory parlweb:/tmp/cvs-serv7520/src/common/misc

Modified Files:
      Tag: slang-event-changes-branch
	module.mk.in msgpairarray.sm pint-cached-config.c 
	pint-cached-config.h pint-event.c pint-event.h pint-textlog.c 
	pint-util.c pint-util.h pvfs2-debug.c pvfs2-util.c 
	server-config-mgr.c server-config.c server-config.h 
	state-machine-fns.h str-utils.c str-utils.h 
Added Files:
      Tag: slang-event-changes-branch
	realpath.c realpath.h 
Log Message:
updates to my event changes to bring them inline with trunk


--- /dev/null	2003-01-30 05:24:37.000000000 -0500
+++ realpath.c	2005-08-25 16:38:18.000000000 -0400
@@ -0,0 +1,190 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+/*
+ * realpath.c -- canonicalize pathname by removing symlinks
+ * Copyright (C) 1993 Rick Sladkey <jrs at world.std.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library Public License as published by
+ * the Free Software Foundation; either version 2, 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 Library Public License for more details.
+ */
+
+#define resolve_symlinks
+
+/*
+ * This routine is part of libc.  We include it nevertheless,
+ * since the libc version has some security flaws.
+ */
+
+#include <limits.h>     /* for PATH_MAX */
+#ifndef PATH_MAX
+#define PATH_MAX 8192
+#endif
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "realpath.h"
+#include "pvfs2-types.h"
+
+#define MAX_READLINKS 32
+
+/* PINT_realpath()
+ *
+ * canonicalizes path and places the result into resolved_path.  Includes
+ * cleaning of symbolic links, trailing slashes, and .. or . components.
+ * maxreslth is the maximum length allowed in resolved_path.
+ *
+ * returns 0 on succes, -PVFS_error on failure.
+ */
+int PINT_realpath(
+    const char *path,
+    char *resolved_path,
+    int maxreslth)
+{
+    int readlinks = 0;
+    char *npath;
+    char link_path[PATH_MAX + 1];
+    int n;
+    char *buf = NULL;
+    int ret;
+
+    npath = resolved_path;
+
+    /* If it's a relative pathname use getcwd for starters. */
+    if (*path != '/')
+    {
+        if (!getcwd(npath, maxreslth - 2))
+        {
+            return(-PVFS_EINVAL);
+        }
+        npath += strlen(npath);
+        if (npath[-1] != '/')
+            *npath++ = '/';
+    }
+    else
+    {
+        *npath++ = '/';
+        path++;
+    }
+
+    /* Expand each slash-separated pathname component. */
+    while (*path != '\0')
+    {
+        /* Ignore stray "/" */
+        if (*path == '/')
+        {
+            path++;
+            continue;
+        }
+        if (*path == '.' && (path[1] == '\0' || path[1] == '/'))
+        {
+            /* Ignore "." */
+            path++;
+            continue;
+        }
+        if (*path == '.' && path[1] == '.' &&
+            (path[2] == '\0' || path[2] == '/'))
+        {
+            /* Backup for ".." */
+            path += 2;
+            while (npath > resolved_path + 1 && (--npath)[-1] != '/')
+                ;
+            continue;
+        }
+        /* Safely copy the next pathname component. */
+        while (*path != '\0' && *path != '/')
+        {
+            if (npath - resolved_path > maxreslth - 2)
+            {
+                ret = -PVFS_ENAMETOOLONG;
+                goto err;
+            }
+            *npath++ = *path++;
+        }
+
+        /* Protect against infinite loops. */
+        if (readlinks++ > MAX_READLINKS)
+        {
+            ret = -PVFS_ELOOP;
+            goto err;
+        }
+
+        /* See if last pathname component is a symlink. */
+        *npath = '\0';
+        n = readlink(resolved_path, link_path, PATH_MAX);
+        if (n < 0)
+        {
+            /* EINVAL means the file exists but isn't a symlink. */
+            if (errno != EINVAL)
+            {
+                ret = -PVFS_EINVAL;
+                goto err;
+            }
+        }
+        else
+        {
+#ifdef resolve_symlinks /* Richard Gooch dislikes sl resolution */
+            int m;
+
+            /* Note: readlink doesn't add the null byte. */
+            link_path[n] = '\0';
+            if (*link_path == '/')
+                /* Start over for an absolute symlink. */
+                npath = resolved_path;
+            else
+                /* Otherwise back up over this component. */
+                while (*(--npath) != '/')
+                    ;
+
+            /* Insert symlink contents into path. */
+            m = strlen(path);
+            if (buf)
+                free(buf);
+            buf = malloc(m + n + 1);
+            if(!buf)
+            {
+                ret = -PVFS_ENOMEM;
+                goto err;
+            }
+            memcpy(buf, link_path, n);
+            memcpy(buf + n, path, m + 1);
+            path = buf;
+#endif
+        }
+        *npath++ = '/';
+    }
+    /* Delete trailing slash but don't whomp a lone slash. */
+    if (npath != resolved_path + 1 && npath[-1] == '/')
+        npath--;
+    /* Make sure it's null terminated. */
+    *npath = '\0';
+
+    if (buf)
+        free(buf);
+    return 0;
+
+  err:
+    if (buf)
+        free(buf);
+    return ret;
+}
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ * End:
+ *
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */

--- /dev/null	2003-01-30 05:24:37.000000000 -0500
+++ realpath.h	2005-08-25 16:38:18.000000000 -0400
@@ -0,0 +1,36 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+
+
+/*
+ * realpath.c -- canonicalize pathname by removing symlinks
+ * Copyright (C) 1993 Rick Sladkey <jrs at world.std.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library Public License as published by
+ * the Free Software Foundation; either version 2, 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 Library Public License for more details.
+ */
+
+int PINT_realpath(
+    const char *path,
+    char *resolved_path,
+    int m);
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ * End:
+ *
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */

Index: module.mk.in
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/module.mk.in,v
diff -p -u -r1.21.6.1 -r1.21.6.2
--- module.mk.in	8 Jul 2005 20:58:31 -0000	1.21.6.1
+++ module.mk.in	25 Aug 2005 20:38:17 -0000	1.21.6.2
@@ -12,7 +12,8 @@ LIBSRC += $(DIR)/server-config.c \
 	  $(DIR)/pint-textlog.c \
 	  $(DIR)/pint-cached-config.c \
 	  $(DIR)/msgpairarray.c \
-	  $(DIR)/pint-util.c
+	  $(DIR)/pint-util.c \
+	  $(DIR)/realpath.c
 SERVERSRC += $(DIR)/server-config.c \
              $(DIR)/server-config-mgr.c \
              $(DIR)/str-utils.c \
@@ -26,6 +27,9 @@ SERVERSRC += $(DIR)/server-config.c \
 	     $(DIR)/pint-cached-config.c \
 	     $(DIR)/msgpairarray.c \
 	     $(DIR)/pint-util.c
+
+MODCFLAGS_$(DIR)/server-config.c = \
+   -I$(srcdir)/src/server
 
 # autogenerated files
 SMCGEN += $(DIR)/msgpairarray.c

Index: msgpairarray.sm
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/msgpairarray.sm,v
diff -p -u -r1.28 -r1.28.2.1
--- msgpairarray.sm	31 Mar 2005 19:12:55 -0000	1.28
+++ msgpairarray.sm	25 Aug 2005 20:38:17 -0000	1.28.2.1
@@ -361,7 +361,7 @@ static int msgpairarray_post(PARENT_SM *
             else
             {
                 PVFS_perror_gossip("Send immediately failed",
-                    msg_p->recv_status.error_code);
+                    msg_p->send_status.error_code);
             }
 
             gossip_err("Send error: cancelling recv.\n");

Index: pint-cached-config.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/pint-cached-config.c,v
diff -p -u -r1.12 -r1.12.6.1
--- pint-cached-config.c	7 Dec 2004 14:38:55 -0000	1.12
+++ pint-cached-config.c	25 Aug 2005 20:38:17 -0000	1.12.6.1
@@ -626,12 +626,14 @@ int PINT_cached_config_map_to_server(
     return (!ret ? BMI_addr_lookup(server_addr, bmi_server_addr) : ret);
 }
 
-/* PINT_bucker_get_num_dfiles()
+/* PINT_cached_config_get_num_dfiles()
  *
- * Return the number of dfiles to use for files with this combination
- * of fs id, distribution, and attributes.  If the distribution and
- * attributes do not specify a number of dfiles, the number of io
- * servers will be used.
+ * Returns 0 if the number of dfiles has been successfully set
+ *
+ * Sets the number of dfiles to a distribution approved the value.  Clients
+ * may pass in num_dfiles_requested as a hint, if no hint is given, the server
+ * configuration is checked to find a hint there.  The distribution will
+ * choose a correct number of dfiles even if no hint is set.
  */
 int PINT_cached_config_get_num_dfiles(
     PVFS_fs_id fsid,
@@ -639,14 +641,39 @@ int PINT_cached_config_get_num_dfiles(
     int num_dfiles_requested,
     int *num_dfiles)
 {
-    int ret = -PVFS_EINVAL, num_servers_requested = 0;
-
-    if (PINT_cached_config_get_num_io(fsid, &num_servers_requested) == 0)
+    int ret = -PVFS_EINVAL;
+    int rc;
+    int num_io_servers;
+    
+    /* If the dfile request is zero, check to see if the config has that
+       setting */
+    if (0 == num_dfiles_requested)
     {
-        /* Let the distribution determine the number of dfiles to use */
-        *num_dfiles = dist->methods->get_num_dfiles(
-            dist->params, num_servers_requested, num_dfiles_requested);
+        struct qlist_head *hash_link = NULL;
+        struct config_fs_cache_s *cur_config_cache = NULL;
+        
+        /* Locate the filesystem configuration for this fs id */
+        hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
+        if (hash_link)
+        {
+            cur_config_cache = qlist_entry(
+                hash_link, struct config_fs_cache_s, hash_link);
+            assert(cur_config_cache);
+            assert(cur_config_cache->fs);
+            num_dfiles_requested = cur_config_cache->fs->default_num_dfiles;
+        }
+    }
 
+    /* Determine the number of I/O servers available */
+    rc = PINT_cached_config_get_num_io(fsid, &num_io_servers);
+    
+    if (0 == rc)
+    {
+        /* Allow the distribution to apply its hint to the number of
+           dfiles requested and the number of I/O servers available */
+        *num_dfiles = dist->methods->get_num_dfiles(dist->params,
+                                                    num_io_servers,
+                                                    num_dfiles_requested);
         ret = 0;
     }
     return ret;
@@ -868,6 +895,32 @@ int PINT_cached_config_get_root_handle(
             *fh_root = (PVFS_handle)cur_config_cache->fs->root_handle;
             ret = 0;
         }
+    }
+    return ret;
+}
+
+int PINT_cached_config_get_handle_timeout(
+    PVFS_fs_id fsid,
+    struct timeval *timeout)
+{
+    int ret = -PVFS_EINVAL;
+    struct qlist_head *hash_link = NULL;
+    struct config_fs_cache_s *cur_config_cache = NULL;
+
+    hash_link = qhash_search(PINT_fsid_config_cache_table, &(fsid));
+    if(hash_link)
+    {
+        cur_config_cache = qlist_entry(
+            hash_link, struct config_fs_cache_s, hash_link);
+
+        assert(cur_config_cache);
+        assert(cur_config_cache->fs);
+
+        timeout->tv_sec = 
+            cur_config_cache->fs->handle_recycle_timeout_sec.tv_sec;
+        timeout->tv_usec =
+            cur_config_cache->fs->handle_recycle_timeout_sec.tv_usec;
+        ret = 0;
     }
     return ret;
 }

Index: pint-cached-config.h
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/pint-cached-config.h,v
diff -p -u -r1.6 -r1.6.6.1
--- pint-cached-config.h	10 Aug 2004 20:30:55 -0000	1.6
+++ pint-cached-config.h	25 Aug 2005 20:38:17 -0000	1.6.6.1
@@ -99,6 +99,13 @@ int PINT_cached_config_get_root_handle(
     PVFS_fs_id fsid,
     PVFS_handle *fh_root);
 
+int PINT_cached_config_get_handle_timeout(
+    PVFS_fs_id fsid,
+    struct timeval *timeout);
+
+int PINT_cached_config_reinitialize(
+    struct server_configuration_s *config);
+
 #define map_handle_range_to_extent_list(hrange_list)             \
 do { cur = hrange_list;                                          \
  while(cur) {                                                    \

Index: pint-event.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/pint-event.c,v
diff -p -u -r1.10.6.2 -r1.10.6.3
--- pint-event.c	7 Jun 2005 21:59:12 -0000	1.10.6.2
+++ pint-event.c	25 Aug 2005 20:38:17 -0000	1.10.6.3
@@ -16,6 +16,7 @@
 #include "pvfs2-mgmt.h"
 #include "gossip.h"
 #include "id-generator.h"
+#include "pint-util.h"
 
 #define PINT_EVENT_DEFAULT_TEXTLOG_FILENAME "/tmp/pvfs2-events-log.txt"
 
@@ -293,8 +294,11 @@ void __PINT_event_pablo(enum PVFS_event_
 	case PVFS_EVENT_API_TROVE:
 	    sprintf(description, "trove operation");
 	    break;
-	default:
-	    /* TODO: someone fed us a bad api */
+        case PVFS_EVENT_API_ENCODE_REQ:
+        case PVFS_EVENT_API_ENCODE_RESP:
+        case PVFS_EVENT_API_DECODE_REQ:
+        case PVFS_EVENT_API_DECODE_RESP:
+        case PVFS_EVENT_API_SM:
     }
 
     /* PVFS_EVENT_API_BMI, operation(SEND|RECV), value, id, FLAG (start|end) */
@@ -340,10 +344,16 @@ void __PINT_event_mpe(enum PVFS_event_ap
 	    }
 	case PVFS_EVENT_API_TROVE:
 	    if (flags & PVFS_EVENT_FLAG_START) {
-		MPE_Log_event(PINT_event_trove_start, 0, NULL);
+		MPE_Log_event(PINT_event_trove_wr_start, 0, NULL);
 	    } else if (flags & PVFS_EVENT_FLAG_END) {
-		MPE_Log_event(PINT_event_trove_stop, value, NULL);
+		MPE_Log_event(PINT_event_trove_wr_stop, value, NULL);
 	    }
+        case PVFS_EVENT_API_ENCODE_REQ:
+        case PVFS_EVENT_API_ENCODE_RESP:
+        case PVFS_EVENT_API_DECODE_REQ:
+        case PVFS_EVENT_API_DECODE_RESP:
+        case PVFS_EVENT_API_SM:
+            ; /* XXX: NEEDS SOMETHING */
     }
 
 }
@@ -443,47 +453,98 @@ void PINT_event_log_events(
     gen_mutex_unlock(&event_mutex);
 }
 
-const char * PVFS_event_api_names[PVFS_EVENT_API_COUNT] =
+#define API_KEYWORD_ENTRY(__kw) {#__kw, PVFS_EVENT_API_##__kw}
+
+const PINT_keyword_mask_t PINT_event_api_names[] =
 {
-    "JOB",
-    "BMI",
-    "TROVE",
-    "ENCODE_REQ",
-    "ENCODE_RESP",
-    "DECODE_REQ",
-    "DECODE_RESP",
-    "SM",
-    "STATES"
+    API_KEYWORD_ENTRY(JOB),
+    API_KEYWORD_ENTRY(BMI),
+    API_KEYWORD_ENTRY(TROVE),
+    API_KEYWORD_ENTRY(ENCODE_REQ),
+    API_KEYWORD_ENTRY(ENCODE_RESP),
+    API_KEYWORD_ENTRY(DECODE_REQ),
+    API_KEYWORD_ENTRY(DECODE_RESP),
+    API_KEYWORD_ENTRY(SM),
+    API_KEYWORD_ENTRY(STATES)
 };
 
-const char * PVFS_event_op_names[PVFS_EVENT_OP_COUNT] =
+uint64_t PVFS_event_api_keyword_to_mask(const char *value)
 {
-     "BMI_SEND",
-     "BMI_RECV",
-     "FLOW",
-     "TROVE_READ_AT",
-     "TROVE_WRITE_AT",
-     "TROVE_BSTREAM_FLUSH",
-     "TROVE_KEYVAL_FLUSH",
-     "TROVE_READ_LIST",
-     "TROVE_WRITE_LIST",
-     "TROVE_KEYVAL_READ",
-     "TROVE_KEYVAL_READ_LIST",
-     "TROVE_KEYVAL_WRITE",
-     "TROVE_DSPACE_GETATTR",
-     "TROVE_DSPACE_SETATTR",
-     "TROVE_BSTREAM_RESIZE",
-     "TROVE_KEYVAL_REMOVE",
-     "TROVE_KEYVAL_ITERATE",
-     "TROVE_KEYVAL_ITERATE_KEYS",
-     "TROVE_DSPACE_ITERATE_HANDLES",
-     "TROVE_DSPACE_CREATE",
-     "TROVE_DSPACE_REMOVE",
-     "TROVE_DSPACE_VERIFY",
-     "TROVE_BSTREAM_VALIDATE",
-     "TROVE_KEYVAL_VALIDATE"
+    return PINT_keyword_to_mask(PINT_event_api_names, 
+                                (sizeof(PINT_event_api_names) /
+                                sizeof(PINT_keyword_mask_t)),
+                                value);
+}
+
+const char * PINT_event_api_get_keyword(uint64_t mask)
+{
+    return PINT_mask_to_keyword(PINT_event_api_names,
+                                (sizeof(PINT_event_api_names) /
+                                 sizeof(PINT_keyword_mask_t)),
+                                mask);
+}
+
+char * PINT_event_api_print_keywords(int columns, const char * sep)
+{
+    return PINT_print_keywords(PINT_event_api_names,
+                               sizeof(PINT_event_api_names) /
+                               sizeof(PINT_keyword_mask_t),
+                               columns, sep);
+}
+
+#define OP_KEYWORD_ENTRY(__kw) {#__kw, PVFS_EVENT_##__kw}
+
+const PINT_keyword_mask_t PINT_event_op_names[] =
+{
+    OP_KEYWORD_ENTRY(BMI_SEND),
+    OP_KEYWORD_ENTRY(BMI_RECV),
+    OP_KEYWORD_ENTRY(FLOW),
+    OP_KEYWORD_ENTRY(TROVE_READ_AT),
+    OP_KEYWORD_ENTRY(TROVE_WRITE_AT),
+    OP_KEYWORD_ENTRY(TROVE_BSTREAM_FLUSH),
+    OP_KEYWORD_ENTRY(TROVE_KEYVAL_FLUSH),
+    OP_KEYWORD_ENTRY(TROVE_READ_LIST),
+    OP_KEYWORD_ENTRY(TROVE_WRITE_LIST),
+    OP_KEYWORD_ENTRY(TROVE_KEYVAL_READ),
+    OP_KEYWORD_ENTRY(TROVE_KEYVAL_READ_LIST),
+    OP_KEYWORD_ENTRY(TROVE_KEYVAL_WRITE),
+    OP_KEYWORD_ENTRY(TROVE_DSPACE_GETATTR),
+    OP_KEYWORD_ENTRY(TROVE_DSPACE_SETATTR),
+    OP_KEYWORD_ENTRY(TROVE_BSTREAM_RESIZE),
+    OP_KEYWORD_ENTRY(TROVE_KEYVAL_REMOVE),
+    OP_KEYWORD_ENTRY(TROVE_KEYVAL_ITERATE),
+    OP_KEYWORD_ENTRY(TROVE_KEYVAL_ITERATE_KEYS),
+    OP_KEYWORD_ENTRY(TROVE_DSPACE_ITERATE_HANDLES),
+    OP_KEYWORD_ENTRY(TROVE_DSPACE_CREATE),
+    OP_KEYWORD_ENTRY(TROVE_DSPACE_REMOVE),
+    OP_KEYWORD_ENTRY(TROVE_DSPACE_VERIFY),
+    OP_KEYWORD_ENTRY(TROVE_BSTREAM_VALIDATE),
+    OP_KEYWORD_ENTRY(TROVE_KEYVAL_VALIDATE)
 };  
 
+uint64_t PVFS_event_op_keyword_to_mask(const char *value)
+{
+    return PINT_keyword_to_mask(PINT_event_op_names, 
+                                sizeof(PINT_event_op_names) /
+                                sizeof(PINT_keyword_mask_t),
+                                value);
+}
+
+const char * PINT_event_op_get_keyword(uint64_t mask)
+{
+    return PINT_mask_to_keyword(PINT_event_op_names,
+                                sizeof(PINT_event_op_names) /
+                                sizeof(PINT_keyword_mask_t),
+                                mask);
+}
+
+char * PINT_event_op_print_keywords(int columns, const char * sep)
+{
+    return PINT_print_keywords(PINT_event_op_names,
+                               sizeof(PINT_event_op_names) /
+                               sizeof(PINT_keyword_mask_t),
+                               columns, sep);
+}
 
 /*
  * Local variables:

Index: pint-event.h
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/pint-event.h,v
diff -p -u -r1.12.6.2 -r1.12.6.3
--- pint-event.h	7 Jun 2005 21:59:12 -0000	1.12.6.2
+++ pint-event.h	25 Aug 2005 20:38:17 -0000	1.12.6.3
@@ -7,6 +7,7 @@
 #ifndef __PINT_EVENT_H
 #define __PINT_EVENT_H
 
+#include "pvfs2-config.h"
 #include "pvfs2-types.h"
 #include "pvfs2-mgmt.h"
 #include "gen-locks.h"
@@ -19,6 +20,9 @@
 extern int PINT_event_on;
 extern int32_t PINT_event_api_mask;
 extern int32_t PINT_event_op_mask;
+
+const char * PINT_event_api_get_keyword(uint64_t mask);
+const char * PINT_event_op_get_keyword(uint64_t mask);
 
 int PINT_event_initialize(int ring_size);
 void PINT_event_finalize(void);

Index: pint-textlog.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/Attic/pint-textlog.c,v
diff -p -u -r1.1.2.2 -r1.1.2.3
--- pint-textlog.c	7 Jun 2005 21:59:12 -0000	1.1.2.2
+++ pint-textlog.c	25 Aug 2005 20:38:17 -0000	1.1.2.3
@@ -28,6 +28,7 @@
 #include "gossip.h"
 #include "quickhash.h"
 #include "pint-event.h"
+#include "pint-textlog.h"
 
 #define STATE_TABLE_SIZE 503
 
@@ -64,19 +65,6 @@ static char * PINT_event_server_operatio
 	"PROTO_ERROR",
 };
 
-static int PINT_event_log2(int _val)
-{
-    int res = 0;
-    while(!(_val & (1 << res)))
-    {
-        ++res;
-    }
-    return res;
-}
-
-#define PINT_event_api_get_name(_api) PVFS_event_api_names[PINT_event_log2(_api)]
-
-#define PINT_event_op_get_name(_op) PVFS_event_op_names[_op - 1]
 
 /* We need to keep track of the start events
  * so that we can match them up with the end events
@@ -250,8 +238,8 @@ static inline int PINT_textlog_write_sta
         res = fprintf(fp,
                       "%s:%s topo=State "
                       "color=(%d,%d,%d,127,true) width=1 ]\n",
-                      PINT_event_api_get_name(event->api),
-                      PINT_event_op_get_name(event->operation),
+                      PINT_event_api_get_keyword(event->api),
+                      PINT_event_op_get_keyword(event->operation),
                       rand() % 255,
                       rand() % 255,
                       rand() % 255);
@@ -278,8 +266,15 @@ static int PINT_textlog_write_event(
     float starttime, endtime;
     int req_index;
     
-    req_index = (int)id_gen_fast_lookup(estart->req_id);
-    
+    /*
+     * req_index = (int)id_gen_fast_lookup(estart->req_id);
+     */
+   
+    /* instead of using the request handle, we give each event
+     * a specific horizontal index based on the operation
+     */
+    req_index = estart->operation;
+
     starttime = PINT_textlog_timeval_to_secs(epoc, estart);
     endtime = PINT_textlog_timeval_to_secs(epoc, eend);
    
@@ -371,26 +366,26 @@ void PINT_textlog_generate(
     FILE * outfp;
     struct timeval epoc;
     int tr_index; 
-    struct qhash_table * id_map;
     QLIST_HEAD(start_events_list);
     int textlog_state_index = 0;
-    
+    struct qhash_table * id_map;
+
+    id_map = qhash_init(PINT_textlog_id_compare, 
+                        PINT_textlog_id_hash, 
+                        STATE_TABLE_SIZE);
+    if(!id_map)
+    {
+        gossip_err("PINT_generate_textlog: qhash_init failed for state map "
+                   "with table size of %d\n", STATE_TABLE_SIZE);
+        goto close_fp;
+    }
+
     outfp = fopen(filename, "w");
     if(!outfp)
     {
         gossip_err("PINT_generate_textlog: Failed to open file %s: %s\n",
                    filename, strerror(errno));
         return;
-    }
-
-    id_map = qhash_init(PINT_textlog_id_compare, 
-			PINT_textlog_id_hash, 
-			STATE_TABLE_SIZE);
-    if(!id_map)
-    {
-	gossip_err("PINT_generate_textlog: qhash_init failed for state map "
-		   "with table size of %d\n", STATE_TABLE_SIZE);
-	goto close_fp;
     }
 
     for(tr_index = 0; tr_index < count; ++tr_index)

Index: pint-util.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/pint-util.c,v
diff -p -u -r1.6 -r1.6.6.1
--- pint-util.c	4 Oct 2004 21:28:18 -0000	1.6
+++ pint-util.c	25 Aug 2005 20:38:17 -0000	1.6.6.1
@@ -1,6 +1,11 @@
 /*
  * (C) 2001 Clemson University and The University of Chicago
  *
+ * Changes by Acxiom Corporation to add PINT_check_mode() helper function
+ * as a replacement for check_mode() in permission checking, also added
+ * PINT_check_group() for supplimental group support 
+ * Copyright © Acxiom Corporation, 2005.
+ *
  * See COPYING in top-level directory.
  */
 
@@ -11,14 +16,27 @@
 #include <sys/resource.h>
 #include <unistd.h>
 #include <assert.h>
+#include <stdio.h>
+#include <grp.h>
+#include <pwd.h>
+#include <sys/types.h>
 
 #include "pvfs2-types.h"
 #include "pint-util.h"
 #include "gen-locks.h"
+#include "gossip.h"
+#include "pvfs2-debug.h"
 
 static int current_tag = 1;
 static gen_mutex_t current_tag_lock = GEN_MUTEX_INITIALIZER;
 
+static gen_mutex_t check_group_mutex = GEN_MUTEX_INITIALIZER;
+static char* check_group_pw_buffer = NULL;
+static long check_group_pw_buffer_size = 0;
+static char* check_group_gr_buffer = NULL;
+static long check_group_gr_buffer_size = 0;
+static int PINT_check_group(uid_t uid, gid_t gid);
+
 void PINT_time_mark(PINT_time_marker *out_marker)
 {
     struct rusage usage;
@@ -110,6 +128,12 @@ int PINT_copy_object_attr(PVFS_object_at
             dest->objtype = src->objtype;
         }
 
+        if (src->mask & PVFS_ATTR_DIR_DIRENT_COUNT)
+        {
+            dest->u.dir.dirent_count = 
+                src->u.dir.dirent_count;
+        }
+
         /*
           NOTE:
           we only copy the size out if we're actually a
@@ -133,53 +157,53 @@ int PINT_copy_object_attr(PVFS_object_at
         }
 
 	if ((src->mask & PVFS_ATTR_COMMON_TYPE) &&
-            (src->objtype == PVFS_TYPE_METAFILE) &&
-            (src->mask & PVFS_ATTR_META_DFILES))
-	{
-	    PVFS_size df_array_size = src->u.meta.dfile_count *
-                sizeof(PVFS_handle);
-
-            if (df_array_size)
+            (src->objtype == PVFS_TYPE_METAFILE))
+        {      
+            if(src->mask & PVFS_ATTR_META_DFILES)
             {
-		if ((dest->mask & PVFS_ATTR_META_DFILES) &&
-		    dest->u.meta.dfile_count > 0)
+                PVFS_size df_array_size = src->u.meta.dfile_count *
+                    sizeof(PVFS_handle);
+
+                if (df_array_size)
                 {
-                    if (dest->u.meta.dfile_array)
+                    if ((dest->mask & PVFS_ATTR_META_DFILES) &&
+                        dest->u.meta.dfile_count > 0)
+                    {
+                        if (dest->u.meta.dfile_array)
+                        {
+                            free(dest->u.meta.dfile_array);
+                        }
+                    }
+                    dest->u.meta.dfile_array = malloc(df_array_size);
+                    if (!dest->u.meta.dfile_array)
                     {
-                        free(dest->u.meta.dfile_array);
+                        return ret;
                     }
+                    memcpy(dest->u.meta.dfile_array,
+                           src->u.meta.dfile_array, df_array_size);
                 }
-		dest->u.meta.dfile_array = malloc(df_array_size);
-		if (!dest->u.meta.dfile_array)
-		{
-                    return ret;
-		}
-		memcpy(dest->u.meta.dfile_array,
-                       src->u.meta.dfile_array, df_array_size);
-	    }
-            else
-            {
-		dest->u.meta.dfile_array = NULL;
-	    }
-	    dest->u.meta.dfile_count = src->u.meta.dfile_count;
-	}
-
-	if ((src->mask & PVFS_ATTR_COMMON_TYPE) &&
-            (src->objtype == PVFS_TYPE_METAFILE) &&
-            (src->mask & PVFS_ATTR_META_DIST))
-	{
-            assert(src->u.meta.dist_size > 0);
-
-	    if ((dest->mask & PVFS_ATTR_META_DIST))
-            {
-                PINT_dist_free(dest->u.meta.dist);
+                else
+                {
+                    dest->u.meta.dfile_array = NULL;
+                }
+                dest->u.meta.dfile_count = src->u.meta.dfile_count;
             }
-            dest->u.meta.dist = PINT_dist_copy(src->u.meta.dist);
-            if (dest->u.meta.dist == NULL)
+
+            if(src->mask & PVFS_ATTR_META_DIST)
             {
-                return ret;
+                assert(src->u.meta.dist_size > 0);
+
+                if ((dest->mask & PVFS_ATTR_META_DIST))
+                {
+                    PINT_dist_free(dest->u.meta.dist);
+                }
+                dest->u.meta.dist = PINT_dist_copy(src->u.meta.dist);
+                if (dest->u.meta.dist == NULL)
+                {
+                    return ret;
+                }
+                dest->u.meta.dist_size = src->u.meta.dist_size;
             }
-            dest->u.meta.dist_size = src->u.meta.dist_size;
         }
 
         if (src->mask & PVFS_ATTR_SYMLNK_TARGET)
@@ -231,6 +255,373 @@ void PINT_free_object_attr(PVFS_object_a
             }
         }
     }
+}
+
+uint64_t PINT_keyword_to_mask(const PINT_keyword_mask_t * keyword_map, 
+                              size_t length, 
+                              const char *value)
+{
+    uint64_t mask = -1;
+    char *s = NULL, *t = NULL;
+    const char *toks = ", ";
+    int i = 0, negate = 0;
+
+    if (value)
+    {
+        s = strdup(value);
+        t = strtok(s, toks);
+
+        while(t)
+        {
+            if (*t == '-')
+            {
+                negate = 1;
+                ++t;
+            }
+
+            for(i = 0; i < length; i++)
+            {
+                if (!strcasecmp(t, keyword_map[i].keyword))
+                {
+                    if (negate)
+                    {
+                        mask &= ~keyword_map[i].mask_val;
+                    }
+                    else
+                    {
+                        mask |= keyword_map[i].mask_val;
+                    }
+                    break;
+                }
+            }
+            t = strtok(NULL, toks);
+        }
+        free(s);
+    }
+    return mask;
+}
+
+const char * PINT_mask_to_keyword(const PINT_keyword_mask_t * mask_map,
+                                  size_t length,
+                                  uint64_t mask)
+{
+    int i = 0;
+    for(; i < length; ++i)
+    {
+        if(mask_map[i].mask_val & mask)
+        {
+            return mask_map[i].keyword;
+        }
+    }
+    return NULL;
+}
+
+char * PINT_print_keywords(const PINT_keyword_mask_t * keyword_array,
+                           size_t arraylen,
+                           int columns, 
+                           const char * sep)
+{
+    int i = 0;
+    char * kstr = NULL;
+    int kstrlen = 0;
+    int lastlinelen = 0;
+    int seplen = strlen(sep);
+    int sprlen = 0;
+    
+    while(i < (arraylen-1))
+    {
+       kstr = realloc(kstr, 
+                      kstrlen + 
+                      strlen(keyword_array[i].keyword) + 
+                      seplen + 2);
+       if(!kstr)
+       {
+           return NULL;
+       }
+
+       sprlen = sprintf(kstr + kstrlen, "%s%s",
+                        keyword_array[i].keyword,
+                        sep);
+       kstrlen += sprlen;
+
+       if((kstrlen - lastlinelen) > columns)
+       {
+           sprintf(kstr + kstrlen, "\n");
+           kstrlen++;
+           lastlinelen = kstrlen;
+       }
+       ++i;
+    }
+       
+    kstr = realloc(kstr, kstrlen + strlen(keyword_array[i].keyword) + 1);
+    if(!kstr)
+    {
+        return NULL;
+    }
+
+    sprintf(kstr + kstrlen, "%s", keyword_array[i].keyword);
+
+    return kstr;
+}
+
+
+/* PINT_check_mode()
+ *
+ * checks to see if the type of access described by "access_type" is permitted 
+ * for user "uid" of group "gid" on the object with attributes "attr"
+ *
+ * returns 0 on success, -PVFS_EPERM if permission is not granted
+ */
+int PINT_check_mode(
+    PVFS_object_attr *attr,
+    PVFS_uid uid, PVFS_gid gid,
+    enum PINT_access_type access_type)
+{
+    int in_group_flag = 0;
+    int ret = 0;
+    uint32_t perm_mask = (PVFS_ATTR_COMMON_UID |
+                          PVFS_ATTR_COMMON_GID |
+                          PVFS_ATTR_COMMON_PERM);
+
+    /* if we don't have masks for the permission information that we
+     * need, then the system is broken
+     */
+    assert((attr->mask & perm_mask) == perm_mask);
+
+    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - check_mode called --- "
+                 "(uid=%d,gid=%d,access_type=%d)\n", uid, gid, access_type);
+    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - object attributes --- "
+                 "(uid=%d,gid=%d,mode=%d)\n", attr->owner, attr->group,
+                 attr->perms);
+
+    /* give root permission, no matter what */
+    gossip_debug(GOSSIP_PERMISSIONS_DEBUG,
+                 " - checking if uid (%d) is root ...\n", uid);
+    if (uid == 0)
+    {
+        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
+        return 0;
+    }
+    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
+
+    /* see if uid matches object owner */
+    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking if owner (%d) "
+        "matches uid (%d)...\n", attr->owner, uid);
+    if(attr->owner == uid)
+    {
+        /* see if object user permissions match access type */
+        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
+        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking if permissions "
+            "(%d) allows access type (%d) for user...\n", attr->perms, access_type);
+        if(access_type == PINT_ACCESS_READABLE && (attr->perms &
+            PVFS_U_READ))
+        {
+            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
+            return(0);
+        }
+        if(access_type == PINT_ACCESS_WRITABLE && (attr->perms &
+            PVFS_U_WRITE))
+        {
+            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
+            return(0);
+        }
+        if(access_type == PINT_ACCESS_EXECUTABLE && (attr->perms &
+            PVFS_U_EXECUTE))
+        {
+            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
+            return(0);
+        }
+        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
+    }
+    else
+    {
+        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
+    }
+
+    /* see if other bits allow access */
+    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking if permissions "
+        "(%d) allows access type (%d) by others...\n", attr->perms, access_type);
+    if(access_type == PINT_ACCESS_READABLE && (attr->perms &
+        PVFS_O_READ))
+    {
+        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
+        return(0);
+    }
+    if(access_type == PINT_ACCESS_WRITABLE && (attr->perms &
+        PVFS_O_WRITE))
+    {
+        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
+        return(0);
+    }
+    if(access_type == PINT_ACCESS_EXECUTABLE && (attr->perms &
+        PVFS_O_EXECUTE))
+    {
+        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
+        return(0);
+    }
+    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
+
+    /* see if gid matches object group */
+    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking if group (%d) "
+        "matches gid (%d)...\n", attr->group, gid);
+    if(attr->group == gid)
+    {
+        /* default group match */
+        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
+        in_group_flag = 1;
+    }
+    else
+    {
+        /* no default group match, check supplementary groups */
+        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
+        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking for"
+            " supplementary group match...\n");
+        ret = PINT_check_group(uid, attr->group);
+        if(ret == 0)
+        {
+            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
+            in_group_flag = 1;
+        }
+        else
+        {
+            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
+            if(ret != -PVFS_ENOENT)
+            {
+                /* system error; not just failed match */
+                return(ret);
+            }
+        }
+    }
+
+    if(in_group_flag)
+    {
+        /* see if object group permissions match access type */
+        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking if permissions "
+            "(%d) allows access type (%d) for group...\n", attr->perms, access_type);
+        if(access_type == PINT_ACCESS_READABLE && (attr->perms &
+            PVFS_G_READ))
+        {
+            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
+            return(0);
+        }
+        if(access_type == PINT_ACCESS_WRITABLE && (attr->perms &
+            PVFS_G_WRITE))
+        {
+            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
+            return(0);
+        }
+        if(access_type == PINT_ACCESS_EXECUTABLE && (attr->perms &
+            PVFS_G_EXECUTE))
+        {
+            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
+            return(0);
+        }
+        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
+    }
+  
+    /* default case: access denied */
+    return -PVFS_EPERM;
+}
+
+/* PINT_check_group()
+ *
+ * checks to see if uid is a member of gid
+ * 
+ * returns 0 on success, -PVFS_ENOENT if not a member, other PVFS error codes
+ * on system failure
+ */
+static int PINT_check_group(uid_t uid, gid_t gid)
+{
+    struct passwd pwd;
+    struct passwd* pwd_p = NULL;
+    struct group grp;
+    struct group* grp_p = NULL;
+    int i = 0;
+    int ret = -1;
+
+    /* Explanation: 
+     *
+     * We use the _r variants of getpwuid and getgrgid in order to insure
+     * thread safety; particularly if this function ever gets called in a
+     * client side situation in which we can't prevent the application from
+     * making conflicting calls.
+     *
+     * These _r functions require that a buffer be supplied for the user and
+     * group information, however.  These buffers may be unconfortably large
+     * for the stack, so we malloc them on a static pointer and then mutex
+     * lock this function so that it can still be reentrant.
+     */
+
+    gen_mutex_lock(&check_group_mutex);
+
+    if(!check_group_pw_buffer)
+    {
+        /* need to create a buffer for pw and grp entries */
+#if defined(_SC_GETGR_R_SIZE_MAX) && defined(_SC_GETPW_R_SIZE_MAX)
+        /* newish posix systems can tell us what the max buffer size is */
+        check_group_gr_buffer_size = sysconf(_SC_GETGR_R_SIZE_MAX);
+        check_group_pw_buffer_size = sysconf(_SC_GETPW_R_SIZE_MAX);
+#else
+        /* fall back for older systems */
+        check_group_pw_buffer_size = 1024;
+        check_group_gr_buffer_size = 1024;
+#endif
+        check_group_pw_buffer = (char*)malloc(check_group_pw_buffer_size);
+        check_group_gr_buffer = (char*)malloc(check_group_gr_buffer_size);
+        if(!check_group_pw_buffer || !check_group_gr_buffer)
+        {
+            if(check_group_pw_buffer)
+            {
+                free(check_group_pw_buffer);
+                check_group_pw_buffer = NULL;
+            }
+            if(check_group_gr_buffer)
+            {
+                free(check_group_gr_buffer);
+                check_group_gr_buffer = NULL;
+            }
+            gen_mutex_unlock(&check_group_mutex);
+            return(-PVFS_ENOMEM);
+        }
+    }
+
+    /* get user information */
+    ret = getpwuid_r(uid, &pwd, check_group_pw_buffer,
+        check_group_pw_buffer_size,
+        &pwd_p);
+    if(ret != 0)
+    {
+        gen_mutex_unlock(&check_group_mutex);
+        return(-PVFS_ENOENT);
+    }
+
+    /* check primary group */
+    if(pwd.pw_gid == gid) return 0;
+
+    /* get other group information */
+    ret = getgrgid_r(gid, &grp, check_group_gr_buffer,
+        check_group_gr_buffer_size,
+        &grp_p);
+    if(ret != 0)
+    {
+        gen_mutex_unlock(&check_group_mutex);
+        return(-PVFS_ENOENT);
+    }
+
+    gen_mutex_unlock(&check_group_mutex);
+
+
+    for(i = 0; grp.gr_mem[i] != NULL; i++)
+    {
+        if(0 == strcmp(pwd.pw_name, grp.gr_mem[i]) )
+        {
+            gen_mutex_unlock(&check_group_mutex);
+            return 0;
+        } 
+    }
+
+    gen_mutex_unlock(&check_group_mutex);
+    return(-PVFS_ENOENT);
 }
 
 /*

Index: pint-util.h
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/pint-util.h,v
diff -p -u -r1.6 -r1.6.6.1
--- pint-util.h	3 Oct 2004 19:00:54 -0000	1.6
+++ pint-util.h	25 Aug 2005 20:38:17 -0000	1.6.6.1
@@ -47,6 +47,39 @@ void PINT_time_diff(PINT_time_marker mar
     double* out_utime_sec,
     double* out_stime_sec);
 
+/* allows us to define arrays that map human readable keywords to mask values */
+typedef struct 
+{
+    char *keyword;
+    uint64_t mask_val;
+} PINT_keyword_mask_t;
+
+uint64_t PINT_keyword_to_mask(const PINT_keyword_mask_t * keyword_array, 
+                              size_t length, 
+                              const char *value);
+
+const char * PINT_mask_to_keyword(const PINT_keyword_mask_t * mask_map,
+                                  size_t length,
+                                  uint64_t mask);
+
+char * PINT_print_keywords(const PINT_keyword_mask_t * keyword_array,
+                           size_t arraylen,
+                           int columns, 
+                           const char * sep);
+
+enum PINT_access_type
+{
+    PINT_ACCESS_EXECUTABLE = 1,
+    PINT_ACCESS_WRITABLE = 2,
+    PINT_ACCESS_READABLE = 4,
+};
+
+int PINT_check_mode(
+    PVFS_object_attr *attr,
+    PVFS_uid uid, PVFS_gid gid,
+    enum PINT_access_type access_type);
+
+
 #endif /* __PINT_UTIL_H */
 
 /*

Index: pvfs2-debug.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/pvfs2-debug.c,v
diff -p -u -r1.29 -r1.29.6.1
--- pvfs2-debug.c	27 Oct 2004 19:12:27 -0000	1.29
+++ pvfs2-debug.c	25 Aug 2005 20:38:17 -0000	1.29.6.1
@@ -10,13 +10,7 @@
 #include <stdlib.h>
 
 #include "pvfs2-debug.h"
-
-/* a private internal type */
-typedef struct 
-{
-    char *keyword;
-    uint64_t mask_val;
-} __keyword_mask_t;
+#include "pint-util.h"
 
 #define __DEBUG_ALL                                               \
 (GOSSIP_TROVE_DEBUG | GOSSIP_BMI_DEBUG_ALL | GOSSIP_SERVER_DEBUG |\
@@ -29,10 +23,12 @@ GOSSIP_REMOVE_DEBUG | GOSSIP_GETATTR_DEB
 GOSSIP_IO_DEBUG | GOSSIP_DBPF_OPEN_CACHE_DEBUG |                  \
 GOSSIP_PERMISSIONS_DEBUG | GOSSIP_CANCEL_DEBUG |                  \
 GOSSIP_MSGPAIR_DEBUG | GOSSIP_CLIENTCORE_DEBUG |                  \
-GOSSIP_SETATTR_DEBUG | GOSSIP_MKDIR_DEBUG)
+GOSSIP_SETATTR_DEBUG | GOSSIP_MKDIR_DEBUG |                       \
+GOSSIP_SETEATTR_DEBUG | GOSSIP_GETEATTR_DEBUG |                   \
+GOSSIP_ACCESS_DEBUG | GOSSIP_ACCESS_DETAIL_DEBUG)
 
 /* map all config keywords to pvfs2 debug masks here */
-static __keyword_mask_t s_keyword_mask_map[] =
+static PINT_keyword_mask_t s_keyword_mask_map[] =
 {
     { "storage", GOSSIP_TROVE_DEBUG },
     { "trove", GOSSIP_TROVE_DEBUG },
@@ -40,6 +36,7 @@ static __keyword_mask_t s_keyword_mask_m
     { "network", GOSSIP_BMI_DEBUG_ALL },
     { "server", GOSSIP_SERVER_DEBUG },
     { "client", GOSSIP_CLIENT_DEBUG },
+    { "varstrip", GOSSIP_VARSTRIP_DEBUG },
     { "job", GOSSIP_JOB_DEBUG },
     { "request", GOSSIP_REQUEST_DEBUG },
     { "reqsched", GOSSIP_REQ_SCHED_DEBUG },
@@ -54,6 +51,8 @@ static __keyword_mask_t s_keyword_mask_m
     { "remove", GOSSIP_REMOVE_DEBUG },
     { "getattr", GOSSIP_GETATTR_DEBUG },
     { "setattr", GOSSIP_SETATTR_DEBUG },
+    { "geteattr", GOSSIP_GETEATTR_DEBUG },
+    { "seteattr", GOSSIP_SETEATTR_DEBUG },
     { "readdir", GOSSIP_READDIR_DEBUG },
     { "mkdir", GOSSIP_MKDIR_DEBUG },
     { "io", GOSSIP_IO_DEBUG },
@@ -63,6 +62,8 @@ static __keyword_mask_t s_keyword_mask_m
     { "msgpair", GOSSIP_MSGPAIR_DEBUG },
     { "clientcore", GOSSIP_CLIENTCORE_DEBUG },
     { "clientcore_timing", GOSSIP_CLIENTCORE_TIMING_DEBUG },
+    { "access", GOSSIP_ACCESS_DEBUG },
+    { "access_detail", GOSSIP_ACCESS_DETAIL_DEBUG },
     { "verbose",  (__DEBUG_ALL & ~GOSSIP_REQ_SCHED_DEBUG)},
     { "none", GOSSIP_NO_DEBUG },
     { "all",  __DEBUG_ALL }
@@ -70,7 +71,7 @@ static __keyword_mask_t s_keyword_mask_m
 #undef __DEBUG_ALL
 
 static const int num_keyword_mask_map = (int)           \
-(sizeof(s_keyword_mask_map) / sizeof(__keyword_mask_t));
+(sizeof(s_keyword_mask_map) / sizeof(PINT_keyword_mask_t));
 
 /*
  * Based on human readable keywords, translate them into
@@ -83,44 +84,8 @@ static const int num_keyword_mask_map = 
  */
 uint64_t PVFS_debug_eventlog_to_mask(const char *event_logging)
 {
-    uint64_t mask = 0;
-    char *s = NULL, *t = NULL;
-    const char *toks = ", ";
-    int i = 0, negate = 0;
-
-    if (event_logging)
-    {
-        s = strdup(event_logging);
-        t = strtok(s, toks);
-
-        while(t)
-        {
-            if (*t == '-')
-            {
-                negate = 1;
-                ++t;
-            }
-
-            for(i = 0; i < num_keyword_mask_map; i++)
-            {
-                if (!strcmp(t, s_keyword_mask_map[i].keyword))
-                {
-                    if (negate)
-                    {
-                        mask &= ~s_keyword_mask_map[i].mask_val;
-                    }
-                    else
-                    {
-                        mask |= s_keyword_mask_map[i].mask_val;
-                    }
-                    break;
-                }
-            }
-            t = strtok(NULL, toks);
-        }
-        free(s);
-    }
-    return mask;
+    return PINT_keyword_to_mask(
+        s_keyword_mask_map, num_keyword_mask_map, event_logging);
 }
 
 /*
@@ -133,7 +98,7 @@ uint64_t PVFS_debug_eventlog_to_mask(con
 char *PVFS_debug_get_next_debug_keyword(int position)
 {
     int num_entries = (int)(sizeof(s_keyword_mask_map) /
-                            sizeof(__keyword_mask_t));
+                            sizeof(PINT_keyword_mask_t));
 
     return (((position > -1) && (position < num_entries)) ?
             s_keyword_mask_map[position].keyword : NULL);

Index: pvfs2-util.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/pvfs2-util.c,v
diff -p -u -r1.74 -r1.74.6.1
--- pvfs2-util.c	27 Oct 2004 19:12:27 -0000	1.74
+++ pvfs2-util.c	25 Aug 2005 20:38:17 -0000	1.74.6.1
@@ -1,6 +1,10 @@
 /*
  * (C) 2001 Clemson University and The University of Chicago
  *
+ * Changes by Acxiom Corporation to add relative path support to
+ * PVFS_util_resolve(),
+ * Copyright © Acxiom Corporation, 2005
+ *
  * See COPYING in top-level directory.
  */
 
@@ -13,14 +17,18 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/time.h>
+#include <libgen.h>
 
 #include "pvfs2-config.h"
 #include "pvfs2-sysint.h"
 #include "pvfs2-util.h"
 #include "pvfs2-debug.h"
 #include "gossip.h"
+#include "pvfs2-attr.h"
+#include "pvfs2-types-debug.h"
 #include "str-utils.h"
 #include "gen-locks.h"
+#include "realpath.h"
 
 /* TODO: add replacement functions for systems without getmntent() */
 #ifndef HAVE_GETMNTENT
@@ -53,6 +61,14 @@ static int parse_encoding_string(
     const char *cp,
     enum PVFS_encoding_type *et);
 
+static int parse_num_dfiles_string(const char* cp, int* num_dfiles);
+
+static int PINT_util_resolve_absolute(
+    const char* local_path,
+    PVFS_fs_id* out_fs_id,
+    char* out_fs_path,
+    int out_fs_path_max);
+
 void PVFS_util_gen_credentials(
     PVFS_credentials *credentials)
 {
@@ -118,17 +134,17 @@ int PVFS_util_copy_sys_attr(
         dest_attr->objtype = src_attr->objtype;
         dest_attr->mask = src_attr->mask;
 
-        if ((src_attr->mask & PVFS_ATTR_COMMON_TYPE) &&
-            (src_attr->objtype == PVFS_TYPE_SYMLINK) &&
+        if((src_attr->mask & PVFS_ATTR_SYS_LNK_TARGET) &&
             src_attr->link_target)
         {
             dest_attr->link_target = strdup(src_attr->link_target);
             if (!dest_attr->link_target)
             {
                 ret = -PVFS_ENOMEM;
+                return ret;
             }
-            ret = 0;
         }
+        ret = 0;
     }
     return ret;
 }
@@ -137,7 +153,7 @@ void PVFS_util_release_sys_attr(PVFS_sys
 {
     if (attr)
     {
-        if ((attr->mask & PVFS_ATTR_COMMON_TYPE) &&
+        if ((attr->mask & PVFS_ATTR_SYS_TYPE) &&
             (attr->objtype == PVFS_TYPE_SYMLINK) && attr->link_target)
         {
             free(attr->link_target);
@@ -166,9 +182,10 @@ const PVFS_util_tab *PVFS_util_parse_pvf
     const char *tabfile)
 {
     FILE *mnt_fp = NULL;
-    int file_count = 4;
-    const char *file_list[4] =
-        { NULL, "/etc/fstab", "/etc/pvfs2tab", "pvfs2tab" };
+    int file_count = 5;
+    /* NOTE: mtab should be last for clean error logic below */
+    const char *file_list[5] =
+        { NULL, "/etc/fstab", "/etc/pvfs2tab", "pvfs2tab", "/etc/mtab" };
     const char *targetfile = NULL;
     struct mntent *tmp_ent;
     int i, j;
@@ -192,7 +209,6 @@ const PVFS_util_tab *PVFS_util_parse_pvf
           first check for environment variable override
         */
         file_list[0] = getenv("PVFS2TAB_FILE");
-        file_count = 4;
     }
 
     gen_mutex_lock(&s_stat_tab_mutex);
@@ -322,9 +338,29 @@ const PVFS_util_tab *PVFS_util_parse_pvf
                 }
                 if (slashcount != 3)
                 {
-                    gossip_lerr("Error: invalid tab file entry: %s\n",
-                                tmp_ent->mnt_fsname);
-                    goto error_exit;
+                    /* if we are looking at the mtab, then just silently
+                     * treat this error as if we didn't find an entry at
+                     * all; they may have mounted using an odd syntax on a
+                     * 2.4 kernel system
+                     */
+                    if(!strcmp(targetfile, "/etc/mtab"))
+                    {
+                        gossip_err("Error: could not find any pvfs2 tabfile entries.\n");
+                        gossip_err("Error: tried the following tabfiles:\n");
+                        for (j = 0; j < file_count; j++)
+                        {
+                            gossip_err("       %s\n", file_list[j]);
+                        }
+                        goto error_exit;
+                    }
+                    else
+                    {
+                        gossip_err("Error: invalid tab file entry: %s\n",
+                                    tmp_ent->mnt_fsname);
+                        gossip_err("Error: offending tab file: %s\n",
+                                    targetfile);
+                        goto error_exit;
+                    }
                 }
 
                 /* find a reference point in the string */
@@ -393,6 +429,23 @@ const PVFS_util_tab *PVFS_util_parse_pvf
                     goto error_exit;
                 }
             }
+
+            /* find out if a particular flow protocol was specified */
+            current_tab->mntent_array[i].default_num_dfiles = 0;
+            cp = hasmntopt(tmp_ent, "num_dfiles");
+            if (cp)
+            {
+                ret = parse_num_dfiles_string(
+                    cp,
+                    &(current_tab->mntent_array[i].default_num_dfiles));
+
+                if (ret < 0)
+                {
+                    goto error_exit;
+                }
+            }
+
+            /* Loop counter increment */
             i++;
         }
     }
@@ -530,6 +583,7 @@ int PVFS_util_add_dynamic_mntent(struct 
             }
         }
 
+#if 0
         /* check the dynamic region if we haven't found a match yet */
         for(j = 0; j < s_stat_tab_array[
                 PVFS2_DYNAMIC_TAB_INDEX].mntent_count; j++)
@@ -537,17 +591,20 @@ int PVFS_util_add_dynamic_mntent(struct 
             current_mnt = &(s_stat_tab_array[PVFS2_DYNAMIC_TAB_INDEX].
                             mntent_array[j]);
 
-            if (current_mnt->fs_id == mntent->fs_id)
-            {
-                gossip_debug(
-                    GOSSIP_CLIENT_DEBUG, "* File system %d already "
-                    "mounted on %s already exists [dynamic]\n",
-                    mntent->fs_id, current_mnt->mnt_dir);
-
+            if ((current_mnt->fs_id == mntent->fs_id) &&
+                (strcmp(current_mnt->pvfs_config_servers[0],
+                        mntent->pvfs_config_servers[0]) != 0))
+            {
+                gossip_err("Error: FS with id %d is already mounted using"
+                           " a different config server.\n", (int)mntent->fs_id); 
+                gossip_err("Error: This could indicate that a duplicate fsid"
+                           " is being used.\n");
+                gossip_err("Error: Please check your server configuration.\n");
                 gen_mutex_unlock(&s_stat_tab_mutex);
-                return -PVFS_EEXIST;
+                return -PVFS_ENXIO;
             }
         }
+#endif
 
         /* copy the mntent to our table in the dynamic tab area */
         new_index = s_stat_tab_array[
@@ -639,7 +696,8 @@ int PVFS_util_remove_internal_mntent(
             for(j = 0; j < s_stat_tab_array[i].mntent_count; j++)
             {
                 current_mnt = &(s_stat_tab_array[i].mntent_array[j]);
-                if (current_mnt->fs_id == mntent->fs_id)
+                if ((current_mnt->fs_id == mntent->fs_id)
+                    && (strcmp(current_mnt->mnt_dir, mntent->mnt_dir) == 0))
                 {
                     found_index = i;
                     found = 1;
@@ -700,7 +758,8 @@ int PVFS_util_remove_internal_mntent(
             {
                 current_mnt = &s_stat_tab_array[found_index].mntent_array[i];
 
-                if (current_mnt->fs_id == mntent->fs_id)
+                if ((current_mnt->fs_id == mntent->fs_id)
+                    && (strcmp(current_mnt->mnt_dir, mntent->mnt_dir) == 0))
                 {
                     PVFS_util_free_mntent(current_mnt);
                     continue;
@@ -735,10 +794,45 @@ int PVFS_util_remove_internal_mntent(
     return ret;
 }
 
+/*
+ * PVFS_util_get_mntent_copy()
+ *
+ * Given a pointer to a valid mount entry, out_mntent, copy the contents of
+ * the mount entry  for fs_id into out_mntent.
+ *
+ * returns 0 on success, -PVFS_error on failure
+ */
+int PVFS_util_get_mntent_copy(PVFS_fs_id fs_id,
+                              struct PVFS_sys_mntent* out_mntent)
+{
+    int i = 0;
+
+    /* Search for mntent by fsid */
+    gen_mutex_lock(&s_stat_tab_mutex);
+    for(i = 0; i < s_stat_tab_count; i++)
+    {
+        int j;
+        for(j = 0; j < s_stat_tab_array[i].mntent_count; j++)
+        {
+            struct PVFS_sys_mntent* mnt_iter;
+            mnt_iter = &(s_stat_tab_array[i].mntent_array[j]);
+
+            if (mnt_iter->fs_id == fs_id)
+            {
+                PVFS_util_copy_mntent(out_mntent, mnt_iter);
+                gen_mutex_unlock(&s_stat_tab_mutex);
+                return 0;
+            }
+        }
+    }
+    gen_mutex_unlock(&s_stat_tab_mutex);
+    return -PVFS_EINVAL;
+}
+
 /* PVFS_util_resolve()
  *
  * given a local path of a file that resides on a pvfs2 volume,
- * determine what the fsid and fs relative path is
+ * determine what the fsid and fs relative path is.  
  *
  * returns 0 on succees, -PVFS_error on failure
  */
@@ -748,65 +842,83 @@ int PVFS_util_resolve(
     char* out_fs_path,
     int out_fs_path_max)
 {
-    int i = 0, j = 0;
-    int ret = -PVFS_EINVAL;
-
-    gen_mutex_lock(&s_stat_tab_mutex);
+    int ret = -1;
+    char* tmp_path = NULL;
+    char* parent_path = NULL;
+    int base_len = 0;
 
-    for(i=0; i < s_stat_tab_count; i++)
+    /* the most common case first; just try to resolve the path that we
+     * were given
+     */
+    ret = PINT_util_resolve_absolute(local_path, out_fs_id, out_fs_path,
+        out_fs_path_max);
+    if(ret == 0)
     {
-        for(j=0; j<s_stat_tab_array[i].mntent_count; j++)
-        {
-            ret = PINT_remove_dir_prefix(
-                local_path, s_stat_tab_array[i].mntent_array[j].mnt_dir,
-                out_fs_path, out_fs_path_max);
-            if(ret == 0)
-            {
-                *out_fs_id = s_stat_tab_array[i].mntent_array[j].fs_id;
-                if(*out_fs_id == PVFS_FS_ID_NULL)
-                {
-                    gossip_err("Error: %s resides on a PVFS2 file system "
-                    "that has not yet been initialized.\n", local_path);
-
-                    gen_mutex_unlock(&s_stat_tab_mutex);
-                    return(-PVFS_ENXIO);
-                }
-                gen_mutex_unlock(&s_stat_tab_mutex);
-                return(0);
-            }
-        }
+        /* done */
+        return(0);
     }
-
-    /* check the dynamic tab area if we haven't resolved anything yet */
-    for(j = 0; j < s_stat_tab_array[
-            PVFS2_DYNAMIC_TAB_INDEX].mntent_count; j++)
+    if(ret == -PVFS_ENOENT)
     {
-        ret = PINT_remove_dir_prefix(
-            local_path, s_stat_tab_array[
-                PVFS2_DYNAMIC_TAB_INDEX].mntent_array[j].mnt_dir,
-            out_fs_path, out_fs_path_max);
-        if (ret == 0)
+        /* if the path wasn't found, try canonicalizing the path in case it
+         * refers to a relative path on a mounted volume or contains symlinks
+         */
+        tmp_path = (char*)malloc(PVFS_NAME_MAX*sizeof(char));
+        if(!tmp_path)
         {
-            *out_fs_id = s_stat_tab_array[
-                PVFS2_DYNAMIC_TAB_INDEX].mntent_array[j].fs_id;
-            if(*out_fs_id == PVFS_FS_ID_NULL)
+            return(-PVFS_ENOMEM);
+        }
+        memset(tmp_path, 0, PVFS_NAME_MAX*sizeof(char));
+        ret = PINT_realpath(local_path, tmp_path, (PVFS_NAME_MAX-1));
+        if(ret == -PVFS_EINVAL)
+        {
+            /* one more try; canonicalize the parent in case this function
+             * is called before object creation; the basename
+             * doesn't yet exist but we still need to find the PVFS volume
+             */
+            parent_path = (char*)malloc(PVFS_NAME_MAX*sizeof(char));
+            if(!parent_path)
             {
-                gossip_err("Error: %s resides on a PVFS2 file system "
-                           "that has not yet been initialized.\n",
-                           local_path);
-
-                gen_mutex_unlock(&s_stat_tab_mutex);
-                return(-PVFS_ENXIO);
+                free(tmp_path);
+                return(-PVFS_ENOMEM);
             }
-            gen_mutex_unlock(&s_stat_tab_mutex);
-            return(0);
+            /* find size of basename so we can reserve space for it */
+            /* note: basename() and dirname() modifiy args, thus the strcpy */
+            strcpy(parent_path, local_path);
+            base_len = strlen(basename(parent_path));
+            strcpy(parent_path, local_path);
+            ret = PINT_realpath(dirname(parent_path), tmp_path,
+                (PVFS_NAME_MAX-base_len-2));
+            if(ret < 0)
+            {
+                free(tmp_path);
+                free(parent_path);
+                /* last chance failed; this is not a valid pvfs2 path */
+                return(-PVFS_ENOENT);
+            }
+            /* glue the basename back on */
+            strcpy(parent_path, local_path);
+            strcat(tmp_path, "/");
+            strcat(tmp_path, basename(parent_path));
+            free(parent_path);
+        }
+        else if(ret < 0)
+        {
+            /* first canonicalize failed; this is not a valid pvfs2 path */
+            free(tmp_path);
+            return(-PVFS_ENOENT);
         }
+
+        ret = PINT_util_resolve_absolute(tmp_path, out_fs_id, out_fs_path,
+            out_fs_path_max);
+        free(tmp_path);
+
+        /* fall through and preserve "ret" to be returned */
     }
 
-    gen_mutex_unlock(&s_stat_tab_mutex);
-    return(-PVFS_ENOENT);
+    return(ret);
 }
 
+
 /* PVFS_util_init_defaults()
  *
  * performs the standard set of initialization steps for the system
@@ -1015,11 +1127,7 @@ static int parse_flowproto_string(
         comma[0] = '\0';
     }
 
-    if (!strcmp(flow, "bmi_trove"))
-    {
-        *flowproto = FLOWPROTO_BMI_TROVE;
-    }
-    else if (!strcmp(flow, "dump_offsets"))
+    if (!strcmp(flow, "dump_offsets"))
     {
         *flowproto = FLOWPROTO_DUMP_OFFSETS;
     }
@@ -1142,6 +1250,7 @@ int PVFS_util_copy_mntent(
         dest_mntent->flowproto = src_mntent->flowproto;
         dest_mntent->encoding = src_mntent->encoding;
         dest_mntent->fs_id = src_mntent->fs_id;
+        dest_mntent->default_num_dfiles = src_mntent->default_num_dfiles;
     }
     return 0;
 
@@ -1288,6 +1397,207 @@ void PINT_release_pvfstab(void)
     gen_mutex_unlock(&s_stat_tab_mutex);
 }
 
+inline uint32_t PVFS_util_sys_to_object_attr_mask(
+    uint32_t sys_attrmask)
+{
+
+    /*
+      adjust parameters as necessary; what's happening here
+      is that we're converting sys_attr masks to obj_attr masks
+      before passing the getattr request to the server.
+    */
+    uint32_t attrmask = 0;
+    if (sys_attrmask & PVFS_ATTR_SYS_SIZE)
+    {
+        /* need datafile handles and distribution in order to get 
+         * datafile handles and know what function to call to get
+         * the file size.
+         */
+        attrmask |= (PVFS_ATTR_META_ALL | PVFS_ATTR_DATA_SIZE);
+    }
+
+    if (sys_attrmask & PVFS_ATTR_SYS_DFILE_COUNT)
+    {
+        attrmask |= PVFS_ATTR_META_DFILES;
+    }
+
+    if (sys_attrmask & PVFS_ATTR_SYS_LNK_TARGET)
+    {
+        attrmask |= PVFS_ATTR_SYMLNK_TARGET;
+    }
+
+    gossip_debug(GOSSIP_GETATTR_DEBUG,
+                 "attrmask being passed to server: ");
+    PINT_attrmask_print(GOSSIP_GETATTR_DEBUG, attrmask);
+
+    return attrmask;
+}
+
+inline uint32_t PVFS_util_object_to_sys_attr_mask( 
+    uint32_t obj_mask)
+{
+    int sys_mask = 0;
+
+    if (obj_mask & PVFS_ATTR_COMMON_UID)
+    {
+        sys_mask |= PVFS_ATTR_SYS_UID;
+    }
+    if (obj_mask & PVFS_ATTR_COMMON_GID)
+    {
+        sys_mask |= PVFS_ATTR_SYS_GID;
+    }
+    if (obj_mask & PVFS_ATTR_COMMON_PERM)
+    {
+        sys_mask |= PVFS_ATTR_SYS_PERM;
+    }
+    if (obj_mask & PVFS_ATTR_COMMON_ATIME)
+    {
+        sys_mask |= PVFS_ATTR_SYS_ATIME;
+    }
+    if (obj_mask & PVFS_ATTR_COMMON_CTIME)
+    {
+        sys_mask |= PVFS_ATTR_SYS_CTIME;
+    }
+    if (obj_mask & PVFS_ATTR_COMMON_MTIME)
+    {
+        sys_mask |= PVFS_ATTR_SYS_MTIME;
+    }
+    if (obj_mask & PVFS_ATTR_COMMON_TYPE)
+    {
+        sys_mask |= PVFS_ATTR_SYS_TYPE;
+    }
+    if (obj_mask & PVFS_ATTR_DATA_SIZE)
+    {
+        sys_mask |= PVFS_ATTR_DATA_SIZE;
+    }
+    if (obj_mask & PVFS_ATTR_SYMLNK_TARGET)
+    {
+        sys_mask |= PVFS_ATTR_SYS_LNK_TARGET;
+    }
+    return sys_mask;
+}
+
+/*
+ * Pull out the wire encoding specified as a mount option in the tab
+ * file.
+ *
+ * Input string is not modified; result goes into et.
+ *
+ * Returns 0 if all okay.
+ */
+static int parse_num_dfiles_string(const char* cp, int* num_dfiles)
+{
+    int parsed_value = 0;
+    char* end_ptr = NULL;
+
+    gossip_debug(GOSSIP_CLIENT_DEBUG, "%s: input is %s\n",
+                 __func__, cp);
+    
+    cp += strlen("num_dfiles");
+
+    /* Skip optional spacing */
+    for (; isspace(*cp); cp++);
+    
+    if (*cp != '=')
+    {
+        gossip_err("Error: %s: malformed num_dfiles option in tab file.\n",
+                   __func__);
+        return -PVFS_EINVAL;
+    }
+    
+    /* Skip optional spacing */
+    for (++cp; isspace(*cp); cp++);
+
+    parsed_value = strtol(cp, &end_ptr, 10);
+
+    /* If a numerica value was found, continue
+       else, report an error */
+    if (end_ptr != cp)
+    {
+        *num_dfiles = parsed_value;
+    }
+    else
+    {
+        gossip_err("Error: %s: malformed num_dfiles option in tab file.\n",
+                   __func__);
+        return -PVFS_EINVAL;
+    }
+
+    return 0;
+}
+
+/* PINT_util_resolve_absolute()
+ *
+ * given a local path of a file that may reside on a pvfs2 volume,
+ * determine what the fsid and fs relative path is. Makes no attempt
+ * to canonicalize the path.
+ *
+ * returns 0 on succees, -PVFS_error on failure
+ */
+static int PINT_util_resolve_absolute(
+    const char* local_path,
+    PVFS_fs_id* out_fs_id,
+    char* out_fs_path,
+    int out_fs_path_max)
+{
+    int i = 0, j = 0;
+    int ret = -PVFS_EINVAL;
+
+    gen_mutex_lock(&s_stat_tab_mutex);
+
+    for(i=0; i < s_stat_tab_count; i++)
+    {
+        for(j=0; j<s_stat_tab_array[i].mntent_count; j++)
+        {
+            ret = PINT_remove_dir_prefix(
+                local_path, s_stat_tab_array[i].mntent_array[j].mnt_dir,
+                out_fs_path, out_fs_path_max);
+            if(ret == 0)
+            {
+                *out_fs_id = s_stat_tab_array[i].mntent_array[j].fs_id;
+                if(*out_fs_id == PVFS_FS_ID_NULL)
+                {
+                    gossip_err("Error: %s resides on a PVFS2 file system "
+                    "that has not yet been initialized.\n", local_path);
+
+                    gen_mutex_unlock(&s_stat_tab_mutex);
+                    return(-PVFS_ENXIO);
+                }
+                gen_mutex_unlock(&s_stat_tab_mutex);
+                return(0);
+            }
+        }
+    }
+
+    /* check the dynamic tab area if we haven't resolved anything yet */
+    for(j = 0; j < s_stat_tab_array[
+            PVFS2_DYNAMIC_TAB_INDEX].mntent_count; j++)
+    {
+        ret = PINT_remove_dir_prefix(
+            local_path, s_stat_tab_array[
+                PVFS2_DYNAMIC_TAB_INDEX].mntent_array[j].mnt_dir,
+            out_fs_path, out_fs_path_max);
+        if (ret == 0)
+        {
+            *out_fs_id = s_stat_tab_array[
+                PVFS2_DYNAMIC_TAB_INDEX].mntent_array[j].fs_id;
+            if(*out_fs_id == PVFS_FS_ID_NULL)
+            {
+                gossip_err("Error: %s resides on a PVFS2 file system "
+                           "that has not yet been initialized.\n",
+                           local_path);
+
+                gen_mutex_unlock(&s_stat_tab_mutex);
+                return(-PVFS_ENXIO);
+            }
+            gen_mutex_unlock(&s_stat_tab_mutex);
+            return(0);
+        }
+    }
+
+    gen_mutex_unlock(&s_stat_tab_mutex);
+    return(-PVFS_ENOENT);
+}
 /*
  * Local variables:
  *  c-indent-level: 4

Index: server-config-mgr.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/server-config-mgr.c,v
diff -p -u -r1.13 -r1.13.6.1
--- server-config-mgr.c	5 Oct 2004 15:04:17 -0000	1.13
+++ server-config-mgr.c	25 Aug 2005 20:38:18 -0000	1.13.6.1
@@ -33,6 +33,7 @@ typedef struct
 
     gen_mutex_t *server_config_mutex;
     struct server_configuration_s *server_config;
+    int ref_count; /* allows same config to be added multiple times */
 } server_config_t;
 
 static struct qhash_table *s_fsid_to_config_table = NULL;
@@ -167,9 +168,7 @@ int PINT_server_config_mgr_reload_cached
 
         for (i = 0; i < s_fsid_to_config_table->table_size; i++)
         {
-            hash_link = qhash_search_at_index(
-                s_fsid_to_config_table, i);
-            if (hash_link)
+            qhash_for_each(hash_link, &s_fsid_to_config_table->array[i])
             {
                 config = qlist_entry(
                     hash_link, server_config_t, hash_link);
@@ -238,8 +237,15 @@ int PINT_server_config_mgr_add_config(
         hash_link = qhash_search(s_fsid_to_config_table, &fs_id);
         if (hash_link)
         {
-            ret = -PVFS_EEXIST;
-            goto add_failure;
+            gossip_debug(GOSSIP_CLIENT_DEBUG, "PINT_server_config_mgr_add_"
+                         "config: increasing reference count.\n");
+            /* config is already stored here, increase reference count */
+            config = qlist_entry(hash_link, server_config_t, hash_link);
+            assert(config);
+            assert(config->server_config);
+            config->ref_count++;
+            gen_mutex_unlock(s_server_config_mgr_mutex);
+            return(0);
         }
 
         config = (server_config_t *)malloc(sizeof(server_config_t));
@@ -259,6 +265,7 @@ int PINT_server_config_mgr_add_config(
 
         config->server_config = config_s;
         config->fs_id = fs_id;
+        config->ref_count = 1;
 
         qhash_add(s_fsid_to_config_table, &fs_id,
                   &config->hash_link);
@@ -305,7 +312,7 @@ int PINT_server_config_mgr_remove_config
         gen_mutex_lock(s_server_config_mgr_mutex);
         SC_MGR_ASSERT_OK(ret);
 
-        hash_link = qhash_search_and_remove(
+        hash_link = qhash_search(
             s_fsid_to_config_table, &fs_id);
         if (hash_link)
         {
@@ -314,26 +321,38 @@ int PINT_server_config_mgr_remove_config
             assert(config->server_config);
             assert(config->fs_id == fs_id);
 
-            gossip_debug(GOSSIP_CLIENT_DEBUG, "%s: "
-                         "Removed config object %p with fs_id %d\n",
-                         __func__, config, fs_id);
-
-            /*
-              config objects are allocated by fs-add.c:PVFS_sys_fs_add
-              but we free them here
-            */
-            PINT_config_release(config->server_config);
-            free(config->server_config);
+            config->ref_count--;
 
-            if (gen_mutex_trylock(config->server_config_mutex) == EBUSY)
+            if(config->ref_count == 0)
             {
-                gossip_err("FIXME: Destroying mutex that is in use!\n");
-            }
-            gen_mutex_unlock(config->server_config_mutex);
-            gen_mutex_destroy(config->server_config_mutex);
+                gossip_debug(GOSSIP_CLIENT_DEBUG, "%s: "
+                             "Removed config object %p with fs_id %d\n",
+                             __func__, config, fs_id);
+                qhash_del(&config->hash_link);
+
+                /*
+                 * config objects are allocated by fs-add.c:PVFS_sys_fs_add
+                 * but we free them here
+                 */
+                PINT_config_release(config->server_config);
+                free(config->server_config);
 
-            free(config);
-            config = NULL;
+                if(gen_mutex_trylock(config->server_config_mutex) == EBUSY)
+                {
+                    gossip_err("FIXME: Destroying mutex that is in use!\n");
+                }
+                gen_mutex_unlock(config->server_config_mutex);
+                gen_mutex_destroy(config->server_config_mutex);
+
+                free(config);
+                config = NULL;
+            }
+            else
+            {
+                gossip_debug(GOSSIP_CLIENT_DEBUG, "%s: "
+                             "Config object %p with fs_id %d still in use.\n",
+                             __func__, config, fs_id);
+            }
 
             ret = 0;
         }

Index: server-config.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/server-config.c,v
diff -p -u -r1.67.4.1 -r1.67.4.2
--- server-config.c	7 Jun 2005 21:59:12 -0000	1.67.4.1
+++ server-config.c	25 Aug 2005 20:38:18 -0000	1.67.4.2
@@ -21,7 +21,9 @@
 #include "gossip.h"
 #include "extent-utils.h"
 #include "mkspace.h"
+#include "pint-distribution.h"
 #include "pvfs2-config.h"
+#include "pvfs2-server.h"
 
 static DOTCONF_CB(get_pvfs_server_id);
 static DOTCONF_CB(get_logstamp);
@@ -38,10 +40,12 @@ static DOTCONF_CB(enter_mhranges_context
 static DOTCONF_CB(exit_mhranges_context);
 static DOTCONF_CB(enter_dhranges_context);
 static DOTCONF_CB(exit_dhranges_context);
+static DOTCONF_CB(enter_distribution_context);
+static DOTCONF_CB(exit_distribution_context);
 static DOTCONF_CB(get_unexp_req);
 static DOTCONF_CB(get_perf_update_interval);
 static DOTCONF_CB(get_root_handle);
-static DOTCONF_CB(get_filesystem_name);
+static DOTCONF_CB(get_name);
 static DOTCONF_CB(get_logfile);
 static DOTCONF_CB(get_event_logging_list);
 static DOTCONF_CB(get_event_log_size);
@@ -56,9 +60,20 @@ static DOTCONF_CB(get_attr_cache_size);
 static DOTCONF_CB(get_attr_cache_max_num_elems);
 static DOTCONF_CB(get_trove_sync_meta);
 static DOTCONF_CB(get_trove_sync_data);
+static DOTCONF_CB(get_param);
+static DOTCONF_CB(get_value);
+static DOTCONF_CB(get_default_num_dfiles);
+static DOTCONF_CB(get_server_job_bmi_timeout);
+static DOTCONF_CB(get_server_job_flow_timeout);
+static DOTCONF_CB(get_client_job_bmi_timeout);
+static DOTCONF_CB(get_client_job_flow_timeout);
+static DOTCONF_CB(get_client_retry_limit);
+static DOTCONF_CB(get_client_retry_delay);
+static FUNC_ERRORHANDLER(errorhandler);
+const char *contextchecker(command_t *cmd, unsigned long mask);
 
 /* internal helper functions */
-static int is_valid_alias(char *str);
+static int is_valid_alias(PINT_llist * host_aliases, char *str);
 static int is_valid_handle_range_description(char *h_range);
 static void free_host_handle_mapping(void *ptr);
 static void free_host_alias(void *ptr);
@@ -67,6 +82,7 @@ static void copy_filesystem(
     struct filesystem_configuration_s *dest_fs,
     struct filesystem_configuration_s *src_fs);
 static int cache_config_files(
+    struct server_configuration_s *config_s,
     char *global_config_filename,
     char *server_config_filename);
 static int is_populated_filesystem_configuration(
@@ -90,50 +106,447 @@ static struct host_handle_mapping_s *get
 static int build_extent_array(
     char *handle_range_str,
     PVFS_handle_extent_array *handle_extent_array);
+
 #ifdef __PVFS2_TROVE_SUPPORT__
 static int is_root_handle_in_my_range(
     struct server_configuration_s *config_s,
     struct filesystem_configuration_s *fs);
 #endif
 
-static struct server_configuration_s *config_s = NULL;
-
+/* 
+ * NOTE: The documentation for the server config format is generated
+ * from the following static array.  The documentation for an option
+ * is taken from the comments found before the beginning of each sub-structure
+ * as shown.
+ */
 static const configoption_t options[] =
 {
-    {"HostID",ARG_STR, get_pvfs_server_id,NULL,CTX_ALL},
-    {"StorageSpace",ARG_STR, get_storage_space,NULL,CTX_ALL},
-    {"<Defaults>",ARG_NONE, enter_defaults_context,NULL,CTX_ALL},
-    {"</Defaults>",ARG_NONE, exit_defaults_context,NULL,CTX_ALL},
-    {"<Aliases>",ARG_NONE, enter_aliases_context,NULL,CTX_ALL},
-    {"</Aliases>",ARG_NONE, exit_aliases_context,NULL,CTX_ALL},
-    {"Alias",ARG_LIST, get_alias_list,NULL,CTX_ALL},
-    {"<FileSystem>",ARG_NONE, enter_filesystem_context,NULL,CTX_ALL},
-    {"</FileSystem>",ARG_NONE, exit_filesystem_context,NULL,CTX_ALL},
-    {"<StorageHints>",ARG_NONE, enter_storage_hints_context,NULL,CTX_ALL},
-    {"</StorageHints>",ARG_NONE, exit_storage_hints_context,NULL,CTX_ALL},
-    {"<MetaHandleRanges>",ARG_NONE, enter_mhranges_context,NULL,CTX_ALL},
-    {"</MetaHandleRanges>",ARG_NONE, exit_mhranges_context,NULL,CTX_ALL},
-    {"<DataHandleRanges>",ARG_NONE, enter_dhranges_context,NULL,CTX_ALL},
-    {"</DataHandleRanges>",ARG_NONE, exit_dhranges_context,NULL,CTX_ALL},
-    {"Range",ARG_LIST, get_range_list,NULL,CTX_ALL},
-    {"RootHandle",ARG_STR, get_root_handle,NULL,CTX_ALL},
-    {"Name",ARG_STR, get_filesystem_name,NULL,CTX_ALL},
-    {"ID",ARG_INT, get_filesystem_collid,NULL,CTX_ALL},
-    {"LogFile",ARG_STR, get_logfile,NULL,CTX_ALL},
-    {"EventLogging",ARG_LIST, get_event_logging_list,NULL,CTX_ALL},
-    {"EventLogSize",ARG_INT, get_event_log_size,NULL,CTX_ALL},
-    {"UnexpectedRequests",ARG_INT, get_unexp_req,NULL,CTX_ALL},
-    {"PerfUpdateInterval",ARG_INT, get_perf_update_interval,NULL,CTX_ALL},
-    {"BMIModules",ARG_LIST, get_bmi_module_list,NULL,CTX_ALL},
-    {"FlowModules",ARG_LIST, get_flow_module_list,NULL,CTX_ALL},
+    /* 
+     * Specifies a string identifier for the pvfs2 server that is to be
+     * run on this host.  The format of this string is:
+     *
+     * {transport}://{hostname}:{port}
+     *
+     * Where {transport} is one of the possible BMI transport modules
+     * (tcp, ib, gm).  Example:
+     *
+     * tcp://myhost.mydn:12345
+     *
+     */
+    {"HostID",ARG_STR, get_pvfs_server_id,NULL,CTX_GLOBAL,NULL},
+    
+    /* Specifies the local path for the pvfs2 server to use as storage space.
+     * Example:
+     *
+     * /tmp/pvfs.storage
+     */
+    {"StorageSpace",ARG_STR, get_storage_space,NULL,CTX_GLOBAL,NULL},
+
+    /* Specifies the beginning of the Defaults context.  Options specified
+     * within the Defaults context are used as default values over all the
+     * pvfs2 server specific config files.
+     */
+    {"<Defaults>",ARG_NONE, enter_defaults_context,NULL,CTX_GLOBAL,NULL},
+
+    /* Specifies the end-tag for the Defaults context.
+     */
+    {"</Defaults>",ARG_NONE, exit_defaults_context,NULL,CTX_DEFAULTS,NULL},
+
+    /* Specifies the beginning of the Aliases context.  This groups 
+     * the Alias mapping options.
+     *
+     * The Aliases context should be defined before any FileSystem contexts
+     * are defined, as options in the FileSystem context usually need to
+     * reference the aliases defined in this context.
+     */
+    {"<Aliases>",ARG_NONE, enter_aliases_context,NULL,CTX_GLOBAL,NULL},
+
+    /* Specifies the end-tag for the Aliases context.
+     */
+    {"</Aliases>",ARG_NONE, exit_aliases_context,NULL,CTX_ALIASES,NULL},
+
+    /* Specifies an alias in the form of a non-whitespace string that
+     * can be used to reference a BMI server address (a HostID).  This
+     * allows us to reference individual servers by an alias instead of their
+     * full HostID.  The format of the Alias option is:
+     *
+     * Alias {alias string} {bmi address}
+     *
+     * As an example:
+     *
+     * Alias mynode1 tcp://hostname1.clustername1.domainname:12345
+     */
+    {"Alias",ARG_LIST, get_alias_list,NULL,CTX_ALIASES,NULL},
+
+    /* Specifies the beginning of a Filesystem context.  This groups
+     * options specific to a filesystem.  A pvfs2 server may manage
+     * more than one filesystem, so a config file may have more than
+     * one Filesystem context, each defining the parameters of a different
+     * Filesystem.
+     */
+    {"<FileSystem>",ARG_NONE, enter_filesystem_context,NULL,CTX_GLOBAL,NULL},
+
+    /* Specifies the end-tag of a Filesystem context.
+     */
+    {"</FileSystem>",ARG_NONE, exit_filesystem_context,NULL,CTX_FILESYSTEM,
+        NULL},
+
+    /* Specifies the beginning of a StorageHints context.  This groups
+     * options specific to a filesystem and related to the behavior of the
+     * storage system.  Mostly these options are passed directly to the
+     * TROVE storage module which may or may not support them.  The
+     * DBPF module (the only TROVE module implemented at present) supports
+     * all of them.
+     */
+    {"<StorageHints>",ARG_NONE, enter_storage_hints_context,NULL,
+        CTX_FILESYSTEM,NULL},
+
+    /* Specifies the end-tag of the StorageHints context.
+     */
+    {"</StorageHints>",ARG_NONE, exit_storage_hints_context,NULL,
+        CTX_STORAGEHINTS,NULL},
+
+    /* This context groups together the Range options that define valid values
+     * for meta handles on a per-host basis for this filesystem.
+     *
+     * The MetaHandleRanges context is required to be present in a
+     * Filesystem context.
+     */
+    {"<MetaHandleRanges>",ARG_NONE, enter_mhranges_context,NULL,
+        CTX_FILESYSTEM,NULL},
+
+    /* Specifies the end-tag for the MetaHandleRanges context.
+     */
+    {"</MetaHandleRanges>",ARG_NONE, exit_mhranges_context,NULL,
+        CTX_METAHANDLERANGES,NULL},
+
+    /* This context groups together the Range options that define valid values
+     * for the data handles on a per-host basis for this filesystem.
+     *
+     * A DataHandleRanges context is required to be present in a
+     * Filesystem context.
+     */
+    {"<DataHandleRanges>",ARG_NONE, enter_dhranges_context,NULL,
+        CTX_FILESYSTEM,NULL},
+
+    /* Specifies the end-tag for the DataHandleRanges context.
+     */
+    {"</DataHandleRanges>",ARG_NONE, exit_dhranges_context,NULL,
+        CTX_DATAHANDLERANGES,NULL},
+    
+    /* Provides a context for defining the filesystem's default
+     * distribution to use and the parameters to be set for that distribution.
+     *
+     * Valid options within the Distribution context are Name, Param, and Value.
+     *
+     * This context is an optional context within the Filesystem context.  If
+     * not specified, the filesystem defaults to the simple-stripe distribution.
+     */
+    {"<Distribution>",ARG_NONE, enter_distribution_context,NULL,
+        CTX_FILESYSTEM,NULL},
+
+    /* Specifies the end-tag for the Distribution context.
+     */
+    {"</Distribution>",ARG_NONE, exit_distribution_context,NULL,
+        CTX_DISTRIBUTION,NULL},
+
+    /* As logical files are created in pvfs2, the data files and meta files
+     * that represent them are given filesystem unique handle values.  The
+     * user can specify a range of values (or set of ranges) 
+     * to be allocated to data files and meta files for a particular server,
+     * using the Range option in the DataHandleRanges and MetaHandleRanges
+     * contexts.  Note that in most cases, its easier to let the 
+     * pvfs2-genconfig script determine the best ranges to specify.
+     *
+     * This option specifies a range of handle values that can be used for 
+     * a particular pvfs2 server in a particular context (meta handles
+     * or data handles).  The DataHandleRanges and MetaHandleRanges contexts
+     * should contain one or more Range options.  The format is:
+     *
+     * Range {alias} {min value1}-{max value1}[, {min value2}-{max value2},...]
+     *
+     * Where {alias} is one of the alias strings already specified in the
+     * Aliases context.
+     *
+     * {min value} and {max value} are positive integer values that specify
+     * the range of possible handles that can be given out for that particular
+     * host.  {max value} must be less than 18446744073709551615 (UINT64_MAX).
+     *
+     * As shown in the specified format, multiple ranges can be specified for
+     * the same alias.  The format requires that max value of a given range
+     * is less than the min value of the next one, 
+     * i.e. {max value1}<{min value2}
+     * 
+     * Example of a Range option for data handles:
+     *
+     * Range mynode1 2147483651-4294967297
+     */
+    {"Range",ARG_LIST, get_range_list,NULL,
+        CTX_METAHANDLERANGES|CTX_DATAHANDLERANGES,NULL},
+
+    /* Specifies the handle value for the root of the Filesystem.  This
+     * is a required option in the Filesystem context.  The format is:
+     *
+     * RootHandle {handle value}
+     *
+     * Where {handle value} is a positive integer no greater than 
+     * 18446744073709551615 (UIN64_MAX).
+     *
+     * In general its best to let the pvfs2-genconfig script specify a
+     * RootHandle value for the filesystem.
+     */
+    {"RootHandle",ARG_STR, get_root_handle,NULL,
+        CTX_FILESYSTEM,NULL},
+
+    /* This option specifies the name of the particular filesystem or
+     * distribution that its defined in.  It is a required option in
+     * Filesystem and Distribution contexts.
+     */
+    {"Name",ARG_STR, get_name,NULL,
+        CTX_FILESYSTEM|CTX_DISTRIBUTION,NULL},
+
+    /* A pvfs2 server may manage more than one filesystem, and so a
+     * unique identifier is used to represent each one.  
+     * This option specifies such an ID (sometimes called a 'collection
+     * id') for the filesystem it is defined in.  
+     *
+     * The ID value can be any positive integer, no greater than
+     * 2147483647 (INT32_MAX).  It is a required option in the Filesystem
+     * context.
+     */
+    {"ID",ARG_INT, get_filesystem_collid,NULL,
+        CTX_FILESYSTEM,NULL},
+
+    /* The gossip interface in pvfs2 allows users to specify different
+     * levels of logging for the pvfs2 server.  The output of these
+     * different log levels is written to a file, which is specified in
+     * this option.  The value of the option must be the path pointing to a 
+     * file with valid write permissions.  The Logfile option can be
+     * specified for all the pvfs2 servers in the Defaults context or for
+     * a particular server in the Global context.
+     */
+    {"LogFile",ARG_STR, get_logfile,NULL,
+        CTX_DEFAULTS|CTX_GLOBAL,"/tmp/pvfs2-server.log"},
+
+    /* The gossip interface in pvfs2 allows users to specify different
+     * levels of logging for the pvfs2 server.  This option sets that level for
+     * either all servers (by being defined in the Defaults context) or for
+     * a particular server by defining it in the Global context.  Possible
+     * values for event logging are:
+     *
+     * __EVENTLOGGING__
+     *
+     * The value of the EventLogging option can be a comma separated list
+     * of the above values.  Individual values can also be negated with
+     * a '-'.  Examples of possible values are:
+     *
+     * EventLogging flow,msgpair,io
+     * EventLogging -storage
+     * EventLogging -flow,-flowproto
+     */
+    {"EventLogging",ARG_LIST, get_event_logging_list,NULL,
+        CTX_DEFAULTS|CTX_GLOBAL,"none,"},
+
+    /* At startup each pvfs2 server allocates space for a set number
+     * of incoming requests to prevent the allocation delay at the beginning
+     * of each unexpected request.  This parameter specifies the number
+     * of requests for which to allocate space.
+     *
+     * If set in the Defaults context, its value will be used for all servers.
+     * The default value can also be overwritten by setting a separate value
+     * in the Global context.
+     */
+     {"UnexpectedRequests",ARG_INT, get_unexp_req,NULL,
+         CTX_DEFAULTS|CTX_GLOBAL,"50"},
+
+     /* Specifies the timeout value in seconds for BMI jobs on the server.
+      */
+     {"ServerJobBMITimeoutSecs",ARG_INT, get_server_job_bmi_timeout,NULL,
+         CTX_DEFAULTS|CTX_GLOBAL, "30"},
+     
+     /* Specifies the timeout value in seconds for TROVE jobs on the server.
+      */
+     {"ServerJobFlowTimeoutSecs",ARG_INT, get_server_job_flow_timeout,NULL,
+         CTX_DEFAULTS|CTX_GLOBAL, "30"},
+     
+     /* Specifies the timeout value in seconds for BMI jobs on the client.
+      */
+     {"ClientJobBMITimeoutSecs",ARG_INT, get_client_job_bmi_timeout,NULL,
+         CTX_DEFAULTS|CTX_GLOBAL, "300"},
+
+     /* Specifies the timeout value in seconds for FLOW jobs on the client.
+      */
+     {"ClientJobFlowTimeoutSecs",ARG_INT, get_client_job_flow_timeout,NULL,
+         CTX_DEFAULTS|CTX_GLOBAL, "300"},
+
+     /* Specifies the number of retry attempts for operations (when possible)
+      */
+     {"ClientRetryLimit",ARG_INT, get_client_retry_limit,NULL,
+         CTX_DEFAULTS|CTX_GLOBAL, "5"},
+
+     /* Specifies the delay in milliseconds to wait between retries.
+      */
+     {"ClientRetryDelayMilliSecs",ARG_INT, get_client_retry_delay,NULL,
+         CTX_DEFAULTS|CTX_GLOBAL, "2000"},
+
+     /* This specifies the frequency (in milliseconds) 
+      * that performance monitor should be updated
+      * when the pvfs2 server is running in admin mode.
+      *
+      * Can be set in either Default or Global contexts.
+      */
+    {"PerfUpdateInterval",ARG_INT, get_perf_update_interval,NULL,
+        CTX_DEFAULTS|CTX_GLOBAL,"1000"},
+
+    /* List the BMI modules to load when the server is started.  At present,
+     * only tcp, infiniband, and myrinet are valid BMI modules.  
+     * The format of the list is a comma separated list of one of:
+     *
+     * bmi_tcp
+     * bmi_ib
+     * bmi_gm
+     *
+     * For example:
+     *
+     * BMIModules bmi_tcp,bmi_ib
+     *
+     * Note that only the bmi modules compiled into pvfs2 should be
+     * specified in this list.  The BMIModules option can be specified
+     * in either the Defaults or Global contexts.
+     */
+    {"BMIModules",ARG_LIST, get_bmi_module_list,NULL,
+        CTX_DEFAULTS|CTX_GLOBAL,NULL},
+    
+    /* List the flow modules to load when the server is started.  The modules
+     * available for loading currently are:
+     *
+     * flowproto_multiqueue - A flow module that handles all the possible flows,
+     * bmi->trove, trove->bmi, mem->bmi, bmi->mem.  At present, this is the
+     * default and only available flow for production use.
+     *
+     * flowproto_bmi_cache - A flow module that enables the use of the NCAC
+     * (network-centric adaptive cache) in the pvfs2 server.  Since the NCAC
+     * is currently disable and unsupported, this module exists as a proof
+     * of concept only.
+     *
+     * flowproto_dump_offsets - Used for debugging, this module allows the
+     * developer to see what/when flows are being posted, without making
+     * any actual BMI or TROVE requests.  This should only be used if you
+     * know what you're doing.
+     *
+     */
+    {"FlowModules",ARG_LIST, get_flow_module_list,NULL,
+        CTX_DEFAULTS|CTX_GLOBAL,"flowproto_multiqueue,"},
+
+    /* The TROVE storage layer has a management component that deals with
+     * allocating handle values for new metafiles and datafiles.  The underlying
+     * trove module can be given a hint to tell it how long to wait before
+     * reusing handle values that have become freed up (only deleting files will
+     * free up a handle).  The HandleRecycleTimeoutSecs option specifies
+     * the number of seconds to wait for each filesystem.  This is an
+     * optional parameter that can be specified in the StorageHints context.
+     */
     {"HandleRecycleTimeoutSecs", ARG_INT,
-     get_handle_recycle_timeout_seconds, NULL, CTX_ALL},
-    {"AttrCacheKeywords",ARG_LIST, get_attr_cache_keywords_list,NULL,CTX_ALL},
-    {"AttrCacheSize",ARG_INT, get_attr_cache_size, NULL,CTX_ALL},
-    {"AttrCacheMaxNumElems",ARG_INT,get_attr_cache_max_num_elems,NULL,CTX_ALL},
-    {"TroveSyncMeta",ARG_STR, get_trove_sync_meta, NULL, CTX_ALL},
-    {"TroveSyncData",ARG_STR, get_trove_sync_data, NULL, CTX_ALL},
-    {"LogStamp",ARG_STR, get_logstamp,NULL,CTX_ALL},
+         get_handle_recycle_timeout_seconds, NULL, 
+         CTX_STORAGEHINTS,"360"},
+    
+    /* The TROVE layer has an attribute caching component that handles
+     * caching of stored attributes.  This is used to improve the performance of
+     * metadata accesses.  The AttrCacheKeywords option is a list of the
+     * object types that should get cached in the attribute cache.  
+     * The possible values for this option are:
+     *
+     * datafile_handles - This will cache the array of datafile handles for
+     *                    each logical file in this filesystem
+     * 
+     * metafile_dist - This will cache (for each logical file)
+     *                 the file distribution information used to create/manage
+     *                 the datafiles.  
+     *
+     * dir_ent - This will cache the handles of the directory entries in this
+     *           filesystem
+     *
+     * symlink_target - This will cache the target path for the symbolic links
+     *                  in this filesystem
+     *
+     * The format of this option is a comma-separated list of one or more
+     * of the above values.  For example:
+     *
+     * AttrCacheKeywords datafile_handles,metafile_dist,dir_ent
+     */
+    {"AttrCacheKeywords",ARG_LIST, get_attr_cache_keywords_list,NULL,
+        CTX_STORAGEHINTS,
+        "datafile_handles,metafile_dist,dir_ent,symlink_target,"},
+    
+    /* The attribute cache in the TROVE layer mentioned in the documentation
+     * for the AttrCacheKeywords option is managed as a hashtable.  The
+     * AttrCacheSize adjusts the number of buckets that this hashtable contains.
+     * This value can be adjusted for better performance.  A good hashtable
+     * size should always be a prime number.
+     */
+    {"AttrCacheSize",ARG_INT, get_attr_cache_size, NULL,
+        CTX_STORAGEHINTS,"511"},
+
+    /* This option specifies the max cache size of the attribute cache 
+     * in the TROVE layer mentioned in the documentation
+     * for the AttrCacheKeywords option.  This value can be adjusted for
+     * better performance.
+     */
+    {"AttrCacheMaxNumElems",ARG_INT,get_attr_cache_max_num_elems,NULL,
+        CTX_STORAGEHINTS,"1024"},
+    
+    /* The TroveSyncMeta option allows users to turn off metadata
+     * synchronization with every metadata write.  This can greatly improve
+     * performance.  In general, this value should probably be set to yes,
+     * otherwise metadata transaction could be lost in the event of server
+     * failover.
+     */
+    {"TroveSyncMeta",ARG_STR, get_trove_sync_meta, NULL, 
+        CTX_STORAGEHINTS,"yes"},
+
+    /* The TroveSyncData option allows users to turn off datafile
+     * synchronization with every write operation.  This can greatly improve
+     * performance, but may cause lost data in the event of server failover.
+     */
+    {"TroveSyncData",ARG_STR, get_trove_sync_data, NULL, 
+        CTX_STORAGEHINTS,"yes"},
+
+    /* Specifies the format of the date/timestamp that events will have
+     * in the event log.  Possible values are:
+     *
+     * usec: [%H:%M:%S
+     *
+     * datetime: [%m/%d %H:%M]
+     *
+     * none
+     *
+     * The format of the option is one of the above values.  For example,
+     *
+     * LogStamp datetime
+     */
+    {"LogStamp",ARG_STR, get_logstamp,NULL,
+        CTX_DEFAULTS|CTX_GLOBAL,"usec"},
+    
+    /* This option specifies a parameter name to be passed to the 
+     * distribution to be used.  This option should be immediately
+     * followed by a Value option.
+     */
+    {"Param", ARG_STR, get_param, NULL, 
+        CTX_DISTRIBUTION,NULL},
+    
+    /* This option specifies the value of the parameter who's name
+     * was specified in the previous option.
+     */
+    {"Value", ARG_INT, get_value, NULL, 
+        CTX_DISTRIBUTION,NULL},
+    
+    /* This option specifies the default number of datafiles to use
+     * when a new file is created.  The value is passed to the distribution
+     * and it determines whether to use that value or not.
+     */
+    {"DefaultNumDFiles", ARG_INT, get_default_num_dfiles, NULL,
+        CTX_FILESYSTEM,"0"},
+
     LAST_OPTION
 };
 
@@ -154,6 +567,7 @@ int PINT_parse_config(
     char *global_config_filename,
     char *server_config_filename)
 {
+    struct server_configuration_s *config_s;
     configfile_t *configfile = (configfile_t *)0;
 
     if (!config_obj)
@@ -168,8 +582,15 @@ int PINT_parse_config(
 
     /* set some global defaults for optional parameters */
     config_s->logstamp_type = GOSSIP_LOGSTAMP_DEFAULT;
+    config_s->server_job_bmi_timeout = PVFS2_SERVER_JOB_BMI_TIMEOUT_DEFAULT;
+    config_s->server_job_flow_timeout = PVFS2_SERVER_JOB_FLOW_TIMEOUT_DEFAULT;
+    config_s->client_job_bmi_timeout = PVFS2_CLIENT_JOB_BMI_TIMEOUT_DEFAULT;
+    config_s->client_job_flow_timeout = PVFS2_CLIENT_JOB_FLOW_TIMEOUT_DEFAULT;
+    config_s->client_retry_limit = PVFS2_CLIENT_RETRY_LIMIT_DEFAULT;
+    config_s->client_retry_delay_ms = PVFS2_CLIENT_RETRY_DELAY_MS_DEFAULT;
 
-    if (cache_config_files(global_config_filename, server_config_filename))
+    if (cache_config_files(
+            config_s, global_config_filename, server_config_filename))
     {
         return 1;
     }
@@ -177,39 +598,42 @@ int PINT_parse_config(
     assert(config_s->server_config_buflen && config_s->server_config_buf);
 
     /* first read in the fs.conf defaults config file */
-    config_s->configuration_context = GLOBAL_CONFIG;
+    config_s->configuration_context = CTX_GLOBAL;
     configfile = PINT_dotconf_create(config_s->fs_config_filename,
-                                     options, NULL, CASE_INSENSITIVE);
+                                     options, (void *)config_s, 
+                                     CASE_INSENSITIVE);
     if (!configfile)
     {
         gossip_err("Error opening config file %s\n",
                    config_s->fs_config_filename);
         return 1;
     }
-
-    if (PINT_dotconf_command_loop(configfile) == 0)
+    configfile->errorhandler = (dotconf_errorhandler_t)errorhandler;
+    configfile->contextchecker = (dotconf_contextchecker_t)contextchecker;
+    
+    if(PINT_dotconf_command_loop(configfile) == 0)
     {
-        gossip_err("Error reading config file %s\n",
-                   config_s->fs_config_filename);
+        /* NOTE: dotconf error handler will log message */
         return 1;
     }
     PINT_dotconf_cleanup(configfile);
 
     /* then read in the server.conf (host specific) config file */
-    config_s->configuration_context = GLOBAL_CONFIG;
+    config_s->configuration_context = CTX_GLOBAL;
     configfile = PINT_dotconf_create(config_s->server_config_filename,
-                                options, NULL, CASE_INSENSITIVE);
+                                options, (void *)config_s, CASE_INSENSITIVE);
     if (!configfile)
     {
         gossip_err("Error opening config file: %s\n",
                    config_s->server_config_filename);
         return 1;
     }
+    configfile->errorhandler = (dotconf_errorhandler_t)errorhandler;
+    configfile->contextchecker = (dotconf_contextchecker_t)contextchecker;
 
     if (PINT_dotconf_command_loop(configfile) == 0)
     {
-        gossip_err("Error reading config file %s\n",
-                   config_s->server_config_filename);
+        /* NOTE: dotconf error handler will log message */
         return 1;
     }
     PINT_dotconf_cleanup(configfile);
@@ -235,30 +659,48 @@ int PINT_parse_config(
 	return 1;
     }
 
+    /* We set to the default flow module since there's only one.
+    */
     if (!config_s->flow_modules)
     {
-	gossip_err("Configuration file error. "
-                   "No Flow modules specified.\n");
+        gossip_err("Configuration file error. No flow module specified\n");
 	return 1;
     }
-
+    
+    /* Users don't need to learn about this unless they want to
+    */
     if (!config_s->perf_update_interval)
     {
-	gossip_err("Configuration file error.  "
+        gossip_err("Configuration file error.  "
                    "No PerfUpdateInterval specified.\n");
-	return 1;
+        return 1;
     }
-
+    
     return 0;
 }
 
-DOTCONF_CB(get_pvfs_server_id)
+const char *contextchecker(command_t *cmd, unsigned long mask)
 {
-    if (config_s->configuration_context != GLOBAL_CONFIG)
+    struct server_configuration_s *config_s = cmd->context;
+
+    if(!(mask & config_s->configuration_context))
     {
-        gossip_err("HostID Tag can only be in the Global context");
-        return NULL;
+        return "Option can't be defined in that context";
     }
+    return NULL;
+}
+    
+FUNC_ERRORHANDLER(errorhandler)
+{
+    gossip_err("Error: %s line %ld: %s", configfile->filename,
+        configfile->line, msg);
+    return(1);
+}
+
+DOTCONF_CB(get_pvfs_server_id)
+{
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
     if (config_s->host_id)
     {
         gossip_err("WARNING: HostID value being overwritten (from "
@@ -271,13 +713,8 @@ DOTCONF_CB(get_pvfs_server_id)
 
 DOTCONF_CB(get_logstamp)
 {
-    if ((config_s->configuration_context != DEFAULTS_CONFIG) &&
-        (config_s->configuration_context != GLOBAL_CONFIG))
-    {
-        gossip_err("Error: LogStamp tag can only be in a "
-                   "Defaults or Global block");
-        return NULL;
-    }
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
 
     if(!strcmp(cmd->data.str, "none"))
     {
@@ -293,8 +730,7 @@ DOTCONF_CB(get_logstamp)
     }
     else
     {
-        gossip_err("Error: LogStamp tag (if specified) must have one of the following values: none, usec, or datetime.\n");
-        return NULL;
+        return("LogStamp tag (if specified) must have one of the following values: none, usec, or datetime.\n");
     }
 
     return NULL;
@@ -303,11 +739,8 @@ DOTCONF_CB(get_logstamp)
 
 DOTCONF_CB(get_storage_space)
 {
-    if (config_s->configuration_context != GLOBAL_CONFIG)
-    {
-        gossip_err("StorageSpace Tag can only be in the Global context");
-        return NULL;
-    }
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
     if (config_s->storage_path)
     {
         gossip_err("WARNING: StorageSpace value being overwritten.\n");
@@ -320,63 +753,48 @@ DOTCONF_CB(get_storage_space)
 
 DOTCONF_CB(enter_defaults_context)
 {
-    if (config_s->configuration_context != GLOBAL_CONFIG)
-    {
-        gossip_err("Error in context.  Cannot have Defaults tag here\n");
-        return NULL;
-    }
-    config_s->configuration_context = DEFAULTS_CONFIG;
-    return NULL;
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->configuration_context = CTX_DEFAULTS;
+
+    return PINT_dotconf_set_defaults(
+        cmd->configfile, CTX_DEFAULTS);
 }
 
 DOTCONF_CB(exit_defaults_context)
 {
-    if (config_s->configuration_context != DEFAULTS_CONFIG)
-    {
-        gossip_err("Error in context.  Cannot have /Defaults tag here\n");
-        return NULL;
-    }
-    config_s->configuration_context = GLOBAL_CONFIG;
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->configuration_context = CTX_GLOBAL;
     return NULL;
 }
 
 DOTCONF_CB(enter_aliases_context)
 {
-    if (config_s->configuration_context != GLOBAL_CONFIG)
-    {
-        gossip_err("Error in context.  Cannot have Aliases tag here\n");
-        return NULL;
-    }
-    config_s->configuration_context = ALIASES_CONFIG;
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->configuration_context = CTX_ALIASES;
     return NULL;
 }
 
 DOTCONF_CB(exit_aliases_context)
 {
-    if (config_s->configuration_context != ALIASES_CONFIG)
-    {
-        gossip_err("Error in context.  Cannot have /Aliases tag here\n");
-        return NULL;
-    }
-    config_s->configuration_context = GLOBAL_CONFIG;
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->configuration_context = CTX_GLOBAL;
     return NULL;
 }
 
 DOTCONF_CB(enter_filesystem_context)
 {
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
     struct filesystem_configuration_s *fs_conf = NULL;
 
     if (config_s->host_aliases == NULL)
     {
-        gossip_err("Error in context.  Filesystem tag cannot "
+        return("Error in context.  Filesystem tag cannot "
                    "be declared before an Aliases tag.\n");
-        return NULL;
-    }
-
-    if (config_s->configuration_context != GLOBAL_CONFIG)
-    {
-        gossip_err("Error in context.  Cannot have Filesystem tag here\n");
-        return NULL;
     }
 
     fs_conf = (struct filesystem_configuration_s *)
@@ -396,19 +814,18 @@ DOTCONF_CB(enter_filesystem_context)
     }
     PINT_llist_add_to_head(config_s->file_systems,(void *)fs_conf);
     assert(PINT_llist_head(config_s->file_systems) == (void *)fs_conf);
-    config_s->configuration_context = FILESYSTEM_CONFIG;
-    return NULL;
+    config_s->configuration_context = CTX_FILESYSTEM;
+
+    return PINT_dotconf_set_defaults(
+        cmd->configfile,
+        CTX_FILESYSTEM);
 }
 
 DOTCONF_CB(exit_filesystem_context)
 {
     struct filesystem_configuration_s *fs_conf = NULL;
-
-    if (config_s->configuration_context != FILESYSTEM_CONFIG)
-    {
-        gossip_err("Error in context.  Cannot have /Filesystem tag here\n");
-        return NULL;
-    }
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
 
     fs_conf = (struct filesystem_configuration_s *)
         PINT_llist_head(config_s->file_systems);
@@ -421,165 +838,181 @@ DOTCONF_CB(exit_filesystem_context)
     if (!is_populated_filesystem_configuration(fs_conf))
     {
         gossip_err("Error: Filesystem configuration is invalid!\n");
-        gossip_err("Possible Error in context.  Cannot have /Filesystem "
-                   "tag before all filesystem attributes are declared\n");
-        return NULL;
+        return("Possible Error in context.  Cannot have /Filesystem "
+                   "tag before all filesystem attributes are declared.\n");
     }
 
-    config_s->configuration_context = GLOBAL_CONFIG;
+    config_s->configuration_context = CTX_GLOBAL;
     return NULL;
 }
 
 DOTCONF_CB(enter_storage_hints_context)
 {
-    if (config_s->configuration_context != FILESYSTEM_CONFIG)
-    {
-        gossip_err("Error in context.  Cannot "
-                   "have StorageHints tag here\n");
-        return NULL;
-    }
-    config_s->configuration_context = STORAGEHINTS_CONFIG;
-    return NULL;
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->configuration_context = CTX_STORAGEHINTS;
+
+    return PINT_dotconf_set_defaults(
+        cmd->configfile, CTX_STORAGEHINTS);
 }
 
 DOTCONF_CB(exit_storage_hints_context)
 {
-    if (config_s->configuration_context != STORAGEHINTS_CONFIG)
-    {
-        gossip_err("Error in context.  Cannot "
-                   "have /StorageHints tag here\n");
-        return NULL;
-    }
-    config_s->configuration_context = FILESYSTEM_CONFIG;
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->configuration_context = CTX_FILESYSTEM;
     return NULL;
 }
 
 
 DOTCONF_CB(enter_mhranges_context)
 {
-    if (config_s->configuration_context != FILESYSTEM_CONFIG)
-    {
-        gossip_err("Error in context.  Cannot have "
-                   "MetaHandleRanges tag here\n");
-        return NULL;
-    }
-    config_s->configuration_context = META_HANDLERANGES_CONFIG;
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->configuration_context = CTX_METAHANDLERANGES;
     return NULL;
 }
 
 DOTCONF_CB(exit_mhranges_context)
 {
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
     struct filesystem_configuration_s *fs_conf = NULL;
 
-    if (config_s->configuration_context != META_HANDLERANGES_CONFIG)
-    {
-        gossip_err("Error in context.  Cannot have "
-                   "/MetaHandleRanges tag here\n");
-        return NULL;
-    }
-
     fs_conf = (struct filesystem_configuration_s *)
         PINT_llist_head(config_s->file_systems);
     assert(fs_conf);
 
     if (!fs_conf->meta_handle_ranges)
     {
-        gossip_err("Error! No valid mhandle ranges added to %s\n",
-                   fs_conf->file_system_name);
+        return("No valid mhandle ranges added to file system.\n");
     }
-    config_s->configuration_context = FILESYSTEM_CONFIG;
+    config_s->configuration_context = CTX_FILESYSTEM;
     return NULL;
 }
 
 DOTCONF_CB(enter_dhranges_context)
 {
-    if (config_s->configuration_context != FILESYSTEM_CONFIG)
-    {
-        gossip_err("Error in context.  Cannot have "
-                   "DataHandleRanges tag here\n");
-        return NULL;
-    }
-    config_s->configuration_context = DATA_HANDLERANGES_CONFIG;
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->configuration_context = CTX_DATAHANDLERANGES;
     return NULL;
 }
 
 DOTCONF_CB(exit_dhranges_context)
 {
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
     struct filesystem_configuration_s *fs_conf = NULL;
 
-    if (config_s->configuration_context != DATA_HANDLERANGES_CONFIG)
-    {
-        gossip_err("Error in context.  Cannot have "
-                   "/DataHandleRanges tag here\n");
-        return NULL;
-    }
-
     fs_conf = (struct filesystem_configuration_s *)
         PINT_llist_head(config_s->file_systems);
     assert(fs_conf);
 
     if (!fs_conf->data_handle_ranges)
     {
-        gossip_err("Error! No valid dhandle ranges added to %s\n",
-                   fs_conf->file_system_name);
+        return("No valid dhandle ranges added to file system.\n");
     }
-    config_s->configuration_context = FILESYSTEM_CONFIG;
+    config_s->configuration_context = CTX_FILESYSTEM;
+    return NULL;
+}
+
+DOTCONF_CB(enter_distribution_context)
+{
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->configuration_context = CTX_DISTRIBUTION;
+    return NULL;
+}
+
+DOTCONF_CB(exit_distribution_context)
+{
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->configuration_context = CTX_GLOBAL;
     return NULL;
 }
 
 DOTCONF_CB(get_unexp_req)
 {
-    if ((config_s->configuration_context != DEFAULTS_CONFIG) &&
-        (config_s->configuration_context != GLOBAL_CONFIG))
-    {
-        gossip_err("UnexpectedRequests Tag can only be in a "
-                   "Defaults or Global block");
-        return NULL;
-    }
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
     config_s->initial_unexpected_requests = cmd->data.value;
     return NULL;
 }
 
+DOTCONF_CB(get_server_job_bmi_timeout)
+{
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->server_job_bmi_timeout = cmd->data.value;
+    return NULL;
+}
+
+DOTCONF_CB(get_server_job_flow_timeout)
+{
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->server_job_flow_timeout = cmd->data.value;
+    return NULL;
+}
+
+DOTCONF_CB(get_client_job_bmi_timeout)
+{
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->client_job_bmi_timeout = cmd->data.value;
+    return NULL;
+}
+
+DOTCONF_CB(get_client_job_flow_timeout)
+{
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->client_job_flow_timeout = cmd->data.value;
+    return NULL;
+}
+
+DOTCONF_CB(get_client_retry_limit)
+{
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->client_retry_limit = cmd->data.value;
+    return NULL;
+}
+
+DOTCONF_CB(get_client_retry_delay)
+{
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->client_retry_delay_ms = cmd->data.value;
+    return NULL;
+}
+
 DOTCONF_CB(get_perf_update_interval)
 {
-    if ((config_s->configuration_context != DEFAULTS_CONFIG) &&
-        (config_s->configuration_context != GLOBAL_CONFIG))
-    {
-        gossip_err("PerfUpdateInterval Tag can only be in a "
-                   "Defaults or Global block");
-        return NULL;
-    }
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
     config_s->perf_update_interval = cmd->data.value;
     return NULL;
 }
 
 DOTCONF_CB(get_logfile)
 {
-    if ((config_s->configuration_context != DEFAULTS_CONFIG) &&
-        (config_s->configuration_context != GLOBAL_CONFIG))
-    {
-        gossip_err("LogFile Tag can only be in a Defaults "
-                   "or Global block");
-        return NULL;
-    }
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
     config_s->logfile = (cmd->data.str ? strdup(cmd->data.str) : NULL);
     return NULL;
 }
 
 DOTCONF_CB(get_event_logging_list)
 {
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
     int i = 0, len = 0;
     char buf[512] = {0};
     char *ptr = buf;
 
-    if ((config_s->configuration_context != DEFAULTS_CONFIG) &&
-        (config_s->configuration_context != GLOBAL_CONFIG))
-    {
-        gossip_err("EventLogging Tag can only be in a "
-                   "Defaults or Global block");
-        return NULL;
-    }
-
     if (config_s->event_logging != NULL)
     {
         len = strlen(config_s->event_logging);
@@ -623,13 +1056,8 @@ DOTCONF_CB(get_flow_module_list)
     char buf[512] = {0};
     char *ptr = buf;
 
-    if ((config_s->configuration_context != DEFAULTS_CONFIG) &&
-        (config_s->configuration_context != GLOBAL_CONFIG))
-    {
-        gossip_err("FlowModules Tag can only be in a "
-                   "Defaults or Global block");
-        return NULL;
-    }
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
 
     if (config_s->flow_modules != NULL)
     {
@@ -654,13 +1082,8 @@ DOTCONF_CB(get_bmi_module_list)
     char buf[512] = {0};
     char *ptr = buf;
 
-    if ((config_s->configuration_context != DEFAULTS_CONFIG) &&
-        (config_s->configuration_context != GLOBAL_CONFIG))
-    {
-        gossip_err("BMIModules Tag can only be in a "
-                   "Defaults or Global block");
-        return NULL;
-    }
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
 
     if (config_s->bmi_modules != NULL)
     {
@@ -681,24 +1104,13 @@ DOTCONF_CB(get_bmi_module_list)
 DOTCONF_CB(get_handle_recycle_timeout_seconds)
 {
     struct filesystem_configuration_s *fs_conf = NULL;
-
-    if (config_s->configuration_context != STORAGEHINTS_CONFIG)
-    {
-        gossip_err("HandleRecycleTimeoutSecs Tag can only be in a "
-                   "StorageHints block");
-        return NULL;
-    }
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
 
     fs_conf = (struct filesystem_configuration_s *)
         PINT_llist_head(config_s->file_systems);
     assert(fs_conf);
 
-    if (fs_conf->handle_recycle_timeout_sec.tv_sec)
-    {
-        gossip_err("WARNING: Overwriting %d with %d\n",
-                   (int)fs_conf->handle_recycle_timeout_sec.tv_sec,
-                   (int)cmd->data.value);
-    }
     fs_conf->handle_recycle_timeout_sec.tv_sec = (int)cmd->data.value;
     fs_conf->handle_recycle_timeout_sec.tv_usec = 0;
 
@@ -712,12 +1124,8 @@ DOTCONF_CB(get_attr_cache_keywords_list)
     char *ptr = buf;
     struct filesystem_configuration_s *fs_conf = NULL;
 
-    if (config_s->configuration_context != STORAGEHINTS_CONFIG)
-    {
-        gossip_err("AttrCacheKeywords Tag can only be in a "
-                   "Filesystem block");
-        return NULL;
-    }
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
 
     fs_conf = (struct filesystem_configuration_s *)
         PINT_llist_head(config_s->file_systems);
@@ -748,23 +1156,13 @@ DOTCONF_CB(get_attr_cache_size)
 {
     struct filesystem_configuration_s *fs_conf = NULL;
 
-    if (config_s->configuration_context != STORAGEHINTS_CONFIG)
-    {
-        gossip_err("AttrCacheSize Tag can only be in a "
-                   "StorageHints block");
-        return NULL;
-    }
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
 
     fs_conf = (struct filesystem_configuration_s *)
         PINT_llist_head(config_s->file_systems);
     assert(fs_conf);
 
-    if (fs_conf->attr_cache_size)
-    {
-        gossip_err("WARNING: Overwriting %d with %d\n",
-                   fs_conf->attr_cache_size,
-                   (int)cmd->data.value);
-    }
     fs_conf->attr_cache_size = (int)cmd->data.value;
     return NULL;
 }
@@ -772,24 +1170,13 @@ DOTCONF_CB(get_attr_cache_size)
 DOTCONF_CB(get_attr_cache_max_num_elems)
 {
     struct filesystem_configuration_s *fs_conf = NULL;
-
-    if (config_s->configuration_context != STORAGEHINTS_CONFIG)
-    {
-        gossip_err("AttrCacheMaxNumElems Tag can only be in a "
-                   "StorageHints block");
-        return NULL;
-    }
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
 
     fs_conf = (struct filesystem_configuration_s *)
         PINT_llist_head(config_s->file_systems);
     assert(fs_conf);
 
-    if (fs_conf->attr_cache_max_num_elems)
-    {
-        gossip_err("WARNING: Overwriting %d with %d\n",
-                   fs_conf->attr_cache_max_num_elems,
-                   (int)cmd->data.value);
-    }
     fs_conf->attr_cache_max_num_elems = (int)cmd->data.value;
     return NULL;
 }
@@ -797,108 +1184,125 @@ DOTCONF_CB(get_attr_cache_max_num_elems)
 DOTCONF_CB(get_trove_sync_meta)
 {
     struct filesystem_configuration_s *fs_conf = NULL;
-
-    if (config_s->configuration_context != STORAGEHINTS_CONFIG)
-    {
-        gossip_err("TroveSyncMeta Tag can only be in a "
-                   "StorageHints block");
-        return NULL;
-    }
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
 
     fs_conf = (struct filesystem_configuration_s *)
         PINT_llist_head(config_s->file_systems);
     assert(fs_conf);
 
+    if(strcasecmp(cmd->data.str, "yes") == 0)
+    {
+        fs_conf->trove_sync_meta = TROVE_SYNC;
+    }
+    else if(strcasecmp(cmd->data.str, "no") == 0)
+    {
+        fs_conf->trove_sync_meta = 0;
+    }
+    else
+    {
+        return("TroveSyncMeta value must be 'yes' or 'no'.\n");
+    }
 #ifndef HAVE_DB_DIRTY_READ
-    fs_conf->trove_sync_meta = ((strcasecmp(cmd->data.str, "yes") == 0) ?
-                                TROVE_SYNC : 0);
     if (fs_conf->trove_sync_meta != TROVE_SYNC)
     {
-        gossip_err("Forcing TroveSyncMeta to be yes instead of %s\n",
+        gossip_err("WARNING: Forcing TroveSyncMeta to be yes instead of %s\n",
                    cmd->data.str);
-        gossip_err("Non-sync mode is NOT supported without "
-                   "DB_DIRTY_READ support\n");
+        gossip_err("WARNING: Non-sync mode is NOT supported without "
+                   "DB_DIRTY_READ support.\n");
         fs_conf->trove_sync_meta = TROVE_SYNC;
     }
-#else
-    fs_conf->trove_sync_meta = ((strcasecmp(cmd->data.str, "yes") == 0) ?
-                                TROVE_SYNC : 0);
 #endif
+
     return NULL;
 }
 
 DOTCONF_CB(get_trove_sync_data)
 {
     struct filesystem_configuration_s *fs_conf = NULL;
-
-    if (config_s->configuration_context != STORAGEHINTS_CONFIG)
-    {
-        gossip_err("TroveSyncData Tag can only be in a "
-                   "StorageHints block");
-        return NULL;
-    }
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
 
     fs_conf = (struct filesystem_configuration_s *)
         PINT_llist_head(config_s->file_systems);
     assert(fs_conf);
 
-    fs_conf->trove_sync_data = ((strcasecmp(cmd->data.str, "yes") == 0) ?
-                                TROVE_SYNC : 0);
+    if(strcasecmp(cmd->data.str, "yes") == 0)
+    {
+        fs_conf->trove_sync_data = TROVE_SYNC;
+    }
+    else if(strcasecmp(cmd->data.str, "no") == 0)
+    {
+        fs_conf->trove_sync_data = 0;
+    }
+    else
+    {
+        return("TroveSyncData value must be 'yes' or 'no'.\n");
+    }
+
     return NULL;
 }
 
 DOTCONF_CB(get_root_handle)
 {
     struct filesystem_configuration_s *fs_conf = NULL;
+    unsigned long long int tmp_var;
+    int ret = -1;
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
 
-    if (config_s->configuration_context != FILESYSTEM_CONFIG)
-    {
-        gossip_err("RootHandle Tag can only be in a Filesystem block");
-        return NULL;
-    }
     fs_conf = (struct filesystem_configuration_s *)
         PINT_llist_head(config_s->file_systems);
     assert(fs_conf);
-#ifdef HAVE_STRTOULL
-        fs_conf->root_handle = (PVFS_handle)strtoull(
-            cmd->data.str, NULL, 10);
-#else
-        fs_conf->root_handle = (PVFS_handle)strtoul(
-            cmd->data.str, NULL, 10);
-#endif
+    ret = sscanf(cmd->data.str, "%Lu", &tmp_var);
+    if(ret != 1)
+    {
+        return("RootHandle does not have a long long unsigned value.\n");
+    }
+    fs_conf->root_handle = (PVFS_handle)tmp_var;
     return NULL;
 }
 
-DOTCONF_CB(get_filesystem_name)
+DOTCONF_CB(get_name)
 {
-    struct filesystem_configuration_s *fs_conf = NULL;
-
-    if (config_s->configuration_context != FILESYSTEM_CONFIG)
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    if (config_s->configuration_context == CTX_FILESYSTEM)
     {
-        gossip_err("Name Tags can only be within Filesystem tags");
-        return NULL;
+        struct filesystem_configuration_s *fs_conf = NULL;
+
+        fs_conf = (struct filesystem_configuration_s *)
+            PINT_llist_head(config_s->file_systems);
+        if (fs_conf->file_system_name)
+        {
+            gossip_err("WARNING: Overwriting %s with %s\n",
+                       fs_conf->file_system_name,cmd->data.str);
+        }
+        fs_conf->file_system_name =
+            (cmd->data.str ? strdup(cmd->data.str) : NULL);
     }
-    fs_conf = (struct filesystem_configuration_s *)
-        PINT_llist_head(config_s->file_systems);
-    if (fs_conf->file_system_name)
+    else if (config_s->configuration_context == CTX_DISTRIBUTION)
     {
-        gossip_err("WARNING: Overwriting %s with %s\n",
-                   fs_conf->file_system_name,cmd->data.str);
+        if (0 == config_s->default_dist_config.name)
+        {
+            config_s->default_dist_config.name =
+                (cmd->data.str ? strdup(cmd->data.str) : NULL);
+            config_s->default_dist_config.param_list = PINT_llist_new();
+        }
+        else
+        {
+            return "Only one distribution configuration is allowed.\n";
+        }
     }
-    fs_conf->file_system_name =
-        (cmd->data.str ? strdup(cmd->data.str) : NULL);
     return NULL;
 }
 
 DOTCONF_CB(get_filesystem_collid)
 {
     struct filesystem_configuration_s *fs_conf = NULL;
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
 
-    if (config_s->configuration_context != FILESYSTEM_CONFIG)
-    {
-        gossip_err("ID Tags can only be within Filesystem tags");
-        return NULL;
-    }
     fs_conf = (struct filesystem_configuration_s *)
         PINT_llist_head(config_s->file_systems);
     if (fs_conf->coll_id)
@@ -910,17 +1314,31 @@ DOTCONF_CB(get_filesystem_collid)
     return NULL;
 }
 
+static int compare_aliases(void * vkey,
+                           void * valias2)
+{
+    char * hostaliaskey1 = (char *)vkey;
+    host_alias_s * alias2 = (host_alias_s *)valias2;
+    
+    return strcmp(hostaliaskey1, alias2->host_alias);
+}
+
 DOTCONF_CB(get_alias_list)
 {
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
     struct host_alias_s *cur_alias = NULL;
 
-    if (config_s->configuration_context != ALIASES_CONFIG)
+    assert(cmd->arg_count == 2);
+
+    /* prevent users from adding the same alias twice */
+    if(config_s->host_aliases &&
+       PINT_llist_search(config_s->host_aliases, 
+                      (void *)cmd->data.list[0],
+                      compare_aliases))
     {
-        gossip_err("Error in context.  Cannot have Alias "
-                   "outside of Aliases context\n");
-        return NULL;
+        return "Error: alias already defined";
     }
-    assert(cmd->arg_count == 2);
 
     cur_alias = (host_alias_s *)
         malloc(sizeof(host_alias_s));
@@ -931,6 +1349,7 @@ DOTCONF_CB(get_alias_list)
     {
         config_s->host_aliases = PINT_llist_new();
     }
+    
     PINT_llist_add_to_tail(config_s->host_aliases,(void *)cur_alias);
     return NULL;
 }
@@ -941,21 +1360,15 @@ DOTCONF_CB(get_range_list)
     struct filesystem_configuration_s *fs_conf = NULL;
     struct host_handle_mapping_s *handle_mapping = NULL;
     PINT_llist **handle_range_list = NULL;
-
-    if ((config_s->configuration_context != META_HANDLERANGES_CONFIG) &&
-        (config_s->configuration_context != DATA_HANDLERANGES_CONFIG))
-    {
-        gossip_err("Error in context.  Cannot have Range keyword "
-                   "outside of [Meta|Data]HandleRanges context\n");
-        return NULL;
-    }
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
 
     fs_conf = (struct filesystem_configuration_s *)
         PINT_llist_head(config_s->file_systems);
     assert(fs_conf);
 
     handle_range_list = ((config_s->configuration_context ==
-                          META_HANDLERANGES_CONFIG) ?
+                          CTX_METAHANDLERANGES) ?
                          &fs_conf->meta_handle_ranges :
                          &fs_conf->data_handle_ranges);
 
@@ -966,7 +1379,7 @@ DOTCONF_CB(get_range_list)
 
     for(i = 0; i < cmd->arg_count; i += 2)
     {
-        if (is_valid_alias(cmd->data.list[i]))
+        if (is_valid_alias(config_s->host_aliases, cmd->data.list[i]))
         {
             i++;
             assert(cmd->data.list[i]);
@@ -977,10 +1390,8 @@ DOTCONF_CB(get_range_list)
                     *handle_range_list, cmd->data.list[i-1]);
                 if (!handle_mapping)
                 {
-                    gossip_err("Error: Alias %s allocation failed; "
-                               "aborting alias handle range addition!\n",
-                               cmd->data.list[i-1]);
-                    return NULL;
+                    return("Error: Alias allocation failed; "
+                               "aborting alias handle range addition!\n");
                 }
 
                 if (!handle_mapping->alias_mapping)
@@ -1027,19 +1438,61 @@ DOTCONF_CB(get_range_list)
             }
             else
             {
-                gossip_err("Error in handle range description.\n %s is "
-                            "invalid input data!\n",cmd->data.list[i]);
+                return("Error in handle range description.\n");
             }
         }
         else
         {
-            gossip_err("Error! %s is an unrecognized alias\n",
-                        cmd->data.list[i]);
+            return("Unrecognized alias.\n");
         }
     }
     return NULL;
 }
 
+DOTCONF_CB(get_param)
+{
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    distribution_param_configuration* param =
+        malloc(sizeof(distribution_param_configuration));
+
+    if (NULL != param)
+    {
+        memset(param, 0, sizeof(param));
+        param->name = (cmd->data.str ? strdup(cmd->data.str) : NULL);
+        PINT_llist_add_to_tail(config_s->default_dist_config.param_list,
+                               param);
+    }
+    return NULL;
+}
+
+DOTCONF_CB(get_value)
+{
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    distribution_param_configuration* param;
+    param = (distribution_param_configuration*)PINT_llist_tail(
+        config_s->default_dist_config.param_list);
+    if (NULL != param)
+    {
+        param->value = (PVFS_size)cmd->data.value;
+    }
+    return NULL;
+}
+
+DOTCONF_CB(get_default_num_dfiles)
+{
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    struct filesystem_configuration_s *fs_conf = NULL;
+
+    fs_conf = (struct filesystem_configuration_s *)
+        PINT_llist_head(config_s->file_systems);
+
+    fs_conf->default_num_dfiles = (int)cmd->data.value;
+    return NULL;
+}
+
 /*
  * Function: PINT_config_release
  *
@@ -1125,7 +1578,7 @@ void PINT_config_release(struct server_c
     }
 }
 
-static int is_valid_alias(char *str)
+static int is_valid_alias(PINT_llist * host_aliases, char *str)
 {
     int ret = 0;
     PINT_llist *cur = NULL;
@@ -1133,7 +1586,7 @@ static int is_valid_alias(char *str)
 
     if (str)
     {
-        cur = config_s->host_aliases;
+        cur = host_aliases;
         while(cur)
         {
             cur_alias = PINT_llist_head(cur);
@@ -1190,7 +1643,7 @@ static int is_populated_filesystem_confi
              fs->meta_handle_ranges && fs->data_handle_ranges &&
              fs->root_handle) ? 1 : 0);
 }
-
+    
 static int is_root_handle_in_a_meta_range(
     struct server_configuration_s *config,
     struct filesystem_configuration_s *fs)
@@ -1346,6 +1799,7 @@ static void copy_filesystem(
 
         dest_fs->coll_id = src_fs->coll_id;
         dest_fs->root_handle = src_fs->root_handle;
+        dest_fs->default_num_dfiles = src_fs->default_num_dfiles;
 
         dest_fs->flowproto = src_fs->flowproto;
         dest_fs->encoding = src_fs->encoding;
@@ -1570,7 +2024,6 @@ static int build_extent_array(
     return 0;
 }
 
-
 /*
  * Function: PINT_config_get_host_addr_ptr
  *
@@ -1817,6 +2270,7 @@ char *PINT_config_get_merged_handle_rang
   call should properly de-alloc all consumed memory.
 */
 static int cache_config_files(
+    struct server_configuration_s *config_s,
     char *global_config_filename,
     char *server_config_filename)
 {
@@ -2025,8 +2479,8 @@ int PINT_config_is_valid_configuration(
     PINT_llist *cur = NULL;
     struct filesystem_configuration_s *cur_fs = NULL;
     
-    if (config_s && config_s->logfile && config_s->event_logging &&
-        config_s->bmi_modules)
+    if (config_s && config_s->bmi_modules && config_s->event_logging &&
+        config_s->logfile)
     {
         cur = config_s->file_systems;
         while(cur)
@@ -2442,7 +2896,7 @@ int PINT_config_get_trove_sync_meta(
 
     if (config)
     {
-        fs_conf = PINT_config_find_fs_id(config_s, fs_id);
+        fs_conf = PINT_config_find_fs_id(config, fs_id);
     }
     return (fs_conf ? fs_conf->trove_sync_meta : TROVE_SYNC);
 }
@@ -2459,7 +2913,7 @@ int PINT_config_get_trove_sync_data(
 
     if (config)
     {
-        fs_conf = PINT_config_find_fs_id(config_s, fs_id);
+        fs_conf = PINT_config_find_fs_id(config, fs_id);
     }
     return (fs_conf ? fs_conf->trove_sync_data : TROVE_SYNC);
 }

Index: server-config.h
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/server-config.h,v
diff -p -u -r1.42.4.1 -r1.42.4.2
--- server-config.h	7 Jun 2005 21:59:12 -0000	1.42.4.1
+++ server-config.h	25 Aug 2005 20:38:18 -0000	1.42.4.2
@@ -15,15 +15,16 @@
 #include "trove.h"
 #endif
 
-enum 
+enum
 {
-    GLOBAL_CONFIG = 1,
-    FILESYSTEM_CONFIG = 2,
-    DEFAULTS_CONFIG = 3,
-    ALIASES_CONFIG = 4,
-    META_HANDLERANGES_CONFIG = 5,
-    DATA_HANDLERANGES_CONFIG = 6,
-    STORAGEHINTS_CONFIG = 7
+    CTX_GLOBAL           = (1 << 1),
+    CTX_DEFAULTS         = (1 << 2),
+    CTX_ALIASES          = (1 << 3),
+    CTX_FILESYSTEM       = (1 << 4),
+    CTX_METAHANDLERANGES = (1 << 5),
+    CTX_DATAHANDLERANGES = (1 << 6),
+    CTX_STORAGEHINTS     = (1 << 7),
+    CTX_DISTRIBUTION     = (1 << 8)
 };
 
 typedef struct phys_server_desc
@@ -58,6 +59,7 @@ typedef struct filesystem_configuration_
     char *file_system_name;
     PVFS_fs_id coll_id;
     PVFS_handle  root_handle;
+    int default_num_dfiles;
 
     /* ptrs are type host_handle_mapping_s* */
     PINT_llist *meta_handle_ranges;
@@ -81,6 +83,21 @@ typedef struct filesystem_configuration_
 
 } filesystem_configuration_s;
 
+typedef struct distribution_param_configuration_s
+{
+    char* name;
+    int64_t value;  /* Temporarily hard code to 64bit type */
+
+} distribution_param_configuration;
+
+/* Config struct to hold overloaded distribution defaults */
+typedef struct distribution_configuration_s
+{
+    char* name;
+    PINT_llist* param_list;
+
+} distribution_configuration;
+
 typedef struct server_configuration_s
 {
     char *host_id;
@@ -92,6 +109,12 @@ typedef struct server_configuration_s
     ssize_t server_config_buflen;   /* the server.conf file length      */
     char *server_config_buf;        /* the server.conf file contents    */
     int  initial_unexpected_requests;
+    int  server_job_bmi_timeout;    /* job timeout values in seconds    */
+    int  server_job_flow_timeout;
+    int  client_job_bmi_timeout; 
+    int  client_job_flow_timeout;
+    int  client_retry_limit;        /* how many times to retry client operations */
+    int  client_retry_delay_ms;     /* delay between retries */
     int  perf_update_interval;      /* how quickly (in msecs) to
                                        update perf monitor              */
     char *logfile;
@@ -104,6 +127,8 @@ typedef struct server_configuration_s
     PINT_llist *host_aliases;       /* ptrs are type host_alias_s       */
     PINT_llist *file_systems;       /* ptrs are type
                                        filesystem_configuration_s       */
+    distribution_configuration default_dist_config;  /* distribution conf */
+
 } server_configuration_s;
 
 int PINT_parse_config(

Index: state-machine-fns.h
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/state-machine-fns.h,v
diff -p -u -r1.15.6.2 -r1.15.6.3
--- state-machine-fns.h	7 Jun 2005 21:59:12 -0000	1.15.6.2
+++ state-machine-fns.h	25 Aug 2005 20:38:18 -0000	1.15.6.3
@@ -25,6 +25,10 @@
  * includes state-machine.h, because state-machine.h needs a key #define
  * before it can be included.
  *
+ * The PINT_OP_STATE_TABLE has been replaced with a macro that must be #defined
+ * instead: PINT_OP_STATE_GET_MACHINE.  
+ * This allows the _locate function to be used in the client as well.
+ *
  * A good example of this is the pvfs2-server.h in the src/server directory,
  * which includes state-machine.h at the bottom, and server-state-machine.c,
  * which includes first pvfs2-server.h and then state-machine-fns.h.
@@ -37,10 +41,7 @@
 /* Prototypes for functions defined in here */
 static inline int PINT_state_machine_halt(void);
 static inline int PINT_state_machine_next(struct PINT_OP_STATE *,job_status_s *r);
-static inline int PINT_state_machine_invoke(struct PINT_OP_STATE *,job_status_s *r);
-#ifdef PINT_OP_STATE_TABLE
 static union PINT_state_array_values *PINT_state_machine_locate(struct PINT_OP_STATE *);
-#endif
 static inline union PINT_state_array_values *PINT_pop_state(struct PINT_OP_STATE *s);
 static inline void PINT_push_state(struct PINT_OP_STATE *s, union PINT_state_array_values *p);
 
@@ -192,25 +193,23 @@ static union PINT_state_array_values *PI
     union PINT_state_array_values *current_tmp;
 
     /* check for valid inputs */
-    if (!s_op || s_op->op < 0 
-        || s_op->op > PVFS_MAX_SERVER_OP)
+    if (!s_op || s_op->op < 0)
     {
 	gossip_err("State machine requested not valid\n");
 	return NULL;
     }
-    if (PINT_OP_STATE_TABLE[s_op->op].sm->state_machine != NULL)
+    if (PINT_OP_STATE_GET_MACHINE(s_op->op) != NULL)
     {
-	current_tmp = PINT_OP_STATE_TABLE[s_op->op].sm->state_machine;        
+	current_tmp = PINT_OP_STATE_GET_MACHINE(s_op->op)->state_machine;
         /* added the state name string as the first entry in the
          * state's array values.  Skip past it to get to the type
          * of action. --slang
          */
         current_tmp += 1;
-        
-        /* handle the case in which the first state points to a nested
-         * machine, rather than a simple function
-         */
-        while(current_tmp->flag == SM_JUMP)
+ 	/* handle the case in which the first state points to a nested
+	 * machine, rather than a simple function
+	 */
+	while(current_tmp->flag == SM_JUMP)
 	{
 	    PINT_push_state(s_op, current_tmp);
 	    current_tmp += 1;
@@ -230,7 +229,6 @@ static union PINT_state_array_values *PI
     gossip_err("State machine not found for operation %d\n",s_op->op);
     return NULL;
 }
-#endif
 
 static inline union PINT_state_array_values *PINT_pop_state(struct PINT_OP_STATE *s)
 {

Index: str-utils.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/str-utils.c,v
diff -p -u -r1.16 -r1.16.6.1
--- str-utils.c	2 Aug 2004 17:29:23 -0000	1.16
+++ str-utils.c	25 Aug 2005 20:38:18 -0000	1.16.6.1
@@ -366,7 +366,7 @@ int PINT_split_string_list(char ***token
     }
 
     /* allocate pointers for each */
-    *tokens = (char **) malloc(sizeof(char **));
+    *tokens = (char **) malloc(sizeof(char *) * tokencount);
     if (!(*tokens))
     {
 	return 0;
@@ -375,7 +375,7 @@ int PINT_split_string_list(char ***token
     /* copy out all of the tokenized strings */
     holder = comma_list;
     end = comma_list + strlen(comma_list);
-    for (i = 0; i < tokencount; i++)
+    for (i = 0; i < tokencount && holder; i++)
     {
 	holder2 = index(holder, ',');
 	if (!holder2)
@@ -410,6 +410,27 @@ int PINT_split_string_list(char ***token
 	free(*tokens);
     }
     return (0);
+}
+
+/* PINT_free_string_list()
+ * 
+ * Free the string list allocated by PINT_split_string_list()
+ */
+void PINT_free_string_list(char ** list, int len)
+{
+    int i = 0;
+
+    if(list)
+    {
+        for(; i < len; ++i)
+        {
+            if(list[i])
+            {
+                free(list[i]);
+            }
+        }
+        free(list);
+    }
 }
 
 /* PINT_remove_base_dir()

Index: str-utils.h
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/str-utils.h,v
diff -p -u -r1.14 -r1.14.6.1
--- str-utils.h	2 Aug 2004 17:29:23 -0000	1.14
+++ str-utils.h	25 Aug 2005 20:38:18 -0000	1.14.6.1
@@ -36,6 +36,9 @@ int PINT_get_next_path(
 int PINT_split_string_list(
     char ***tokens,
     const char *comma_list);
+void PINT_free_string_list(
+    char ** list, 
+    int len);
 int PINT_remove_base_dir(
     char *pathname,
     char *out_dir,



More information about the PVFS2-CVS mailing list