These patches are based on part of the functionality Murali originally
contributed in this email thread:

http://www.beowulf-underground.org/pipermail/pvfs2-developers/2005-November/001624.html

Thanks for the patches!

No, thank you - you did all of the hard work!

Examples:

[EMAIL PROTECTED] setfattr -n "user.pvfs2.num_dfiles" -v "1" 
/mnt/pvfs2/directory

[EMAIL PROTECTED] setfattr -n "user.pvfs2.dist_name" -v "basic_dist"
/mnt/pvfs2/directory

[EMAIL PROTECTED] setfattr -n "user.pvfs2.dist_params" -v "strip_size:4096"
/mnt/pvfs2/directory

Can you also add an entry in the FAQ for these if you haven't done it
already?

I have attached an updated version of the patch that adds some faq entries for the examples above.

-Phil
diff -Naur pvfs2-old/include/pvfs2-sysint.h pvfs2/include/pvfs2-sysint.h
--- pvfs2-old/include/pvfs2-sysint.h	2006-05-22 23:50:11.000000000 +0200
+++ pvfs2/include/pvfs2-sysint.h	2006-06-07 03:48:46.000000000 +0200
@@ -36,8 +36,10 @@
     PVFS_time mtime;
     PVFS_time ctime;
     PVFS_size size;
-    PVFS2_ALIGN_VAR(char *, link_target); /* NOTE: caller must free this */
+    PVFS2_ALIGN_VAR(char *, link_target);/* NOTE: caller must free if valid */
     PVFS2_ALIGN_VAR(int32_t, dfile_count); /* Changed to int32_t so that size of structure does not change */
+    PVFS2_ALIGN_VAR(char*, dist_name);   /* NOTE: caller must free if valid */
+    PVFS2_ALIGN_VAR(char*, dist_params); /* NOTE: caller must free if valid */
     PVFS_size dirent_count;
     PVFS_ds_type objtype;
     uint32_t mask;
diff -Naur pvfs2-old/include/pvfs2-types.h pvfs2/include/pvfs2-types.h
--- pvfs2-old/include/pvfs2-types.h	2006-05-29 18:21:10.000000000 +0200
+++ pvfs2/include/pvfs2-types.h	2006-06-07 03:48:46.000000000 +0200
@@ -245,6 +245,7 @@
 #define PVFS_ATTR_SYS_LNK_TARGET            (1 << 24)
 #define PVFS_ATTR_SYS_DFILE_COUNT           (1 << 25)
 #define PVFS_ATTR_SYS_DIRENT_COUNT          (1 << 26)
+#define PVFS_ATTR_SYS_DIR_HINT              (1 << 27)
 #define PVFS_ATTR_SYS_UID                   (1 << 0)
 #define PVFS_ATTR_SYS_GID                   (1 << 1)
 #define PVFS_ATTR_SYS_PERM                  (1 << 2)
@@ -261,10 +262,14 @@
 #define PVFS_ATTR_SYS_ALL                    \
 (PVFS_ATTR_SYS_COMMON_ALL | PVFS_ATTR_SYS_SIZE | \
  PVFS_ATTR_SYS_LNK_TARGET | PVFS_ATTR_SYS_DFILE_COUNT | \
+ PVFS_ATTR_SYS_DIRENT_COUNT | PVFS_ATTR_SYS_DIR_HINT)
+#define PVFS_ATTR_SYS_ALL_NOHINT                \
+(PVFS_ATTR_SYS_COMMON_ALL | PVFS_ATTR_SYS_SIZE | \
+ PVFS_ATTR_SYS_LNK_TARGET | PVFS_ATTR_SYS_DFILE_COUNT | \
  PVFS_ATTR_SYS_DIRENT_COUNT)
 #define PVFS_ATTR_SYS_ALL_NOSIZE                   \
 (PVFS_ATTR_SYS_COMMON_ALL | PVFS_ATTR_SYS_LNK_TARGET | \
- PVFS_ATTR_SYS_DFILE_COUNT | PVFS_ATTR_SYS_DIRENT_COUNT)
+ PVFS_ATTR_SYS_DFILE_COUNT | PVFS_ATTR_SYS_DIRENT_COUNT | PVFS_ATTR_SYS_DIR_HINT)
 #define PVFS_ATTR_SYS_ALL_SETABLE \
 (PVFS_ATTR_SYS_COMMON_ALL-PVFS_ATTR_SYS_TYPE)
 
diff -Naur pvfs2-old/src/apps/admin/pvfs2-cp.c pvfs2/src/apps/admin/pvfs2-cp.c
--- pvfs2-old/src/apps/admin/pvfs2-cp.c	2006-05-29 18:16:36.000000000 +0200
+++ pvfs2/src/apps/admin/pvfs2-cp.c	2006-06-07 03:48:46.000000000 +0200
@@ -558,7 +558,7 @@
         if ((ret == 0) && (open_type == OPEN_SRC))
         {
             memset(&resp_getattr, 0, sizeof(PVFS_sysresp_getattr));
-            ret = PVFS_sys_getattr(resp_lookup.ref, PVFS_ATTR_SYS_ALL,
+            ret = PVFS_sys_getattr(resp_lookup.ref, PVFS_ATTR_SYS_ALL_NOHINT,
                                    credentials, &resp_getattr);
             if (ret)
             {
diff -Naur pvfs2-old/src/apps/admin/pvfs2-fs-dump.c pvfs2/src/apps/admin/pvfs2-fs-dump.c
--- pvfs2-old/src/apps/admin/pvfs2-fs-dump.c	2006-05-29 18:16:36.000000000 +0200
+++ pvfs2/src/apps/admin/pvfs2-fs-dump.c	2006-06-07 03:49:37.000000000 +0200
@@ -439,7 +439,7 @@
     pref = lookup_resp.ref;
 
     PVFS_sys_getattr(pref,
-		     PVFS_ATTR_SYS_ALL,
+		     PVFS_ATTR_SYS_ALL_NOHINT,
 		     creds,
 		     &getattr_resp);
 
@@ -505,7 +505,7 @@
             entry_ref.fs_id  = cur_fs;
 
             if ((ret = PVFS_sys_getattr(entry_ref,
-                             PVFS_ATTR_SYS_ALL,
+                             PVFS_ATTR_SYS_ALL_NOHINT,
                              creds,
                              &getattr_resp)) != 0)
             {
diff -Naur pvfs2-old/src/apps/admin/pvfs2-fsck.c pvfs2/src/apps/admin/pvfs2-fsck.c
--- pvfs2-old/src/apps/admin/pvfs2-fsck.c	2006-05-29 18:16:36.000000000 +0200
+++ pvfs2/src/apps/admin/pvfs2-fsck.c	2006-06-07 03:50:11.000000000 +0200
@@ -449,7 +449,7 @@
     pref = lookup_resp.ref;
 
     PVFS_sys_getattr(pref,
-		     PVFS_ATTR_SYS_ALL,
+		     PVFS_ATTR_SYS_ALL_NOHINT,
 		     creds,
 		     &getattr_resp);
 
@@ -565,7 +565,7 @@
             }
 
             ret = PVFS_sys_getattr(entry_ref,
-                                   PVFS_ATTR_SYS_ALL,
+                                   PVFS_ATTR_SYS_ALL_NOHINT,
                                    creds,
                                    &getattr_resp);
             if (ret != 0) {
@@ -795,7 +795,7 @@
 	handle_ref.fs_id  = cur_fs;
 
 	ret = PVFS_sys_getattr(handle_ref,
-			       PVFS_ATTR_SYS_ALL,
+			       PVFS_ATTR_SYS_ALL_NOHINT,
 			       creds,
 			       &getattr_resp);
 	if (ret) {
@@ -876,7 +876,7 @@
 	handle_ref.fs_id  = cur_fs;
 
 	ret = PVFS_sys_getattr(handle_ref,
-			       PVFS_ATTR_SYS_ALL,
+			       PVFS_ATTR_SYS_ALL_NOHINT,
 			       creds,
 			       &getattr_resp);
 	if (ret) {
@@ -987,7 +987,7 @@
 	handle_ref.fs_id  = cur_fs;
 
 	ret = PVFS_sys_getattr(handle_ref,
-			       PVFS_ATTR_SYS_ALL,
+			       PVFS_ATTR_SYS_ALL_NOHINT,
 			       creds,
 			       &getattr_resp);
 	if (ret) {
diff -Naur pvfs2-old/src/apps/admin/pvfs2-ls.c pvfs2/src/apps/admin/pvfs2-ls.c
--- pvfs2-old/src/apps/admin/pvfs2-ls.c	2006-05-27 20:55:43.000000000 +0200
+++ pvfs2/src/apps/admin/pvfs2-ls.c	2006-06-07 03:48:46.000000000 +0200
@@ -367,7 +367,7 @@
     memset(&getattr_response,0, sizeof(PVFS_sysresp_getattr));
     PVFS_util_gen_credentials(&credentials);
 
-    ret = PVFS_sys_getattr(ref, PVFS_ATTR_SYS_ALL,
+    ret = PVFS_sys_getattr(ref, PVFS_ATTR_SYS_ALL_NOHINT,
                            &credentials, &getattr_response);
     if (ret)
     {
@@ -415,7 +415,7 @@
     pvfs_dirent_incount = MAX_NUM_DIRENTS;
 
     memset(&getattr_response,0,sizeof(PVFS_sysresp_getattr));
-    if (PVFS_sys_getattr(ref, PVFS_ATTR_SYS_ALL,
+    if (PVFS_sys_getattr(ref, PVFS_ATTR_SYS_ALL_NOHINT,
                          &credentials, &getattr_response) == 0)
     {
         if ((getattr_response.attr.objtype == PVFS_TYPE_METAFILE) ||
diff -Naur pvfs2-old/src/apps/admin/pvfs2-stat.c pvfs2/src/apps/admin/pvfs2-stat.c
--- pvfs2-old/src/apps/admin/pvfs2-stat.c	2006-03-09 22:17:48.000000000 +0100
+++ pvfs2/src/apps/admin/pvfs2-stat.c	2006-06-07 03:48:46.000000000 +0200
@@ -225,7 +225,7 @@
    ref.fs_id  = fs_id;
    
    ret = PVFS_sys_getattr(ref, 
-                          PVFS_ATTR_SYS_ALL,
+                          PVFS_ATTR_SYS_ALL_NOHINT,
                           (PVFS_credentials *) credentials, 
                           &getattr_response);
 
diff -Naur pvfs2-old/src/apps/admin/pvfs2-viewdist.c pvfs2/src/apps/admin/pvfs2-viewdist.c
--- pvfs2-old/src/apps/admin/pvfs2-viewdist.c	2006-05-29 18:16:36.000000000 +0200
+++ pvfs2/src/apps/admin/pvfs2-viewdist.c	2006-06-07 03:48:46.000000000 +0200
@@ -404,7 +404,7 @@
         ref.fs_id = resp_lookup.ref.fs_id;
 
         memset(&resp_getattr, 0, sizeof(PVFS_sysresp_getattr));
-        ret = PVFS_sys_getattr(ref, PVFS_ATTR_SYS_ALL,
+        ret = PVFS_sys_getattr(ref, PVFS_ATTR_SYS_ALL_NOHINT,
                                credentials, &resp_getattr);
         if (ret)
         {
diff -Naur pvfs2-old/src/client/sysint/client-state-machine.h pvfs2/src/client/sysint/client-state-machine.h
--- pvfs2-old/src/client/sysint/client-state-machine.h	2006-05-29 18:21:10.000000000 +0200
+++ pvfs2/src/client/sysint/client-state-machine.h	2006-06-07 03:48:46.000000000 +0200
@@ -95,6 +95,8 @@
     PVFS_sysresp_mkdir *mkdir_resp; /* in/out parameter */
     PVFS_sys_attr sys_attr;         /* input parameter  */
 
+    PVFS_ds_keyval *key_array;
+    PVFS_ds_keyval *val_array;
     int retry_count;
     int stored_error_code;
     PVFS_handle metafile_handle;
diff -Naur pvfs2-old/src/client/sysint/sys-create.sm pvfs2/src/client/sysint/sys-create.sm
--- pvfs2-old/src/client/sysint/sys-create.sm	2006-05-22 23:50:13.000000000 +0200
+++ pvfs2/src/client/sysint/sys-create.sm	2006-06-07 03:48:46.000000000 +0200
@@ -24,6 +24,7 @@
 #include "pint-distribution.h"
 #include "PINT-reqproto-encode.h"
 #include "pint-util.h"
+#include "pint-dist-utils.h"
 #include "ncache.h"
 #include "pvfs2-internal.h"
 
@@ -417,7 +418,7 @@
     PINT_SM_GETATTR_STATE_FILL(
         sm_p->getattr,
         sm_p->object_ref,
-        PVFS_ATTR_COMMON_ALL, 
+        PVFS_ATTR_COMMON_ALL|PVFS_ATTR_DIR_HINT, 
         PVFS_TYPE_DIRECTORY,
         0);
 
@@ -1042,6 +1043,9 @@
     PINT_client_sm *sm_p, job_status_s *js_p)
 {
     PVFS_object_attr *attr = NULL;
+    int num_dfiles_requested_override = 0;
+    PINT_dist *current_dist; 
+    int ret = 0;
 
     gossip_debug(GOSSIP_CLIENT_DEBUG, "create state: parent_getattr_inspect\n");
 
@@ -1060,7 +1064,108 @@
         sm_p->u.create.sys_attr.group = attr->group;
         /* note that permission checking is left to server even in this case */
     }
+    gossip_debug(GOSSIP_CLIENT_DEBUG, "create_parent_getattr: [%p] "
+        "dfile_count     = %d "
+        "dist_name_len   = %d "
+        "dist_params_len = %d\n",
+        attr,
+        attr->u.dir.hint.dfile_count,
+        attr->u.dir.hint.dist_name_len,
+        attr->u.dir.hint.dist_params_len);
+
+    num_dfiles_requested_override = attr->u.dir.hint.dfile_count;
+    /* override the # of data files for this create */
+    if (num_dfiles_requested_override > 0)
+    {
+        /* Determine the number of dfiles */
+        PINT_cached_config_get_num_dfiles(sm_p->object_ref.fs_id,
+                sm_p->u.create.dist,
+                num_dfiles_requested_override,
+                &sm_p->u.create.num_data_files);
+    }
+    gossip_debug(GOSSIP_CLIENT_DEBUG, "Setting number of datafiles to %d [requested %d]\n", 
+        sm_p->u.create.num_data_files, num_dfiles_requested_override);
+    current_dist = sm_p->u.create.dist;
+    /* We have an overriding distribution name for this directory.. honor that */
+    if (attr->u.dir.hint.dist_name_len > 0)
+    {
+        /* switch it only if it is different! */
+        if (strcmp(attr->u.dir.hint.dist_name, current_dist->dist_name))
+        {
+            PINT_dist *new_dist = NULL;
+            new_dist = PINT_dist_create(attr->u.dir.hint.dist_name);
+            if (new_dist)
+            {
+                gossip_debug(GOSSIP_CLIENT_DEBUG, "Overridding distribution name to %s instead of %s\n",
+                    attr->u.dir.hint.dist_name,
+                    current_dist->dist_name);
+                PINT_dist_free(current_dist);
+                sm_p->u.create.dist = new_dist;
+                current_dist = new_dist;
+            }
+            else
+            {
+                gossip_debug(GOSSIP_CLIENT_DEBUG, "Could not override distribution name with %s instead of %s\n",
+                    attr->u.dir.hint.dist_name,
+                    current_dist->dist_name);
+            }
+        }
+        else {
+            gossip_debug(GOSSIP_CLIENT_DEBUG, "retaining current distribution name %s\n",
+                current_dist->dist_name);
+        }
+    }
 
+    /* okay, we might need to override some dist params as well */
+    if (attr->u.dir.hint.dist_params_len > 0)
+    {
+        /* We have a series of comma separated key:val strings */
+        char **key, **val;
+        int64_t tmp_val;
+        int nparams = 0;
+
+        /* ignore parse errors! */
+        if (PINT_split_keyvals(attr->u.dir.hint.dist_params,
+            &nparams, &key, &val) == 0)
+        {
+            int i;
+            for (i = 0; i < nparams; i++)
+            {
+                gossip_debug(GOSSIP_CLIENT_DEBUG, "distribution parameter %s, value %s\n",
+                    key[i], val[i]);
+                /* NOTE: just as in server-config.c when parsing "Param" and
+                 * "Value" fields, we will assume that all values are 64 bit
+                 * integers.  The only difference here is that we scan
+                 * directly into a 64 bit integer, rather than converting
+                 * from the int format that dotconf supports.
+                 */
+                ret = sscanf(val[i], SCANF_lld, &tmp_val);
+                if(ret != 1)
+                {
+                    gossip_err("Error: unsupported type for distribution parameter %s, value %s found in directory hints.\n", 
+                        key[i], val[i]);
+                    gossip_err("Error: continuing anyway.\n");
+                }
+                else
+                {
+                    if(current_dist->methods->set_param(current_dist->dist_name,
+                        current_dist->params,
+                        key[i],
+                        &tmp_val))
+                    {
+
+                        gossip_err("Error: could not override hinted distribution parameter %s, value %s found in directory hints\n",
+                            key[i],
+                            val[i]);
+                    }
+                 }
+                 free(key[i]);
+                 free(val[i]);
+            }
+            free(key);
+            free(val);
+        }
+    }
     return(1);
 }
 
diff -Naur pvfs2-old/src/client/sysint/sys-getattr.sm pvfs2/src/client/sysint/sys-getattr.sm
--- pvfs2-old/src/client/sysint/sys-getattr.sm	2006-05-22 23:50:13.000000000 +0200
+++ pvfs2/src/client/sysint/sys-getattr.sm	2006-06-07 03:48:46.000000000 +0200
@@ -539,7 +539,6 @@
                           &resp_p->u.getattr.attr);
 
     attr =  &sm_p->getattr.attr;
-    assert(attr);
 
     /* if the ref_type mask is set to a non-zero value (!PVFS_TYPE_NONE)
      * a -PVFS_error will be triggered if the
@@ -618,7 +617,18 @@
             }
             return 0;
         case PVFS_TYPE_DIRECTORY:
+        {
+            gossip_debug(GOSSIP_CLIENT_DEBUG,
+                "getattr comp_fn [%p] "
+                "dfile_count = %d "
+                "dist_name_len = %d "
+                "dist_params_len = %d\n",
+                attr,
+                attr->u.dir.hint.dfile_count,
+                attr->u.dir.hint.dist_name_len,
+                attr->u.dir.hint.dist_params_len);
             return 0;
+        }
         case PVFS_TYPE_SYMLINK:
             return 0;
         case PVFS_TYPE_DATAFILE:
@@ -845,6 +855,42 @@
     {
         sysresp->attr.dfile_count = attr->u.meta.dfile_count;
     }
+    if (attr->objtype == PVFS_TYPE_DIRECTORY)
+    {
+        gossip_debug(GOSSIP_CLIENT_DEBUG, "dfile_count: %d\n", 
+            attr->u.dir.hint.dfile_count);
+        gossip_debug(GOSSIP_CLIENT_DEBUG, "dist_name_len = %d, dist_params_len = %d\n",
+            attr->u.dir.hint.dist_name_len, attr->u.dir.hint.dist_params_len);
+        sysresp->attr.dfile_count = attr->u.dir.hint.dfile_count;
+        /* 
+         * If we retrieved any extended attributes for the directory
+         * in question, the caller's responsibility to free it up
+         */
+        if (attr->u.dir.hint.dist_name_len > 0 && 
+            (sm_p->getattr.req_attrmask & PVFS_ATTR_DIR_HINT))
+        {
+            sysresp->attr.dist_name = strdup(attr->u.dir.hint.dist_name);
+            if (!sysresp->attr.dist_name)
+            {
+                js_p->error_code = -PVFS_ENOMEM;
+                return 0;
+            }
+            gossip_debug(GOSSIP_CLIENT_DEBUG, "dist_name_hint: %s\n", sysresp->attr.dist_name);
+        }
+        if (attr->u.dir.hint.dist_params_len > 0 &&
+            (sm_p->getattr.req_attrmask & PVFS_ATTR_DIR_HINT))
+        {
+            sysresp->attr.dist_params = strdup(attr->u.dir.hint.dist_params);
+            if (!sysresp->attr.dist_params)
+            {
+                free(sysresp->attr.dist_name);
+                sysresp->attr.dist_name = NULL;
+                js_p->error_code = -PVFS_ENOMEM;
+                return 0;
+            }
+            gossip_debug(GOSSIP_CLIENT_DEBUG, "dist_name_params: %s\n", sysresp->attr.dist_params);
+        }
+    }
 
     /* copy outgoing sys_attr fields from returned object_attr */
     sysresp->attr.owner = attr->owner;
diff -Naur pvfs2-old/src/client/sysint/sys-mkdir.sm pvfs2/src/client/sysint/sys-mkdir.sm
--- pvfs2-old/src/client/sysint/sys-mkdir.sm	2006-05-22 23:50:13.000000000 +0200
+++ pvfs2/src/client/sysint/sys-mkdir.sm	2006-06-07 03:48:46.000000000 +0200
@@ -32,7 +32,8 @@
 
 enum
 {
-    MKDIR_RETRY = 180
+    MKDIR_RETRY = 180,
+    MKDIR_SKIP_EATTR = 181
 };
 
 static int mkdir_init(
@@ -45,6 +46,10 @@
     PINT_client_sm *sm_p, job_status_s *js_p);
 static int mkdir_crdirent_failure(
     PINT_client_sm *sm_p, job_status_s *js_p);
+static int mkdir_seteattr_setup_msgpair(
+    PINT_client_sm *sm_p, job_status_s *js_p);
+static int mkdir_seteattr_failure(
+    PINT_client_sm *sm_p, job_status_s *js_p);
 static int mkdir_delete_handle_setup_msgpair(
     PINT_client_sm *sm_p, job_status_s *js_p);
 static int mkdir_cleanup(
@@ -68,6 +73,9 @@
     mkdir_msg_setup_msgpair,
     mkdir_msg_xfer_msgpair,
     mkdir_msg_failure,
+    mkdir_seteattr_setup_msgpair,
+    mkdir_seteattr_xfer_msgpair,
+    mkdir_seteattr_failure,
     mkdir_crdirent_setup_msgpair,
     mkdir_crdirent_xfer_msgpair,
     mkdir_crdirent_failure,
@@ -105,7 +113,7 @@
     state mkdir_msg_xfer_msgpair
     {
         jump pvfs2_msgpairarray_sm;
-        success => mkdir_crdirent_setup_msgpair;
+        success => mkdir_seteattr_setup_msgpair;
         default => mkdir_msg_failure;
     }
 
@@ -115,6 +123,27 @@
         default => cleanup;
     }
 
+    state mkdir_seteattr_setup_msgpair
+    {
+        run mkdir_seteattr_setup_msgpair;
+        MKDIR_SKIP_EATTR => mkdir_crdirent_setup_msgpair;
+        success => mkdir_seteattr_xfer_msgpair;
+        default => mkdir_seteattr_failure;
+    }
+
+    state mkdir_seteattr_xfer_msgpair
+    {
+        jump pvfs2_msgpairarray_sm;
+        success => mkdir_crdirent_setup_msgpair;
+        default => mkdir_seteattr_failure;
+    }
+
+    state mkdir_seteattr_failure
+    {
+        run mkdir_seteattr_failure;
+        default => delete_handle_setup_msgpair;
+    }
+
     state mkdir_crdirent_setup_msgpair
     {
         run mkdir_crdirent_setup_msgpair;
@@ -277,7 +306,7 @@
     PINT_SM_GETATTR_STATE_FILL(
         sm_p->getattr,
         sm_p->object_ref,
-        PVFS_ATTR_COMMON_ALL, 
+        (PVFS_ATTR_COMMON_ALL|PVFS_ATTR_DIR_HINT), 
         PVFS_TYPE_DIRECTORY,
         0);
 
@@ -498,6 +527,20 @@
 {
     gossip_debug(GOSSIP_CLIENT_DEBUG, "mkdir state: cleanup\n");
 
+    if(sm_p->u.mkdir.val_array)
+    {
+        if((sm_p->getattr.attr.mask & PVFS_ATTR_DIR_HINT) &&
+            (sm_p->getattr.attr.u.dir.hint.dfile_count > 0))
+        {
+            free(sm_p->u.mkdir.val_array[0].buffer);
+        }
+        free(sm_p->u.mkdir.val_array);
+    }
+    if(sm_p->u.mkdir.key_array)
+    {
+        free(sm_p->u.mkdir.key_array);
+    }
+
     PVFS_util_release_sys_attr(&sm_p->u.mkdir.sys_attr);
 
     PINT_SM_GETATTR_STATE_CLEAR(sm_p->getattr);
@@ -572,6 +615,152 @@
     return(1);
 }
 
+static int mkdir_seteattr_setup_msgpair(
+    PINT_client_sm *sm_p, job_status_s *js_p)
+{
+    int eattr_count = 0;
+    int cur_index = 0;
+    PINT_sm_msgpair_state *msg_p = NULL;
+    int ret = -PVFS_EINVAL;
+
+    /* NOTE: any memory allocated here will be free'd in the cleanup function */
+
+    gossip_debug(GOSSIP_CLIENT_DEBUG, "mkdir state: seteattr_setup_msgpair\n");
+    
+    /* don't set any hint attributes if the parent doesn't have them */
+    if(!(sm_p->getattr.attr.mask & PVFS_ATTR_DIR_HINT))
+    {
+        gossip_debug(GOSSIP_CLIENT_DEBUG, "mkdir state: skipping seteattr\n");
+        js_p->error_code = MKDIR_SKIP_EATTR;
+        return(1);
+    }
+
+    /* count how many hints we acquired */
+    if(sm_p->getattr.attr.u.dir.hint.dfile_count > 0)
+        eattr_count++;
+    if(sm_p->getattr.attr.u.dir.hint.dist_name != NULL)
+        eattr_count++;
+    if(sm_p->getattr.attr.u.dir.hint.dist_params != NULL)
+        eattr_count++;
+
+    if(eattr_count == 0)
+    {
+        /* nothing to inherit */
+        js_p->error_code = MKDIR_SKIP_EATTR;
+        return(1);
+    }
+
+    sm_p->u.mkdir.key_array = (PVFS_ds_keyval*)calloc(eattr_count,
+        sizeof(PVFS_ds_keyval));
+    if(!sm_p->u.mkdir.key_array)
+    {
+        js_p->error_code = -PVFS_ENOMEM;
+        return(1);
+    }
+
+    sm_p->u.mkdir.val_array = (PVFS_ds_keyval*)calloc(eattr_count,
+        sizeof(PVFS_ds_keyval));
+    if(!sm_p->u.mkdir.val_array)
+    {
+        js_p->error_code = -PVFS_ENOMEM;
+        return(1);
+    }
+
+    if(sm_p->getattr.attr.u.dir.hint.dfile_count > 0)
+    {
+        gossip_debug(GOSSIP_CLIENT_DEBUG, "mkdir: setting num_dfiles\n");
+        sm_p->u.mkdir.key_array[cur_index].buffer = "user.pvfs2.num_dfiles";
+        sm_p->u.mkdir.key_array[cur_index].buffer_sz = 
+            strlen("user.pvfs2.num_dfiles") + 1;
+
+        sm_p->u.mkdir.val_array[cur_index].buffer = calloc(1, 16);
+        if(!sm_p->u.mkdir.val_array[cur_index].buffer)
+        {
+            js_p->error_code = -PVFS_ENOMEM;
+            return(1);
+        }
+        snprintf((char*)sm_p->u.mkdir.val_array[cur_index].buffer,
+            16, "%d", sm_p->getattr.attr.u.dir.hint.dfile_count);
+        sm_p->u.mkdir.val_array[cur_index].buffer_sz = 
+            strlen((char*)sm_p->u.mkdir.val_array[cur_index].buffer) + 1;
+
+        cur_index++;
+    }
+    if(sm_p->getattr.attr.u.dir.hint.dist_name != NULL)
+    {
+        gossip_debug(GOSSIP_CLIENT_DEBUG, "mkdir: setting dist_name\n");
+        sm_p->u.mkdir.key_array[cur_index].buffer = "user.pvfs2.dist_name";
+        sm_p->u.mkdir.key_array[cur_index].buffer_sz = 
+            strlen("user.pvfs2.dist_name") + 1;
+        sm_p->u.mkdir.val_array[cur_index].buffer =
+            sm_p->getattr.attr.u.dir.hint.dist_name;
+        sm_p->u.mkdir.val_array[cur_index].buffer_sz =
+            sm_p->getattr.attr.u.dir.hint.dist_name_len;
+
+        cur_index++;
+    }
+    if(sm_p->getattr.attr.u.dir.hint.dist_params != NULL)
+    {
+        gossip_debug(GOSSIP_CLIENT_DEBUG, "mkdir: setting dist_params\n");
+        sm_p->u.mkdir.key_array[cur_index].buffer = "user.pvfs2.dist_params";
+        sm_p->u.mkdir.key_array[cur_index].buffer_sz = 
+            strlen("user.pvfs2.dist_params") + 1;
+
+        sm_p->u.mkdir.val_array[cur_index].buffer = 
+            sm_p->getattr.attr.u.dir.hint.dist_params;
+        sm_p->u.mkdir.val_array[cur_index].buffer_sz = 
+            sm_p->getattr.attr.u.dir.hint.dist_params_len;
+
+        cur_index++;
+    }
+
+    PINT_init_msgpair(sm_p, msg_p);
+
+    PINT_SERVREQ_SETEATTR_FILL(
+            sm_p->msgpair.req,
+            (*sm_p->cred_p),
+            sm_p->object_ref.fs_id,
+            sm_p->u.mkdir.metafile_handle,
+            0,
+            eattr_count,
+            sm_p->u.mkdir.key_array,
+            sm_p->u.mkdir.val_array
+            );
+
+    sm_p->msgarray = &(sm_p->msgpair);
+    sm_p->msgarray_count = 1;
+    sm_p->msgpair.fs_id = sm_p->object_ref.fs_id;
+    sm_p->msgpair.handle = sm_p->u.mkdir.metafile_handle;
+    sm_p->msgpair.retry_flag = PVFS_MSGPAIR_RETRY;
+    /* NOTE: no comp_fn needed. */
+
+    ret = PINT_cached_config_map_to_server(
+            &sm_p->msgpair.svr_addr,
+            sm_p->msgpair.handle,
+            sm_p->msgpair.fs_id);
+    if (ret)
+    {
+        gossip_err("Failed to map meta server address\n");
+        js_p->error_code = ret;
+    }
+    else
+    {
+        js_p->error_code = 0;
+    }
+    return(1);
+}
+
+static int mkdir_seteattr_failure(
+    PINT_client_sm *sm_p, job_status_s *js_p)
+{
+    sm_p->u.mkdir.stored_error_code = js_p->error_code;
+
+    gossip_debug(GOSSIP_CLIENT_DEBUG, "mkdir state: mkdir_seteattr_failure\n");
+
+    PVFS_perror_gossip("mkdir seteattr failed", js_p->error_code);
+    return 1;
+}
+
 /*
  * Local variables:
  *  mode: c
diff -Naur pvfs2-old/src/common/misc/pint-util.c pvfs2/src/common/misc/pint-util.c
--- pvfs2-old/src/common/misc/pint-util.c	2005-08-23 20:44:17.000000000 +0200
+++ pvfs2/src/common/misc/pint-util.c	2006-06-07 03:48:46.000000000 +0200
@@ -133,6 +133,33 @@
                 src->u.dir.dirent_count;
         }
 
+        if (src->mask & PVFS_ATTR_DIR_HINT)
+        {
+            dest->u.dir.hint.dfile_count = 
+                src->u.dir.hint.dfile_count;
+            dest->u.dir.hint.dist_name_len =
+                src->u.dir.hint.dist_name_len;
+            if (dest->u.dir.hint.dist_name_len > 0)
+            {
+                dest->u.dir.hint.dist_name = strdup(src->u.dir.hint.dist_name);
+                if (dest->u.dir.hint.dist_name == NULL)
+                {
+                    return ret;
+                }
+            }
+            dest->u.dir.hint.dist_params_len =
+                src->u.dir.hint.dist_params_len;
+            if (dest->u.dir.hint.dist_params_len > 0)
+            {
+                dest->u.dir.hint.dist_params = strdup(src->u.dir.hint.dist_params);
+                if (dest->u.dir.hint.dist_params == NULL)
+                {
+                    free(dest->u.dir.hint.dist_name);
+                    return ret;
+                }
+            }
+        }
+
         /*
           NOTE:
           we only copy the size out if we're actually a
@@ -253,6 +280,20 @@
                 }
             }
         }
+        else if (attr->objtype == PVFS_TYPE_DIRECTORY)
+        {
+            if ((attr->mask & PVFS_ATTR_DIR_HINT) || (attr->mask & PVFS_ATTR_DIR_DIRENT_COUNT))
+            {
+                if (attr->u.dir.hint.dist_name)
+                {
+                    free(attr->u.dir.hint.dist_name);
+                }
+                if (attr->u.dir.hint.dist_params)
+                {
+                    free(attr->u.dir.hint.dist_params);
+                }
+            }
+        }
     }
 }
 
diff -Naur pvfs2-old/src/common/misc/pvfs2-util.c pvfs2/src/common/misc/pvfs2-util.c
--- pvfs2-old/src/common/misc/pvfs2-util.c	2006-05-31 00:18:42.000000000 +0200
+++ pvfs2/src/common/misc/pvfs2-util.c	2006-06-07 03:48:46.000000000 +0200
@@ -175,6 +175,28 @@
                 return ret;
             }
         }
+        else if ((src_attr->mask & PVFS_ATTR_SYS_DIR_HINT))
+        {
+            if (src_attr->dist_name)
+            {
+                dest_attr->dist_name = strdup(src_attr->dist_name);
+                if (dest_attr->dist_name == NULL)
+                {
+                    ret = -PVFS_ENOMEM;
+                    return ret;
+                }
+            }
+            if (src_attr->dist_params)
+            {
+                dest_attr->dist_params = strdup(src_attr->dist_params);
+                if (dest_attr->dist_params == NULL)
+                {
+                    free(dest_attr->dist_name);
+                    ret = -PVFS_ENOMEM;
+                    return ret;
+                }
+            }
+        }
         ret = 0;
     }
     return ret;
@@ -190,6 +212,16 @@
             free(attr->link_target);
             attr->link_target = NULL;
         }
+        else if ((attr->mask & PVFS_ATTR_SYS_DIR_HINT) &&
+            (attr->objtype == PVFS_TYPE_DIRECTORY))
+        {
+            if (attr->dist_name)
+                free(attr->dist_name);
+            if (attr->dist_params)
+                free(attr->dist_params);
+            attr->dist_name = NULL;
+            attr->dist_params = NULL;
+        }
     }
 }
 
@@ -1471,6 +1503,11 @@
         attrmask |= PVFS_ATTR_DIR_DIRENT_COUNT;
     }
 
+    if (sys_attrmask & PVFS_ATTR_SYS_DIR_HINT)
+    {
+        attrmask |= PVFS_ATTR_DIR_HINT;
+    }
+
     if (sys_attrmask & PVFS_ATTR_SYS_LNK_TARGET)
     {
         attrmask |= PVFS_ATTR_SYMLNK_TARGET;
@@ -1532,6 +1569,10 @@
     {
         sys_mask |= PVFS_ATTR_SYS_DFILE_COUNT;
     }
+    if (obj_mask & PVFS_ATTR_DIR_HINT)
+    {
+        sys_mask |= PVFS_ATTR_SYS_DIR_HINT;
+    }
     return sys_mask;
 }
 
diff -Naur pvfs2-old/src/common/misc/str-utils.c pvfs2/src/common/misc/str-utils.c
--- pvfs2-old/src/common/misc/str-utils.c	2005-08-23 20:44:17.000000000 +0200
+++ pvfs2/src/common/misc/str-utils.c	2006-06-07 03:48:46.000000000 +0200
@@ -680,6 +680,134 @@
 #endif
 
 /*
+ * PINT_split_keyvals()
+ *
+ * Splits a given string into a number of key:val strings.
+ *
+ * Parameters:
+ * The given string must be comma separated, and each
+ * segment within the comma regions must be of of
+ * the form key:val.
+ * Return the number of such keyval pairs and a 
+ * pointer to a double dimensional array of keys and values.
+ * In case of errors, a -ve PVFS error is returned.
+ *
+ * Example inputs and return values:
+ *
+ * NULL - return -PVFS_EINVAL
+ * ab:23 - return nkey as 1, pkey <"ab">, pval <"23">
+ * ab:23,bc:34 - returns nkey as 2, pkey <"ab", "bc">, pval<"23", "34">
+ *
+ */
+int PINT_split_keyvals(char *string, int *nkey, 
+        char ***pkey, char ***pval)
+{
+    char **key, **val, *ptr, *params;
+    int nparams = 0, i;
+
+    if (string == NULL || nkey == NULL 
+            || pkey == NULL || pval == NULL)
+    {
+      return -PVFS_EINVAL;
+    }
+    params = strdup(string);
+    if (params == NULL)
+    {
+      return -PVFS_ENOMEM;
+    }
+    ptr = params;
+    while (ptr)
+    {
+        if (*ptr != ',' || *ptr != '\0')
+                 nparams++;
+        ptr++;
+        ptr = strchr(ptr, ',');
+    }
+    if (nparams == 0)
+    {
+      free(params);
+      return -PVFS_EINVAL;
+    }
+    ptr = params;
+    key = (char **) calloc(nparams, sizeof(char *));
+    val = (char **) calloc(nparams, sizeof(char *));
+    if (key == NULL || val ==  NULL)
+    {
+      free(key);
+      free(val);
+      free(params);
+      return -PVFS_ENOMEM;
+    }
+    for (i = 0; i < nparams; i++)
+    {
+        char *ptr2;
+        if (i > 0 && ptr)
+        {
+            *ptr = '\0';
+            ptr++;
+        }
+        else if (ptr == NULL)
+        {
+            break;
+        }
+        ptr2 = strchr(ptr, ':');
+        if (ptr2 == NULL)
+        {
+            break;
+        }
+        key[i] = ptr;
+        ptr = strchr(ptr, ',');
+        if (ptr != NULL && ptr < ptr2)
+        {
+            break;
+        }
+        *ptr2 = '\0';
+        val[i] = ptr2 + 1;
+    }
+    if (i != nparams)
+    {
+      free(key);
+      free(val);
+      free(params);
+      return -PVFS_EINVAL;
+    }
+    else
+    {
+      for (i = 0; i < nparams; i++)
+      {
+          char *ptr1, *ptr2;
+          ptr1 = strdup(key[i]);
+          ptr2 = strdup(val[i]);
+          if (ptr1 == NULL || ptr2 == NULL)
+              break;
+          if (strchr(ptr1, ':') || strchr(ptr2, ':'))
+              break;
+          key[i] = ptr1;
+          val[i] = ptr2;
+      }
+      if (i != nparams)
+      {
+          int j;
+          for (j = 0; j < i; j++)
+          {
+              if (key[j]) free(key[j]);
+              if (val[j]) free(val[j]);
+          }
+          free(key);
+          free(val);
+          free(params);
+          return -PVFS_EINVAL;
+      }
+      free(params);
+      *nkey = nparams;
+      *pkey = key;
+      *pval = val;
+      return 0;
+    }
+}
+
+
+/*
  * Local variables:
  *  c-indent-level: 4
  *  c-basic-offset: 4
diff -Naur pvfs2-old/src/common/misc/str-utils.h pvfs2/src/common/misc/str-utils.h
--- pvfs2-old/src/common/misc/str-utils.h	2005-08-23 20:44:17.000000000 +0200
+++ pvfs2/src/common/misc/str-utils.h	2006-06-07 03:48:46.000000000 +0200
@@ -60,6 +60,8 @@
 char *strstr(const char *haystack, const char *needle);
 #endif
 
+int PINT_split_keyvals(char *string, int *nkey, 
+        char ***pkey, char ***pval);
 #endif
 /*
  * Local variables:
diff -Naur pvfs2-old/src/kernel/linux-2.6/inode.c pvfs2/src/kernel/linux-2.6/inode.c
--- pvfs2-old/src/kernel/linux-2.6/inode.c	2006-01-07 04:08:59.000000000 +0100
+++ pvfs2/src/kernel/linux-2.6/inode.c	2006-06-07 03:48:46.000000000 +0200
@@ -341,7 +341,7 @@
      * A revalidate expects that all fields of the inode would be refreshed
      * So we have no choice but to refresh all attributes.
      */
-    ret = pvfs2_inode_getattr(inode, PVFS_ATTR_SYS_ALL);
+    ret = pvfs2_inode_getattr(inode, PVFS_ATTR_SYS_ALL_NOHINT);
     if (ret)
     {
         /* assume an I/O error and flag inode as bad */
@@ -367,7 +367,7 @@
      * of the inode would be refreshed. So again, we dont have too much of a choice
      * but refresh all the attributes.
      */
-    ret = pvfs2_inode_getattr(inode, PVFS_ATTR_SYS_ALL);
+    ret = pvfs2_inode_getattr(inode, PVFS_ATTR_SYS_ALL_NOHINT);
     if (ret == 0)
     {
         generic_fillattr(inode, kstat);
diff -Naur pvfs2-old/src/kernel/linux-2.6/pvfs2-kernel.h pvfs2/src/kernel/linux-2.6/pvfs2-kernel.h
--- pvfs2-old/src/kernel/linux-2.6/pvfs2-kernel.h	2006-05-30 06:53:27.000000000 +0200
+++ pvfs2/src/kernel/linux-2.6/pvfs2-kernel.h	2006-06-07 03:48:46.000000000 +0200
@@ -930,7 +930,7 @@
          * The dentry revalidating function expects that all fields of the inode
          * would be refreshed, so we dont have much of a choice here too.
          */
-        ret = ((pvfs2_inode_getattr(inode, PVFS_ATTR_SYS_ALL) == 0) ? 1 : 0);
+        ret = ((pvfs2_inode_getattr(inode, PVFS_ATTR_SYS_ALL_NOHINT) == 0) ? 1 : 0);
 #if 0
 /* Calling make_bad_inode() here results in a bad reference count on the
  * inode.  It therefore gets cached until the module is unloaded, when we get 
diff -Naur pvfs2-old/src/kernel/linux-2.6/super.c pvfs2/src/kernel/linux-2.6/super.c
--- pvfs2-old/src/kernel/linux-2.6/super.c	2006-05-05 02:48:00.000000000 +0200
+++ pvfs2/src/kernel/linux-2.6/super.c	2006-06-07 03:51:10.000000000 +0200
@@ -213,7 +213,7 @@
        called after a successful dentry lookup if the inode is not
        present in the inode cache already.  so this is our chance.
     */
-    if (pvfs2_inode_getattr(inode, PVFS_ATTR_SYS_ALL) != 0)
+    if (pvfs2_inode_getattr(inode, PVFS_ATTR_SYS_ALL_NOHINT) != 0)
     {
         /* assume an I/O error and mark the inode as bad */
         pvfs2_make_bad_inode(inode);
@@ -245,7 +245,7 @@
         pvfs2_print("pvfs2: pvfs2_read_inode: allocated %p (inode = %lu | "
                 "ct = %d)\n", pvfs2_inode, inode->i_ino,
                 (int)atomic_read(&inode->i_count));
-        if (pvfs2_inode_getattr(inode, PVFS_ATTR_SYS_ALL) != 0)
+        if (pvfs2_inode_getattr(inode, PVFS_ATTR_SYS_ALL_NOHINT) != 0)
         {
             pvfs2_make_bad_inode(inode);
         }
diff -Naur pvfs2-old/src/proto/PINT-le-bytefield.c pvfs2/src/proto/PINT-le-bytefield.c
--- pvfs2-old/src/proto/PINT-le-bytefield.c	2005-12-23 23:22:14.000000000 +0100
+++ pvfs2/src/proto/PINT-le-bytefield.c	2006-06-07 03:48:46.000000000 +0200
@@ -657,7 +657,8 @@
 #undef CASE
 
     if (ptr != (char *)input_buffer + input_size) {
-	gossip_lerr("%s: improper input buffer size", __func__);
+	gossip_lerr("%s: improper input buffer size [%p + %d != %p]\n", __func__,
+                input_buffer, input_size, ptr);
 	ret = -PVFS_EPROTO;
     }
 
diff -Naur pvfs2-old/src/proto/endecode-funcs.h pvfs2/src/proto/endecode-funcs.h
--- pvfs2-old/src/proto/endecode-funcs.h	2006-06-05 21:57:27.000000000 +0200
+++ pvfs2/src/proto/endecode-funcs.h	2006-06-07 03:48:46.000000000 +0200
@@ -229,6 +229,26 @@
 #define endecode_fields_5_struct(name, t1, x1, t2, x2, t3, x3, t4, x4, t5, x5) \
     endecode_fields_5_generic(name, struct name, t1, x1, t2, x2, t3, x3, t4, x4, t5, x5)
 
+#define endecode_fields_7(name,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7) \
+static inline void encode_##name(char **pptr, const name *x) { \
+    encode_##t1(pptr, &x->x1); \
+    encode_##t2(pptr, &x->x2); \
+    encode_##t3(pptr, &x->x3); \
+    encode_##t4(pptr, &x->x4); \
+    encode_##t5(pptr, &x->x5); \
+    encode_##t6(pptr, &x->x6); \
+    encode_##t7(pptr, &x->x7); \
+} \
+static inline void decode_##name(char **pptr, name *x) { \
+    decode_##t1(pptr, &x->x1); \
+    decode_##t2(pptr, &x->x2); \
+    decode_##t3(pptr, &x->x3); \
+    decode_##t4(pptr, &x->x4); \
+    decode_##t5(pptr, &x->x5); \
+    decode_##t6(pptr, &x->x6); \
+    decode_##t7(pptr, &x->x7); \
+}
+
 #define endecode_fields_7_struct(name,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7) \
 static inline void encode_##name(char **pptr, const struct name *x) { \
     encode_##t1(pptr, &x->x1); \
diff -Naur pvfs2-old/src/proto/pvfs2-attr.h pvfs2/src/proto/pvfs2-attr.h
--- pvfs2-old/src/proto/pvfs2-attr.h	2005-10-06 15:43:04.000000000 +0200
+++ pvfs2/src/proto/pvfs2-attr.h	2006-06-07 03:48:46.000000000 +0200
@@ -44,7 +44,9 @@
 
 /* internal attribute masks for directory objects */
 #define PVFS_ATTR_DIR_DIRENT_COUNT         (1 << 19)
-#define PVFS_ATTR_DIR_ALL PVFS_ATTR_DIR_DIRENT_COUNT
+#define PVFS_ATTR_DIR_HINT                  (1 << 20)
+#define PVFS_ATTR_DIR_ALL \
+(PVFS_ATTR_DIR_DIRENT_COUNT | PVFS_ATTR_DIR_HINT)
 
 /* attributes specific to metadata objects */
 struct PVFS_metafile_attr_s
@@ -90,13 +92,49 @@
 typedef struct PVFS_datafile_attr_s PVFS_datafile_attr;
 endecode_fields_1(PVFS_datafile_attr, PVFS_size, size)
 
+/* extended hint attributes for a directory object */
+struct PVFS_directory_hint_s
+{
+    uint32_t  dist_name_len;
+    /* what is the distribution name? */
+    char     *dist_name;
+    /* what are the distribution parameters? */
+    uint32_t  dist_params_len;
+    char     *dist_params;
+    /* how many dfiles ought to be used */
+    uint32_t dfile_count;
+};
+typedef struct PVFS_directory_hint_s PVFS_directory_hint;
+
+#ifdef __PINT_REQPROTO_ENCODE_FUNCS_C
+endecode_fields_7(PVFS_directory_hint,
+        uint32_t, dist_name_len,
+        skip4,,
+        string, dist_name,
+        uint32_t, dist_params_len,
+        skip4,,
+        string, dist_params,
+        uint32_t, dfile_count)
+#endif
+
 /* attributes specific to directory objects */
 struct PVFS_directory_attr_s
 {
     PVFS_size dirent_count;
+    PVFS_directory_hint hint;
 };
 typedef struct PVFS_directory_attr_s PVFS_directory_attr;
-endecode_fields_1(PVFS_directory_attr, PVFS_size, dirent_count)
+
+#ifdef __PINT_REQPROTO_ENCODE_FUNCS_C
+#define encode_PVFS_directory_attr(pptr, x) do { \
+    encode_PVFS_size(pptr, &(x)->dirent_count);\
+    encode_PVFS_directory_hint(pptr, &(x)->hint);\
+} while(0)
+#define decode_PVFS_directory_attr(pptr, x) do { \
+    decode_PVFS_size(pptr, &(x)->dirent_count);\
+    decode_PVFS_directory_hint(pptr, &(x)->hint);\
+} while(0)
+#endif
 
 /* attributes specific to symlinks */
 struct PVFS_symlink_attr_s
@@ -151,7 +189,7 @@
 	encode_PVFS_datafile_attr(pptr, &(x)->u.data); \
     if ((x)->mask & PVFS_ATTR_SYMLNK_TARGET) \
 	encode_PVFS_symlink_attr(pptr, &(x)->u.sym); \
-    if ((x)->mask & PVFS_ATTR_DIR_DIRENT_COUNT) \
+    if (((x)->mask & PVFS_ATTR_DIR_DIRENT_COUNT) || ((x)->mask & PVFS_ATTR_DIR_HINT)) \
 	encode_PVFS_directory_attr(pptr, &(x)->u.dir); \
 } while (0)
 #define decode_PVFS_object_attr(pptr,x) do { \
@@ -172,18 +210,26 @@
 	decode_PVFS_datafile_attr(pptr, &(x)->u.data); \
     if ((x)->mask & PVFS_ATTR_SYMLNK_TARGET) \
 	decode_PVFS_symlink_attr(pptr, &(x)->u.sym); \
-    if ((x)->mask & PVFS_ATTR_DIR_DIRENT_COUNT) \
+    if (((x)->mask & PVFS_ATTR_DIR_DIRENT_COUNT) || ((x)->mask & PVFS_ATTR_DIR_HINT)) \
 	decode_PVFS_directory_attr(pptr, &(x)->u.dir); \
 } while (0)
 #endif
-/* attr buffer needs room for larger of symlink path or meta fields: an attrib
- * structure can never hold information for both a symlink and a metafile  */
+/* attr buffer needs room for larger of symlink path, meta fields or dir hints: an attrib
+ * structure can never hold information for not more than a symlink or a metafile or a dir object */
+#define extra_size_PVFS_object_attr_dir  (PVFS_REQ_LIMIT_DIST_BYTES + \
+  PVFS_REQ_LIMIT_DIST_NAME + roundup8(sizeof(PVFS_directory_attr)))
+
 #define extra_size_PVFS_object_attr_meta (PVFS_REQ_LIMIT_DIST_BYTES + \
   PVFS_REQ_LIMIT_DFILE_COUNT * sizeof(PVFS_handle))
+
 #define extra_size_PVFS_object_attr_symlink (PVFS_REQ_LIMIT_PATH_NAME_BYTES)
-#define extra_size_PVFS_object_attr ((extra_size_PVFS_object_attr_meta > \
- extra_size_PVFS_object_attr_symlink) ? extra_size_PVFS_object_attr_meta : \
- extra_size_PVFS_object_attr_symlink)
+
+#ifndef max3
+#define max3(a, b, c) (a) < (b) ? (b) < (c) ? (c) : (b) : (a) < (c) ? (c) : (a)
+#endif
+
+#define extra_size_PVFS_object_attr \
+        max3(extra_size_PVFS_object_attr_meta, extra_size_PVFS_object_attr_symlink, extra_size_PVFS_object_attr_dir)
 
 #endif /* __PVFS2_ATTR_H */
 
diff -Naur pvfs2-old/src/proto/pvfs2-req-proto.h pvfs2/src/proto/pvfs2-req-proto.h
--- pvfs2-old/src/proto/pvfs2-req-proto.h	2006-05-19 03:03:59.000000000 +0200
+++ pvfs2/src/proto/pvfs2-req-proto.h	2006-06-07 03:48:46.000000000 +0200
@@ -108,6 +108,8 @@
 #define PVFS_REQ_LIMIT_SEGMENT_BYTES      PVFS_SEGMENT_MAX
 /* max total size of I/O request descriptions */
 #define PVFS_REQ_LIMIT_IOREQ_BYTES        8192
+/* maximum size of distribution name used for the hints */
+#define PVFS_REQ_LIMIT_DIST_NAME          128
 /* max count of segments allowed per path lookup (note that this governs 
  * the number of handles and attributes returned in lookup_path responses)
  */
diff -Naur pvfs2-old/src/server/get-attr.sm pvfs2/src/server/get-attr.sm
--- pvfs2-old/src/server/get-attr.sm	2006-06-05 21:57:28.000000000 +0200
+++ pvfs2/src/server/get-attr.sm	2006-06-07 03:52:25.000000000 +0200
@@ -29,6 +29,21 @@
 #include "pint-util.h"
 #include "pvfs2-internal.h"
 
+enum 
+{
+    DIST_NAME_KEY = 0,
+    DIST_PARAMS_KEY = 1,
+    NUM_DFILES_KEY = 2,
+    NUM_SPECIAL_KEYS = 3,
+};
+
+PINT_server_trove_keys_s Trove_Special_Keys[] =
+{
+    {"user.pvfs2.dist_name", 21},
+    {"user.pvfs2.dist_params", 23},
+    {"user.pvfs2.num_dfiles", 22},
+};
+
 enum
 {
     STATE_METAFILE = 7,
@@ -46,6 +61,10 @@
     PINT_server_op *s_op, job_status_s *js_p);
 static int getattr_interpret_dirent_count(
     PINT_server_op *s_op, job_status_s *js_p);
+static int getattr_get_dir_hint(
+    PINT_server_op *s_op, job_status_s *js_p);
+static int getattr_interpret_dir_hint(
+    PINT_server_op *s_op, job_status_s *js_p);
 static int getattr_read_metafile_datafile_handles_if_required(
     PINT_server_op *s_op, job_status_s *js_p);
 static int getattr_read_metafile_distribution_if_required(
@@ -66,6 +85,8 @@
     read_metafile_distribution_if_required,
     get_dirent_count,
     interpret_dirent_count,
+    get_dir_hint,
+    interpret_dir_hint,
     setup_resp)
 {
     state verify_attribs
@@ -106,6 +127,18 @@
     state interpret_dirent_count
     {
         run getattr_interpret_dirent_count;
+        default => get_dir_hint;
+    }
+
+    state get_dir_hint
+    {
+        run getattr_get_dir_hint;
+        default => interpret_dir_hint;
+    }
+
+    state interpret_dir_hint
+    {
+        run getattr_interpret_dir_hint;
         default => setup_resp;
     }
 
@@ -321,6 +354,20 @@
             js_p->error_code = 0;
             assert(resp_attr->mask & PVFS_ATTR_COMMON_ALL);
         }
+        if (s_op->u.getattr.attrmask & PVFS_ATTR_DIR_HINT)
+        {
+            gossip_debug(GOSSIP_GETATTR_DEBUG,
+                        " getattr: dfile_count needed.\n");
+            assert(resp_attr->mask & PVFS_ATTR_COMMON_ALL);
+            resp_attr->mask |= PVFS_ATTR_DIR_HINT;
+            js_p->error_code = STATE_DIR;
+        }
+        else
+        {
+            gossip_debug(GOSSIP_GETATTR_DEBUG,
+                        " getattr: dfile_count not needed\n");
+            assert(resp_attr->mask & PVFS_ATTR_COMMON_ALL);
+        }
     }
     else if (resp_attr->objtype == PVFS_TYPE_DIRDATA)
     {
@@ -639,6 +686,17 @@
             return 1;
         }
     }
+    else if ((resp_attr->objtype == PVFS_TYPE_DIRECTORY) &&
+            (resp_attr->mask & PVFS_ATTR_DIR_HINT))
+    {
+        gossip_debug(GOSSIP_GETATTR_DEBUG, " server returning "
+            "dfile_count = %d "
+            "dist_name_len    = %d "
+            "dist_params_len  = %d\n",
+            resp_attr->u.dir.hint.dfile_count,
+            resp_attr->u.dir.hint.dist_name_len,
+            resp_attr->u.dir.hint.dist_params_len);
+    }
 
     gossip_debug(GOSSIP_GETATTR_DEBUG,"@ End %s attributes: sending "
                  "status %d (error = %d)\n",
@@ -656,6 +714,27 @@
 
 static int getattr_cleanup(PINT_server_op *s_op, job_status_s *js_p)
 {
+
+    if(s_op->val_a)
+    {
+        if(s_op->val_a[NUM_DFILES_KEY].buffer)
+        {
+            free(s_op->val_a[NUM_DFILES_KEY].buffer);
+        }
+        free(s_op->val_a);
+        s_op->val_a = NULL;
+    }
+    if(s_op->key_a)
+    {
+        free(s_op->key_a);
+        s_op->key_a = NULL;
+    }
+    if(s_op->u.getattr.err_array)
+    {
+        free(s_op->u.getattr.err_array);
+        s_op->u.getattr.err_array = NULL;
+    }
+
     PINT_free_object_attr(&s_op->resp.u.getattr.attr);
     return(server_state_machine_complete(s_op));
 }
@@ -712,6 +791,177 @@
     return 1;
 }
 
+static int getattr_get_dir_hint(
+    PINT_server_op *s_op, job_status_s *js_p)
+{
+    int ret, i;
+    job_id_t tmp_id;
+
+    /* NOTE: memory allocations are released in the getattr_cleanup()
+     * function 
+     */
+   
+    PINT_STATE_DEBUG("get_dir_hint");
+
+    gossip_debug(GOSSIP_SERVER_DEBUG, "  trying to getxattr of %s,%s,%s "
+                 "of dir handle (coll_id = %d, handle = %llu\n",
+                 Trove_Special_Keys[DIST_NAME_KEY].key,
+                 Trove_Special_Keys[DIST_PARAMS_KEY].key, 
+                 Trove_Special_Keys[NUM_DFILES_KEY].key,
+                 s_op->u.getattr.fs_id, llu(s_op->u.getattr.handle));
+
+    s_op->resp.u.getattr.attr.u.dir.hint.dist_params = 
+        (char *) calloc(1, PVFS_REQ_LIMIT_DIST_BYTES);
+    if (!s_op->resp.u.getattr.attr.u.dir.hint.dist_params)
+    {
+        js_p->error_code = -PVFS_ENOMEM;
+        return 1;
+    }
+    s_op->resp.u.getattr.attr.u.dir.hint.dist_params_len = 
+        PVFS_REQ_LIMIT_DIST_BYTES;
+
+    s_op->resp.u.getattr.attr.u.dir.hint.dist_name = 
+        (char *) calloc(1, PVFS_REQ_LIMIT_DIST_NAME);
+    if (!s_op->resp.u.getattr.attr.u.dir.hint.dist_name)
+    {
+        js_p->error_code = -PVFS_ENOMEM;
+        return 1;
+    }
+    s_op->resp.u.getattr.attr.u.dir.hint.dist_name_len   = 
+        PVFS_REQ_LIMIT_DIST_NAME;
+
+    s_op->key_a = 
+        (PVFS_ds_keyval *) calloc(NUM_SPECIAL_KEYS, sizeof(PVFS_ds_keyval));
+    if (s_op->key_a == NULL)
+    {
+        js_p->error_code = -PVFS_ENOMEM;
+        return 1;
+    }
+    s_op->val_a = (PVFS_ds_keyval *) calloc(NUM_SPECIAL_KEYS, sizeof(PVFS_ds_keyval));
+    if (s_op->val_a == NULL)
+    {
+        js_p->error_code = -PVFS_ENOMEM;
+        return 1;
+    }
+    s_op->u.getattr.err_array = (PVFS_error*)calloc(NUM_SPECIAL_KEYS,
+        sizeof(PVFS_error));
+    if(s_op->u.getattr.err_array == NULL)
+    {
+        js_p->error_code = -PVFS_ENOMEM;
+        return 1;
+
+    }
+    for (i = 0; i < NUM_SPECIAL_KEYS; i++)
+    {
+        s_op->key_a[i].buffer = Trove_Special_Keys[i].key;
+        s_op->key_a[i].buffer_sz = Trove_Special_Keys[i].size;
+        if (i == NUM_DFILES_KEY)
+        {
+            s_op->val_a[i].buffer = (char *) calloc(1, 16);
+            if(s_op->val_a[i].buffer == NULL)
+            {
+                js_p->error_code = -PVFS_ENOMEM;
+                return 1;
+            }
+            s_op->val_a[i].buffer_sz = 16;
+        }
+        else if (i == DIST_PARAMS_KEY) {
+            s_op->val_a[i].buffer = s_op->resp.u.getattr.attr.u.dir.hint.dist_params;
+            s_op->val_a[i].buffer_sz = s_op->resp.u.getattr.attr.u.dir.hint.dist_params_len;
+        }
+        else if (i == DIST_NAME_KEY) {
+            s_op->val_a[i].buffer = s_op->resp.u.getattr.attr.u.dir.hint.dist_name;
+            s_op->val_a[i].buffer_sz = s_op->resp.u.getattr.attr.u.dir.hint.dist_name_len;
+        }
+    }
+
+    js_p->error_code = 0;
+    ret = job_trove_keyval_read_list(
+        s_op->req->u.getattr.fs_id, 
+        s_op->req->u.getattr.handle,
+        s_op->key_a, s_op->val_a, s_op->u.getattr.err_array, NUM_SPECIAL_KEYS,
+        0, NULL, s_op, 0, js_p, &tmp_id,
+        server_job_context);
+
+    return ret;
+}
+
+static int getattr_interpret_dir_hint(
+    PINT_server_op *s_op, job_status_s *js_p)
+{
+    PINT_STATE_DEBUG("interpret_dfile_count");
+
+    if(js_p->error_code != 0 && js_p->error_code != -TROVE_ENOENT)
+    {
+        /* if we failed to get any of the keys, and the error code is due to
+         * something other than the keys simply not being present, then
+         * propigate the error.
+         */
+        return(1);
+    }
+
+    gossip_debug(GOSSIP_SERVER_DEBUG, 
+        "getattr: job status code = %d\n", js_p->error_code);
+    if (s_op->val_a && s_op->key_a)
+    {
+        long int dfile_count = 0;
+
+        if (s_op->u.getattr.err_array[DIST_NAME_KEY] == 0)
+        {
+            gossip_debug(GOSSIP_SERVER_DEBUG, 
+                "val_a[DIST_NAME_KEY] %p read_sz = %d dist_name = %s\n", 
+                s_op->val_a[DIST_NAME_KEY].buffer, 
+                s_op->val_a[DIST_NAME_KEY].read_sz,
+                (char *)s_op->val_a[DIST_NAME_KEY].buffer);
+            s_op->resp.u.getattr.attr.u.dir.hint.dist_name_len = 
+                s_op->val_a[DIST_NAME_KEY].read_sz;
+        }
+        else
+        {
+            s_op->resp.u.getattr.attr.u.dir.hint.dist_name_len = 0;
+        }
+
+        if (s_op->u.getattr.err_array[DIST_PARAMS_KEY] == 0)
+        {
+            gossip_debug(GOSSIP_SERVER_DEBUG, 
+                "val_a[DIST_PARAMS_KEY] %p read_sz = %d dist_params = %s\n", 
+                s_op->val_a[DIST_PARAMS_KEY].buffer, 
+                s_op->val_a[DIST_PARAMS_KEY].read_sz,
+                (char *)s_op->val_a[DIST_PARAMS_KEY].buffer);
+            s_op->resp.u.getattr.attr.u.dir.hint.dist_params_len = 
+                s_op->val_a[DIST_PARAMS_KEY].read_sz;
+        }
+        else
+        {
+            s_op->resp.u.getattr.attr.u.dir.hint.dist_params_len = 0;
+        }
+
+        if (s_op->u.getattr.err_array[NUM_DFILES_KEY] == 0)
+        {
+            char *endptr = NULL;
+            gossip_debug(GOSSIP_SERVER_DEBUG, "val_a[NUM_DFILES_KEY] %p read_sz = %d\n", 
+                s_op->val_a[NUM_DFILES_KEY].buffer, 
+                s_op->val_a[NUM_DFILES_KEY].read_sz);
+            dfile_count = strtol(s_op->val_a[NUM_DFILES_KEY].buffer, &endptr, 10);
+            if (*endptr != '\0' || dfile_count < 0)
+            {
+                dfile_count = 0;
+            }
+            free(s_op->val_a[NUM_DFILES_KEY].buffer);
+            s_op->val_a[NUM_DFILES_KEY].buffer = NULL;
+            s_op->val_a[NUM_DFILES_KEY].buffer_sz = 0;
+        }
+
+        s_op->resp.u.getattr.attr.u.dir.hint.dfile_count = dfile_count;
+
+        gossip_debug(GOSSIP_SERVER_DEBUG, "getattr: dfile_count: %d\n",
+            s_op->resp.u.getattr.attr.u.dir.hint.dfile_count);
+
+        js_p->error_code = 0;
+    }
+    return 1;
+}
+
 /*
  * Local variables:
  *  mode: c
diff -Naur pvfs2-old/src/server/pvfs2-server.h pvfs2/src/server/pvfs2-server.h
--- pvfs2-old/src/server/pvfs2-server.h	2006-06-05 21:57:28.000000000 +0200
+++ pvfs2/src/server/pvfs2-server.h	2006-06-07 03:48:46.000000000 +0200
@@ -311,6 +311,7 @@
     PVFS_fs_id fs_id;
     PVFS_ds_attributes dirdata_ds_attr;
     uint32_t attrmask;
+    PVFS_error* err_array;
 };
 
 /* this is used in both set_eattr, get_eattr and list_eattr */
Index: pvfs2_src/doc/pvfs2-faq.tex
===================================================================
--- pvfs2_src/doc/pvfs2-faq.tex	(revision 2098)
+++ pvfs2_src/doc/pvfs2-faq.tex	(revision 2099)
@@ -759,6 +759,52 @@
 to use, we suggest ext3 with ``journal data writeback'' option as a
 reasonable choice.
 
+\subsection{Is there any way to tune particular directories for different
+workloads?}
+
+Yes.  This can be done by using extended attributes to set directory
+hints.  Three hints are currently supported, and they allow you to specify
+the distribution, distribution parameters, and number of datafiles to
+stripe across.  They will not change the characteristics of existing
+files, but they will take effect for any newly created files within the
+directory.  These hints will also be inherited by any new
+subdirectories.
+
+\subsubsection{Distribution}
+
+The distribution can be set as follows:
+
+\begin{verbatim}
+prompt# setfattr -n "user.pvfs2.dist_name" -v "basic_dist" /mnt/pvfs2/directory
+\end{verbatim}
+
+Supported distribution names can be found by looking in the pvfs2-dist-*
+header files.
+
+\subsubsection{Distribution parameters}
+
+Some distributions allow you to set parameters that impact how the
+distribution behaves.  These parameters can be set as follows:
+
+\begin{verbatim}
+prompt# setfattr -n "user.pvfs2.dist_params" -v "strip_size:4096" /mnt/pvfs2/directory
+\end{verbatim}
+
+You can specify more than one "parameter:value" pair by seperating them with
+commas.
+
+\subsubsection{Number of datafiles}
+
+You can also specify the number of datafiles to stripe across: 
+
+\begin{verbatim}
+prompt# setfattr -n "user.pvfs2.num_dfiles" -v "1" /mnt/pvfs2/directory
+\end{verbatim}
+
+PVFS2 defaults to striping files across each server in the file system.
+However, you may find that for small files it is advantages to limit each
+file to only a subset of servers (or even just one).
+
 \subsection{My app still runs more slowly than I would like.  What can I do?}
 \label{sec:tuning}
 
_______________________________________________
Pvfs2-developers mailing list
Pvfs2-developers@beowulf-underground.org
http://www.beowulf-underground.org/mailman/listinfo/pvfs2-developers

Reply via email to